forked from test34/can_wizard
initial commit
This commit is contained in:
commit
3fb1c8dd81
20 changed files with 2776 additions and 0 deletions
143
.clang-format
Normal file
143
.clang-format
Normal 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
3
.clangd
Normal 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
26
.editorconfig
Normal 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
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
.devcontainer
|
||||
.vscode
|
||||
build
|
||||
sdkconfig.old
|
||||
dependencies.lock
|
||||
.idea/
|
||||
cmake-build-debug/
|
||||
.cache/
|
6
CMakeLists.txt
Normal file
6
CMakeLists.txt
Normal 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
154
README.md
Normal 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
13
main/CMakeLists.txt
Normal 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
15
main/Kconfig.env_caps
Normal 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
37
main/Kconfig.projbuild
Normal 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
81
main/can.c
Normal 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
19
main/can.h
Normal 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
277
main/cmd_system.c
Normal 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
13
main/cmd_system.h
Normal 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
81
main/console_task.c
Normal 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
8
main/console_task.h
Normal 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
20
main/fs.c
Normal 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
11
main/fs.h
Normal 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
83
main/main.c
Normal 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
6
partitions.csv
Normal 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,
|
|
Loading…
Reference in a new issue