Skip to content

Commit 47db4cf

Browse files
Copilotpetesramek
andcommitted
refactor: remove TinyProtocol.h, normalize filenames, add new callbacks and autoUpdateISR
Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> Agent-Logs-Url: https://github.com/petesramek/tiny-link/sessions/1659faa2-ece6-416c-b0da-e88ac4a0b26d
1 parent 6d0a98f commit 47db4cf

14 files changed

Lines changed: 319 additions & 58 deletions

File tree

examples/Basic_Duplex_Callback/ESPM3_Bridge.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ void setup() {
2828
Serial.begin(9600);
2929

3030
// Register the callback
31-
link.onReceive(onSensorDataReceived);
31+
link.onDataReceived(onSensorDataReceived);
3232

3333
Serial.println("TinyLink v0.4.0 Callback Bridge Started.");
3434
}

examples/Basic_Duplex_Callback/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This example demonstrates a **full-duplex, bidirectional** link between an **MH-
44

55
## 🌟 Features
66

7-
- **Callback Logic**: Uses link.onReceive() to trigger functions automatically upon data arrival.
7+
- **Callback Logic**: Uses link.onDataReceived() to trigger functions automatically upon data arrival.
88
- **Bi-Directional**: Both devices act as peers, sending and receiving data simultaneously.
99
- **Reliable**: Protected by **COBS framing** and **Fletcher-16 checksums**.
1010

@@ -30,15 +30,15 @@ void myHandler(const MyData& data) {
3030
}
3131

3232
void setup() {
33-
link.onReceive(myHandler); // Register the listener
33+
link.onDataReceived(myHandler); // Register the listener
3434
}
3535

