initial commit

This commit is contained in:
Данила Горнушко 2023-11-22 14:48:03 +03:00
commit 3fb1c8dd81
20 changed files with 2776 additions and 0 deletions

143
.clang-format Normal file
View file

@ -0,0 +1,143 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: None
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortEnumsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: true
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: true
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: BeforeHash
IndentWidth: 4
IndentWrappedFunctionNames: false
# Requires Clang >= 15, could also cause incorrect code formatting:
# InsertBraces: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReferenceAlignment: Pointer
ReflowComments: true
SeparateDefinitionBlocks: Always
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
SpaceAroundPointerQualifiers: Default
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...

3
.clangd Normal file
View file

@ -0,0 +1,3 @@
CompileFlags:
Add: [-march=rv32imc]
Remove: [-fstrict-volatile-bitfields, -fno-tree-switch-conversion, -fstrict-volatile-bitfields, -mlongcalls]

26
.editorconfig Normal file
View file

@ -0,0 +1,26 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Set default charset
charset = utf-8
# 4 space indentation
[*.{c, h, cpp}]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.devcontainer
.vscode
build
sdkconfig.old
dependencies.lock
.idea/
cmake-build-debug/
.cache/

6
CMakeLists.txt Normal file
View file

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(can_wizard)

154
README.md Normal file
View file

@ -0,0 +1,154 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- |
# Console Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example illustrates the usage of the [Console Component](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/console.html#console) to create an interactive shell on the ESP32. The interactive shell running on the ESP32 can then be controlled/interacted with over a serial port (UART).
The interactive shell implemented in this example contains a wide variety of commands, and can act as a basis for applications that require a command-line interface (CLI).
## How to use example
### Hardware Required
This example should be able to run on any commonly available ESP32 development board.
### Configure the project
```
idf.py menuconfig
```
* Enable/disable `Example Configuration > Store command history in flash` as necessary
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
Enter the `help` command get a full list of all available commands. The following is a sample session of the Console Example where a variety of commands provided by the Console Example are used. Note that GPIO15 is connected to GND to remove the boot log output.
```
This is an example of ESP-IDF console component.
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
[esp32]> help
help
Print the list of registered commands
free
Get the total size of heap memory available
restart
Restart the program
deep_sleep [-t <t>] [--io=<n>] [--io_level=<0|1>]
Enter deep sleep mode. Two wakeup modes are supported: timer and GPIO. If no
wakeup option is specified, will sleep indefinitely.
-t, --time=<t> Wake up time, ms
--io=<n> If specified, wakeup using GPIO with given number
--io_level=<0|1> GPIO level to trigger wakeup
join [--timeout=<t>] <ssid> [<pass>]
Join WiFi AP as a station
--timeout=<t> Connection timeout, ms
<ssid> SSID of AP
<pass> PSK of AP
[esp32]> free
257200
[esp32]> deep_sleep -t 1000
I (146929) deep_sleep: Enabling timer wakeup, timeout=1000000us
I (619) heap_init: Initializing. RAM available for dynamic allocation:
I (620) heap_init: At 3FFAE2A0 len 00001D60 (7 KiB): DRAM
I (626) heap_init: At 3FFB7EA0 len 00028160 (160 KiB): DRAM
I (645) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (664) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (684) heap_init: At 40093EA8 len 0000C158 (48 KiB): IRAM
This is an example of ESP-IDF console component.
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
[esp32]> join --timeout 10000 test_ap test_password
I (182639) connect: Connecting to 'test_ap'
I (184619) connect: Connected
[esp32]> free
212328
[esp32]> restart
I (205639) restart: Restarting
I (616) heap_init: Initializing. RAM available for dynamic allocation:
I (617) heap_init: At 3FFAE2A0 len 00001D60 (7 KiB): DRAM
I (623) heap_init: At 3FFB7EA0 len 00028160 (160 KiB): DRAM
I (642) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (661) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (681) heap_init: At 40093EA8 len 0000C158 (48 KiB): IRAM
This is an example of ESP-IDF console component.
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
[esp32]>
```
## Troubleshooting
### Line Endings
The line endings in the Console Example are configured to match particular serial monitors. Therefore, if the following log output appears, consider using a different serial monitor (e.g. Putty for Windows) or modify the example's [UART configuration](#Configuring-UART-and-VFS).
```
This is an example of ESP-IDF console component.
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
Your terminal application does not support escape sequences.
Line editing and history features are disabled.
On Windows, try using Putty instead.
esp32>
```
## Example Breakdown
### Configuring UART
The ``initialize_console()`` function in the example configures some aspects of UART relevant to the operation of the console.
- **Line Endings**: The default line endings are configured to match those expected/generated by common serial monitor programs, such as `screen`, `minicom`, and the `esp-idf-monitor` included in the SDK. The default behavior for these commands are:
- When 'enter' key is pressed on the keyboard, `CR` (0x13) code is sent to the serial device.
- To move the cursor to the beginning of the next line, serial device needs to send `CR LF` (0x13 0x10) sequence.
### Line editing
The main source file of the example illustrates how to use `linenoise` library, including line completion, hints, and history.
### Commands
Several commands are registered using `esp_console_cmd_register()` function. See the `register_wifi()` and `register_system()` functions in `cmd_wifi.c` and `cmd_system.c` files.
### Command handling
Main loop inside `app_main()` function illustrates how to use `linenoise` and `esp_console_run()` to implement read/eval loop.
### Argument parsing
Several commands implemented in `cmd_wifi.c` and `cmd_system.c` use the Argtable3 library to parse and check the arguments.
### Command history
Each time a new command line is obtained from `linenoise`, it is written into history and the history is saved into a file in flash memory. On reset, history is initialized from that file.

