-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
Dev
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
#pragma once | ||
|
||
#include <furi.h> | ||
#include <furi_hal.h> | ||
#include <gui/gui.h> | ||
#include <gui/modules/byte_input.h> | ||
#include <gui/modules/submenu.h> | ||
#include <gui/modules/text_box.h> | ||
#include <gui/modules/variable_item_list.h> | ||
#include <gui/scene_manager.h> | ||
#include <gui/view_dispatcher.h> | ||
#include <dialogs/dialogs.h> | ||
#include <storage/storage.h> | ||
#include <expansion/expansion.h> | ||
#include <expansion/expansion_settings.h> | ||
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
Check failure on line 15 in ModbusApp/Modbus.h GitHub Actions / ufbt: Build for Dev branch
|
||
|
||
#include <stm32wbxx_ll_lpuart.h> | ||
#include <stm32wbxx_ll_usart.h> | ||
|
||
#include "scenes_config/app_scene_functions.h" | ||
|
||
#define PATHAPP "apps_data/modbus" | ||
#define PATHAPPEXT EXT_PATH(PATHAPP) | ||
#define PATHLOGS PATHAPPEXT "/logs" | ||
|
||
#define BR_VALUES 12 | ||
#define DATAWIDTH_VALUES 3 | ||
#define STOPBITS_VALUES 4 | ||
#define PARITY_VALUES 3 | ||
#define TIMEOUT_VALUES 255 | ||
#define DIGITALFORMAT_VALUES 2 | ||
#define ANALOGFORMAT_VALUES 2 | ||
#define SAVE_LOG_VALUES 2 | ||
|
||
#define RX_BUF_SIZE 255 | ||
#define UART_CH FuriHalSerialIdUsart | ||
#define TEXT_BOX_LEN 4096 | ||
#define FURI_HAL_SERIAL_USART_OVERSAMPLING 0x00000000U | ||
#define TIMEOUT_SCALER 50 | ||
|
||
#define FixedModbusSize 4 | ||
#define FixedPaket \ | ||
((!app->modbus->slave && FUNCTION <= 0x06) || (app->modbus->slave && FUNCTION >= 0x0F)) | ||
#define SLAVE buf[0] | ||
#define FUNCTION buf[1] | ||
#define EXCEPTION buf[2] - 1 | ||
#define STARTADDRESS (buf[2] << 8 | buf[3]) | ||
#define QUANTITY (buf[4] << 8 | buf[5]) | ||
#define BYTECOUNT buf[6] | ||
#define CRCH buf[len - 2] | ||
#define CRCL buf[len - 1] | ||
|
||
////////////////////////// Defining Structs ////////////////////////// | ||
typedef enum { | ||
Submenu_View, | ||
VarList_View, | ||
TextBox_View, | ||
ByteInput_View | ||
} Views; | ||
typedef enum { | ||
Settings_Option, | ||
Sniffer_Option, | ||
Sender_Option, | ||
Read_LOG_Option, | ||
About_Option, | ||
Manual_Sender_Option, | ||
Buffer_Sender_Option | ||
} Main_options; | ||
|
||
typedef struct { | ||
uint8_t baudrate; | ||
uint8_t dataWidth; | ||
uint8_t stopBits; | ||
uint8_t parity; | ||
uint8_t timeout; | ||
bool hexOutput; | ||
bool saveLOG; | ||
} Config; | ||
|
||
typedef struct { | ||
Config* cfg; | ||
FuriThread* rxThread; | ||
FuriStreamBuffer* rxStream; | ||
FuriHalSerialHandle* serial_handle; | ||
uint8_t rxBuff[RX_BUF_SIZE + 1]; | ||
} Uart; | ||
typedef struct { | ||
bool slave; | ||
FuriString* timeout; | ||
} Modbus; | ||
#define Ring_Buf_Size 255 | ||
typedef struct { | ||
uint8_t delimiters[32]; | ||
uint8_t ringBuffer[Ring_Buf_Size]; | ||
uint16_t writeIdx; | ||
uint8_t delimiterIdx; | ||
uint8_t readIdx; | ||
} RingBuffer; | ||
|
||
typedef struct { | ||
SceneManager* sceneManager; | ||
ViewDispatcher* viewDispatcher; | ||
Submenu* subMenu; | ||
VariableItemList* varList; | ||
ByteInput* byteInput; | ||
Uart* uart; | ||
Modbus* modbus; | ||
DialogsApp* dialogs; | ||
Storage* storage; | ||
File* LOGfile; | ||
char* logFilePath; | ||
bool LOGfileReady; | ||
|
||
size_t rows; | ||
size_t textLen; | ||
|
||
FuriTimer* timer; | ||
TextBox* textBox; | ||
FuriString* text; | ||
|
||
uint8_t msgBuf[RX_BUF_SIZE + 1]; | ||
size_t msgLen; | ||
RingBuffer* ringBuffer; | ||
Expansion* expansion; | ||
} App; | ||
|
||
typedef enum { | ||
BaudRate_Option, | ||
DataWidth_Option, | ||
StopBits_Option, | ||
Parity_Option, | ||
TimeOut_Option, | ||
OutputFormat_Option, | ||
SaveLOG_Option | ||
} Settings_Options; | ||
|
||
typedef enum { | ||
Refresh = 0 | ||
} UartEvents; | ||
|
||
typedef enum { | ||
WorkerEvtStop = (1 << 0), | ||
WorkerEvtRxDone = (1 << 1), | ||
WorkerEvtTxStart = (1 << 2), | ||
WorkerEvtCfgChange = (1 << 3), | ||
|
||
} WorkerEvtFlags; | ||
#define WORKER_ALL_EVENTS (WorkerEvtStop | WorkerEvtRxDone | WorkerEvtTxStart | WorkerEvtCfgChange) | ||
|
||
extern const char* baudrateValues[]; | ||
extern const char* dataWidthValues[]; | ||
extern const char* stopBitsValues[]; | ||
extern const char* parityValues[]; | ||
extern const char* saveLOGValues[]; | ||
extern const char* outputFormatValues[]; | ||
extern const char* functionNames[]; | ||
extern const char* exceptionCodes[]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
#include "modbus_parser.h" | ||
|
||
#include "../Modbus.h" | ||
#include "../modbus_ring_buffer/modbus_ring_buffer.h" | ||
|
||
uint16_t getCRC(uint8_t* buf, uint8_t len) { | ||
uint16_t crc = 0xFFFF; | ||
|
||
for(int pos = 0; pos < len; pos++) { | ||
crc ^= (uint16_t)buf[pos]; | ||
|
||
for(int i = 8; i != 0; i--) { | ||
if((crc & 0x0001) != 0) { | ||
crc >>= 1; | ||
crc ^= 0xA001; | ||
} else | ||
crc >>= 1; | ||
} | ||
} | ||
return crc; | ||
} | ||
|
||
static void discreteValuesParser(void* context, uint8_t* buff, size_t len, FuriString* data) { | ||
App* app = context; | ||
uint8_t value = 0; | ||
uint8_t offset = 0; | ||
while(len) { | ||
memcpy(&value, buff + offset, 1); | ||
offset++; | ||
if(!app->uart->cfg->hexOutput) { | ||
furi_string_cat_printf(data, "\n-Byte%d: \n->", offset); | ||
for(int i = 0; i < 8; i++) | ||
furi_string_cat_printf( | ||
data, | ||
"%s%s", | ||
value >> i & 0x01 ? "ON" : "OFF", | ||
i == 3 ? "\n->" : | ||
i == 7 ? "" : | ||
","); | ||
} else | ||
furi_string_cat_printf(data, "\n->Byte%d: 0x%02X", offset, value); | ||
len--; | ||
} | ||
} | ||
|
||
static void analogValuesParser(void* context, uint8_t* buff, size_t len, FuriString* data) { | ||
App* app = context; | ||
uint16_t value = 0; | ||
size_t offset = 0; | ||
|
||
while(offset < len) { | ||
value = 0; | ||
if(offset + 1 < len) { | ||
memcpy(((uint8_t*)&value) + 1, buff + offset, sizeof(uint8_t)); | ||
memcpy((uint8_t*)&value, buff + offset + 1, sizeof(uint8_t)); | ||
} else if(offset < len) { | ||
memcpy(((uint8_t*)&value) + 1, buff + offset, sizeof(uint8_t)); | ||
} | ||
|
||
furi_string_cat_printf( | ||
data, | ||
app->uart->cfg->hexOutput ? "\n->Reg%d: 0x%04X" : "\n->Reg%d: %d", | ||
offset / 2, | ||
value); | ||
|
||
offset += 2; | ||
} | ||
} | ||
|
||
static void pduParser(void* context, bool slave, uint8_t* buf, size_t len, FuriString* data) { | ||
App* app = context; | ||
size_t offset = 2; | ||
uint16_t address = 0; | ||
uint16_t qty = 0; | ||
uint16_t bCount = 0; | ||
uint16_t value = 0; | ||
UNUSED(len); | ||
furi_string_cat_printf( | ||
data, "\n%s", functionNames[FUNCTION <= 6 ? FUNCTION - 1 : FUNCTION - 9]); | ||
furi_string_cat_printf( | ||
data, app->uart->cfg->hexOutput ? "\nPeripheral: 0x%02X" : "\nPeripheral: %d", SLAVE); | ||
memcpy( | ||
slave && FUNCTION <= 4 ? &bCount : &address, buf + offset, slave && FUNCTION <= 4 ? 1 : 2); | ||
|
||
offset += slave && FUNCTION <= 4 ? 1 : 2; | ||
address = address >> 8 | address << 8; | ||
if(app->uart->cfg->hexOutput) | ||
furi_string_cat_printf( | ||
data, | ||
slave && FUNCTION <= 4 ? "\nbCount: 0x%02X" : "\nAddress: 0x%04X", | ||
slave && FUNCTION <= 4 ? bCount : address); | ||
else | ||
furi_string_cat_printf( | ||
data, | ||
slave && FUNCTION <= 4 ? "\nbCount: %d" : "\nAddress: %d", | ||
slave && FUNCTION <= 4 ? bCount : address); | ||
|
||
if(FUNCTION >= 0x0F || (!slave && FUNCTION <= 0x04)) { | ||
memcpy(&qty, buf + offset, 2); | ||
offset += 2; | ||
qty = qty >> 8 | qty << 8; | ||
furi_string_cat_printf( | ||
data, app->uart->cfg->hexOutput ? "\nQty: 0x%04X" : "\nQty: %d", qty); | ||
} else if(FUNCTION >= 0x05) { | ||
memcpy(&value, buf + offset, 2); | ||
offset += 2; | ||
value = value >> 8 | value << 8; | ||
if(FUNCTION == 0x05) | ||
furi_string_cat_printf(data, "\nValue: %s", buf[4] ? "ON" : "OFF"); | ||
else | ||
furi_string_cat_printf( | ||
data, app->uart->cfg->hexOutput ? "\nValue: 0x%04X" : "\nValue: %d", value); | ||
} else if(FUNCTION <= 0x02) | ||
discreteValuesParser(app, buf + offset, bCount, data); | ||
else | ||
analogValuesParser(app, buf + offset, bCount, data); | ||
|
||
if(FUNCTION >= 0x0F && !slave) { | ||
memcpy(&bCount, buf + offset, 1); | ||
offset++; | ||
furi_string_cat_printf( | ||
data, app->uart->cfg->hexOutput ? "\nbCount: 0x%02X" : "\nbCount: %d", bCount); | ||
if(FUNCTION == 0x0F) | ||
discreteValuesParser(app, buf + offset, bCount, data); | ||
else | ||
analogValuesParser(app, buf + offset, bCount, data); | ||
} | ||
furi_string_cat_printf(data, "\nCRC: 0x%02X", CRCL | CRCH << 8); | ||
} | ||
static void ErrParser(uint8_t* buf, size_t len, FuriString* data) { | ||
furi_string_cat_printf( | ||
data, "\nException code (%02X):\n%s\n", FUNCTION, exceptionCodes[EXCEPTION]); | ||
for(size_t i = 0; i < len; i++) | ||
furi_string_cat_printf(data, "%02X", buf[i]); | ||
} | ||
static void ModbusParser(uint8_t* buf, size_t len, App* app, FuriString* data) { | ||
if(FUNCTION > 0x80) { | ||
ErrParser(buf, len, data); | ||
} else if((FUNCTION > 0x06 && FUNCTION < 0x0F) || FUNCTION > 0x10) { | ||
furi_string_cat_printf(data, "\nUNSUPPORTED!!!\nFUNCTION(0x%02X)\n", FUNCTION); | ||
for(size_t i = 0; i < len; i++) | ||
furi_string_cat_printf(data, "%02X", buf[i]); | ||
} else if(FixedPaket && len - 4 != FixedModbusSize) { | ||
furi_string_cat_str(data, "\nLength-Type MissMatch!!!\n"); | ||
for(size_t i = 0; i < len; i++) | ||
furi_string_cat_printf(data, "%02X", buf[i]); | ||
furi_string_cat_printf( | ||
data, | ||
"\nCheck Reponse TimeOut!!!\nCurrent: %dms", | ||
app->uart->cfg->timeout * TIMEOUT_SCALER); | ||
} else { | ||
if(!app->modbus->slave) { | ||
for(size_t i = 0; i < len; i++) | ||
app->msgBuf[i] = buf[i]; | ||
writeRingBuffer(app->ringBuffer, buf, len); | ||
app->msgLen = len; | ||
} | ||
pduParser(app, app->modbus->slave, buf, len, data); | ||
} | ||
} | ||
void handle_rx_data_cb(uint8_t* buf, size_t len, void* context) { | ||
furi_assert(context); | ||
App* app = context; | ||
buf[len] = '\0'; | ||
FuriString* data = furi_string_alloc(); | ||
furi_string_reset(data); | ||
///* | ||
furi_string_cat_printf( | ||
data, "\n-----%s----", app->modbus->slave ? "PERIPHERAL-" : "---HUB----"); | ||
if((CRCH | CRCL << 8) == getCRC(buf, len - 2)) { | ||
ModbusParser(buf, len, app, data); | ||
} else { | ||
furi_string_cat_str(data, "\nCRC check Failed:\n"); | ||
for(size_t i = 0; i < len; i++) | ||
furi_string_cat_printf(data, "%02X", buf[i]); | ||
furi_string_cat_str(data, "\nPlease check UART Settings!!!"); | ||
} | ||
//*/ | ||
// for(size_t i = 0; i < len; i++) furi_string_cat_printf(data, "%02X", | ||
// buf[i]); furi_string_cat_str(data, "\n"); | ||
app->textLen += furi_string_size(data); | ||
if(app->textLen >= 3500 - 1) { | ||
furi_string_right(app->text, app->textLen / 2); | ||
app->textLen = furi_string_size(app->text) + furi_string_size(data); | ||
} | ||
furi_string_cat_str(app->text, furi_string_get_cstr(data)); | ||
|
||
if(app->LOGfileReady) | ||
storage_file_write(app->LOGfile, furi_string_get_cstr(data), furi_string_size(data)); | ||
|
||
furi_string_free(data); | ||
|
||
view_dispatcher_send_custom_event(app->viewDispatcher, Refresh); | ||
|
||
if(app->modbus->slave) { | ||
app->modbus->slave = false; | ||
furi_timer_stop(app->timer); | ||
} else { | ||
app->modbus->slave = true; | ||
furi_timer_start(app->timer, app->uart->cfg->timeout * TIMEOUT_SCALER); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#pragma once | ||
|
||
#include <furi.h> | ||
|
||
void handle_rx_data_cb(uint8_t* buf, size_t len, void* context); | ||
uint16_t getCRC(uint8_t* buf, uint8_t len); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#include "modbus_ring_buffer.h" | ||
|
||
RingBuffer* ring_buffer_alloc() { | ||
RingBuffer* buffer = malloc(sizeof(RingBuffer)); | ||
buffer->writeIdx = 0; | ||
buffer->delimiterIdx = 0; | ||
for(uint8_t i = 0; i < 32; i++) | ||
buffer->delimiters[i] = 255; | ||
return buffer; | ||
} | ||
void ring_buffer_free(RingBuffer* buffer) { | ||
free(buffer); | ||
} | ||
void writeRingBuffer(RingBuffer* rb, uint8_t* buf, size_t len) { | ||
for(size_t i = 0; i < len; i++) { | ||
rb->ringBuffer[rb->writeIdx] = buf[i]; | ||
if(i == len - 1) rb->delimiters[rb->delimiterIdx] = rb->writeIdx; | ||
if(++rb->writeIdx > 255) { | ||
rb->delimiterIdx = 0; | ||
rb->writeIdx = 0; | ||
} | ||
} | ||
rb->delimiterIdx++; | ||
} |