3636
void loop() {
3737
link.update(); // The engine executes the handler automatically
3838
}
3939
```
4040
41-
**`link.onReceive()`**: Registers a custom function to be called as soon as a valid packet is verified.
41+
**`link.onDataReceived()`**: Registers a custom function to be called as soon as a valid packet is verified.
4242
**`link.update()`**: Maintains the protocol engine and triggers the registered callback internally.
4343
**`Asynchronous`**: The callback pattern removes the need for manual `available()` checks or `flush()` calls in your main loop.
4444

examples/Basic_Duplex_Callback/Tiny88_Sensor.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void setup() {
2121
pinMode(LED_BUILTIN, OUTPUT);
2222

2323
// Register the listener
24-
link.onReceive(handleIncoming);
24+
link.onDataReceived(handleIncoming);
2525
}
2626

2727
void loop() {

examples/Gateway_Handshake_Calback/ESPM3_Bridge.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void handleSensorData(const SensorData& data) {
1616

1717
void setup() {
1818
Serial.begin(9600);
19-
sensorLink.onReceive(handleSensorData);
19+
sensorLink.onDataReceived(handleSensorData);
2020

2121
// 1. Clear any boot-up "UART noise"
2222
while(Serial.available()) Serial.read();

examples/Gateway_Handshake_Calback/Tiny88_Sensor.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void setup() {
2626
pinMode(4, OUTPUT); // ESP_EN Pin
2727

2828
// Register the asynchronous listener
29-
statusLink.onReceive(onGatewayReady);
29+
statusLink.onDataReceived(onGatewayReady);
3030

3131
// Initial Trigger: Power on the ESP
3232
digitalWrite(4, HIGH);

examples/Gateway_Handshake_Polling/Tiny88_Sensor.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void onStatus(const GatewayStatus& status) {
1616

1717
void setup() {
1818
Serial.begin(9600);
19-
statusLink.onReceive(onStatus);
19+
statusLink.onDataReceived(onStatus);
2020

2121
// 1. Wake up ESP (Assuming ESP_EN is on Pin 4)
2222
pinMode(4, OUTPUT);

examples/PC_Monitor/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This example demonstrates how to use **TinyLink** in a native C++ desktop enviro
66

77
**Cross-Platform**: Uses `TinyPosixAdapter` for Linux/macOS and `TinyWindowsAdapter` for Windows.
88
**Bi-Directional**: Receives sensor data from the MCU and sends command packets back every 5 seconds.
9-
**Asynchronous**: Uses the `onReceive` callback to handle incoming COBS frames without blocking the main loop.
9+
**Asynchronous**: Uses the `onDataReceived` callback to handle incoming COBS frames without blocking the main loop.
1010

1111
## 🛠 Hardware Setup
1212

examples/PC_Monitor/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ int main() {
3434

3535
// 4. Initialize TinyLink
3636
TinyLink<MyData, PCAdapter> link(hw);
37-
link.onReceive(onMcuData);
37+
link.onDataReceived(onMcuData);
3838

3939
std::cout << "TinyLink Monitor started on " << PORT << "..." << std::endl;
4040
std::cout << "Press Ctrl+C to exit." << std::endl;

src/TinyLink.h

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
#ifndef TINY_LINK_H
77
#define TINY_LINK_H
88

9-
#include "TinyProtocol.h"
9+
#include "protocol/MessageType.h"
10+
#include "protocol/Status.h"
11+
#include "protocol/State.h"
12+
#include "protocol/Stats.h"
1013
#include "internal/codec/CobsCodec.h"
1114
#include "internal/codec/Fletcher16.h"
1215
#include "internal/codec/Packet.h"
13-
#include "version.h"
16+
#include "Version.h"
1417
#include "internal/protocol/AckMessage.h"
1518
#include "internal/protocol/LogMessage.h"
1619
#include "internal/protocol/HandshakeMessage.h"
@@ -60,7 +63,10 @@ namespace tinylink {
6063
template <typename T, typename Adapter, adapter_check_t<Adapter> = 0>
6164
class TinyLink {
6265
public:
63-
typedef void (*ReceiverCallback)(const T& data);
66+
typedef void (*DataCallback)(const T& data);
67+
typedef void (*LogCallback)(const LogMessage& msg);
68+
typedef void (*HandshakeCallback)(const HandshakeMessage& msg);
69+
typedef void (*AckCallback)(const TinyAck& ack);
6470

6571
private:
6672

@@ -70,10 +76,14 @@ namespace tinylink {
7076
// user data : 3 + sizeof(T) + 2
7177
// internal ACK : 3 + sizeof(TinyAck=2) + 2 = 7
7278
// Handshake : 3 + sizeof(HandshakeMessage=1) + 2 = 6
79+
// Log : 3 + sizeof(LogMessage=32) + 2 = 37
7380
//
74-
static const size_t INTERNAL_PAYLOAD_SIZE =
81+
static const size_t INTERNAL_PAYLOAD_ACK_HS =
7582
sizeof(TinyAck) > sizeof(HandshakeMessage)
7683
? sizeof(TinyAck) : sizeof(HandshakeMessage);
84+
static const size_t INTERNAL_PAYLOAD_SIZE =
85+
INTERNAL_PAYLOAD_ACK_HS > sizeof(LogMessage)
86+
? INTERNAL_PAYLOAD_ACK_HS : sizeof(LogMessage);
7787
static const size_t MAX_PAYLOAD_SIZE =
7888
sizeof(T) > INTERNAL_PAYLOAD_SIZE
7989
? sizeof(T) : INTERNAL_PAYLOAD_SIZE;
@@ -91,7 +101,12 @@ namespace tinylink {
91101
Adapter* _hw;
92102
T _data;
93103
TinyStats _stats;
94-
ReceiverCallback _onReceive;
104+
DataCallback _onDataReceived;
105+
LogCallback _onLogReceived;
106+
HandshakeCallback _onHandshakeReceived;
107+
AckCallback _onAckReceived;
108+
109+
static TinyLink* _s_instance; ///< For enableAutoUpdate() / autoUpdateISR()
95110

96111
uint8_t _pBuf[PLAIN_SIZE];
97112
uint8_t _rawBuf[MAX_FRAME_ENC];
@@ -210,7 +225,9 @@ namespace tinylink {
210225

211226
// ---- Constructor ----------------------------------------------------
212227
explicit TinyLink(Adapter& hw)
213-
: _hw(&hw), _data(), _stats(), _onReceive(nullptr),
228+
: _hw(&hw), _data(), _stats(),
229+
_onDataReceived(nullptr), _onLogReceived(nullptr),
230+
_onHandshakeReceived(nullptr), _onAckReceived(nullptr),
214231
_rawIdx(0), _currType(0), _currSeq(0), _nextSeq(0),
215232
_hasNew(false), _lastByte(0), _timeout(250),
216233
_state(TinyState::WAIT_FOR_SYNC),
@@ -226,8 +243,48 @@ namespace tinylink {
226243

227244
// ---- Configuration --------------------------------------------------
228245

229-
void onReceive(ReceiverCallback cb) { _onReceive = cb; }
230-
void setTimeout(unsigned long ms) { _timeout = ms; }
246+
/** @brief Register a callback for incoming user data frames. */
247+
void onDataReceived(DataCallback cb) { _onDataReceived = cb; }
248+
/** @brief Register a callback for incoming log frames. */
249+
void onLogReceived(LogCallback cb) { _onLogReceived = cb; }
250+
/** @brief Register a callback for incoming handshake frames. */
251+
void onHandshakeReceived(HandshakeCallback cb) { _onHandshakeReceived = cb; }
252+
/** @brief Register a callback for incoming ACK frames. */
253+
void onAckReceived(AckCallback cb) { _onAckReceived = cb; }
254+
255+
void setTimeout(unsigned long ms) { _timeout = ms; }
256+
257+
/**
258+
* @brief Register this instance for interrupt-driven updates.
259+
*
260+
* After calling enableAutoUpdate(), the static function autoUpdateISR()
261+
* can be passed to a hardware timer or UART interrupt attachment routine.
262+
* The ISR will call update() on this TinyLink instance without requiring
263+
* the user to do so in their main loop.
264+
*
265+
* Example (Arduino with TimerOne library):
266+
* @code
267+
* link.enableAutoUpdate();
268+
* Timer1.attachInterrupt(TinyLink<MyData, MyAdapter>::autoUpdateISR, 1000);
269+
* @endcode
270+
*
271+
* @note Only one TinyLink instance per T+Adapter type combination can be
272+
* registered at a time. A second call overwrites the previous one.
273+
*/
274+
void enableAutoUpdate() { _s_instance = this; }
275+
276+
/**
277+
* @brief Static ISR-compatible update function.
278+
*
279+
* Attach this function to a hardware timer, UART RX interrupt, or any
280+
* platform-specific interrupt source to drive the protocol engine
281+
* automatically.
282+
*
283+
* @see enableAutoUpdate()
284+
*/
285+
static void autoUpdateISR() {
286+
if (_s_instance) _s_instance->update();
287+
}
231288

232289
/**
233290
* @brief Initiate the link and start the handshake exchange.
@@ -278,7 +335,10 @@ namespace tinylink {
278335
_lastHandshakeSent = 0;
279336
_lastSent = 0;
280337
_stats.clear();
281-
_onReceive = nullptr;
338+
_onDataReceived = nullptr;
339+
_onLogReceived = nullptr;
340+
_onHandshakeReceived = nullptr;
341+
_onAckReceived = nullptr;
282342
}
283343

284344
/** @brief Clears all protocol statistics counters. */
@@ -400,6 +460,11 @@ namespace tinylink {
400460
if (hsLen == sizeof(HandshakeMessage)) {
401461
handleHandshakeMessage(hsBuf, hsLen,
402462
priorState);
463+
if (_onHandshakeReceived) {
464+
HandshakeMessage hm;
465+
memcpy(&hm, hsBuf, sizeof(hm));
466+
_onHandshakeReceived(hm);
467+
}
403468
} else {
404469
// Malformed HS — restore to idle state.
405470
_state = (priorState == TinyState::CONNECTING ||
@@ -421,12 +486,38 @@ namespace tinylink {
421486
ackBuf, sizeof(ackBuf));
422487
if (ackLen == sizeof(TinyAck)) {
423488
_state = TinyState::WAIT_FOR_SYNC;
489+
if (_onAckReceived) {
490+
TinyAck ack;
491+
memcpy(&ack, ackBuf, sizeof(ack));
492+
_onAckReceived(ack);
493+
}
424494
} else {
425495
_stats.increment(TinyStatus::ERR_CRC);
426496
_state = priorState;
427497
}
428498
continue;
429499
}
500+
501+
// Log: always dispatched via dedicated callback.
502+
if (wireType ==
503+
message_type_to_wire(MessageType::Log)) {
504+
if (_onLogReceived) {
505+
LogMessage logMsg;
506+
uint8_t rtype = 0, rseq = 0;
507+
size_t logLen = tinylink::packet::unpack(
508+
_pBuf, dLen, &rtype, &rseq,
509+
reinterpret_cast<uint8_t*>(&logMsg),
510+
sizeof(logMsg));
511+
if (logLen == sizeof(LogMessage)) {
512+
_onLogReceived(logMsg);
513+
}
514+
}
515+
_state = (priorState == TinyState::AWAITING_ACK ||
516+
priorState == TinyState::CONNECTING)
517+
? priorState
518+
: TinyState::WAIT_FOR_SYNC;
519+
continue;
520+
}
430521
}
431522

432523
// ---- User data frame dispatch ----
@@ -447,10 +538,10 @@ namespace tinylink {
447538
? TinyState::AWAITING_ACK
448539
: TinyState::WAIT_FOR_SYNC;
449540

450-
if (_onReceive) {
541+
if (_onDataReceived) {
451542
// Callback fires while state is FRAME_COMPLETE
452543
// so it can observe the dispatch moment.
453-
_onReceive(_data);
544+
_onDataReceived(_data);
454545
_state = nextState;
455546
} else {
456547
// Polling: transition first, then signal.
@@ -555,4 +646,10 @@ namespace tinylink {
555646

556647
} // namespace tinylink
557648

649+
// ---------------------------------------------------------------------------
650+
// Static member definition (template, so lives in the header)
651+
// ---------------------------------------------------------------------------
652+
template <typename T, typename Adapter, tinylink::adapter_check_t<Adapter> N>
653+
tinylink::TinyLink<T, Adapter, N>* tinylink::TinyLink<T, Adapter, N>::_s_instance = nullptr;
654+
558655
#endif // TINY_LINK_H

src/TinyProtocol.h

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)