13
main/CMakeLists.txt Normal file
View file

@ -0,0 +1,13 @@
set(COMPONENT_SRCS
"main.c"
"cmd_system.c"
"can.c"
"console_task.c"
"fs.c"
)
set(COMPONENT_ADD_INCLUDEDIRS
"."
)
register_component()

15
main/Kconfig.env_caps Normal file
View file

@ -0,0 +1,15 @@
config ENV_GPIO_RANGE_MIN
int
default 0
config ENV_GPIO_RANGE_MAX
int
default 21
config ENV_GPIO_IN_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX

37
main/Kconfig.projbuild Normal file
View file

@ -0,0 +1,37 @@
menu "Can_wizard Configuration"
orsource "Kconfig.env_caps"
config CAN_RX_GPIO
int "CAN RX GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 9
help
GPIO number (IOxx) to connect ESP to CAN transceiver.
Some GPIOs are used for other purposes (USB, flash connections, etc.) and cannot be used for CAN.
config CAN_TX_GPIO
int "CAN TX GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 8
help
GPIO number (IOxx) to connect ESP to CAN transceiver.
Some GPIOs are used for other purposes (USB, flash connections, etc.) and cannot be used for CAN.
config CAN_TASK_PRIORITY
int "CAN task priority"
range 0 22
default 5
help
A priority of FreeRTOS task can_task. See more about tasks priorities in FreeRTOS documentation.
config CONSOLE_TASK_PRIORITY
int "Console task priority"
range 0 22
default 2
help
A priority of FreeRTOS task can_task. See more about tasks priorities in FreeRTOS documentation.
endmenu

81
main/can.c Normal file
View file

