Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ed88727

Browse files
authoredAug 22, 2024··
Merge pull request #5 from ElectronicCats/dev
Dev
2 parents 6583e13 + b033a77 commit ed88727

22 files changed

+1311
-1151
lines changed
 

‎ModbusApp/Modbus.c

+23-1,151
Large diffs are not rendered by default.

‎ModbusApp/Modbus.h

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
#include <furi_hal.h>
5+
#include <gui/gui.h>
6+
#include <gui/modules/byte_input.h>
7+
#include <gui/modules/submenu.h>
8+
#include <gui/modules/text_box.h>
9+
#include <gui/modules/variable_item_list.h>
10+
#include <gui/scene_manager.h>
11+
#include <gui/view_dispatcher.h>
12+
#include <dialogs/dialogs.h>
13+
#include <storage/storage.h>
14+
#include <expansion/expansion.h>
15+
#include <expansion/expansion_settings.h>
16+
17+
#include <stm32wbxx_ll_lpuart.h>
18+
#include <stm32wbxx_ll_usart.h>
19+
20+
#include "scenes_config/app_scene_functions.h"
21+
22+
#define PATHAPP "apps_data/modbus"
23+
#define PATHAPPEXT EXT_PATH(PATHAPP)
24+
#define PATHLOGS PATHAPPEXT "/logs"
25+
26+
#define BR_VALUES 12
27+
#define DATAWIDTH_VALUES 3
28+
#define STOPBITS_VALUES 4
29+
#define PARITY_VALUES 3
30+
#define TIMEOUT_VALUES 255
31+
#define DIGITALFORMAT_VALUES 2
32+
#define ANALOGFORMAT_VALUES 2
33+
#define SAVE_LOG_VALUES 2
34+
35+
#define RX_BUF_SIZE 255
36+
#define UART_CH FuriHalSerialIdUsart
37+
#define TEXT_BOX_LEN 4096
38+
#define FURI_HAL_SERIAL_USART_OVERSAMPLING 0x00000000U
39+
#define TIMEOUT_SCALER 50
40+
41+
#define FixedModbusSize 4
42+
#define FixedPaket \
43+
((!app->modbus->slave && FUNCTION <= 0x06) || (app->modbus->slave && FUNCTION >= 0x0F))
44+
#define SLAVE buf[0]
45+
#define FUNCTION buf[1]
46+
#define EXCEPTION buf[2] - 1
47+
#define STARTADDRESS (buf[2] << 8 | buf[3])
48+
#define QUANTITY (buf[4] << 8 | buf[5])
49+
#define BYTECOUNT buf[6]
50+
#define CRCH buf[len - 2]
51+
#define CRCL buf[len - 1]
52+
53+
////////////////////////// Defining Structs //////////////////////////
54+
typedef enum {
55+
Submenu_View,
56+
VarList_View,
57+
TextBox_View,
58+
ByteInput_View
59+
} Views;
60+
typedef enum {
61+
Settings_Option,
62+
Sniffer_Option,
63+
Sender_Option,
64+
Read_LOG_Option,
65+
About_Option,
66+
Manual_Sender_Option,
67+
Buffer_Sender_Option
68+
} Main_options;
69+
70+
typedef struct {
71+
uint8_t baudrate;
72+
uint8_t dataWidth;
73+
uint8_t stopBits;
74+
uint8_t parity;
75+
uint8_t timeout;
76+
bool hexOutput;
77+
bool saveLOG;
78+
} Config;
79+
80+
typedef struct {
81+
Config* cfg;
82+
FuriThread* rxThread;
83+
FuriStreamBuffer* rxStream;
84+
FuriHalSerialHandle* serial_handle;
85+
uint8_t rxBuff[RX_BUF_SIZE + 1];
86+
} Uart;
87+
typedef struct {
88+
bool slave;
89+
FuriString* timeout;
90+
} Modbus;
91+
#define Ring_Buf_Size 255
92+
typedef struct {
93+
uint8_t delimiters[32];
94+
uint8_t ringBuffer[Ring_Buf_Size];
95+
uint16_t writeIdx;
96+
uint8_t delimiterIdx;
97+
uint8_t readIdx;
98+
} RingBuffer;
99+
100+
typedef struct {
101+
SceneManager* sceneManager;
102+
ViewDispatcher* viewDispatcher;
103+
Submenu* subMenu;
104+
VariableItemList* varList;
105+
ByteInput* byteInput;
106+
Uart* uart;
107+
Modbus* modbus;
108+
DialogsApp* dialogs;
109+
Storage* storage;
110+
File* LOGfile;
111+
char* logFilePath;
112+
bool LOGfileReady;
113+
114+
size_t rows;
115+
size_t textLen;
116+
117+
FuriTimer* timer;
118+
TextBox* textBox;
119+
FuriString* text;
120+
121+
uint8_t msgBuf[RX_BUF_SIZE + 1];
122+
size_t msgLen;
123+
RingBuffer* ringBuffer;
124+
Expansion* expansion;
125+
} App;
126+
127+
typedef enum {
128+
BaudRate_Option,
129+
DataWidth_Option,
130+
StopBits_Option,
131+
Parity_Option,
132+
TimeOut_Option,
133+
OutputFormat_Option,
134+
SaveLOG_Option
135+
} Settings_Options;
136+
137+
typedef enum {
138+
Refresh = 0
139+
} UartEvents;
140+
141+
typedef enum {
142+
WorkerEvtStop = (1 << 0),
143+
WorkerEvtRxDone = (1 << 1),
144+
WorkerEvtTxStart = (1 << 2),
145+
WorkerEvtCfgChange = (1 << 3),
146+
147+
} WorkerEvtFlags;
148+
#define WORKER_ALL_EVENTS (WorkerEvtStop | WorkerEvtRxDone | WorkerEvtTxStart | WorkerEvtCfgChange)
149+
150+
extern const char* baudrateValues[];
151+
extern const char* dataWidthValues[];
152+
extern const char* stopBitsValues[];
153+
extern const char* parityValues[];
154+
extern const char* saveLOGValues[];
155+
extern const char* outputFormatValues[];
156+
extern const char* functionNames[];
157+
extern const char* exceptionCodes[];
+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#include "modbus_parser.h"
2+
3+
#include "../Modbus.h"
4+
#include "../modbus_ring_buffer/modbus_ring_buffer.h"
5+
6+
uint16_t getCRC(uint8_t* buf, uint8_t len) {
7+
uint16_t crc = 0xFFFF;
8+
9+
for(int pos = 0; pos < len; pos++) {
10+
crc ^= (uint16_t)buf[pos];
11+
12+
for(int i = 8; i != 0; i--) {
13+
if((crc & 0x0001) != 0) {
14+
crc >>= 1;
15+
crc ^= 0xA001;
16+
} else
17+
crc >>= 1;
18+
}
19+
}
20+
return crc;
21+
}
22+
23+
static void discreteValuesParser(void* context, uint8_t* buff, size_t len, FuriString* data) {
24+
App* app = context;
25+
uint8_t value = 0;
26+
uint8_t offset = 0;
27+
while(len) {
28+
memcpy(&value, buff + offset, 1);
29+
offset++;
30+
if(!app->uart->cfg->hexOutput) {
31+
furi_string_cat_printf(data, "\n-Byte%d: \n->", offset);
32+
for(int i = 0; i < 8; i++)
33+
furi_string_cat_printf(
34+
data,
35+
"%s%s",
36+
value >> i & 0x01 ? "ON" : "OFF",
37+
i == 3 ? "\n->" :
38+
i == 7 ? "" :
39+
",");
40+
} else
41+
furi_string_cat_printf(data, "\n->Byte%d: 0x%02X", offset, value);
42+
len--;
43+
}
44+
}
45+
46+
static void analogValuesParser(void* context, uint8_t* buff, size_t len, FuriString* data) {
47+
App* app = context;
48+
uint16_t value = 0;
49+
size_t offset = 0;
50+
51+
while(offset < len) {
52+
value = 0;
53+
if(offset + 1 < len) {
54+
memcpy(((uint8_t*)&value) + 1, buff + offset, sizeof(uint8_t));
55+
memcpy((uint8_t*)&value, buff + offset + 1, sizeof(uint8_t));
56+
} else if(offset < len) {
57+
memcpy(((uint8_t*)&value) + 1, buff + offset, sizeof(uint8_t));
58+
}
59+
60+
furi_string_cat_printf(
61+
data,
62+
app->uart->cfg->hexOutput ? "\n->Reg%d: 0x%04X" : "\n->Reg%d: %d",
63+
offset / 2,
64+
value);
65+
66+
offset += 2;
67+
}
68+
}
69+
70+
static void pduParser(void* context, bool slave, uint8_t* buf, size_t len, FuriString* data) {
71+
App* app = context;
72+
size_t offset = 2;
73+
uint16_t address = 0;
74+
uint16_t qty = 0;
75+
uint16_t bCount = 0;
76+
uint16_t value = 0;
77+
UNUSED(len);
78+
furi_string_cat_printf(
79+
data, "\n%s", functionNames[FUNCTION <= 6 ? FUNCTION - 1 : FUNCTION - 9]);
80+
furi_string_cat_printf(
81+
data, app->uart->cfg->hexOutput ? "\nPeripheral: 0x%02X" : "\nPeripheral: %d", SLAVE);
82+
memcpy(
83+
slave && FUNCTION <= 4 ? &bCount : &address, buf + offset, slave && FUNCTION <= 4 ? 1 : 2);
84+
85+
offset += slave && FUNCTION <= 4 ? 1 : 2;
86+
address = address >> 8 | address << 8;
87+
if(app->uart->cfg->hexOutput)
88+
furi_string_cat_printf(
89+
data,
90+
slave && FUNCTION <= 4 ? "\nbCount: 0x%02X" : "\nAddress: 0x%04X",
91+
slave && FUNCTION <= 4 ? bCount : address);
92+
else
93+
furi_string_cat_printf(
94+
data,
95+
slave && FUNCTION <= 4 ? "\nbCount: %d" : "\nAddress: %d",
96+
slave && FUNCTION <= 4 ? bCount : address);
97+
98+
if(FUNCTION >= 0x0F || (!slave && FUNCTION <= 0x04)) {
99+
memcpy(&qty, buf + offset, 2);
100+
offset += 2;
101+
qty = qty >> 8 | qty << 8;
102+
furi_string_cat_printf(
103+
data, app->uart->cfg->hexOutput ? "\nQty: 0x%04X" : "\nQty: %d", qty);
104+
} else if(FUNCTION >= 0x05) {
105+
memcpy(&value, buf + offset, 2);
106+
offset += 2;
107+
value = value >> 8 | value << 8;
108+
if(FUNCTION == 0x05)
109+
furi_string_cat_printf(data, "\nValue: %s", buf[4] ? "ON" : "OFF");
110+
else
111+
furi_string_cat_printf(
112+
data, app->uart->cfg->hexOutput ? "\nValue: 0x%04X" : "\nValue: %d", value);
113+
} else if(FUNCTION <= 0x02)
114+
discreteValuesParser(app, buf + offset, bCount, data);
115+
else
116+
analogValuesParser(app, buf + offset, bCount, data);
117+
118+
if(FUNCTION >= 0x0F && !slave) {
119+
memcpy(&bCount, buf + offset, 1);
120+
offset++;
121+
furi_string_cat_printf(
122+
data, app->uart->cfg->hexOutput ? "\nbCount: 0x%02X" : "\nbCount: %d", bCount);
123+
if(FUNCTION == 0x0F)
124+
discreteValuesParser(app, buf + offset, bCount, data);
125+
else
126+
analogValuesParser(app, buf + offset, bCount, data);
127+
}
128+
furi_string_cat_printf(data, "\nCRC: 0x%02X", CRCL | CRCH << 8);
129+
}
130+
static void ErrParser(uint8_t* buf, size_t len, FuriString* data) {
131+
furi_string_cat_printf(
132+
data, "\nException code (%02X):\n%s\n", FUNCTION, exceptionCodes[EXCEPTION]);
133+
for(size_t i = 0; i < len; i++)
134+
furi_string_cat_printf(data, "%02X", buf[i]);
135+
}
136+
static void ModbusParser(uint8_t* buf, size_t len, App* app, FuriString* data) {
137+
if(FUNCTION > 0x80) {
138+
ErrParser(buf, len, data);
139+
} else if((FUNCTION > 0x06 && FUNCTION < 0x0F) || FUNCTION > 0x10) {
140+
furi_string_cat_printf(data, "\nUNSUPPORTED!!!\nFUNCTION(0x%02X)\n", FUNCTION);
141+
for(size_t i = 0; i < len; i++)
142+
furi_string_cat_printf(data, "%02X", buf[i]);
143+
} else if(FixedPaket && len - 4 != FixedModbusSize) {
144+
furi_string_cat_str(data, "\nLength-Type MissMatch!!!\n");
145+
for(size_t i = 0; i < len; i++)
146+
furi_string_cat_printf(data, "%02X", buf[i]);
147+
furi_string_cat_printf(
148+
data,
149+
"\nCheck Reponse TimeOut!!!\nCurrent: %dms",
150+
app->uart->cfg->timeout * TIMEOUT_SCALER);
151+
} else {
152+
if(!app->modbus->slave) {
153+
for(size_t i = 0; i < len; i++)
154+
app->msgBuf[i] = buf[i];
155+
writeRingBuffer(app->ringBuffer, buf, len);
156+
app->msgLen = len;
157+
}
158+
pduParser(app, app->modbus->slave, buf, len, data);
159+
}
160+
}
161+
void handle_rx_data_cb(uint8_t* buf, size_t len, void* context) {
162+
furi_assert(context);
163+
App* app = context;
164+
buf[len] = '\0';
165+
FuriString* data = furi_string_alloc();
166+
furi_string_reset(data);
167+
///*
168+
furi_string_cat_printf(
169+
data, "\n-----%s----", app->modbus->slave ? "PERIPHERAL-" : "---HUB----");
170+
if((CRCH | CRCL << 8) == getCRC(buf, len - 2)) {
171+
ModbusParser(buf, len, app, data);
172+
} else {
173+
furi_string_cat_str(data, "\nCRC check Failed:\n");
174+
for(size_t i = 0; i < len; i++)
175+
furi_string_cat_printf(data, "%02X", buf[i]);
176+
furi_string_cat_str(data, "\nPlease check UART Settings!!!");
177+
}
178+
//*/
179+
// for(size_t i = 0; i < len; i++) furi_string_cat_printf(data, "%02X",
180+
// buf[i]); furi_string_cat_str(data, "\n");
181+
app->textLen += furi_string_size(data);
182+
if(app->textLen >= 3500 - 1) {
183+
furi_string_right(app->text, app->textLen / 2);
184+
app->textLen = furi_string_size(app->text) + furi_string_size(data);
185+
}
186+
furi_string_cat_str(app->text, furi_string_get_cstr(data));
187+
188+
if(app->LOGfileReady)
189+
storage_file_write(app->LOGfile, furi_string_get_cstr(data), furi_string_size(data));
190+
191+
furi_string_free(data);
192+
193+
view_dispatcher_send_custom_event(app->viewDispatcher, Refresh);
194+
195+
if(app->modbus->slave) {
196+
app->modbus->slave = false;
197+
furi_timer_stop(app->timer);
198+
} else {
199+
app->modbus->slave = true;
200+
furi_timer_start(app->timer, app->uart->cfg->timeout * TIMEOUT_SCALER);
201+
}
202+
}
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
5+
void handle_rx_data_cb(uint8_t* buf, size_t len, void* context);
6+
uint16_t getCRC(uint8_t* buf, uint8_t len);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "modbus_ring_buffer.h"
2+
3+
RingBuffer* ring_buffer_alloc() {
4+
RingBuffer* buffer = malloc(sizeof(RingBuffer));
5+
buffer->writeIdx = 0;
6+
buffer->delimiterIdx = 0;
7+
for(uint8_t i = 0; i < 32; i++)
8+
buffer->delimiters[i] = 255;
9+
return buffer;
10+
}
11+
void ring_buffer_free(RingBuffer* buffer) {
12+
free(buffer);
13+
}
14+
void writeRingBuffer(RingBuffer* rb, uint8_t* buf, size_t len) {
15+
for(size_t i = 0; i < len; i++) {
16+
rb->ringBuffer[rb->writeIdx] = buf[i];
17+
if(i == len - 1) rb->delimiters[rb->delimiterIdx] = rb->writeIdx;
18+
if(++rb->writeIdx > 255) {
19+
rb->delimiterIdx = 0;
20+
rb->writeIdx = 0;
21+
}
22+
}
23+
rb->delimiterIdx++;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
5+
#include "../Modbus.h"
6+
7+
RingBuffer* ring_buffer_alloc();
8+
void ring_buffer_free(RingBuffer* buffer);
9+
void writeRingBuffer(RingBuffer* rb, uint8_t* buf, size_t len);
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "modbus_sender.h"
2+
#include "../modbus_parser/modbus_parser.h"
3+
4+
void ModbusSender(void* context) {
5+
App* app = context;
6+
// 02 | 0F | 00 00 | 00 04 | 01 | 0C | 7E 86
7+
Uart* uart = app->uart;
8+
uint16_t crc = getCRC(app->msgBuf, app->msgLen - 2);
9+
app->msgBuf[app->msgLen - 2] = crc & 0x00FF;
10+
app->msgBuf[app->msgLen - 1] = (crc & 0xFF00) >> 8;
11+
furi_hal_gpio_write(&gpio_ext_pc0, true);
12+
furi_hal_gpio_write(&gpio_ext_pc1, true);
13+
furi_hal_serial_tx(uart->serial_handle, app->msgBuf, app->msgLen);
14+
furi_hal_serial_tx_wait_complete(uart->serial_handle);
15+
furi_hal_gpio_write(&gpio_ext_pc0, false);
16+
furi_hal_gpio_write(&gpio_ext_pc1, false);
17+
app->modbus->slave = true;
18+
furi_timer_start(app->timer, app->uart->cfg->timeout * TIMEOUT_SCALER);
19+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
5+
#include "../Modbus.h"
6+
7+
void ModbusSender(void* context);
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include "modbus_storage.h"
2+
3+
char* sequential_file_resolve_path(
4+
Storage* storage,
5+
const char* dir,
6+
const char* prefix,
7+
const char* extension) {
8+
if(storage == NULL || dir == NULL || prefix == NULL || extension == NULL) {
9+
return NULL;
10+
}
11+
12+
char file_path[256];
13+
int file_index = 0;
14+
15+
do {
16+
if(snprintf(
17+
file_path, sizeof(file_path), "%s/%s_%d.%s", dir, prefix, file_index, extension) <
18+
0) {
19+
return NULL;
20+
}
21+
file_index++;
22+
} while(storage_file_exists(storage, file_path));
23+
24+
return strdup(file_path);
25+
}
26+
27+
void makePaths(App* app) {
28+
furi_assert(app);
29+
if(!storage_simply_mkdir(app->storage, PATHAPPEXT)) {
30+
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
31+
}
32+
if(!storage_simply_mkdir(app->storage, PATHLOGS)) {
33+
dialog_message_show_storage_error(app->dialogs, "Cannot create\nlogs folder");
34+
}
35+
}
36+
bool OpenLogFile(App* app) {
37+
// browse for files
38+
FuriString* predefined_filepath = furi_string_alloc_set_str(PATHLOGS);
39+
FuriString* selected_filepath = furi_string_alloc();
40+
DialogsFileBrowserOptions browser_options;
41+
dialog_file_browser_set_basic_options(&browser_options, ".log", NULL);
42+
if(!dialog_file_browser_show(
43+
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
44+
return false;
45+
}
46+
if(storage_file_open(
47+
app->LOGfile, furi_string_get_cstr(selected_filepath), FSAM_READ, FSOM_OPEN_EXISTING)) {
48+
app->uart->cfg->saveLOG = false;
49+
furi_string_reset(app->text);
50+
char buf[storage_file_size(app->LOGfile)];
51+
storage_file_read(app->LOGfile, buf, sizeof(buf));
52+
buf[sizeof(buf)] = '\0';
53+
furi_string_cat_str(app->text, buf);
54+
} else {
55+
dialog_message_show_storage_error(app->dialogs, "Cannot open File");
56+
return false;
57+
}
58+
storage_file_close(app->LOGfile);
59+
furi_string_free(selected_filepath);
60+
furi_string_free(predefined_filepath);
61+
return true;
62+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
5+
#include "../Modbus.h"
6+
7+
char* sequential_file_resolve_path(
8+
Storage* storage,
9+
const char* dir,
10+
const char* prefix,
11+
const char* extension);
12+
bool OpenLogFile(App* app);
13+
void makePaths(App* app);

‎ModbusApp/modbus_uart/modbus_uart.c

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#include "modbus_uart.h"
2+
#include "../modbus_sender/modbus_sender.h"
3+
#include "../modbus_parser/modbus_parser.h"
4+
5+
LL_USART_InitTypeDef buildUartSettings(Config* cfg) {
6+
LL_USART_InitTypeDef USART_InitStruct;
7+
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
8+
9+
USART_InitStruct.BaudRate = atoi(baudrateValues[cfg->baudrate]);
10+
USART_InitStruct.DataWidth =
11+
(cfg->dataWidth == 0 ? LL_USART_DATAWIDTH_7B :
12+
cfg->dataWidth == 2 ? LL_USART_DATAWIDTH_9B :
13+
LL_USART_DATAWIDTH_8B);
14+
15+
USART_InitStruct.StopBits =
16+
(cfg->stopBits == 0 ? LL_USART_STOPBITS_0_5 :
17+
cfg->stopBits == 2 ? LL_USART_STOPBITS_1_5 :
18+
cfg->stopBits == 3 ? LL_USART_STOPBITS_2 :
19+
LL_USART_STOPBITS_1);
20+
21+
USART_InitStruct.Parity =
22+
(cfg->parity == 1 ? LL_USART_PARITY_EVEN :
23+
cfg->parity == 2 ? LL_USART_PARITY_ODD :
24+
LL_USART_PARITY_NONE);
25+
26+
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
27+
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
28+
USART_InitStruct.OverSampling = FURI_HAL_SERIAL_USART_OVERSAMPLING;
29+
return USART_InitStruct;
30+
}
31+
void uart_set_config(void* context) {
32+
furi_assert(context);
33+
App* app = context;
34+
UNUSED(app);
35+
// furi_thread_flags_set(furi_thread_get_id(app->uart->rxThread),
36+
// WorkerEvtCfgChange);
37+
}
38+
void Serial_Begin(FuriHalSerialHandle* handle, LL_USART_InitTypeDef USART_InitStruct) {
39+
furi_hal_bus_enable(FuriHalBusUSART1);
40+
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
41+
42+
furi_hal_gpio_init_ex(
43+
&gpio_usart_tx,
44+
GpioModeAltFunctionPushPull,
45+
GpioPullUp,
46+
GpioSpeedVeryHigh,
47+
GpioAltFn7USART1);
48+
furi_hal_gpio_init_ex(
49+
&gpio_usart_rx,
50+
GpioModeAltFunctionPushPull,
51+
GpioPullUp,
52+
GpioSpeedVeryHigh,
53+
GpioAltFn7USART1);
54+
LL_USART_Init(USART1, &USART_InitStruct);
55+
LL_USART_EnableFIFO(USART1);
56+
LL_USART_ConfigAsyncMode(USART1);
57+
58+
LL_USART_Enable(USART1);
59+
60+
while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1))
61+
;
62+
63+
furi_hal_serial_set_br(handle, USART_InitStruct.BaudRate);
64+
LL_USART_DisableIT_ERROR(USART1);
65+
}
66+
67+
static void
68+
on_rx_cb(FuriHalSerialHandle* handle, FuriHalSerialRxEvent ev, size_t size, void* context) {
69+
Uart* uart = context;
70+
if(ev & (FuriHalSerialRxEventData | FuriHalSerialRxEventIdle)) {
71+
uint8_t data[FURI_HAL_SERIAL_DMA_BUFFER_SIZE] = {0};
72+
while(size) {
73+
size_t ret = furi_hal_serial_dma_rx(
74+
handle,
75+
data,
76+
(size > FURI_HAL_SERIAL_DMA_BUFFER_SIZE) ? FURI_HAL_SERIAL_DMA_BUFFER_SIZE : size);
77+
furi_stream_buffer_send(uart->rxStream, data, ret, 0);
78+
size -= ret;
79+
};
80+
furi_thread_flags_set(furi_thread_get_id(uart->rxThread), WorkerEvtRxDone);
81+
}
82+
}
83+
void serial_init(Uart* uart, uint8_t uart_ch) {
84+
furi_assert(!uart->serial_handle);
85+
uart->serial_handle = furi_hal_serial_control_acquire(uart_ch);
86+
furi_assert(uart->serial_handle);
87+
88+
Serial_Begin(uart->serial_handle, buildUartSettings(uart->cfg));
89+
furi_hal_serial_dma_rx_start(uart->serial_handle, on_rx_cb, uart, false);
90+
}
91+
void serial_deinit(Uart* uart) {
92+
furi_assert(uart->serial_handle);
93+
94+
furi_hal_serial_dma_rx_stop(uart->serial_handle);
95+
furi_hal_serial_deinit(uart->serial_handle);
96+
furi_hal_serial_control_release(uart->serial_handle);
97+
uart->serial_handle = NULL;
98+
}
99+
void timerDone(void* context) {
100+
App* app = context;
101+
app->modbus->slave = false;
102+
}
103+
int32_t uart_worker(void* context) {
104+
App* app = context;
105+
while(1) {
106+
uint32_t events =
107+
furi_thread_flags_wait(WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
108+
furi_check((events & FuriFlagError) == 0);
109+
if(events & WorkerEvtStop) break;
110+
if(events & WorkerEvtCfgChange) {
111+
serial_deinit(app->uart);
112+
serial_init(app->uart, UART_CH);
113+
}
114+
if(events & WorkerEvtRxDone) {
115+
size_t len =
116+
furi_stream_buffer_receive(app->uart->rxStream, app->uart->rxBuff, RX_BUF_SIZE, 0);
117+
if(len > 0) {
118+
handle_rx_data_cb(app->uart->rxBuff, len, app);
119+
}
120+
}
121+
if(events & WorkerEvtTxStart) {
122+
ModbusSender(app);
123+
}
124+
}
125+
126+
return 0;
127+
}

‎ModbusApp/modbus_uart/modbus_uart.h

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
#include "../Modbus.h"
5+
6+
LL_USART_InitTypeDef buildUartSettings(Config* cfg);
7+
void uart_set_config(void* context);
8+
void Serial_Begin(FuriHalSerialHandle* handle, LL_USART_InitTypeDef USART_InitStruct);
9+
int32_t uart_worker(void* context);
10+
void timerDone(void* context);
11+
void serial_deinit(Uart* uart);
12+
void serial_init(Uart* uart, uint8_t uart_ch);

‎ModbusApp/scenes/byte_input_scene.c

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "../Modbus.h"
2+
3+
////////////////////////// ByteInput Scene ////////////////////////
4+
void SetValue(void* context) {
5+
App* app = context;
6+
scene_manager_handle_back_event(app->sceneManager);
7+
}
8+
void app_scene_byte_input_on_enter(void* context) {
9+
App* app = context;
10+
uint8_t* buf = app->msgBuf;
11+
uint8_t offset = scene_manager_get_scene_state(app->sceneManager, app_scene_byte_input);
12+
switch(scene_manager_get_scene_state(app->sceneManager, app_scene_byte_input)) {
13+
case 0:
14+
byte_input_set_header_text(app->byteInput, "Set Slave");
15+
byte_input_set_result_callback(app->byteInput, SetValue, NULL, app, &SLAVE, 1);
16+
view_dispatcher_switch_to_view(app->viewDispatcher, ByteInput_View);
17+
break;
18+
case 1:
19+
byte_input_set_header_text(app->byteInput, "Set Function");
20+
byte_input_set_result_callback(app->byteInput, SetValue, NULL, app, &FUNCTION, 1);
21+
view_dispatcher_switch_to_view(app->viewDispatcher, ByteInput_View);
22+
break;
23+
case 2:
24+
byte_input_set_header_text(app->byteInput, "Set Address");
25+
byte_input_set_result_callback(app->byteInput, SetValue, NULL, app, &buf[2], 2);
26+
view_dispatcher_switch_to_view(app->viewDispatcher, ByteInput_View);
27+
break;
28+
case 3:
29+
byte_input_set_header_text(app->byteInput, "Set value or quantity");
30+
byte_input_set_result_callback(app->byteInput, SetValue, NULL, app, &buf[4], 2);
31+
view_dispatcher_switch_to_view(app->viewDispatcher, ByteInput_View);
32+
break;
33+
default:
34+
if(FUNCTION == 0x0F)
35+
offset += 2;
36+
else
37+
offset += offset - 3;
38+
byte_input_set_header_text(app->byteInput, "Set x value");
39+
byte_input_set_result_callback(
40+
app->byteInput, SetValue, NULL, app, &buf[offset], FUNCTION == 0x0F ? 1 : 2);
41+
view_dispatcher_switch_to_view(app->viewDispatcher, ByteInput_View);
42+
break;
43+
}
44+
}
45+
bool app_scene_byte_input_on_event(void* context, SceneManagerEvent event) {
46+
UNUSED(context);
47+
UNUSED(event);
48+
return false;
49+
}
50+
void app_scene_byte_input_on_exit(void* context) {
51+
App* app = context;
52+
UNUSED(app);
53+
}

‎ModbusApp/scenes/main_scene.c

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "../Modbus.h"
2+
#include "../modbus_storage/modbus_storage.h"
3+
4+
////////////////////////// Main Scene //////////////////////////
5+
void mainOptionsCB(void* context, uint32_t index) {
6+
App* app = context;
7+
8+
switch(index) {
9+
case Settings_Option:
10+
scene_manager_set_scene_state(app->sceneManager, app_scene_main, Settings_Option);
11+
scene_manager_next_scene(app->sceneManager, app_scene_settings);
12+
break;
13+
case Sniffer_Option:
14+
scene_manager_set_scene_state(app->sceneManager, app_scene_main, Sniffer_Option);
15+
scene_manager_set_scene_state(app->sceneManager, app_scene_sniffer, Sniffer_Option);
16+
scene_manager_next_scene(app->sceneManager, app_scene_sniffer);
17+
break;
18+
case Sender_Option:
19+
scene_manager_set_scene_state(app->sceneManager, app_scene_main, Sender_Option);
20+
scene_manager_next_scene(app->sceneManager, app_scene_sender);
21+
break;
22+
case Read_LOG_Option:
23+
scene_manager_set_scene_state(app->sceneManager, app_scene_main, Read_LOG_Option);
24+
if(OpenLogFile(app)) {
25+
scene_manager_set_scene_state(app->sceneManager, app_scene_sniffer, Read_LOG_Option);
26+
scene_manager_next_scene(app->sceneManager, app_scene_sniffer);
27+
}
28+
break;
29+
case About_Option:
30+
scene_manager_set_scene_state(app->sceneManager, app_scene_main, About_Option);
31+
scene_manager_set_scene_state(app->sceneManager, app_scene_sniffer, About_Option);
32+
scene_manager_next_scene(app->sceneManager, app_scene_sniffer);
33+
break;
34+
default:
35+
break;
36+
}
37+
}
38+
39+
void app_scene_main_on_enter(void* context) {
40+
App* app = context;
41+
submenu_reset(app->subMenu);
42+
submenu_set_header(app->subMenu, "Main");
43+
submenu_add_item(app->subMenu, "Settings", Settings_Option, mainOptionsCB, app);
44+
submenu_add_item(app->subMenu, "Sniffer", Sniffer_Option, mainOptionsCB, app);
45+
submenu_add_item(app->subMenu, "Sender", Sender_Option, mainOptionsCB, app);
46+
submenu_add_item(app->subMenu, "Read LOG", Read_LOG_Option, mainOptionsCB, app);
47+
submenu_add_item(app->subMenu, "About", About_Option, mainOptionsCB, app);
48+
submenu_set_selected_item(
49+
app->subMenu, scene_manager_get_scene_state(app->sceneManager, app_scene_main));
50+
view_dispatcher_switch_to_view(app->viewDispatcher, Submenu_View);
51+
}
52+
bool app_scene_main_on_event(void* context, SceneManagerEvent event) {
53+
UNUSED(context);
54+
UNUSED(event);
55+
return false;
56+
}
57+
void app_scene_main_on_exit(void* context) {
58+
App* app = context;
59+
submenu_reset(app->subMenu);
60+
}
+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include "../Modbus.h"
2+
3+
void BuildSender(App* app, uint8_t* buf);
4+
5+
////////////////////////// Manual Sender Scene //////////////////////////
6+
const char* fns[] = {"0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x0F", "0x10"};
7+
8+
void itemChangeCB(VariableItem* item) {
9+
App* app = variable_item_get_context(item);
10+
uint8_t* buf = app->msgBuf;
11+
uint8_t index = variable_item_get_current_value_index(item);
12+
uint8_t selectedIndex = variable_item_list_get_selected_item_index(app->varList);
13+
uint16_t Value;
14+
char str[10];
15+
switch(selectedIndex) {
16+
case 0:
17+
snprintf(str, sizeof(str), "%d", index + 1);
18+
variable_item_set_current_value_text(item, strdup(str));
19+
buf[0] = index + 1;
20+
break;
21+
case 1:
22+
variable_item_set_current_value_text(item, fns[index]);
23+
FUNCTION = index <= 0x05 ? index + 1 : index + 9;
24+
buf[4] = 0;
25+
buf[5] = 1;
26+
BuildSender(app, buf);
27+
break;
28+
case 2:
29+
snprintf(str, sizeof(str), "%d", index);
30+
variable_item_set_current_value_text(item, strdup(str));
31+
buf[2] = index >> 8 & 0x00FF;
32+
buf[3] = index & 0x00FF;
33+
break;
34+
case 3:
35+
if(FUNCTION != 0x05 && FUNCTION != 0x06) {
36+
index++;
37+
snprintf(str, sizeof(str), "%d", index);
38+
variable_item_set_current_value_text(item, strdup(str));
39+
buf[4] = index >> 8 & 0x00FF;
40+
buf[5] = index & 0x00FF;
41+
if(FUNCTION >= 0x0F) {
42+
Value = (buf[4] << 8 | buf[5]);
43+
if(FUNCTION == 0x0F)
44+
Value = Value % 8 ? Value / 8 + 1 : Value / 8;
45+
else
46+
Value = Value * 2;
47+
item = variable_item_list_get(app->varList, 4);
48+
snprintf(str, sizeof(str), "[ %d ]", Value);
49+
variable_item_set_current_value_text(item, strdup(str));
50+
if(BYTECOUNT != Value) {
51+
BYTECOUNT = Value;
52+
BuildSender(app, buf);
53+
}
54+
}
55+
} else {
56+
Value = FUNCTION == 5 ? index ? 0xFF00 : 0x0000 : index;
57+
snprintf(str, sizeof(str), "0x%04X", Value);
58+
variable_item_set_current_value_text(
59+
item, FUNCTION == 0x05 ? index ? "ON" : "OFF" : str);
60+
buf[4] = Value >> 8 & 0x00FF;
61+
buf[5] = Value & 0x00FF;
62+
}
63+
break;
64+
default:
65+
Value = index;
66+
snprintf(str, sizeof(str), FUNCTION == 0x10 ? "0x%04X" : "0x%02X", Value);
67+
variable_item_set_current_value_text(item, str);
68+
if(FUNCTION == 0x0F) {
69+
selectedIndex += 2;
70+
buf[selectedIndex] = Value;
71+
} else {
72+
selectedIndex += selectedIndex - 3;
73+
74+
buf[selectedIndex] = Value >> 8 & 0x0FF;
75+
buf[selectedIndex + 1] = Value & 0x00FF;
76+
}
77+
break;
78+
}
79+
}
80+
81+
void itemEnterCB(void* context, uint32_t index) {
82+
App* app = context;
83+
uint8_t* buf = app->msgBuf;
84+
uint8_t SendButton = FUNCTION >= 0x0F ? (FUNCTION == 0x0F ? BYTECOUNT : QUANTITY) + 5 : 4;
85+
scene_manager_set_scene_state(app->sceneManager, app_scene_manual_sender, index);
86+
if(index == SendButton) {
87+
scene_manager_set_scene_state(app->sceneManager, app_scene_sniffer, Sender_Option);
88+
scene_manager_next_scene(app->sceneManager, app_scene_sniffer);
89+
}
90+
91+
else if(index == 1 || (FUNCTION >= 0x0F && index == 4)) {
92+
} else {
93+
if(!(FUNCTION == 0x05 && index == 3)) {
94+
scene_manager_set_scene_state(app->sceneManager, app_scene_byte_input, index);
95+
scene_manager_next_scene(app->sceneManager, app_scene_byte_input);
96+
}
97+
}
98+
}
99+
void BuildValues(App* app, uint16_t byteCount, uint8_t* buf, bool one) {
100+
VariableItem* item;
101+
char lbl[20];
102+
char val[10];
103+
for(uint16_t i = 0; i < byteCount; i += one ? 1 : 2) {
104+
snprintf(lbl, sizeof(lbl), one ? "Byte %d" : "Register %d", one ? i + 1 : i / 2 + 1);
105+
snprintf(
106+
val, sizeof(val), one ? "0x%02X" : "0x%04X", one ? buf[i] : buf[i] << 8 | buf[i + 1]);
107+
item = variable_item_list_add(app->varList, strdup(lbl), 255, itemChangeCB, app);
108+
variable_item_set_current_value_text(item, strdup(val));
109+
variable_item_set_current_value_index(
110+
item, MIN(255, one ? buf[i] : buf[i] << 8 | buf[i + 1]));
111+
}
112+
}
113+
void BuildSender(App* app, uint8_t* buf) {
114+
variable_item_list_reset(app->varList);
115+
VariableItem* item;
116+
uint16_t Value = 0;
117+
char val[10];
118+
SLAVE = MIN(SLAVE, 32);
119+
snprintf(val, sizeof(val), "%d", SLAVE);
120+
item = variable_item_list_add(app->varList, "Peripheral ID", 32, itemChangeCB, app);
121+
variable_item_set_current_value_text(item, strdup(val));
122+
variable_item_set_current_value_index(item, SLAVE - 1);
123+
item = variable_item_list_add(app->varList, "Function", 8, itemChangeCB, app);
124+
variable_item_set_current_value_text(item, fns[FUNCTION <= 6 ? FUNCTION - 1 : FUNCTION - 9]);
125+
variable_item_set_current_value_index(item, FUNCTION <= 6 ? FUNCTION - 1 : FUNCTION - 9);
126+
Value = STARTADDRESS;
127+
snprintf(val, sizeof(val), "%d", Value);
128+
item = variable_item_list_add(app->varList, "Start Address", 255, itemChangeCB, app);
129+
variable_item_set_current_value_text(item, strdup(val));
130+
variable_item_set_current_value_index(item, MIN(255, STARTADDRESS));
131+
if(FUNCTION != 0x05 && FUNCTION != 0x06) {
132+
uint16_t max = FUNCTION == 0x10 ? 0x0A :
133+
FUNCTION == 0x0F ? 0x50 :
134+
FUNCTION <= 0x02 ? 0x7D0 :
135+
0x7D;
136+
Value = MIN(buf[4] << 8 | buf[5], max);
137+
snprintf(val, sizeof(val), "%d", Value);
138+
item = variable_item_list_add(app->varList, "Quantity", max, itemChangeCB, app);
139+
variable_item_set_current_value_text(item, strdup(val));
140+
variable_item_set_current_value_index(item, MIN(Value - 1, MIN(max, 255)));
141+
buf[4] = Value >> 8 & 0x00FF;
142+
buf[5] = Value & 0x00FF;
143+
} else {
144+
Value = buf[4] << 8 | buf[5];
145+
snprintf(val, sizeof(val), "0x%04X", Value);
146+
item = variable_item_list_add(
147+
app->varList, "Value", FUNCTION == 0x05 ? 2 : 255, itemChangeCB, app);
148+
variable_item_set_current_value_text(
149+
item, FUNCTION == 0x05 ? Value ? "ON" : "OFF" : strdup(val));
150+
variable_item_set_current_value_index(
151+
item, FUNCTION == 0x05 ? Value ? 1 : 0 : MIN(Value, 255));
152+
Value = FUNCTION == 5 ? Value ? 0xFF00 : 0x0000 : Value;
153+
buf[4] = Value >> 8 & 0x00FF;
154+
buf[5] = Value & 0x00FF;
155+
}
156+
if(FUNCTION >= 0x0F) {
157+
Value = (buf[4] << 8 | buf[5]);
158+
if(FUNCTION == 0x0F)
159+
Value = Value % 8 ? Value / 8 + 1 : Value / 8;
160+
else
161+
Value = Value * 2;
162+
snprintf(val, sizeof(val), "[ %d ]", Value);
163+
item = variable_item_list_add(app->varList, "ByteCount", 1, NULL, app);
164+
variable_item_set_current_value_text(item, strdup(val));
165+
variable_item_set_current_value_index(item, 0);
166+
BYTECOUNT = Value;
167+
app->msgLen = Value + 9;
168+
BuildValues(app, Value, buf + 7, FUNCTION == 0x0F ? true : false);
169+
}
170+
171+
item = variable_item_list_add(app->varList, "Send Packet", 1, NULL, app);
172+
variable_item_list_set_enter_callback(app->varList, itemEnterCB, app);
173+
variable_item_set_current_value_text(item, "");
174+
variable_item_set_current_value_index(item, 0);
175+
}
176+
void app_scene_manual_sender_on_enter(void* context) {
177+
App* app = context;
178+
BuildSender(app, app->msgBuf);
179+
variable_item_list_set_selected_item(
180+
app->varList, scene_manager_get_scene_state(app->sceneManager, app_scene_manual_sender));
181+
view_dispatcher_switch_to_view(app->viewDispatcher, VarList_View);
182+
}
183+
bool app_scene_manual_sender_on_event(void* context, SceneManagerEvent event) {
184+
UNUSED(context);
185+
UNUSED(event);
186+
return false;
187+
}
188+
void app_scene_manual_sender_on_exit(void* context) {
189+
App* app = context;
190+
variable_item_list_reset(app->varList);
191+
}

‎ModbusApp/scenes/msgs_buffer_scene.c

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "../Modbus.h"
2+
#include "../modbus_parser/modbus_parser.h"
3+
4+
void OnItemEnterCB(void* context, uint32_t index) {
5+
App* app = context;
6+
uint8_t start = index ? app->ringBuffer->delimiters[index - 1] + 1 : 0;
7+
for(uint8_t i = start; i <= app->ringBuffer->delimiters[index]; i++) {
8+
app->msgBuf[i - start] = app->ringBuffer->ringBuffer[i];
9+
if(i == app->ringBuffer->delimiters[index]) app->msgLen = i - start + 1;
10+
}
11+
scene_manager_next_scene(app->sceneManager, app_scene_manual_sender);
12+
}
13+
void BuildCMDList(App* app) {
14+
submenu_set_header(app->subMenu, " ID | FN |Adss");
15+
RingBuffer* rb = app->ringBuffer;
16+
rb->readIdx = 0;
17+
uint8_t buf[255];
18+
uint8_t i = 0;
19+
uint8_t delimiterIdx = 0;
20+
uint8_t len = 0;
21+
char lbl[30];
22+
do {
23+
len = 0;
24+
do {
25+
snprintf(lbl, sizeof(lbl), " %d | %d | %d |", SLAVE, FUNCTION, STARTADDRESS);
26+
buf[len] = rb->ringBuffer[i];
27+
len++;
28+
i++;
29+
} while(i <= rb->delimiters[delimiterIdx] && i < 255);
30+
delimiterIdx++;
31+
if((CRCH | CRCL << 8) == getCRC(buf, len - 2))
32+
submenu_add_item(app->subMenu, lbl, delimiterIdx - 1, OnItemEnterCB, app);
33+
} while(i < 255);
34+
}
35+
void app_scene_msgs_buffer_on_enter(void* context) {
36+
App* app = context;
37+
submenu_reset(app->subMenu);
38+
BuildCMDList(app);
39+
view_dispatcher_switch_to_view(app->viewDispatcher, Submenu_View);
40+
}
41+
bool app_scene_msgs_buffer_on_event(void* context, SceneManagerEvent event) {
42+
UNUSED(context);
43+
UNUSED(event);
44+
return false;
45+
}
46+
void app_scene_msgs_buffer_on_exit(void* context) {
47+
App* app = context;
48+
submenu_reset(app->subMenu);
49+
}

‎ModbusApp/scenes/sender_scene.c

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "../Modbus.h"
2+
3+
////////////////////////// Sender Scene ////////////////////////
4+
void SenderOptionsCB(void* context, uint32_t index) {
5+
App* app = context;
6+
if(index == Manual_Sender_Option) {
7+
scene_manager_set_scene_state(app->sceneManager, app_scene_sender, Manual_Sender_Option);
8+
scene_manager_next_scene(app->sceneManager, app_scene_manual_sender);
9+
} else if(index == Buffer_Sender_Option) {
10+
scene_manager_set_scene_state(app->sceneManager, app_scene_sender, Buffer_Sender_Option);
11+
scene_manager_next_scene(app->sceneManager, app_scene_msgs_buffer);
12+
}
13+
}
14+
void app_scene_sender_on_enter(void* context) {
15+
App* app = context;
16+
submenu_reset(app->subMenu);
17+
submenu_set_header(app->subMenu, "Sender");
18+
submenu_add_item(app->subMenu, "Manual Sender", Manual_Sender_Option, SenderOptionsCB, app);
19+
submenu_add_item(app->subMenu, "Buffer Sender", Buffer_Sender_Option, SenderOptionsCB, app);
20+
submenu_set_selected_item(
21+
app->subMenu, scene_manager_get_scene_state(app->sceneManager, app_scene_main));
22+
view_dispatcher_switch_to_view(app->viewDispatcher, Submenu_View);
23+
}
24+
bool app_scene_sender_on_event(void* context, SceneManagerEvent event) {
25+
UNUSED(context);
26+
UNUSED(event);
27+
return false;
28+
}
29+
void app_scene_sender_on_exit(void* context) {
30+
App* app = context;
31+
submenu_reset(app->subMenu);
32+
}

‎ModbusApp/scenes/settings_scene.c

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "../Modbus.h"
2+
#include "../modbus_storage/modbus_storage.h"
3+
#include "../modbus_uart/modbus_uart.h"
4+
5+
void itemChangedCB(VariableItem* item) {
6+
App* app = variable_item_get_context(item);
7+
uint8_t index = variable_item_get_current_value_index(item);
8+
uint8_t selectedIndex = variable_item_list_get_selected_item_index(app->varList);
9+
switch(selectedIndex) {
10+
case BaudRate_Option:
11+
variable_item_set_current_value_text(item, baudrateValues[index]);
12+
app->uart->cfg->baudrate = index;
13+
break;
14+
case DataWidth_Option:
15+
variable_item_set_current_value_text(item, dataWidthValues[index]);
16+
app->uart->cfg->dataWidth = index;
17+
break;
18+
case StopBits_Option:
19+
variable_item_set_current_value_text(item, stopBitsValues[index]);
20+
app->uart->cfg->stopBits = index;
21+
break;
22+
case Parity_Option:
23+
variable_item_set_current_value_text(item, parityValues[index]);
24+
app->uart->cfg->timeout = index;
25+
break;
26+
case TimeOut_Option:
27+
app->uart->cfg->timeout = index;
28+
variable_item_set_current_value_index(item, index);
29+
furi_string_printf(app->modbus->timeout, "%d", index * TIMEOUT_SCALER);
30+
variable_item_set_current_value_text(item, furi_string_get_cstr(app->modbus->timeout));
31+
break;
32+
case OutputFormat_Option:
33+
variable_item_set_current_value_text(item, outputFormatValues[index]);
34+
app->uart->cfg->hexOutput = index;
35+
break;
36+
case SaveLOG_Option:
37+
variable_item_set_current_value_text(item, saveLOGValues[index]);
38+
app->uart->cfg->saveLOG = index;
39+
break;
40+
default:
41+
break;
42+
}
43+
}
44+
void app_scene_settings_on_enter(void* context) {
45+
App* app = context;
46+
VariableItem* item;
47+
item = variable_item_list_add(app->varList, "Buadrate", BR_VALUES, itemChangedCB, app);
48+
variable_item_set_current_value_index(item, app->uart->cfg->baudrate);
49+
variable_item_set_current_value_text(item, baudrateValues[app->uart->cfg->baudrate]);
50+
item = variable_item_list_add(app->varList, "Data size", DATAWIDTH_VALUES, itemChangedCB, app);
51+
variable_item_set_current_value_index(item, app->uart->cfg->dataWidth);
52+
variable_item_set_current_value_text(item, dataWidthValues[app->uart->cfg->dataWidth]);
53+
item = variable_item_list_add(app->varList, "Stop bits", STOPBITS_VALUES, itemChangedCB, app);
54+
variable_item_set_current_value_index(item, app->uart->cfg->stopBits);
55+
variable_item_set_current_value_text(item, stopBitsValues[app->uart->cfg->stopBits]);
56+
item = variable_item_list_add(app->varList, "Parity", PARITY_VALUES, itemChangedCB, app);
57+
variable_item_set_current_value_index(item, app->uart->cfg->parity);
58+
variable_item_set_current_value_text(item, parityValues[app->uart->cfg->parity]);
59+
item = variable_item_list_add(app->varList, "TimeOut(ms)", TIMEOUT_VALUES, itemChangedCB, app);
60+
variable_item_set_current_value_index(item, app->uart->cfg->timeout);
61+
furi_string_printf(app->modbus->timeout, "%d", app->uart->cfg->timeout * TIMEOUT_SCALER);
62+
variable_item_set_current_value_text(item, furi_string_get_cstr(app->modbus->timeout));
63+
item = variable_item_list_add(
64+
app->varList, "Output Format", DIGITALFORMAT_VALUES, itemChangedCB, app);
65+
variable_item_set_current_value_index(item, app->uart->cfg->hexOutput ? 1 : 0);
66+
variable_item_set_current_value_text(
67+
item, outputFormatValues[app->uart->cfg->hexOutput ? 1 : 0]);
68+
item = variable_item_list_add(app->varList, "Save LOG?", SAVE_LOG_VALUES, itemChangedCB, app);
69+
variable_item_set_current_value_index(item, app->uart->cfg->saveLOG ? 1 : 0);
70+
variable_item_set_current_value_text(item, saveLOGValues[app->uart->cfg->saveLOG ? 1 : 0]);
71+
72+
variable_item_list_set_selected_item(app->varList, 0);
73+
view_dispatcher_switch_to_view(app->viewDispatcher, VarList_View);
74+
}
75+
bool app_scene_settings_on_event(void* context, SceneManagerEvent event) {
76+
UNUSED(context);
77+
UNUSED(event);
78+
return false;
79+
}
80+
void app_scene_settings_on_exit(void* context) {
81+
App* app = context;
82+
if(app->uart->cfg->saveLOG) {
83+
strcpy(
84+
app->logFilePath, sequential_file_resolve_path(app->storage, PATHLOGS, "Log", "log"));
85+
if(app->logFilePath != NULL) {
86+
if(storage_file_open(app->LOGfile, app->logFilePath, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
87+
furi_string_reset(app->text);
88+
app->LOGfileReady = true;
89+
} else {
90+
dialog_message_show_storage_error(app->dialogs, "Cannot open log file");
91+
}
92+
} else {
93+
dialog_message_show_storage_error(app->dialogs, "Cannot resolve log path");
94+
}
95+
}
96+
uart_set_config(app);
97+
variable_item_list_reset(app->varList);
98+
}

‎ModbusApp/scenes/sniffer_scene.c

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "../Modbus.h"
2+
#include "../modbus_uart/modbus_uart.h"
3+
4+
////////////////////////// Sniffer Scene //////////////////////////
5+
void app_scene_sniffer_on_enter(void* context) {
6+
App* app = context;
7+
serial_init(app->uart, UART_CH);
8+
if(scene_manager_get_scene_state(app->sceneManager, app_scene_sniffer) == Sniffer_Option ||
9+
scene_manager_get_scene_state(app->sceneManager, app_scene_sniffer) == Sender_Option) {
10+
text_box_set_font(app->textBox, TextBoxFontText);
11+
text_box_set_focus(app->textBox, TextBoxFocusEnd);
12+
furi_string_cat_printf(
13+
app->text, "Baudrate: %s", baudrateValues[app->uart->cfg->baudrate]);
14+
furi_string_cat_printf(
15+
app->text, "\nData Width: %s", dataWidthValues[app->uart->cfg->dataWidth]);
16+
furi_string_cat_printf(
17+
app->text, "\nStop bits: %s", stopBitsValues[app->uart->cfg->stopBits]);
18+
furi_string_cat_printf(app->text, "\nParity: %s", parityValues[app->uart->cfg->parity]);
19+
furi_string_cat_printf(
20+
app->text, "\nResponse TimeOut: %dms", app->uart->cfg->timeout * TIMEOUT_SCALER);
21+
} else if(scene_manager_get_scene_state(app->sceneManager, app_scene_sniffer) == About_Option) {
22+
text_box_set_font(app->textBox, TextBoxFontText);
23+
text_box_set_focus(app->textBox, TextBoxFocusStart);
24+
furi_string_cat_printf(app->text, "MODBUS APP\n");
25+
furi_string_cat_printf(app->text, "BY: ROBERTO ARELLANO\n");
26+
furi_string_cat_printf(app->text, "ELECTRONIC CATS\n");
27+
furi_string_cat_printf(
28+
app->text,
29+
"https://github.com/ElectronicCats/"
30+
"flipper-rs485modbus/tree/main/ModbusApp/Test1");
31+
}
32+
view_dispatcher_switch_to_view(app->viewDispatcher, TextBox_View);
33+
text_box_set_text(app->textBox, furi_string_get_cstr(app->text));
34+
if(scene_manager_get_scene_state(app->sceneManager, app_scene_sniffer) == Sender_Option) {
35+
furi_thread_flags_set(furi_thread_get_id(app->uart->rxThread), WorkerEvtTxStart);
36+
}
37+
}
38+
bool app_scene_sniffer_on_event(void* context, SceneManagerEvent event) {
39+
App* app = context;
40+
UNUSED(app);
41+
bool consumed = false;
42+
if(event.type == SceneManagerEventTypeCustom) {
43+
consumed = true;
44+
text_box_set_text(app->textBox, furi_string_get_cstr(app->text));
45+
}
46+
return consumed;
47+
}
48+
void app_scene_sniffer_on_exit(void* context) {
49+
App* app = context;
50+
text_box_reset(app->textBox);
51+
furi_string_reset(app->text);
52+
serial_deinit(app->uart);
53+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//---------------------------------------------------------------------
2+
// Here you gonna put all the scenes you wanna use, they have to be in
3+
// order.
4+
//
5+
// For any scene you "add", you have to create 3 functions in every scene,
6+
// they can be on one file or can be in differents files but must be included
7+
// in the program
8+
//
9+
// The name of the functions will be given in the app_scene_functions.c
10+
// there is a code that defines the names and the functions
11+
//---------------------------------------------------------------------
12+
13+
ADD_SCENE(app, main, main)
14+
ADD_SCENE(app, settings, settings)
15+
ADD_SCENE(app, sniffer, sniffer)
16+
ADD_SCENE(app, sender, sender)
17+
ADD_SCENE(app, byte_input, byte_input)
18+
ADD_SCENE(app, manual_sender, manual_sender)
19+
ADD_SCENE(app, msgs_buffer, msgs_buffer)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "app_scene_functions.h"
2+
3+
//--------------------------------------------------------------------
4+
// This part works to create the name of the functions
5+
// of the "on_enter" for every scene.
6+
//--------------------------------------------------------------------
7+
8+
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
9+
void (*const app_on_enter_handlers[])(void*) = {
10+
#include "app_scene_config.h"
11+
};
12+
#undef ADD_SCENE
13+
14+
//--------------------------------------------------------------------
15+
// This part works to create the name of the functions
16+
// of the "on_event" for every scene.
17+
//--------------------------------------------------------------------
18+
19+
// Generate scene on_event handlers array
20+
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
21+
bool (*const app_on_event_handlers[])(void* context, SceneManagerEvent event) = {
22+
#include "app_scene_config.h"
23+
};
24+
#undef ADD_SCENE
25+
26+
//--------------------------------------------------------------------
27+
// This part works to create the name of the functions
28+
// of the "on_exit" for every scene.
29+
//--------------------------------------------------------------------
30+
31+
// Generate scene on_exit handlers array
32+
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
33+
void (*const app_on_exit_handlers[])(void* context) = {
34+
#include "app_scene_config.h"
35+
};
36+
#undef ADD_SCENE
37+
38+
//--------------------------------------------------------------------
39+
// Here we add the callback functions for the scenes.
40+
//--------------------------------------------------------------------
41+
42+
// Initialize scene handlers configuration structure
43+
const SceneManagerHandlers app_scene_handlers = {
44+
.on_enter_handlers = app_on_enter_handlers,
45+
.on_event_handlers = app_on_event_handlers,
46+
.on_exit_handlers = app_on_exit_handlers,
47+
.scene_num = app_scene_enum,
48+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <gui/scene_manager.h>
2+
3+
//--------------------------------------------------------------------
4+
// This part of this code works to create the enum of the scenes
5+
// They have to be in order from the app_scene_config
6+
//--------------------------------------------------------------------
7+
8+
#define ADD_SCENE(prefix, name, id) app_scene_##id,
9+
typedef enum {
10+
#include "app_scene_config.h"
11+
app_scene_enum,
12+
} Appscenes;
13+
#undef ADD_SCENE
14+
15+
//---------------------------------------------------------------------
16+
//---------------------------------------------------------------------
17+
// This code define the functions for every scene we have, it gives the name
18+
// the functions "on_enter", "on_exit" and "on_event"
19+
//---------------------------------------------------------------------
20+
//---------------------------------------------------------------------
21+
22+
extern const SceneManagerHandlers app_scene_handlers; // We define the scene manager handler
23+
24+
//---------------------------------------------------------------------
25+
// This defines and name of the "on_enter" functions
26+
//---------------------------------------------------------------------
27+
28+
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
29+
#include "app_scene_config.h"
30+
#undef ADD_SCENE
31+
32+
//---------------------------------------------------------------------
33+
// This defines and name of the "on_event" functions
34+
//---------------------------------------------------------------------
35+
36+
#define ADD_SCENE(prefix, name, id) \
37+
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
38+
#include "app_scene_config.h"
39+
#undef ADD_SCENE
40+
41+
//---------------------------------------------------------------------
42+
// This defines and name of the "on_exit" functions
43+
//---------------------------------------------------------------------
44+
45+
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
46+
#include "app_scene_config.h"
47+
#undef ADD_SCENE

0 commit comments

Comments
 (0)
Please sign in to comment.