Replace size_t with uint32_t, add default mutex impl, preparing internals for multipart Tx

pull/14/head
Ondřej Hruška 6 years ago
parent e24296598e
commit 137797cc7d
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 31
      TF_Integration.example.c
  2. 134
      TinyFrame.c
  3. 23
      TinyFrame.h
  4. 24
      demo/simple/test.c

@ -10,15 +10,20 @@
* listener timeout feature.
*/
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len)
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
{
// send to UART
}
// --------- Mutex callbacks ----------
// Needed only if TF_USE_MUTEX is 1 in the config file.
// DELETE if mutex is not used
/** Claim the TX interface before composing and sending a frame */
void TF_ClaimTx(TinyFrame *tf)
bool TF_ClaimTx(TinyFrame *tf)
{
// take mutex
return true; // we succeeded
}
/** Free the TX interface after composing and sending a frame */
@ -26,3 +31,25 @@ void TF_ReleaseTx(TinyFrame *tf)
{
// release mutex
}
// --------- Custom checksums ---------
// This should be defined here only if a custom checksum type is used.
// DELETE those if you use one of the built-in checksum types
/** Initialize a checksum */
TF_CKSUM TF_CksumStart(void)
{
return 0;
}
/** Update a checksum with a byte */
TF_CKSUM TF_CksumAdd(TF_CKSUM cksum, uint8_t byte)
{
return cksum ^ byte;
}
/** Finalize the checksum calculation */
TF_CKSUM TF_CksumEnd(TF_CKSUM cksum)
{
return cksum;
}

