initial commit
This commit is contained in:
commit
42e7c98d46
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.pio
|
||||||
|
.pioenvs
|
||||||
|
.piolibdeps
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
]
|
||||||
|
}
|
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"terminal.integrated.env.linux": {
|
||||||
|
"PATH": "/home/david/.platformio/penv/bin:/home/david/.platformio/penv:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/android-sdk/platform-tools:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/opt/android-sdk/platform-tools:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl",
|
||||||
|
"PLATFORMIO_CALLER": "vscode"
|
||||||
|
},
|
||||||
|
"files.associations": {
|
||||||
|
"array": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"string_view": "cpp"
|
||||||
|
}
|
||||||
|
}
|
39
include/README
Normal file
39
include/README
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
46
lib/README
Normal file
46
lib/README
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
7
partitions.csv
Normal file
7
partitions.csv
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xE000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x1E0000,
|
||||||
|
app1, app, ota_1, 0x1F0000,0x1E0000,
|
||||||
|
eeprom, data, 0x99, 0x3D0000,0x1000,
|
||||||
|
spiffs, data, spiffs, 0x3D1000,0x20000,
|
|
15
platformio.ini
Normal file
15
platformio.ini
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:esp32dev]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32dev
|
||||||
|
framework = arduino
|
||||||
|
board_build.partitions = partitions.csv
|
38
src/DummyStream.cpp
Normal file
38
src/DummyStream.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <DummyStream.h>
|
||||||
|
|
||||||
|
DummyStream::DummyStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DummyStream::~DummyStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int DummyStream::available()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DummyStream::read()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DummyStream::peek()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyStream::flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DummyStream::write(uint8_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DummyStream::write(const uint8_t *buffer, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
21
src/DummyStream.h
Normal file
21
src/DummyStream.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef DUMMYSTREAM_H
|
||||||
|
#define DUMMYSTREAM_H
|
||||||
|
|
||||||
|
#include <Stream.h>
|
||||||
|
|
||||||
|
class DummyStream : public Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DummyStream();
|
||||||
|
~DummyStream();
|
||||||
|
|
||||||
|
int available();
|
||||||
|
int read();
|
||||||
|
int peek();
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
size_t write(uint8_t);
|
||||||
|
size_t write(const uint8_t *buffer, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
10
src/bafang.cpp
Normal file
10
src/bafang.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "bafang.h"
|
||||||
|
|
||||||
|
namespace Huawei {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
11
src/bafang.h
Normal file
11
src/bafang.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef BAFANG_H
|
||||||
|
#define BAFANG_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Bafang {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
140
src/commands.cpp
Normal file
140
src/commands.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "bafang.h"
|
||||||
|
#include "commands.h"
|
||||||
|
|
||||||
|
namespace Commands {
|
||||||
|
|
||||||
|
int parseLine(char *line)
|
||||||
|
{
|
||||||
|
const int MAX_ARGV = 16;
|
||||||
|
char *lineStart = line;
|
||||||
|
char *argv[MAX_ARGV];
|
||||||
|
int argc = 0;
|
||||||
|
bool found = false;
|
||||||
|
bool end = false;
|
||||||
|
bool inString = false;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
if(*line == '"' && (line == lineStart || *(line - 1) != '\\'))
|
||||||
|
{
|
||||||
|
inString ^= true;
|
||||||
|
if(!inString)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
end = true;
|
||||||
|
lineStart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!inString && *line == ' ')
|
||||||
|
end = true;
|
||||||
|
|
||||||
|
if(end || !*line)
|
||||||
|
{
|
||||||
|
if(found && argc < MAX_ARGV)
|
||||||
|
argv[argc++] = lineStart;
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
end = false;
|
||||||
|
|
||||||
|
if(!*line)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*line = 0;
|
||||||
|
lineStart = ++line;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
line++;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!argc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for(int i = 0; g_Commands[i].cmd; i++)
|
||||||
|
{
|
||||||
|
if(strcmp(g_Commands[i].cmd, argv[0]) == 0)
|
||||||
|
{
|
||||||
|
int ret = g_Commands[i].fun(argc, argv);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMD_help(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Main::channel()->println("Available Commands\n------------------");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while(g_Commands[i].cmd)
|
||||||
|
{
|
||||||
|
Main::channel()->printf("%17s %s\n", g_Commands[i].cmd, g_Commands[i].help);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
Main::channel()->println();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMD_debug(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(argc != 2) {
|
||||||
|
Main::channel()->println("Usage: debug <0|1>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debug = false;
|
||||||
|
if(strtoul(argv[1], NULL, 10))
|
||||||
|
debug = true;
|
||||||
|
|
||||||
|
Main::g_Debug[Main::g_CurrentChannel] = debug;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMD_wifi(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Main::channel()->printf("connected: %d\n", WiFi.status());
|
||||||
|
Main::channel()->println(WiFi.localIP());
|
||||||
|
WiFi.printDiag(*Main::channel());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMD_serial(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(argc != 3) {
|
||||||
|
Main::channel()->println("Usage: serial <0|1|2> <text>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = strtoul(argv[1], NULL, 10);
|
||||||
|
|
||||||
|
if(port == 0)
|
||||||
|
Serial.println(argv[2]);
|
||||||
|
else if(port == 1)
|
||||||
|
Serial1.println(argv[2]);
|
||||||
|
else if(port == 2)
|
||||||
|
Serial2.println(argv[2]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CommandEntry g_Commands[] =
|
||||||
|
{
|
||||||
|
{"help", CMD_help, " : Display list of commands"},
|
||||||
|
{"debug", CMD_debug, " : debug <0|1>"},
|
||||||
|
{"wifi", CMD_wifi, " : show wifi config"},
|
||||||
|
{"serial", CMD_serial, " : write to serial <0|1|2> <text>"},
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
21
src/commands.h
Normal file
21
src/commands.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef COMMANDS_H
|
||||||
|
#define COMMANDS_H
|
||||||
|
|
||||||
|
namespace Commands {
|
||||||
|
|
||||||
|
int parseLine(char *line);
|
||||||
|
|
||||||
|
struct CommandEntry
|
||||||
|
{
|
||||||
|
const char *cmd;
|
||||||
|
int (*fun)(int argc, char *argv[]);
|
||||||
|
const char *help;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CommandEntry g_Commands[];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
160
src/main.cpp
Normal file
160
src/main.cpp
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#include <BluetoothSerial.h>
|
||||||
|
#include "DummyStream.h"
|
||||||
|
|
||||||
|
#include "bafang.h"
|
||||||
|
#include "commands.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
WiFiServer server(23);
|
||||||
|
WiFiClient serverClient;
|
||||||
|
|
||||||
|
BluetoothSerial SerialBT;
|
||||||
|
DummyStream SerialDummy;
|
||||||
|
|
||||||
|
const char g_WIFI_SSID[] = "BotoX";
|
||||||
|
const char g_WIFI_Passphrase[] = "D4701B981E5F34EF087DE8DA25F19B47F48E0FEA972FD10E3E6CFEE29C431A1F";
|
||||||
|
|
||||||
|
namespace Main
|
||||||
|
{
|
||||||
|
|
||||||
|
int g_CurrentChannel = HWSERIAL;
|
||||||
|
bool g_Debug[NUM_CHANNELS];
|
||||||
|
char g_SerialBuffer[NUM_CHANNELS][255];
|
||||||
|
int g_SerialBufferPos[NUM_CHANNELS];
|
||||||
|
|
||||||
|
unsigned long g_Time1000;
|
||||||
|
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
Serial.println("BOOTED!");
|
||||||
|
|
||||||
|
Serial1.begin(115200);
|
||||||
|
Serial2.begin(115200);
|
||||||
|
|
||||||
|
WiFi.setHostname("ESP32-BAFANG");
|
||||||
|
if(!WiFi.begin(g_WIFI_SSID, g_WIFI_Passphrase))
|
||||||
|
Serial.println("WiFi config error!");
|
||||||
|
else {
|
||||||
|
WiFi.setAutoConnect(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialBT.begin("ESP32-BAFANG");
|
||||||
|
|
||||||
|
ArduinoOTA.onStart([]() {
|
||||||
|
String type;
|
||||||
|
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||||
|
type = "sketch";
|
||||||
|
else // U_SPIFFS
|
||||||
|
type = "filesystem";
|
||||||
|
|
||||||
|
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
||||||
|
Serial.println("Start updating " + type);
|
||||||
|
})
|
||||||
|
.onEnd([]() {
|
||||||
|
Serial.println("\nEnd");
|
||||||
|
})
|
||||||
|
.onProgress([](unsigned int progress, unsigned int total) {
|
||||||
|
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||||
|
})
|
||||||
|
.onError([](ota_error_t error) {
|
||||||
|
Serial.printf("Error[%u]: ", error);
|
||||||
|
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||||
|
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||||
|
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||||
|
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||||
|
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||||
|
});
|
||||||
|
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
server.setNoDelay(true);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream* channel(int num)
|
||||||
|
{
|
||||||
|
if(num == -1)
|
||||||
|
num = g_CurrentChannel;
|
||||||
|
|
||||||
|
if(num == BTSERIAL && SerialBT.hasClient())
|
||||||
|
return &SerialBT;
|
||||||
|
else if(num == TCPSERIAL && serverClient)
|
||||||
|
return &serverClient;
|
||||||
|
else if(num == HWSERIAL)
|
||||||
|
return &Serial;
|
||||||
|
|
||||||
|
return &SerialDummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if(g_Debug[g_CurrentChannel])
|
||||||
|
{
|
||||||
|
while(Serial1.available())
|
||||||
|
{
|
||||||
|
channel()->write(Serial1.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
while(Serial2.available())
|
||||||
|
{
|
||||||
|
channel()->write(Serial2.read());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArduinoOTA.handle();
|
||||||
|
|
||||||
|
if(server.hasClient())
|
||||||
|
{
|
||||||
|
if(serverClient) // disconnect current client if any
|
||||||
|
serverClient.stop();
|
||||||
|
serverClient = server.available();
|
||||||
|
}
|
||||||
|
if(!serverClient)
|
||||||
|
serverClient.stop();
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
while(channel(i)->available())
|
||||||
|
{
|
||||||
|
g_CurrentChannel = i;
|
||||||
|
int c = channel(i)->read();
|
||||||
|
if(c == '\r' || c == '\n' || g_SerialBufferPos[i] == sizeof(*g_SerialBuffer))
|
||||||
|
{
|
||||||
|
g_SerialBuffer[i][g_SerialBufferPos[i]] = 0;
|
||||||
|
|
||||||
|
if(g_SerialBufferPos[i])
|
||||||
|
Commands::parseLine(g_SerialBuffer[i]);
|
||||||
|
|
||||||
|
g_SerialBufferPos[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g_SerialBuffer[i][g_SerialBufferPos[i]] = c;
|
||||||
|
++g_SerialBufferPos[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((millis() - g_Time1000) > 1000)
|
||||||
|
{
|
||||||
|
g_Time1000 = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Main::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
Main::loop();
|
||||||
|
}
|
30
src/main.h
Normal file
30
src/main.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#define MAX_SRV_CLIENTS 4
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NOSERIAL = -1,
|
||||||
|
HWSERIAL = 0,
|
||||||
|
BTSERIAL = 1,
|
||||||
|
TCPSERIAL = 2,
|
||||||
|
NUM_CHANNELS
|
||||||
|
};
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
Stream* channel(int num = -1);
|
||||||
|
|
||||||
|
extern int g_CurrentChannel;
|
||||||
|
extern bool g_Debug[NUM_CHANNELS];
|
||||||
|
extern char g_SerialBuffer[NUM_CHANNELS][255];
|
||||||
|
extern int g_SerialBufferPos[NUM_CHANNELS];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
63
src/utils.cpp
Normal file
63
src/utils.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
static inline uint8_t _char2byte(char c)
|
||||||
|
{
|
||||||
|
if('0' <= c && c <= '9') return (uint8_t)(c - '0');
|
||||||
|
if('A' <= c && c <= 'F') return (uint8_t)(c - 'A' + 10);
|
||||||
|
if('a' <= c && c <= 'f') return (uint8_t)(c - 'a' + 10);
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hex2bytes(const char *str, uint8_t *bytes, int32_t length)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
if(!str || !bytes || length <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for(result = 0; *str; result++)
|
||||||
|
{
|
||||||
|
uint8_t msn = _char2byte(*str++);
|
||||||
|
if(msn == 0xFF) return -1;
|
||||||
|
|
||||||
|
uint8_t lsn = _char2byte(*str++);
|
||||||
|
if(lsn == 0xFF) return -1;
|
||||||
|
|
||||||
|
uint8_t bin = (msn << 4) + lsn;
|
||||||
|
|
||||||
|
if(length-- <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*bytes++ = bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bytes2hex(const uint8_t *bytes, int32_t length, char *str, int32_t strLength)
|
||||||
|
{
|
||||||
|
const char binHex[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
if(!str || strLength < 3)
|
||||||
|
return;
|
||||||
|
*str = 0;
|
||||||
|
|
||||||
|
if(!bytes || length <= 0 || strLength <= 2 * length)
|
||||||
|
{
|
||||||
|
strncpy(str, "ERR", strLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; length > 0; length--, strLength -= 2)
|
||||||
|
{
|
||||||
|
uint8_t byte = *bytes++;
|
||||||
|
|
||||||
|
*str++ = binHex[(byte >> 4) & 0x0F];
|
||||||
|
*str++ = binHex[byte & 0x0F];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strLength-- <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*str++ = 0;
|
||||||
|
}
|
8
src/utils.h
Normal file
8
src/utils.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int hex2bytes(const char *str, uint8_t *bytes, int32_t length);
|
||||||
|
void bytes2hex(const uint8_t *bytes, int32_t length, char *str, int32_t strLength);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user