@ -0,0 +1,81 @@
//
// Created by okhsunrog on 8/17/23.
//
#include "can.h"
#include "esp_log.h"
#include "hal/twai_types.h"
#include "sdkconfig.h"
#include <stdio.h>
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS();
static const twai_general_config_t g_config = {
.mode = TWAI_MODE_NORMAL,
.tx_io = CONFIG_CAN_TX_GPIO,
.rx_io = CONFIG_CAN_RX_GPIO,
.clkout_io = TWAI_IO_UNUSED,
.bus_off_io = TWAI_IO_UNUSED,
.tx_queue_len = 5,
.rx_queue_len = 5,
.alerts_enabled = TWAI_ALERT_BUS_OFF | TWAI_ALERT_BUS_RECOVERED,
.clkout_divider = 0,
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
static const char* LOG_TAG = "can";
void can_init() {
// Install CAN driver
// calculate_hw_can_filter(CONFIG_DEVICE_ID, &f_config, false);
static twai_filter_config_t f_config = {.acceptance_code = 0, .acceptance_mask = 0xFFFFFFFF, .single_filter = true};
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
ESP_LOGI(LOG_TAG, "CAN driver installed");
// Start CAN driver
ESP_ERROR_CHECK(twai_start());
ESP_LOGI(LOG_TAG, "CAN driver started");
}
void can_stop() {
// stop and uninstall twai driver to change hardware filters
ESP_ERROR_CHECK(twai_stop());
ESP_ERROR_CHECK(twai_driver_uninstall());
}
// filtering subset of CAN IDs with hardware filters, need more filtering in software
void calculate_hw_can_filter(uint32_t device_id, twai_filter_config_t* filter, bool ota_mode) {
filter->single_filter = true;
filter->acceptance_code = device_id << 11;
if (ota_mode) {
filter->acceptance_code += 0x100000 << 11;
filter->acceptance_mask = ~((0x1000FF) << 11);
} else {
filter->acceptance_mask = ~((device_id | 0x1F0000) << 11);
}
}
void can_bus_off_check() {
uint32_t alerts = 0;
if (twai_read_alerts(&alerts, 0) == ESP_OK) {
if (alerts & TWAI_ALERT_BUS_OFF) {
ESP_ERROR_CHECK(twai_initiate_recovery());
}
if (alerts & TWAI_ALERT_BUS_RECOVERED) {
ESP_ERROR_CHECK(twai_start());
}
}
}
void can_task(void* arg) {
twai_message_t rx_msg;
// ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
for (;;) { // A Task shall never return or exit.
// esp_task_wdt_reset();
can_bus_off_check();
if (twai_receive(&rx_msg, pdMS_TO_TICKS(10)) != ESP_OK) continue;
// TODO: add software filtering
// if ((((rx_msg.identifier >> 8) & 0xFF) != CONFIG_DEVICE_ID) && (((rx_msg.identifier >> 8) & 0xFF) != 0xFF)) continue;
ESP_LOGI(LOG_TAG, "received can package with ID: %" PRIu32, rx_msg.identifier);
// printf("received can package with ID: %" PRIu32, rx_msg.identifier);
}
}

19
main/can.h Normal file
View file

@ -0,0 +1,19 @@
//
// Created by okhsunrog on 8/17/23.
//
#ifndef MAIN_CAN_H
#define MAIN_CAN_H
#include "driver/twai.h"
#include "sdkconfig.h"
// functions
void can_init();
void can_stop();
void calculate_hw_can_filter(uint32_t device_id, twai_filter_config_t* filter, bool ota_mode);
void can_bus_off_check();
void can_task(void* arg);
#endif // MAIN_CAN_H

277
main/cmd_system.c Normal file
View file

@ -0,0 +1,277 @@
/* Console example — various system commands
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include <unistd.h>
#include "esp_log.h"
#include "esp_console.h"
#include "esp_chip_info.h"
#include "esp_sleep.h"
#include "esp_flash.h"
#include "driver/rtc_io.h"
#include "driver/uart.h"
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "cmd_system.h"
#include "sdkconfig.h"
#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
#define WITH_TASKS_INFO 1
#endif
static const char *TAG = "cmd_system";
static void register_free(void);
static void register_heap(void);
static void register_version(void);
static void register_restart(void);
#if WITH_TASKS_INFO
static void register_tasks(void);
#endif
static void register_log_level(void);
void register_system_common(void)
{
register_free();
register_heap();
register_version();
register_restart();
#if WITH_TASKS_INFO
register_tasks();
#endif
register_log_level();
}
void register_system(void)
{
register_system_common();
}
/* 'version' command */
static int get_version(int argc, char **argv)
{
const char *model;
esp_chip_info_t info;
uint32_t flash_size;
esp_chip_info(&info);
switch(info.model) {
case CHIP_ESP32:
model = "ESP32";
break;
case CHIP_ESP32S2:
model = "ESP32-S2";
break;
case CHIP_ESP32S3:
model = "ESP32-S3";
break;
case CHIP_ESP32C3:
model = "ESP32-C3";
break;
case CHIP_ESP32H2:
model = "ESP32-H2";
break;
case CHIP_ESP32C2:
model = "ESP32-C2";
break;
default:
model = "Unknown";
break;
}
if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
printf("Get flash size failed");
return 1;
}
printf("IDF Version:%s\r\n", esp_get_idf_version());
printf("Chip info:\r\n");
printf("\tmodel:%s\r\n", model);
printf("\tcores:%d\r\n", info.cores);
printf("\tfeature:%s%s%s%s%"PRIu32"%s\r\n",
info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "",
info.features & CHIP_FEATURE_BLE ? "/BLE" : "",
info.features & CHIP_FEATURE_BT ? "/BT" : "",
info.features & CHIP_FEATURE_EMB_FLASH ? "/Embedded-Flash:" : "/External-Flash:",
flash_size / (1024 * 1024), " MB");
printf("\trevision number:%d\r\n", info.revision);
return 0;
}
static void register_version(void)
{
const esp_console_cmd_t cmd = {
.command = "version",
.help = "Get version of chip and SDK",
.hint = NULL,
.func = &get_version,
};
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}
/** 'restart' command restarts the program */
static int restart(int argc, char **argv)
{
ESP_LOGI(TAG, "Restarting");
esp_restart();
}
static void register_restart(void)
{
const esp_console_cmd_t cmd = {
.command = "restart",
.help = "Software reset of the chip",
.hint = NULL,
.func = &restart,
};
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}
/** 'free' command prints available heap memory */
static int free_mem(int argc, char **argv)
{
printf("%"PRIu32"\n", esp_get_free_heap_size());
return 0;
}
static void register_free(void)
{
const esp_console_cmd_t cmd = {
.command = "free",
.help = "Get the current size of free heap memory",
.hint = NULL,
.func = &free_mem,
};
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}
/* 'heap' command prints minumum heap size */
static int heap_size(int argc, char **argv)
{
uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
printf("min heap size: %"PRIu32"\n", heap_size);
return 0;
}
static void register_heap(void)
{
const esp_console_cmd_t heap_cmd = {
.command = "heap",
.help = "Get minimum size of free heap memory that was available during program execution",
.hint = NULL,
.func = &heap_size,
};
ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );
}
/** 'tasks' command prints the list of tasks and related information */
#if WITH_TASKS_INFO
static int tasks_info(int argc, char **argv)
{
const size_t bytes_per_task = 40; /* see vTaskList description */
char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
if (task_list_buffer == NULL) {
ESP_LOGE(TAG, "failed to allocate buffer for vTaskList output");
return 1;
}
fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
fputs("\tAffinity", stdout);
#endif
fputs("\n", stdout);
vTaskList(task_list_buffer);
fputs(task_list_buffer, stdout);
free(task_list_buffer);
return 0;
}
static void register_tasks(void)
{
const esp_console_cmd_t cmd = {
.command = "tasks",
.help = "Get information about running tasks",
.hint = NULL,
.func = &tasks_info,
};
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}
#endif // WITH_TASKS_INFO
static struct {
struct arg_str *tag;
struct arg_str *level;
struct arg_end *end;
} log_level_args;
static const char* s_log_level_names[] = {
"none",
"error",
"warn",
"info",
"debug",
"verbose"
};
static int log_level(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &log_level_args);
if (nerrors != 0) {
arg_print_errors(stderr, log_level_args.end, argv[0]);
return 1;
}
assert(log_level_args.tag->count == 1);
assert(log_level_args.level->count == 1);
const char* tag = log_level_args.tag->sval[0];
const char* level_str = log_level_args.level->sval[0];
esp_log_level_t level;
size_t level_len = strlen(level_str);
for (level = ESP_LOG_NONE; level <= ESP_LOG_VERBOSE; level++) {
if (memcmp(level_str, s_log_level_names[level], level_len) == 0) {
break;
}
}
if (level > ESP_LOG_VERBOSE) {
printf("Invalid log level '%s', choose from none|error|warn|info|debug|verbose\n", level_str);
return 1;
}
if (level > CONFIG_LOG_MAXIMUM_LEVEL) {
printf("Can't set log level to %s, max level limited in menuconfig to %s. "
"Please increase CONFIG_LOG_MAXIMUM_LEVEL in menuconfig.\n",
s_log_level_names[level], s_log_level_names[CONFIG_LOG_MAXIMUM_LEVEL]);
return 1;
}
esp_log_level_set(tag, level);
return 0;
}
static void register_log_level(void)
{
log_level_args.tag = arg_str1(NULL, NULL, "<tag|*>", "Log tag to set the level for, or * to set for all tags");
log_level_args.level = arg_str1(NULL, NULL, "<none|error|warn|debug|verbose>", "Log level to set. Abbreviated words are accepted.");
log_level_args.end = arg_end(2);
const esp_console_cmd_t cmd = {
.command = "log_level",
.help = "Set log level for all tags or a specific tag.",
.hint = NULL,
.func = &log_level,
.argtable = &log_level_args
};
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

13
main/cmd_system.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef MAIN_CMD_SYSTEM_H
#define MAIN_CMD_SYSTEM_H
// Register all system functions
void register_system(void);
// Register common system functions: "version", "restart", "free", "heap", "tasks"
void register_system_common(void);
// Register deep and light sleep functions
void register_system_sleep(void);
#endif // MAIN_CMD_SYSTEM_H

81
main/console_task.c Normal file
View file

@ -0,0 +1,81 @@
#include "console_task.h"
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
//#include "argtable3/argtable3.h"
#include "linenoise/linenoise.h"
#include "esp_log.h"
#include "esp_console.h"
#include "fs.h"
#include "esp_err.h"
#define PROMPT_STR "[root@can_wiz ~]$ "
static const char* TAG = "console task";
void console_task(void* arg) {
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char* prompt = LOG_COLOR_E PROMPT_STR LOG_RESET_COLOR;
printf("\n"
"Type 'help' to get the list of commands.\n"
"Use UP/DOWN arrows to navigate through command history.\n"
"Press TAB when typing command name to auto-complete.\n"
"Ctrl+C will terminate the console environment.\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = PROMPT_STR;
#endif // CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char* line = linenoise(prompt);
if (line == NULL) { /* Break on EOF or error */
break;
}
/* Add the command to the history if not empty*/
if (strlen(line) > 0) {
linenoiseHistoryAdd(line);
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
}
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
ESP_LOGE(TAG, "Error or end-of-input, terminating console");
esp_console_deinit();
}

8
main/console_task.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef MAIN_CONSOLE_TASK_H
#define MAIN_CONSOLE_TASK_H
// functions
void console_task(void* arg);
#endif // MAIN_CONSOLE_TASK_H

20
main/fs.c Normal file
View file

@ -0,0 +1,20 @@
#include "fs.h"
#include "esp_vfs_fat.h"
static const char* TAG = "fs";
/* Console command history can be stored to and loaded from a file.
* The easiest way to do this is to use FATFS filesystem on top of
* wear_levelling library.
*/
void initialize_filesystem(void) {
static wl_handle_t wl_handle;
const esp_vfs_fat_mount_config_t mount_config = {.max_files = 4, .format_if_mount_failed = true};
esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(MOUNT_PATH, "storage", &mount_config, &wl_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
return;
}
}

11
main/fs.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef MAIN_FS_H
#define MAIN_FS_H
#define MOUNT_PATH "/data"
#define HISTORY_PATH MOUNT_PATH "/history.txt"
// functions
void initialize_filesystem(void);
#endif // MAIN_FS_H

83
main/main.c Normal file
View file

@ -0,0 +1,83 @@
#include <stdio.h>
#include <fcntl.h>
#include "esp_err.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "linenoise/linenoise.h"
#include "esp_vfs_usb_serial_jtag.h"
#include "driver/usb_serial_jtag.h"
#include "cmd_system.h"
#include "can.h"
#include "fs.h"
#include "console_task.h"
static void initialize_console(void) {
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Enable non-blocking mode on stdin and stdout */
fcntl(fileno(stdout), F_SETFL, 0);
fcntl(fileno(stdin), F_SETFL, 0);
usb_serial_jtag_driver_config_t usb_serial_jtag_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
/* Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&usb_serial_jtag_config));
/* Tell vfs to use usb-serial-jtag driver */
esp_vfs_usb_serial_jtag_use_driver();
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 8,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK(esp_console_init(&console_config));
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
/* Set command maximum length */
linenoiseSetMaxLineLen(console_config.max_cmdline_length);
/* Allow empty lines */
linenoiseAllowEmpty(true);
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
}
void app_main(void) {
can_init();
xTaskCreate(can_task, "can task", 4096, NULL, CONFIG_CAN_TASK_PRIORITY, NULL);
initialize_filesystem();
initialize_console();
/* Register commands */
esp_console_register_help_command();
register_system();
xTaskCreate(console_task, "console task", 4096, NULL, CONFIG_CONSOLE_TASK_PRIORITY, NULL);
}

6
partitions.csv Normal file
View file

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M,

1772
sdkconfig Normal file

File diff suppressed because it is too large Load diff