@ -14,16 +14,33 @@
#define TF_MAX(a, b) ((a)>(b)?(a):(b))
#define TF_MIN(a, b) ((a)<(b)?(a):(b))
#define TF_TRY(func) do { if(!(func)) return false; } while (0)
// TODO It would be nice to have per-instance configurable checksum types, but that would
// mandate configurable field sizes unless we use u32 everywhere (and possibly shorten
// it when encoding to the buffer). I don't really like this idea so much. -MP
#if TF_USE_MUTEX==0
#if !TF_USE_MUTEX
// Not thread safe lock implementation, used if user did not provide a better one.
// This is less reliable than a real mutex, but will catch most bugs caused by
// inappropriate use fo the API.
/** Claim the TX interface before composing and sending a frame */
static inline void TF_ClaimTx(TinyFrame *tf) { (void)tf; }
static bool TF_ClaimTx(TinyFrame *tf) {
if (tf->soft_lock) {
TF_Error("TF already locked for tx!");
return false;
}
tf->soft_lock = true;
return true;
}
/** Free the TX interface after composing and sending a frame */
static inline void TF_ReleaseTx(TinyFrame *tf) { (void)tf; }
static void TF_ReleaseTx(TinyFrame *tf)
{
tf->soft_lock = false;
}
#endif
//region Checksums
@ -190,9 +207,12 @@
//endregion
/** Init with a user-allocated buffer */
void _TF_FN TF_InitStatic(TinyFrame *tf, TF_Peer peer_bit)
bool _TF_FN TF_InitStatic(TinyFrame *tf, TF_Peer peer_bit)
{
if (tf == NULL) return;
if (tf == NULL) {
TF_Error("TF_InitStatic() failed, tf is null.");
return false;
}
// Zero it out, keeping user config
uint32_t usertag = tf->usertag;
@ -204,12 +224,18 @@ void _TF_FN TF_InitStatic(TinyFrame *tf, TF_Peer peer_bit)
tf->userdata = userdata;
tf->peer_bit = peer_bit;
return true;
}
/** Init with malloc */
TinyFrame * _TF_FN TF_Init(TF_Peer peer_bit)
{
TinyFrame *tf = malloc(sizeof(TinyFrame));
if (!tf) {
TF_Error("TF_Init() failed, out of memory.");
return NULL;
}
TF_InitStatic(tf, peer_bit);
return tf;
}
@ -492,9 +518,9 @@ static void _TF_FN TF_HandleReceivedMessage(TinyFrame *tf)
//endregion Listeners
/** Handle a received byte buffer */
void _TF_FN TF_Accept(TinyFrame *tf, const uint8_t *buffer, size_t count)
void _TF_FN TF_Accept(TinyFrame *tf, const uint8_t *buffer, uint32_t count)
{
size_t i;
uint32_t i;
for (i = 0; i < count; i++) {
TF_AcceptChar(tf, buffer[i]);
}
@ -714,13 +740,13 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c)
* @param msg - message written to the buffer
* @return nr of bytes in outbuff used by the frame, 0 on failure
*/
static inline size_t _TF_FN TF_ComposeHead(TinyFrame *tf, uint8_t *outbuff, TF_Msg *msg)
static inline uint32_t _TF_FN TF_ComposeHead(TinyFrame *tf, uint8_t *outbuff, TF_Msg *msg)
{
int8_t si = 0; // signed small int
uint8_t b = 0;
TF_ID id = 0;
TF_CKSUM cksum = 0;
size_t pos = 0; // can be needed to grow larger than TF_LEN
uint32_t pos = 0; // can be needed to grow larger than TF_LEN
(void)cksum;
@ -769,13 +795,13 @@ static inline size_t _TF_FN TF_ComposeHead(TinyFrame *tf, uint8_t *outbuff, TF_M
* @param cksum - checksum variable, used for all calls to TF_ComposeBody. Must be reset before first use! (CKSUM_RESET(cksum);)
* @return nr of bytes in outbuff used
*/
static size_t _TF_FN TF_ComposeBody(uint8_t *outbuff,
static uint32_t _TF_FN TF_ComposeBody(uint8_t *outbuff,
const uint8_t *data, TF_LEN data_len,
TF_CKSUM *cksum)
{
TF_LEN i = 0;
uint8_t b = 0;
size_t pos = 0;
uint32_t pos = 0;
for (i = 0; i < data_len; i++) {
b = data[i];
@ -793,11 +819,11 @@ static size_t _TF_FN TF_ComposeBody(uint8_t *outbuff,
* @param cksum - checksum variable used for the body
* @return nr of bytes in outbuff used
*/
static size_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
static uint32_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
{
int8_t si = 0; // signed small int
uint8_t b = 0;
size_t pos = 0;
uint32_t pos = 0;
#if TF_CKSUM_TYPE != TF_CKSUM_NONE
CKSUM_FINALIZE(*cksum);
@ -807,57 +833,83 @@ static size_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
}
/**
* Send a message
* Begin building a frame
*
* @param tf - instance
* @param msg - message object
* @param listener - ID listener, or NULL
* @param timeout - listener timeout, 0 is none
* @return true if sent
* @param msg - message to send
* @param listener - response listener or NULL
* @param timeout - listener timeout ticks, 0 = indefinite
* @return success (mutex claimed and listener added, if any)
*/
static bool _TF_FN TF_SendFrame(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
{
size_t len = 0;
size_t remain = 0;
size_t sent = 0;
TF_CKSUM cksum = 0;
TF_TRY(TF_ClaimTx(tf));
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
tf->tx_len = msg->len;
TF_ClaimTx(tf);
if (listener) {
TF_TRY(TF_AddIdListener(tf, msg, listener, timeout));
}
len = TF_ComposeHead(tf, tf->sendbuf, msg);
if (listener) TF_AddIdListener(tf, msg, listener, timeout);
CKSUM_RESET(tf->tx_cksum);
return true;
}
CKSUM_RESET(cksum);
static void _TF_FN TF_SendFrame_Chunk(TinyFrame *tf, const uint8_t *buff, uint32_t length)
{
uint32_t remain;
uint32_t chunk;
uint32_t sent = 0;
remain = msg->len;
remain = length;
while (remain > 0) {
size_t chunk = TF_MIN(TF_SENDBUF_LEN - len, remain);
len += TF_ComposeBody(tf->sendbuf+len, msg->data+sent, (TF_LEN) chunk, &cksum);
// Write what can fit in the tx buffer
chunk = TF_MIN(TF_SENDBUF_LEN - tf->tx_pos, remain);
tf->tx_pos += TF_ComposeBody(tf->sendbuf+tf->tx_pos, buff+sent, (TF_LEN) chunk, &tf->tx_cksum);
remain -= chunk;
sent += chunk;
// Flush if the buffer is full and we have more to send
if (remain > 0 && len == TF_SENDBUF_LEN) {
TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, len);
len = 0;
// Flush if the buffer is full
if (tf->tx_pos == TF_SENDBUF_LEN) {
TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, tf->tx_pos);
tf->tx_pos = 0;
}
}
}
static void _TF_FN TF_SendFrame_End(TinyFrame *tf)
{
// Checksum only if message had a body
if (msg->len > 0) {
if (tf->tx_len > 0) {
// Flush if checksum wouldn't fit in the buffer
if (TF_SENDBUF_LEN - len < sizeof(TF_CKSUM)) {
TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, len);
len = 0;
if (TF_SENDBUF_LEN - tf->tx_pos < sizeof(TF_CKSUM)) {
TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, tf->tx_pos);
tf->tx_pos = 0;
}
// Add checksum, flush what remains to be sent
len += TF_ComposeTail(tf->sendbuf + len, &cksum);
tf->tx_pos += TF_ComposeTail(tf->sendbuf + tf->tx_pos, &tf->tx_cksum);
}
TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, len);
TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, tf->tx_pos);
TF_ReleaseTx(tf);
}
/**
* Send a message
*
* @param tf - instance
* @param msg - message object
* @param listener - ID listener, or NULL
* @param timeout - listener timeout, 0 is none
* @return true if sent
*/
static bool _TF_FN TF_SendFrame(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
{
TF_TRY(TF_SendFrame_Begin(tf, msg, listener, timeout));
TF_SendFrame_Chunk(tf, msg->data, msg->len);
TF_SendFrame_End(tf);
return true;
}
@ -923,7 +975,7 @@ bool _TF_FN TF_RenewIdListener(TinyFrame *tf, TF_ID id)
/** Timebase hook - for timeouts */
void _TF_FN TF_Tick(TinyFrame *tf)
{
TF_COUNT i = 0;
TF_COUNT i;
struct TF_IdListener_ *lst;
// increment parser timeout (timeout is handled when receiving next byte)

@ -193,6 +193,15 @@ struct TinyFrame_ {
TF_TYPE type; //!< Collected message type number
bool discard_data; //!< Set if (len > TF_MAX_PAYLOAD) to read the frame, but ignore the data.
/* Tx state */
uint32_t tx_pos;
uint32_t tx_len;
TF_CKSUM tx_cksum;
#if !TF_USE_MUTEX
bool soft_lock; //!< Lock used if the mutex feature is not enabled.
#endif
/* --- Callbacks --- */
/* Transaction callbacks */
@ -226,6 +235,7 @@ struct TinyFrame_ {
* the instance.
*
* @param peer_bit - peer bit to use for self
* @return TF instance or NULL
*/
TinyFrame *TF_Init(TF_Peer peer_bit);
@ -236,8 +246,9 @@ TinyFrame *TF_Init(TF_Peer peer_bit);
* The .userdata / .usertag field is preserved when TF_InitStatic is called.
*
* @param peer_bit - peer bit to use for self
* @return success
*/
void TF_InitStatic(TinyFrame *tf, TF_Peer peer_bit);
bool TF_InitStatic(TinyFrame *tf, TF_Peer peer_bit);
/**
* De-init the dynamically allocated TF instance
@ -353,7 +364,7 @@ bool TF_RenewIdListener(TinyFrame *tf, TF_ID id);
* @param buffer - byte buffer to process
* @param count - nr of bytes in the buffer
*/
void TF_Accept(TinyFrame *tf, const uint8_t *buffer, size_t count);
void TF_Accept(TinyFrame *tf, const uint8_t *buffer, uint32_t count);
/**
* Accept a single incoming byte
@ -364,11 +375,11 @@ void TF_AcceptChar(TinyFrame *tf, uint8_t c);
/**
* This function should be called periodically.
*
* The time base is used to time-out partial frames in the parser and
* automatically reset it.
* It's also used to expire ID listeners if a timeout is set when registering them.
*
* (suggestion - call this in a SysTick handler)
* A common place to call this from is the SysTick handler.
*/
void TF_Tick(TinyFrame *tf);
@ -379,13 +390,13 @@ void TF_Tick(TinyFrame *tf);
*
* ! Implement this in your application code !
*/
extern void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len);
extern void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len);
// Mutex functions
#if TF_USE_MUTEX
/** Claim the TX interface before composing and sending a frame */
extern void TF_ClaimTx(TinyFrame *tf);
extern bool TF_ClaimTx(TinyFrame *tf);
/** Free the TX interface after composing and sending a frame */
extern void TF_ReleaseTx(TinyFrame *tf);

@ -5,18 +5,27 @@
TinyFrame *demo_tf;
bool do_corrupt = false;
/**
* This function should be defined in the application code.
* It implements the lowest layer - sending bytes to UART (or other)
*/
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len)
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
{
printf("--------------------\n");
printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n");
dumpFrame(buff, len);
uint8_t *xbuff = (uint8_t *)buff;
if (do_corrupt) {
printf("(corrupting to test checksum checking...)\n");
xbuff[8]++;
}
dumpFrame(xbuff, len);
// Send it back as if we received it
TF_Accept(tf, buff, len);
TF_Accept(tf, xbuff, len);
}
/** An example listener function */
@ -63,4 +72,13 @@ void main(void)
msg.len = 0;
msg.type = 0x77;
TF_Query(demo_tf, &msg, testIdListener, 0);
printf("This should fail:\n");
// test checksums are tested
do_corrupt = true;
msg.type = 0x44;
msg.data = (pu8) "Hello2";
msg.len = 7;
TF_Send(demo_tf, &msg);
}

Loading…
Cancel
Save