MLR_Modem
 
Loading...
Searching...
No Matches
SerialModemBase.h
1
7#pragma once
8#include <Arduino.h>
9
13enum class ModemError
14{
15 Ok,
16 Busy,
17 InvalidArg,
18 FailLbt,
19 Fail,
20 BufferTooSmall,
21 Timeout
22};
23
27enum class ModemParseResult
28{
29 Parsing,
30 Garbage,
31 Overflow,
32 FinishedCmdResponse,
33 FinishedDrResponse
34};
35
39enum class CommandType
40{
41 None,
42 Simple,
43 NvmSave,
44 DataTx
45};
46
51{
52 CommandType type;
53 char cmdBuffer[48];
54 const uint8_t *pPayload;
55 uint8_t payloadLen;
56 char suffix[48];
57 uint32_t timeoutMs;
58};
59
60// --- Debug Configuration ---
61// To enable debug prints, define ENABLE_SERIAL_MODEM_DEBUG in your project
62// #define ENABLE_SERIAL_MODEM_DEBUG
63
64#ifdef ENABLE_SERIAL_MODEM_DEBUG
65#define SM_DEBUG_PRINT(...) this->dbgPrint(__VA_ARGS__)
66#define SM_DEBUG_PRINTLN(...) this->dbgPrintln(__VA_ARGS__)
67#define SM_DEBUG_PRINTF(...) this->dbgPrintf(__VA_ARGS__)
68#define SM_DEBUG_WRITE(...) this->dbgWrite(__VA_ARGS__)
69#else
70#define SM_DEBUG_PRINT(...) \
71 do \
72 { \
73 } while (0)
74#define SM_DEBUG_PRINTLN(...) \
75 do \
76 { \
77 } while (0)
78#define SM_DEBUG_PRINTF(...) \
79 do \
80 { \
81 } while (0)
82#define SM_DEBUG_WRITE(...) \
83 do \
84 { \
85 } while (0)
86#endif
87
92{
93public:
95 virtual ~SerialModemBase() = default;
96
101 void setDebugStream(Stream *debugStream);
102
107 void update();
108
112 bool isIdle() const;
113
118 bool isLastCommandComplete() const { return _lastCmdComplete; }
119
123 ModemError getLastCommandResult() const { return _lastCmdResult; }
124
128 const uint8_t *getRxBuffer() const { return _rxBuffer; }
129 uint16_t getRxIndex() const { return _rxIndex; }
130
134 bool isQueueFull() const;
135
139 bool isQueueEmpty() const;
140
144 uint8_t getQueueCount() const;
145
146protected:
147#ifdef ENABLE_SERIAL_MODEM_DEBUG
148 template <typename... Args>
149 void dbgPrint(Args... args)
150 {
151 if (_debugStream)
152 {
153 _debugStream->print(getLogPrefix());
154 _debugStream->print(args...);
155 }
156 }
157 template <typename... Args>
158 void dbgPrintln(Args... args)
159 {
160 if (_debugStream)
161 {
162 _debugStream->print(getLogPrefix());
163 _debugStream->println(args...);
164 }
165 }
166 template <typename... Args>
167 void dbgPrintf(Args... args)
168 {
169 if (_debugStream)
170 {
171 _debugStream->print(getLogPrefix());
172 _debugStream->printf(args...);
173 }
174 }
175 template <typename... Args>
176 void dbgWrite(Args... args)
177 {
178 if (_debugStream)
179 _debugStream->write(args...);
180 }
181#endif
182
183 static constexpr char CD_WRITE_OK_RESPONSE[] = "*WR=PS";
184 static constexpr size_t CD_WRITE_OK_RESPONSE_LEN = 6;
185 static constexpr char CD_VAL_ON[] = "ON";
186 static constexpr char CD_VAL_OFF[] = "OF";
187 static constexpr char CD_CMD_WRITE_SUFFIX[] = "/W";
188
189 // --- Initialization ---
194 void initSerial(Stream &stream);
195
196 // --- Command Queueing (For Derived Classes) ---
197
202 ModemError enqueueCommand(const char *cmd, CommandType type, uint32_t timeoutMs = 1000);
203
207 ModemError enqueueTxCommand(const char *cmdHeader, const uint8_t *payload, uint8_t len, const char *suffix = nullptr, uint32_t timeoutMs = 2000);
208
209 // --- Synchronous Wrappers (Implemented via update() loop) ---
210 // These replace the old blocking implementations but keep the same signature for API compatibility.
211
226 ModemError setByteValue(const char *cmd, uint8_t value, bool save, const char *respPrefix, size_t respLen);
227
236 ModemError getByteValue(const char *cmd, uint8_t *pValue, const char *respPrefix, size_t respLen);
237
246 ModemError setBoolValue(const char *baseCmd, bool enabled, bool save, const char *respPrefix);
247
255 ModemError getBoolValue(const char *cmd, bool *pValue, const char *respPrefix);
256
265 ModemError sendRawCommand(const char *command, char *responseBuffer, size_t bufferSize, uint32_t timeoutMs);
266
271 ModemError waitForSyncComplete(uint32_t timeoutMs);
272
273 // --- Low-Level I/O ---
274 void writeString(const char *str, bool printPrefix = true);
275 void writeData(const uint8_t *data, size_t len);
276 int readByte();
277 void unreadByte(uint8_t c);
278 void clearUnreadByte();
279 void flushGarbage(char keepChar = '*');
280
281 // --- Timeout Management ---
282 void startTimeout(uint32_t ms);
283 bool isTimeout();
284
285 // --- Parsing Helpers ---
286 static bool parseHex(const uint8_t *pData, size_t len, uint32_t *pResult);
287 static bool parseDec(const uint8_t *pData, size_t len, uint32_t *pResult);
288 ModemError parseResponseHex(const uint8_t *buffer, size_t length, const char *prefix, uint8_t hexDigits, uint32_t *pResult);
289 ModemError parseResponseDec(const uint8_t *buffer, size_t length, const char *prefix, const char *suffix, size_t suffixLen, int32_t *pResult);
290
291 // --- Virtual Methods (To be implemented by Derived Classes) ---
297 virtual ModemParseResult parse() = 0;
298 virtual void onRxDataReceived() = 0;
299 virtual const char *getLogPrefix() const = 0;
300
304 virtual void onCommandComplete(ModemError result) {}
305
306protected:
307 // --- String Helpers (with bounds checking) ---
308 static char *appendStr(char *dest, const char *src, const char *destEnd);
309 static char *appendHex2(char *dest, uint8_t val, const char *destEnd);
310
311 // Template helpers for automatic size deduction
312 template <size_t N>
313 static char *appendStr(char (&destBuf)[N], char *currentPtr, const char *src)
314 {
315 return appendStr(currentPtr, src, destBuf + N);
316 }
317 template <size_t N>
318 static char *appendHex2(char (&destBuf)[N], char *currentPtr, uint8_t val)
319 {
320 return appendHex2(currentPtr, val, destBuf + N);
321 }
322
323 Stream *_uart = nullptr;
324 Stream *_debugStream = nullptr;
325
326 // Shared Receive Buffer (Unified)
327 static constexpr size_t RX_BUFFER_SIZE = 300;
329 uint16_t _rxIndex = 0;
330
331 int16_t _oneByteBuf = -1;
332 bool _debugRxNewLine = true;
333
334private:
335 // --- Internal State Machine ---
336 enum class State
337 {
338 Idle,
339 Sending,
340 WaitingResponse,
341 WaitingSaveResponse
342 };
343 State _state = State::Idle;
344
345 // --- Command Queue ---
346 static constexpr uint8_t QUEUE_SIZE = 8;
347 ModemCommand _commandQueue[QUEUE_SIZE];
348 volatile uint8_t _queueHead = 0;
349 volatile uint8_t _queueTail = 0;
350
351 ModemCommand _currentCmd; // Currently executing command
352
353 // --- Sync/Result State ---
354 volatile bool _lastCmdComplete = true;
355 volatile ModemError _lastCmdResult = ModemError::Ok;
356
357 // Timeout state
358 bool _bTimeout = true;
359 uint32_t _startTime = 0;
360 uint32_t _timeOutDuration = 0;
361
365 ModemError enqueueInternal(const char *cmd, CommandType type, const uint8_t *payload, uint8_t len, const char *suffix, uint32_t timeoutMs);
366};
Base class handling low-level serial I/O, debugging, and async transaction logic.
Definition: SerialModemBase.h:92
void startTimeout(uint32_t ms)
Definition: SerialModemBase.cpp:521
ModemError getByteValue(const char *cmd, uint8_t *pValue, const char *respPrefix, size_t respLen)
Helper to get a 1-byte value.
Definition: SerialModemBase.cpp:301
ModemError getBoolValue(const char *cmd, bool *pValue, const char *respPrefix)
Helper to get a boolean value (ON/OF).
Definition: SerialModemBase.cpp:358
virtual void onCommandComplete(ModemError result)
Optional hook called when a queued command finishes.
Definition: SerialModemBase.h:304
static constexpr size_t CD_WRITE_OK_RESPONSE_LEN
Definition: SerialModemBase.h:184
static bool parseHex(const uint8_t *pData, size_t len, uint32_t *pResult)
Definition: SerialModemBase.cpp:539
virtual ModemParseResult parse()=0
Main parser state machine step. Must use readByte() and update _rxBuffer / _rxIndex.
Stream * _debugStream
Definition: SerialModemBase.h:324
bool _debugRxNewLine
Definition: SerialModemBase.h:332
bool isIdle() const
Checks if the internal engine is currently idle (no command processing).
Definition: SerialModemBase.cpp:159
static char * appendStr(char *dest, const char *src, const char *destEnd)
Definition: SerialModemBase.cpp:252
ModemError sendRawCommand(const char *command, char *responseBuffer, size_t bufferSize, uint32_t timeoutMs)
Sends a raw command string and fills the provided buffer with the response.
Definition: SerialModemBase.cpp:384
Stream * _uart
Definition: SerialModemBase.h:323
static char * appendHex2(char(&destBuf)[N], char *currentPtr, uint8_t val)
Definition: SerialModemBase.h:318
static constexpr size_t RX_BUFFER_SIZE
Definition: SerialModemBase.h:327
ModemError parseResponseDec(const uint8_t *buffer, size_t length, const char *prefix, const char *suffix, size_t suffixLen, int32_t *pResult)
Definition: SerialModemBase.cpp:597
virtual const char * getLogPrefix() const =0
bool isLastCommandComplete() const
Checks if the last processed command has finished. Useful for implementing synchronous wrappers.
Definition: SerialModemBase.h:118
ModemError enqueueTxCommand(const char *cmdHeader, const uint8_t *payload, uint8_t len, const char *suffix=nullptr, uint32_t timeoutMs=2000)
Enqueues a data transmission command with payload.
Definition: SerialModemBase.cpp:226
void update()
Main processing loop. Must be called frequently. Handles command queue, transmission,...
Definition: SerialModemBase.cpp:50
uint16_t _rxIndex
Definition: SerialModemBase.h:329
bool isQueueFull() const
Checks if the command queue is full.
Definition: SerialModemBase.cpp:166
static bool parseDec(const uint8_t *pData, size_t len, uint32_t *pResult)
Definition: SerialModemBase.cpp:563
ModemError enqueueCommand(const char *cmd, CommandType type, uint32_t timeoutMs=1000)
Enqueues a command for processing. Non-blocking.
Definition: SerialModemBase.cpp:221
ModemError parseResponseHex(const uint8_t *buffer, size_t length, const char *prefix, uint8_t hexDigits, uint32_t *pResult)
Definition: SerialModemBase.cpp:583
SerialModemBase()
Definition: SerialModemBase.cpp:18
void clearUnreadByte()
Definition: SerialModemBase.cpp:489
ModemError setBoolValue(const char *baseCmd, bool enabled, bool save, const char *respPrefix)
Helper to set a boolean value (ON/OF).
Definition: SerialModemBase.cpp:325
const uint8_t * getRxBuffer() const
Accessor for the shared RX buffer.
Definition: SerialModemBase.h:128
void initSerial(Stream &stream)
Sets the UART stream to use for modem communication.
Definition: SerialModemBase.cpp:36
ModemError waitForSyncComplete(uint32_t timeoutMs)
Helper to wait for the current command to finish (Pseudo-blocking). Calls update() internally.
Definition: SerialModemBase.cpp:233
virtual ~SerialModemBase()=default
void setDebugStream(Stream *debugStream)
Initializes the debug stream.
Definition: SerialModemBase.cpp:31
int16_t _oneByteBuf
Definition: SerialModemBase.h:331
static char * appendHex2(char *dest, uint8_t val, const char *destEnd)
Definition: SerialModemBase.cpp:262
void writeString(const char *str, bool printPrefix=true)
Definition: SerialModemBase.cpp:417
ModemError setByteValue(const char *cmd, uint8_t value, bool save, const char *respPrefix, size_t respLen)
Helper to set a 1-byte value (e.g., @CH0E) and verify the response.
Definition: SerialModemBase.cpp:274
bool isQueueEmpty() const
Checks if the command queue is empty.
Definition: SerialModemBase.cpp:171
static constexpr char CD_VAL_ON[]
Definition: SerialModemBase.h:185
static constexpr char CD_VAL_OFF[]
Definition: SerialModemBase.h:186
ModemError getLastCommandResult() const
Gets the result of the last processed command.
Definition: SerialModemBase.h:123
static constexpr char CD_CMD_WRITE_SUFFIX[]
Definition: SerialModemBase.h:187
uint8_t getQueueCount() const
Gets the number of commands currently in the queue.
Definition: SerialModemBase.cpp:176
void unreadByte(uint8_t c)
Definition: SerialModemBase.cpp:484
static constexpr char CD_WRITE_OK_RESPONSE[]
Definition: SerialModemBase.h:183
static char * appendStr(char(&destBuf)[N], char *currentPtr, const char *src)
Definition: SerialModemBase.h:313
virtual void onRxDataReceived()=0
void flushGarbage(char keepChar=' *')
Definition: SerialModemBase.cpp:494
bool isTimeout()
Definition: SerialModemBase.cpp:528
void writeData(const uint8_t *data, size_t len)
Definition: SerialModemBase.cpp:429
uint8_t _rxBuffer[RX_BUFFER_SIZE]
Definition: SerialModemBase.h:328
int readByte()
Definition: SerialModemBase.cpp:437
uint16_t getRxIndex() const
Definition: SerialModemBase.h:129
Structure to hold queued commands.
Definition: SerialModemBase.h:51
char suffix[48]
Optional suffix for DataTx (e.g., routing options)
Definition: SerialModemBase.h:56
const uint8_t * pPayload
Pointer to payload data (for DataTx)
Definition: SerialModemBase.h:54
CommandType type
Type of command.
Definition: SerialModemBase.h:52
uint8_t payloadLen
Length of payload.
Definition: SerialModemBase.h:55
char cmdBuffer[48]
Command string (header only for DataTx)
Definition: SerialModemBase.h:53
uint32_t timeoutMs
Timeout for this command.
Definition: SerialModemBase.h:57