22 Commits
Author SHA1 Message Date
MightyPork a966345816 updated readme a little 2017-11-21 22:20:28 +01:00
MightyPork ed389d530b make Tx support multi-chunk payload (exceeding buffer size) 2017-11-21 22:17:06 +01:00
MightyPork 041467fcb0 Merge branch 'userdata' 2017-10-16 00:46:44 +02:00
MightyPork 95a7c89b98 improved api and updated readme 2017-10-16 00:46:30 +02:00
MightyPork 4ad1f09f73 great cleaning 2017-10-16 00:29:43 +02:00
MightyPork 87d1841fc8 demo tweaks ... 2017-10-15 23:30:25 +02:00
MightyPork 8415f15c99 demo works ... 2017-10-15 23:19:39 +02:00
MightyPork 46883a9baa kinda working demo 2017-10-15 22:40:53 +02:00
MightyPork e89ca3a6cb some cleaning 2017-10-15 18:32:21 +02:00
MightyPork 01c8ab7f90 oops checksums didnt work 2017-10-15 18:28:27 +02:00
MightyPork d1aec88f23 did some cleaning 2017-10-15 18:18:20 +02:00
MightyPork b89f458c19 fixed bugz 2017-10-13 11:14:20 +02:00
MightyPork b6532962a4 updated C code, added timeouts etc, not tested! 2017-10-12 16:25:05 +02:00
MightyPork c7f4e2c6f9 change api for easier use (only header file!!! WIP) 2017-10-12 12:06:34 +02:00
MightyPorkandGitHub cf4cc6807b Update README.md 2017-09-13 16:13:45 +02:00
MightyPorkandGitHub d1332408bd Update README.md 2017-09-13 16:12:48 +02:00
MightyPorkandGitHub 317f13c35a fix up some comments 2017-09-13 15:51:23 +02:00
MightyPorkandGitHub 1ca04066d2 syntax fixes for bad compilers 2017-04-18 13:22:37 +02:00
MightyPorkandGitHub 2b54631aba remove trailing comma to support bad compilers 2017-04-18 13:19:20 +02:00
MightyPork 4f5c4d69f7 readme fix 2017-04-16 16:54:09 +02:00
MightyPork 61c82b614b Updated & heavily improved 2017-04-16 16:51:53 +02:00
MightyPork c83cdf36e2 beta code, needs testing. Adjustable field sizes, crc16 option, dedicated Type field 2017-04-16 01:55:09 +02:00
21 changed files with 2010 additions and 497 deletions
+7
View File
@@ -27,7 +27,14 @@
*.i*86
*.x86_64
*.hex
*.bin
# Debug files
*.dSYM/
*.su
cmake-build-debug/
tf.bin
.idea/
+25
View File
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.7)
project(tf)
set(CMAKE_CXX_STANDARD GNU89)
set(SOURCE_FILES
demo/simple/test.c
demo/simple/TF_Config.h
demo/socket_demo/master.c
demo/socket_demo/slave.c
demo/socket_demo/TF_Config.h
demo/multipart_tx/test.c
demo/multipart_tx/TF_Config.h
demo/demo.c
demo/demo.h
TinyFrame.c
TinyFrame.h
TF_Config.example.h
demo/utils.c
demo/utils.h
)
include_directories(demo/simple)
add_executable(tf ${SOURCE_FILES})
+68 -36
View File
@@ -1,56 +1,88 @@
# TinyFrame
TinyFrame is a simple library for building and parsing frames
(packets) to be sent over a serial interface (like UART). It's implemented
to be compatible with C89 and platform agnostic.
TinyFrame is a simple library for building and parsing frames to be sent
over a serial interface (e.g. UART, telnet etc.). The code is written
to build with `--std=gnu89` and later.
Frames are protected by a checksum and contain a "unique" ID,
which can be used for chaining messages. Each peer uses a different
value for the first bit of all IDs it generates (the "master flag"
or "peer_bit") to ensure there are no clashes. Typically the master
(PC, main microcontroller) will use "1" and the surrogate (WiFi module,
USB-serial connected gadget, display driver...) uses "0".
TinyFrame is suitable for a wide range of applications, including inter-microcontroller
communication, as a protocol for FTDI-based PC applications or for messaging through
UDP packets. If you find a good use for it, please let me know so I can add it here!
The library lets you bind listeners waiting for any frame, or a
particular ID. This allows for easy implementation of async communication.
Frames can be protected by a checksum (~XOR, CRC16 or CRC32) and contain
a unique ID field which can be used for chaining related messages. The highest bit
of the generated IDs is different in each peer to avoid collisions.
Peers are functionally equivalent and can send messages to each other
(the names "master" and "slave" are used only for convenience and have special meaning
in the demos).
The library lets you register listeners (callback functions) to wait for (1) any frame, (2)
a particular frame Type, or (3) a specific message ID. This high-level API lets you
easily implement various async communication patterns.
## Frame structure
The frame makeup is inspired by that of SBMP (my other, more complicated
and advanced UART protocol library).
All fields in the message frame have a configurable size (see the top of the header file).
By just changing a definition in the header, such as `TF_LEN_BYTES` (1, 2 or 4), the library
seamlessly switches between `uint8_t`, `uint16_t` and `uint32_t`. Choose field lengths that
best suit your application needs.
For example, you don't need 4 bytes (`uint32_t`) for the
length field if your payloads are 20 bytes long, using a 1-byte field (`uint8_t`) will save
3 bytes. This may be significant if you high throughput.
```
<SOF><ID><NOB><PAYLOAD><CKSUM>
,-----+----+-----+------+------------+- - - -+------------,
| SOF | ID | LEN | TYPE | HEAD_CKSUM | DATA | PLD_CKSUM |
| 1 | ? | ? | ? | ? | ... | ? | <- size (bytes)
'-----+----+-----+------+------------+- - - -+------------'
SOF ... start of frame, 0x01
ID ... (master_flag | 7-bit counter) - the frame ID
NOB ... nr of payload bytes in the frame (1..256)
PAYLOAD ... NOB bytes of data, can contain any byte values 1..256
CKSUM ... checksum, implemented as XOR of all preceding bytes in the message
SOF ......... start of frame, 0x01
ID ......... the frame ID (MSb is the peer bit)
LEN ......... nr of data bytes in the frame
TYPE ........ message type (used to run Type Listeners, pick any values you like)
HEAD_CKSUM .. header checksum
DATA ........ LEN bytes of data
DATA_CKSUM .. checksum, implemented as XOR of all preceding bytes in the message
```
The frame ID (in SBMP called "session ID") can be used to chain multiple related
messages and maintain the context this way. For example, a response may copy
the frame ID of the request frame, which then triggers a callback bound by the
requesting peer. Such behavior is application specific and is thus left to the
upper layers of the protocol.
## Usage Hints
- All TinyFrame functions, typedefs and macros start with the `TF_` prefix.
- Both peers must include the library with the same parameters (configured at the top of the header file)
- Start by calling `TF_Init()` with `TF_MASTER` or `TF_SLAVE` as the argument
- Implement `TF_WriteImpl()` - declared at the bottom of the header file as `extern`.
This function is used by `TF_Send()` and others to write bytes to your UART (or other physical layer).
A frame can be sent in it's entirety, or in multiple parts, depending on its size.
- If you wish to use timeouts, periodically call `TF_Tick()`. The calling period determines
the length of 1 tick. This is used to time-out the parser in case it gets stuck
in a bad state (such as receiving a partial frame) and can also time-out ID listeners.
- Bind Type or Generic listeners using `TF_AddTypeListener()` or `TF_AddGenericListener()`.
- Send a message using `TF_Send()`, `TF_Query()`, `TF_SendSimple()`, `TF_QuerySimple()`.
Query functions take a listener callback (function pointer)that will be added as
an ID listener and wait for a response.
- To reply to a message (when your listener gets called), use `TF_Respond()`
with the msg boject you received, replacing the `data` pointer (and `len`) with response.
- Manually reset the parser using `TF_ResetParser()`
## Usage hints
### Message listeners
- Both sides of the protocol (slave and master) should include the same TinyFrame
code.
- Master inits the lib with `TF_Init(1);`, while slave uses `TF_Init(0);`. This is to avoid a message ID conflict.
- Both sides can add Generic and Type listeners (callbacks) using `TF_AddGenericListener(func)` and `TF_AddTypeListener(type, func)`. The listener is a function as showin in the example file test.c or declared in TinyFrame.h
Listeners are callback functions that are called by TinyFrame when a message which
they can handle is received.
`bool myListener(unsigned int frame_id, const unsigned char *buff, unsigned int len) { ... }`
There are 3 listener types:
The listener returns `true` if the message was consumed. If it returns `false`, it can be handled by some other listener (possibly a Generic Listener, if you added one)
- A message is sent using `TF_Send()`, and to use it, the `TF_WriteImpl()` stub must be implemented in the application code. See `test.c` for an example.
- ID listeners
- Type listeners
- Generic listeners
There are also helper functions `TF_Send1()` and `TF_Send2()` which send one or two bytes.
- To reply, use `TF_Respond()` with ID same as in the received message (the listener gets this as it's argument). A listener provided as the last parameter to `TF_Send()` will be called after receiving the response.
Listeners return an enum constant based on what should be done next - remove the listener,
keep it, renew it's timeout, or let some other listener handle the message.
- To remove a listener, use `TF_RemoveListener()`. *Always remove your ID listeners after handling the response!* There's a limit to the number of listeners.
### Examples
- The function `TF_Accept()` is used to handle received chars. Call this in your UART Rx interrupt handler or a similar place.
You'll find various examples in the `demo/` folder. Each example has it's own Makefile,
read it to see what options are available.
The demos are written for Linux, some using sockets and `clone()` for background processing.
They try to simulate real TinyFrame behavior in an embedded system with asynchronous
Rx and Tx. If you can't run the demos, the source files are still good as examples.
+72
View File
@@ -0,0 +1,72 @@
//
// Rename to TF_Config.h
//
#ifndef TF_CONFIG_H
#define TF_CONFIG_H
#include <stdint.h>
//#include <esp8266.h> // when using with esphttpd
//----------------------------- FRAME FORMAT ---------------------------------
// The format can be adjusted to fit your particular application needs
// If the connection is reliable, you can disable the SOF byte and checksums.
// That can save up to 9 bytes of overhead.
// ,-----+----+-----+------+------------+- - - -+------------,
// | SOF | ID | LEN | TYPE | HEAD_CKSUM | DATA | PLD_CKSUM |
// | 1 | ? | ? | ? | ? | ... | ? | <- size (bytes)
// '-----+----+-----+------+------------+- - - -+------------'
// !!! BOTH SIDES MUST USE THE SAME SETTINGS !!!
// Adjust sizes as desired (1,2,4)
#define TF_ID_BYTES 1
#define TF_LEN_BYTES 2
#define TF_TYPE_BYTES 1
// Checksum type
//#define TF_CKSUM_TYPE TF_CKSUM_NONE
//#define TF_CKSUM_TYPE TF_CKSUM_XOR
#define TF_CKSUM_TYPE TF_CKSUM_CRC16
//#define TF_CKSUM_TYPE TF_CKSUM_CRC32
// Use a SOF byte to mark the start of a frame
#define TF_USE_SOF_BYTE 1
// Value of the SOF byte (if TF_USE_SOF_BYTE == 1)
#define TF_SOF_BYTE 0x01
//----------------------- PLATFORM COMPATIBILITY ----------------------------
// used for timeout tick counters - should be large enough for all used timeouts
typedef uint16_t TF_TICKS;
// used in loops iterating over listeners
typedef uint8_t TF_COUNT;
//----------------------------- PARAMETERS ----------------------------------
// Maximum received payload size (static buffer)
// Larger payloads will be rejected.
#define TF_MAX_PAYLOAD_RX 1024
// Size of the sending buffer. Larger payloads will be split to pieces and sent
// in multiple calls to the write function. This can be lowered to reduce RAM usage.
#define TF_SENDBUF_LEN 1024
// --- Listener counts - determine sizes of the static slot tables ---
// Frame ID listeners (wait for response / multi-part message)
#define TF_MAX_ID_LST 10
// Frame Type listeners (wait for frame with a specific first payload byte)
#define TF_MAX_TYPE_LST 10
// Generic listeners (fallback if no other listener catches it)
#define TF_MAX_GEN_LST 5
// Timeout for receiving & parsing a frame
// ticks = number of calls to TF_Tick()
#define TF_PARSER_TIMEOUT_TICKS 10
//------------------------- End of user config ------------------------------
#endif //TF_CONFIG_H
+709 -208
View File
File diff suppressed because it is too large Load Diff
+207 -102
View File
@@ -1,167 +1,272 @@
#ifndef TinyFrameH
#define TinyFrameH
//---------------------------------------------------------------------------
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h> // for uint8_t etc
#include <stdbool.h> // for bool
#include <stdlib.h> // for NULL
//---------------------------------------------------------------------------
// Frame ID listeners (wait for response / multi-part message)
#ifndef TF_MAX_ID_LST
# define TF_MAX_ID_LST 64
// Select checksum type (0 = none, 8 = ~XOR, 16 = CRC16 0x8005, 32 = CRC32)
#define TF_CKSUM_NONE 0
#define TF_CKSUM_XOR 8
#define TF_CKSUM_CRC16 16
#define TF_CKSUM_CRC32 32
#include <TF_Config.h>
//region Resolve data types
#if TF_LEN_BYTES == 1
typedef uint8_t TF_LEN;
#elif TF_LEN_BYTES == 2
typedef uint16_t TF_LEN;
#elif TF_LEN_BYTES == 4
typedef uint32_t TF_LEN;
#else
#error Bad value of TF_LEN_BYTES, must be 1, 2 or 4
#endif
// Frame Type listeners (wait for frame with a specific first payload byte)
#ifndef TF_MAX_TYPE_LST
# define TF_MAX_TYPE_LST 16
#if TF_TYPE_BYTES == 1
typedef uint8_t TF_TYPE;
#elif TF_TYPE_BYTES == 2
typedef uint16_t TF_TYPE;
#elif TF_TYPE_BYTES == 4
typedef uint32_t TF_TYPE;
#else
#error Bad value of TF_TYPE_BYTES, must be 1, 2 or 4
#endif
// Generic listeners (fallback if no other listener catches it)
#ifndef TF_MAX_GEN_LST
# define TF_MAX_GEN_LST 4
#if TF_ID_BYTES == 1
typedef uint8_t TF_ID;
#elif TF_ID_BYTES == 2
typedef uint16_t TF_ID;
#elif TF_ID_BYTES == 4
typedef uint32_t TF_ID;
#else
#error Bad value of TF_ID_BYTES, must be 1, 2 or 4
#endif
#define TF_NEXT_ID -1
#define TF_ERROR -1
#if TF_CKSUM_TYPE == TF_CKSUM_XOR || TF_CKSUM_TYPE == TF_CKSUM_NONE
// ~XOR (if 0, still use 1 byte - it won't be used)
typedef uint8_t TF_CKSUM;
#elif TF_CKSUM_TYPE == TF_CKSUM_CRC16
// CRC16
typedef uint16_t TF_CKSUM;
#elif TF_CKSUM_TYPE == TF_CKSUM_CRC32
// CRC32
typedef uint32_t TF_CKSUM;
#else
#error Bad value for TF_CKSUM_TYPE, must be 8, 16 or 32
#endif
// Bytes added to TF_MAX_PAYLOAD for the send buffer size.
#define TF_OVERHEAD_BYTES \
(1*TF_USE_SOF_BYTE + \
sizeof(TF_ID) + \
sizeof(TF_LEN) + \
sizeof(TF_CKSUM) + \
sizeof(TF_TYPE) + \
sizeof(TF_CKSUM) \
)
//endregion
//---------------------------------------------------------------------------
// Type-dependent masks for bit manipulation in the ID field
#define TF_ID_MASK (TF_ID)(((TF_ID)1 << (sizeof(TF_ID)*8 - 1)) - 1)
#define TF_ID_PEERBIT (TF_ID)((TF_ID)1 << ((sizeof(TF_ID)*8) - 1))
//---------------------------------------------------------------------------
/** Peer bit enum (used for init) */
typedef enum {
TF_SLAVE = 0,
TF_MASTER,
} TF_Peer;
typedef enum {
TF_NEXT = 0, //!< Not handled, let other listeners handle it
TF_STAY = 1, //!< Handled, stay
TF_RENEW = 2, //!< Handled, stay, renew - useful only with listener timeout
TF_CLOSE = 3, //!< Handled, remove self
} TF_Result;
/** Data structure for sending / receiving messages */
typedef struct _TF_MSG_STRUCT_ {
TF_ID frame_id; //!< message ID
bool is_response; //!< internal flag, set when using the Respond function. frame_id is then kept unchanged.
TF_TYPE type; //!< received or sent message type
const uint8_t *data; //!< buffer of received data or data to send. NULL = listener timed out, free userdata!
TF_LEN len; //!< length of the buffer
void *userdata; //!< here's a place for custom data; this data will be stored with the listener
} TF_Msg;
/**
* TinyFrame receive callback type.
* @param frame_id - ID of the received frame
* @param buff - byte buffer with the payload
* @param len - number of bytes in the buffer
* @return true if the frame was consumed
* Clear message struct
*/
typedef bool (*TinyFrameListener)(unsigned int frame_id,
const unsigned char *buff,
unsigned int len);
static inline void TF_ClearMsg(TF_Msg *msg)
{
msg->frame_id = 0;
msg->is_response = false;
msg->type = 0;
msg->data = NULL;
msg->len = 0;
msg->userdata = NULL;
}
/**
* TinyFrame Type Listener callback
*
* @param frame_id - ID of the received frame
* @param type - type field from the message
* @param data - byte buffer with the application data
* @param len - number of bytes in the buffer
* @return listener result
*/
typedef TF_Result (*TF_Listener)(TF_Msg *msg);
/**
* Initialize the TinyFrame engine.
* This can also be used to completely reset it (removing all listeners etc)
*
* @param peer_bit - peer bit to use for self
*/
void TF_Init(bool peer_bit);
void TF_Init(TF_Peer peer_bit);
/**
* Reset the frame parser state machine.
* This does not affect registered listeners.
*/
void TF_ResetParser(void);
/**
* Accept incoming bytes & parse frames
* @param buffer - byte buffer to process
* @param count - nr of bytes in the buffer
*/
void TF_Accept(const unsigned char *buffer, unsigned int count);
/**
* Accept a single incoming byte
* @param c - a received char
*/
void TF_AcceptChar(unsigned char c);
/**
* Register a frame type listener.
* @param frame_type - frame ID to listen for
*
* @param msg - message (contains frame_id and userdata)
* @param cb - callback
* @param timeout - timeout in ticks to auto-remove the listener (0 = keep forever)
* @return slot index (for removing), or TF_ERROR (-1)
*/
int TF_AddIdListener(unsigned int frame_id, TinyFrameListener cb);
bool TF_AddIdListener(TF_Msg *msg, TF_Listener cb, TF_TICKS timeout);
/**
* Remove a listener by the message ID it's registered for
*
* @param frame_id - the frame we're listening for
*/
bool TF_RemoveIdListener(TF_ID frame_id);
/**
* Register a frame type listener.
*
* @param frame_type - frame type to listen for
* @param cb - callback
* @return slot index (for removing), or TF_ERROR (-1)
*/
int TF_AddTypeListener(unsigned char frame_type, TinyFrameListener cb);
/**
* Register a generic listener.
* @param cb - callback
* @return slot index (for removing), or TF_ERROR (-1)
*/
int TF_AddGenericListener(TinyFrameListener cb);
/**
* Remove any listener by the index received when registering it
* @param index - index in the callbacks table
*/
void TF_RemoveListener(unsigned int index);
/**
* Remove a listener by the message ID it's registered for
* @param frame_id - the frame we're listening for
*/
void TF_RemoveIdListener(unsigned int frame_id);
bool TF_AddTypeListener(TF_TYPE frame_type, TF_Listener cb);
/**
* Remove a listener by type.
*
* @param type - the type it's registered for
*/
void TF_RemoveTypeListener(unsigned char type);
bool TF_RemoveTypeListener(TF_TYPE type);
/**
* Remove a callback by the function pointer
* Register a generic listener.
*
* @param cb - callback
* @return slot index (for removing), or TF_ERROR (-1)
*/
bool TF_AddGenericListener(TF_Listener cb);
/**
* Remove a generic listener by function pointer
*
* @param cb - callback function to remove
*/
void TF_RemoveListenerFn(TinyFrameListener cb); // search all listener types
bool TF_RemoveGenericListener(TF_Listener cb);
/**
* Compose a frame
* Send a frame, no listener
*
* @param outbuff - buffer to store the result in
* @param msgid - message ID is stored here, if not NULL
* @param payload - data buffer
* @param len - payload size in bytes, 0 to use strlen
* @param explicit_id - ID to use, TF_NEXT_ID (-1) to chose next free
* @return nr of bytes in outbuff used by the frame, TF_ERROR (-1) on failure
* @param msg - message struct. ID is stored in the frame_id field
* @return success
*/
int TF_Compose(unsigned char *outbuff, unsigned int *msgid,
const unsigned char *payload, unsigned int payload_len,
int explicit_id);
bool TF_Send(TF_Msg *msg);
/**
* Send a frame, and optionally attach an ID listener for response.
* Like TF_Send, but without the struct
*/
bool TF_SendSimple(TF_TYPE type, const uint8_t *data, TF_LEN len);
/**
* Like TF_Query, but without the struct
*/
bool TF_QuerySimple(TF_TYPE type, const uint8_t *data, TF_LEN len, TF_Listener listener, TF_TICKS timeout, void *userdata);
/**
* Send a frame, and optionally attach an ID listener.
*
* @param payload - data to send
* @param payload_len - nr of bytes to send
* @param id_ptr - store the ID here, NULL to don't store.
* The ID may be used to unbind the listener after a timeout.
* @return listener ID if listener was attached, else -1 (FT_ERROR).
* If the listener arg was NULL, returned -1 does not indicate an error.
* @param msg - message struct. ID is stored in the frame_id field
* @param listener - listener waiting for the response (can be NULL)
* @param timeout - listener expiry time in ticks
* @return success
*/
int TF_Send(const unsigned char *payload,
unsigned int payload_len,
TinyFrameListener listener, unsigned int *id_ptr);
/**
* A shorthand for TF_Send() with just one byte as the payload
*/
int TF_Send1(const unsigned char b0,
TinyFrameListener listener, unsigned int *id_ptr);
/**
* A shorthand for TF_Send() with just 2 bytes as the payload
*/
int TF_Send2(const unsigned char b0,
const unsigned char b1,
TinyFrameListener listener, unsigned int *id_ptr);
bool TF_Query(TF_Msg *msg, TF_Listener listener, TF_TICKS timeout);
/**
* Send a response to a received message.
*
* @param payload - data to send
* @param payload_len - nr of bytes to send
* @param frame_id - ID of the original frame
* @param msg - message struct. ID is read from frame_id. set ->renew to reset listener timeout
* @return success
*/
void TF_Respond(const unsigned char *payload,
unsigned int payload_len,
unsigned int frame_id);
bool TF_Respond(TF_Msg *msg);
/**
* Write implementation for TF, to be provided by user code.
* This sends frames composed by TinyFrame to UART
* Renew ID listener timeout
*
* @param id - listener ID to renew
* @return true if listener was found and renewed
*/
extern void TF_WriteImpl(const unsigned char *buff, unsigned int len);
bool TF_RenewIdListener(TF_ID id);
/**
* Accept incoming bytes & parse frames
*
* @param buffer - byte buffer to process
* @param count - nr of bytes in the buffer
*/
void TF_Accept(const uint8_t *buffer, size_t count);
/**
* Accept a single incoming byte
*
* @param c - a received char
*/
void TF_AcceptChar(uint8_t c);
/**
* 'Write bytes' function that sends data to UART
*
* ! Implement this in your application code !
*/
extern void TF_WriteImpl(const uint8_t *buff, size_t len);
/**
* This function should be called periodically.
*
* The time base is used to time-out partial frames in the parser and
* automatically reset it.
*
* (suggestion - call this in a SysTick handler)
*/
void TF_Tick(void);
#endif
+219
View File
@@ -0,0 +1,219 @@
//
// Created by MightyPork on 2017/10/15.
//
#include "demo.h"
// those magic defines are needed so we can use clone()
#define _GNU_SOURCE
#define __USE_GNU
#include <sched.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <signal.h>
volatile int sockfd = -1;
volatile bool conn_disband = false;
/**
* Close socket
*/
void demo_disconn(void)
{
conn_disband = true;
if (sockfd >= 0) close(sockfd);
}
/**
* Demo WriteImpl - send stuff to our peer
*
* @param buff
* @param len
*/
void TF_WriteImpl(const uint8_t *buff, size_t len)
{
printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n");
dumpFrame(buff, len);
usleep(1000);
if (sockfd != -1) {
write(sockfd, buff, len);
} else {
printf("\nNo peer!\n");
}
}
/**
* Client bg thread
*
* @param unused
* @return unused
*/
static int demo_client(void* unused)
{
(void)unused;
ssize_t n = 0;
uint8_t recvBuff[1024];
struct sockaddr_in serv_addr;
printf("\n--- STARTING CLIENT! ---\n");
memset(recvBuff, '0', sizeof(recvBuff));
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Error : Could not create socket \n");
return false;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\n inet_pton error occured\n");
return false;
}
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("\n Error : Connect Failed \n");
perror("PERROR ");
return false;
}
printf("\n Child Process \n");
while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0) {
printf("\033[36m--- RX %ld bytes ---\033[0m\n", n);
dumpFrame(recvBuff, (size_t) n);
TF_Accept(recvBuff, (size_t) n);
}
return 0;
}
/**
* Server bg thread
*
* @param unused
* @return unused
*/
static int demo_server(void* unused)
{
(void)unused;
ssize_t n;
int listenfd = 0;
uint8_t recvBuff[1024];
struct sockaddr_in serv_addr;
int option;
printf("\n--- STARTING SERVER! ---\n");
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
option = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(PORT);
if (bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("Failed to bind");
return 1;
}
if (listen(listenfd, 10) < 0) {
perror("Failed to listen");
return 1;
}
while (1) {
printf("\nWaiting for client...\n");
sockfd = accept(listenfd, (struct sockaddr *) NULL, NULL);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option));
printf("\nClient connected\n");
conn_disband = false;
while ((n = read(sockfd, recvBuff, sizeof(recvBuff) - 1)) > 0 && !conn_disband) {
printf("\033[36m--- RX %ld bytes ---\033[0m\n", n);
dumpFrame(recvBuff, n);
TF_Accept(recvBuff, (size_t) n);
}
if (n < 0) {
printf("\n Read error \n");
}
printf("Closing socket\n");
close(sockfd);
sockfd = -1;
}
return 0;
}
/**
* Trap - clean up
*
* @param sig - signal that caused this
*/
static void signal_handler(int sig)
{
(void)sig;
printf("Shutting down...");
demo_disconn();
exit(sig); // pass the signal through - this is nonstandard behavior but useful for debugging
}
/**
* Sleaping Beauty's fave function
*/
void demo_sleep(void)
{
while(1) usleep(10);
}
/**
* Start the background thread
*
* Slave is started first and doesn't normally init transactions - but it could
*
* @param peer what peer we are
*/
void demo_init(TF_Peer peer)
{
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
int retc;
void *stack = malloc(8192);
if (stack == NULL) {
perror("Oh fuck");
signal_handler(9);
return;
}
printf("Starting %s...\n", peer == TF_MASTER ? "MASTER" : "SLAVE");
// CLONE_VM --- share heap
// CLONE_FILES --- share stdout and stderr
if (peer == TF_MASTER) {
retc = clone(&demo_client, (char *)stack+8192, CLONE_VM|CLONE_FILES, 0);
} else {
retc = clone(&demo_server, (char *)stack+8192, CLONE_VM|CLONE_FILES, 0);
}
if (retc == 0) {
perror("Clone fail");
signal_handler(9);
return;
}
printf("Thread started\n");
}
+23
View File
@@ -0,0 +1,23 @@
//
// Created by MightyPork on 2017/10/15.
//
#ifndef TF_DEMO_H
#define TF_DEMO_H
#include <stdbool.h>
#include "../TinyFrame.h"
#include "utils.h"
#define PORT 9798
/** Sleep and wait for ^C */
void demo_sleep(void);
/** Init server - DOES NOT init TinyFrame! */
void demo_init(TF_Peer peer);
/** Disconnect client from the server - can be called by a server-side callback */
void demo_disconn(void);
#endif //TF_DEMO_H
+11
View File
@@ -0,0 +1,11 @@
CFILES=../utils.c ../../TinyFrame.c
INCLDIRS=-I. -I.. -I../..
CFLAGS=-O0 -ggdb --std=gnu99 -Wno-main -Wall -Wextra $(CFILES) $(INCLDIRS)
run: test.bin
./test.bin
build: test.bin
test.bin: test.c $(CFILES)
gcc test.c $(CFLAGS) -o test.bin
+25
View File
@@ -0,0 +1,25 @@
//
// Created by MightyPork on 2017/10/15.
//
#ifndef TF_CONFIG_H
#define TF_CONFIG_H
#include <stdint.h>
#define TF_ID_BYTES 1
#define TF_LEN_BYTES 2
#define TF_TYPE_BYTES 1
#define TF_CKSUM_TYPE TF_CKSUM_CRC16
#define TF_USE_SOF_BYTE 1
#define TF_SOF_BYTE 0x01
typedef uint16_t TF_TICKS;
typedef uint8_t TF_COUNT;
#define TF_MAX_PAYLOAD_RX 10240
#define TF_SENDBUF_LEN 64
#define TF_MAX_ID_LST 10
#define TF_MAX_TYPE_LST 10
#define TF_MAX_GEN_LST 5
#define TF_PARSER_TIMEOUT_TICKS 10
#endif //TF_CONFIG_H
+297
View File
@@ -0,0 +1,297 @@
#include <stdio.h>
#include <string.h>
#include "../../TinyFrame.h"
#include "../utils.h"
extern const char *romeo;
/**
* This function should be defined in the application code.
* It implements the lowest layer - sending bytes to UART (or other)
*/
void TF_WriteImpl(const uint8_t *buff, size_t len)
{
printf("--------------------\n");
printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n");
dumpFrame(buff, len);
// Send it back as if we received it
TF_Accept(buff, len);
}
/** An example listener function */
TF_Result myListener(TF_Msg *msg)
{
dumpFrameInfo(msg);
if (strcmp(msg->data, romeo) == 0) {
printf("FILE TRANSFERRED OK!\r\n");
} else {
printf("FAIL!!!!\r\n");
}
return TF_STAY;
}
void main(void)
{
TF_Msg msg;
// Set up the TinyFrame library
TF_Init(TF_MASTER); // 1 = master, 0 = slave
TF_AddGenericListener(myListener);
printf("------ Simulate sending a LOOONG message --------\n");
TF_ClearMsg(&msg);
msg.type = 0x22;
msg.data = (pu8)romeo;
msg.len = strlen(romeo);
TF_Send(&msg);
}
const char *romeo ="THE TRAGEDY OF ROMEO AND JULIET\n"
"\n"
"by William Shakespeare\n"
"\n"
"\n"
"\n"
"Dramatis Personae\n"
"\n"
" Chorus.\n"
"\n"
"\n"
" Escalus, Prince of Verona.\n"
"\n"
" Paris, a young Count, kinsman to the Prince.\n"
"\n"
" Montague, heads of two houses at variance with each other.\n"
"\n"
" Capulet, heads of two houses at variance with each other.\n"
"\n"
" An old Man, of the Capulet family.\n"
"\n"
" Romeo, son to Montague.\n"
"\n"
" Tybalt, nephew to Lady Capulet.\n"
"\n"
" Mercutio, kinsman to the Prince and friend to Romeo.\n"
"\n"
" Benvolio, nephew to Montague, and friend to Romeo\n"
"\n"
" Tybalt, nephew to Lady Capulet.\n"
"\n"
" Friar Laurence, Franciscan.\n"
"\n"
" Friar John, Franciscan.\n"
"\n"
" Balthasar, servant to Romeo.\n"
"\n"
" Abram, servant to Montague.\n"
"\n"
" Sampson, servant to Capulet.\n"
"\n"
" Gregory, servant to Capulet.\n"
"\n"
" Peter, servant to Juliet's nurse.\n"
"\n"
" An Apothecary.\n"
"\n"
" Three Musicians.\n"
"\n"
" An Officer.\n"
"\n"
"\n"
" Lady Montague, wife to Montague.\n"
"\n"
" Lady Capulet, wife to Capulet.\n"
"\n"
" Juliet, daughter to Capulet.\n"
"\n"
" Nurse to Juliet.\n"
"\n"
"\n"
" Citizens of Verona; Gentlemen and Gentlewomen of both houses;\n"
" Maskers, Torchbearers, Pages, Guards, Watchmen, Servants, and\n"
" Attendants.\n"
"\n"
" SCENE.--Verona; Mantua.\n"
"\n"
"\n"
"\n"
" THE PROLOGUE\n"
"\n"
" Enter Chorus.\n"
"\n"
"\n"
" Chor. Two households, both alike in dignity,\n"
" In fair Verona, where we lay our scene,\n"
" From ancient grudge break to new mutiny,\n"
" Where civil blood makes civil hands unclean.\n"
" From forth the fatal loins of these two foes\n"
" A pair of star-cross'd lovers take their life;\n"
" Whose misadventur'd piteous overthrows\n"
" Doth with their death bury their parents' strife.\n"
" The fearful passage of their death-mark'd love,\n"
" And the continuance of their parents' rage,\n"
" Which, but their children's end, naught could remove,\n"
" Is now the two hours' traffic of our stage;\n"
" The which if you with patient ears attend,\n"
" What here shall miss, our toil shall strive to mend.\n"
" [Exit.]\n"
"\n"
"\n"
"\n"
"\n"
"ACT I. Scene I.\n"
"Verona. A public place.\n"
"\n"
"Enter Sampson and Gregory (with swords and bucklers) of the house\n"
"of Capulet.\n"
"\n"
"\n"
" Samp. Gregory, on my word, we'll not carry coals.\n"
"\n"
" Greg. No, for then we should be colliers.\n"
"\n"
" Samp. I mean, an we be in choler, we'll draw.\n"
"\n"
" Greg. Ay, while you live, draw your neck out of collar.\n"
"\n"
" Samp. I strike quickly, being moved.\n"
"\n"
" Greg. But thou art not quickly moved to strike.\n"
"\n"
" Samp. A dog of the house of Montague moves me.\n"
"\n"
" Greg. To move is to stir, and to be valiant is to stand.\n"
" Therefore, if thou art moved, thou runn'st away.\n"
"\n"
" Samp. A dog of that house shall move me to stand. I will take\n"
" the wall of any man or maid of Montague's.\n"
"\n"
" Greg. That shows thee a weak slave; for the weakest goes to the\n"
" wall.\n"
"\n"
" Samp. 'Tis true; and therefore women, being the weaker vessels,\n"
" are ever thrust to the wall. Therefore I will push Montague's men\n"
" from the wall and thrust his maids to the wall.\n"
"\n"
" Greg. The quarrel is between our masters and us their men.\n"
"\n"
" Samp. 'Tis all one. I will show myself a tyrant. When I have\n"
" fought with the men, I will be cruel with the maids- I will cut off\n"
" their heads.\n"
"\n"
" Greg. The heads of the maids?\n"
"\n"
" Samp. Ay, the heads of the maids, or their maidenheads.\n"
" Take it in what sense thou wilt.\n"
"\n"
" Greg. They must take it in sense that feel it.\n"
"\n"
" Samp. Me they shall feel while I am able to stand; and 'tis known I\n"
" am a pretty piece of flesh.\n"
"\n"
" Greg. 'Tis well thou art not fish; if thou hadst, thou hadst\n"
" been poor-John. Draw thy tool! Here comes two of the house of\n"
" Montagues.\n"
"\n"
" Enter two other Servingmen [Abram and Balthasar].\n"
"\n"
"\n"
" Samp. My naked weapon is out. Quarrel! I will back thee.\n"
"\n"
" Greg. How? turn thy back and run?\n"
"\n"
" Samp. Fear me not.\n"
"\n"
" Greg. No, marry. I fear thee!\n"
"\n"
" Samp. Let us take the law of our sides; let them begin.\n"
"\n"
" Greg. I will frown as I pass by, and let them take it as they list.\n"
"\n"
" Samp. Nay, as they dare. I will bite my thumb at them; which is\n"
" disgrace to them, if they bear it.\n"
"\n"
" Abr. Do you bite your thumb at us, sir?\n"
"\n"
" Samp. I do bite my thumb, sir.\n"
"\n"
" Abr. Do you bite your thumb at us, sir?\n"
"\n"
" Samp. [aside to Gregory] Is the law of our side if I say ay?\n"
"\n"
" Greg. [aside to Sampson] No.\n"
"\n"
" Samp. No, sir, I do not bite my thumb at you, sir; but I bite my\n"
" thumb, sir.\n"
"\n"
" Greg. Do you quarrel, sir?\n"
"\n"
" Abr. Quarrel, sir? No, sir.\n"
"\n"
" Samp. But if you do, sir, am for you. I serve as good a man as\n"
" you.\n"
"\n"
" Abr. No better.\n"
"\n"
" Samp. Well, sir.\n"
"\n"
" Enter Benvolio.\n"
"\n"
"\n"
" Greg. [aside to Sampson] Say 'better.' Here comes one of my\n"
" master's kinsmen.\n"
"\n"
" Samp. Yes, better, sir.\n"
"\n"
" Abr. You lie.\n"
"\n"
" Samp. Draw, if you be men. Gregory, remember thy swashing blow.\n"
" They fight.\n"
"\n"
" Ben. Part, fools! [Beats down their swords.]\n"
" Put up your swords. You know not what you do.\n"
"\n"
" Enter Tybalt.\n"
"\n"
"\n"
" Tyb. What, art thou drawn among these heartless hinds?\n"
" Turn thee Benvolio! look upon thy death.\n"
"\n"
" Ben. I do but keep the peace. Put up thy sword,\n"
" Or manage it to part these men with me.\n"
"\n"
" Tyb. What, drawn, and talk of peace? I hate the word\n"
" As I hate hell, all Montagues, and thee.\n"
" Have at thee, coward! They fight.\n"
"\n"
" Enter an officer, and three or four Citizens with clubs or\n"
" partisans.\n"
"\n"
"\n"
" Officer. Clubs, bills, and partisans! Strike! beat them down!\n"
"\n"
" Citizens. Down with the Capulets! Down with the Montagues!\n"
"\n"
" Enter Old Capulet in his gown, and his Wife.\n"
"\n"
"\n"
" Cap. What noise is this? Give me my long sword, ho!\n"
"\n"
" Wife. A crutch, a crutch! Why call you for a sword?\n"
"\n"
" Cap. My sword, I say! Old Montague is come\n"
" And flourishes his blade in spite of me.\n"
"\n"
" Enter Old Montague and his Wife.\n"
"\n"
"\n"
" Mon. Thou villain Capulet!- Hold me not, let me go.\n"
"\n"
" M. Wife. Thou shalt not stir one foot to seek a foe.\n"
"\n"
" Enter Prince Escalus, with his Train.\n"
"\n"
"\n"
"END OF FILE\n";
+11
View File
@@ -0,0 +1,11 @@
CFILES=../utils.c ../../TinyFrame.c
INCLDIRS=-I. -I.. -I../..
CFLAGS=-O0 -ggdb --std=gnu99 -Wno-main -Wall -Wextra $(CFILES) $(INCLDIRS)
run: test.bin
./test.bin
build: test.bin
test.bin: test.c $(CFILES)
gcc test.c $(CFLAGS) -o test.bin
+25
View File
@@ -0,0 +1,25 @@
//
// Created by MightyPork on 2017/10/15.
//
#ifndef TF_CONFIG_H
#define TF_CONFIG_H
#include <stdint.h>
#define TF_ID_BYTES 1
#define TF_LEN_BYTES 2
#define TF_TYPE_BYTES 1
#define TF_CKSUM_TYPE TF_CKSUM_CRC16
#define TF_USE_SOF_BYTE 1
#define TF_SOF_BYTE 0x01
typedef uint16_t TF_TICKS;
typedef uint8_t TF_COUNT;
#define TF_MAX_PAYLOAD_RX 1024
#define TF_SENDBUF_LEN 1024
#define TF_MAX_ID_LST 10
#define TF_MAX_TYPE_LST 10
#define TF_MAX_GEN_LST 5
#define TF_PARSER_TIMEOUT_TICKS 10
#endif //TF_CONFIG_H
+65
View File
@@ -0,0 +1,65 @@
#include <stdio.h>
#include <string.h>
#include "../../TinyFrame.h"
#include "../utils.h"
/**
* This function should be defined in the application code.
* It implements the lowest layer - sending bytes to UART (or other)
*/
void TF_WriteImpl(const uint8_t *buff, size_t len)
{
printf("--------------------\n");
printf("\033[32mTF_WriteImpl - sending frame:\033[0m\n");
dumpFrame(buff, len);
// Send it back as if we received it
TF_Accept(buff, len);
}
/** An example listener function */
TF_Result myListener(TF_Msg *msg)
{
dumpFrameInfo(msg);
return TF_STAY;
}
TF_Result testIdListener(TF_Msg *msg)
{
printf("OK - ID Listener triggered for msg!\n");
dumpFrameInfo(msg);
return TF_CLOSE;
}
void main(void)
{
TF_Msg msg;
const char *longstr = "Lorem ipsum dolor sit amet.";
// Set up the TinyFrame library
TF_Init(TF_MASTER); // 1 = master, 0 = slave
TF_AddGenericListener(myListener);
printf("------ Simulate sending a message --------\n");
TF_ClearMsg(&msg);
msg.type = 0x22;
msg.data = (pu8)"Hello TinyFrame";
msg.len = 16;
TF_Send(&msg);
msg.type = 0x33;
msg.data = (pu8)longstr;
msg.len = (TF_LEN) (strlen(longstr)+1); // add the null byte
TF_Send(&msg);
msg.type = 0x44;
msg.data = (pu8)"Hello2";
msg.len = 7;
TF_Send(&msg);
msg.len = 0;
msg.type = 0x77;
TF_Query(&msg, testIdListener, 0);
}
+17
View File
@@ -0,0 +1,17 @@
CFILES=../demo.c ../utils.c ../../TinyFrame.c
INCLDIRS=-I. -I.. -I../..
CFLAGS=-O0 -ggdb --std=gnu99 -Wno-main -Wall -Wextra $(CFILES) $(INCLDIRS)
build: master.bin slave.bin
master: master.bin
./master.bin
slave: slave.bin
./slave.bin
master.bin: master.c $(CFILES)
gcc master.c $(CFLAGS) -o master.bin
slave.bin: slave.c $(CFILES)
gcc slave.c $(CFLAGS) -o slave.bin
+25
View File
@@ -0,0 +1,25 @@
//
// Created by MightyPork on 2017/10/15.
//
#ifndef TF_CONFIG_H
#define TF_CONFIG_H
#include <stdint.h>
#define TF_ID_BYTES 1
#define TF_LEN_BYTES 2
#define TF_TYPE_BYTES 1
#define TF_CKSUM_TYPE TF_CKSUM_CRC16
#define TF_USE_SOF_BYTE 1
#define TF_SOF_BYTE 0x01
typedef uint16_t TF_TICKS;
typedef uint8_t TF_COUNT;
#define TF_MAX_PAYLOAD_RX 1024
#define TF_SENDBUF_LEN 1024
#define TF_MAX_ID_LST 10
#define TF_MAX_TYPE_LST 10
#define TF_MAX_GEN_LST 5
#define TF_PARSER_TIMEOUT_TICKS 10
#endif //TF_CONFIG_H
+35
View File
@@ -0,0 +1,35 @@
//
// Created by MightyPork on 2017/10/15.
//
#include <stdio.h>
#include "../demo.h"
TF_Result testIdListener(TF_Msg *msg)
{
printf("testIdListener()\n");
dumpFrameInfo(msg);
return TF_CLOSE;
}
TF_Result testGenericListener(TF_Msg *msg)
{
printf("testGenericListener()\n");
dumpFrameInfo(msg);
return TF_STAY;
}
int main(void)
{
TF_Init(TF_MASTER);
TF_AddGenericListener(testGenericListener);
demo_init(TF_MASTER);
TF_SendSimple(1, (pu8)"Ahoj", 5);
TF_SendSimple(1, (pu8)"Hello", 6);
TF_QuerySimple(2, (pu8)"Query!", 6, testIdListener, 0, NULL);
demo_sleep();
}
+42
View File
@@ -0,0 +1,42 @@
//
// Created by MightyPork on 2017/10/15.
//
#include <stdio.h>
#include "../demo.h"
#include <memory.h>
TF_Result helloListener(TF_Msg *msg)
{
printf("helloListener()\n");
dumpFrameInfo(msg);
return TF_STAY;
}
TF_Result replyListener(TF_Msg *msg)
{
printf("replyListener()\n");
dumpFrameInfo(msg);
msg->data = (const uint8_t *) "response to query";
msg->len = (TF_LEN) strlen((const char *) msg->data);
TF_Respond(msg);
// unsolicited reply - will not be handled by the ID listener, which is already gone
msg->data = (const uint8_t *) "SPAM";
msg->len = 5;
TF_Respond(msg);
// unrelated message
TF_SendSimple(77, (const uint8_t *) "NAZDAR", 7);
return TF_STAY;
}
int main(void)
{
TF_Init(TF_SLAVE);
TF_AddTypeListener(1, helloListener);
TF_AddTypeListener(2, replyListener);
demo_init(TF_SLAVE);
demo_sleep();
}
+32
View File
@@ -0,0 +1,32 @@
//
// Created by MightyPork on 2017/10/15.
//
#include "utils.h"
#include <stdio.h>
// helper func for testing
void dumpFrame(const uint8_t *buff, size_t len)
{
size_t i;
for(i = 0; i < len; i++) {
printf("%3u \033[94m%02X\033[0m", buff[i], buff[i]);
if (buff[i] >= 0x20 && buff[i] < 127) {
printf(" %c", buff[i]);
} else {
printf(" \033[31m.\033[0m");
}
printf("\n");
}
printf("--- end of frame ---\n\n");
}
void dumpFrameInfo(TF_Msg *msg)
{
printf("\033[33mFrame info\n"
" type: %02Xh\n"
" data: \"%.*s\"\n"
" len: %u\n"
" id: %Xh\033[0m\n\n",
msg->type, msg->len, msg->data, msg->len, msg->frame_id);
}
+26
View File
@@ -0,0 +1,26 @@
//
// Created by MightyPork on 2017/10/15.
//
#ifndef TF_UTILS_H
#define TF_UTILS_H
#include <stdio.h>
#include "../TinyFrame.h"
/** pointer to unsigned char */
typedef unsigned char* pu8;
/**
* Dump a binary frame as hex, dec and ASCII
*/
void dumpFrame(const uint8_t *buff, size_t len);
/**
* Dump message metadata (not the content)
*
* @param msg
*/
void dumpFrameInfo(TF_Msg *msg);
#endif //TF_UTILS_H
-82
View File
@@ -1,82 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "TinyFrame.h"
// helper func for testing
static void dumpFrame(const unsigned char *buff, unsigned int len)
{
int i;
for(i = 0; i < len; i++) {
printf("%3u %c\n", buff[i], buff[i]);
}
printf("--- end of frame ---\n");
}
/**
* This function should be defined in the application code.
* It implements the lowest layer - sending bytes to UART (or other)
*/
void TF_WriteImpl(const unsigned char *buff, unsigned int len)
{
printf("\033[32;1mTF_WriteImpl - sending frame:\033[0m\n");
dumpFrame(buff, len);
}
/** An example listener function */
bool myListener(unsigned int frame_id, const unsigned char *buff, unsigned int len)
{
printf("\033[33mrx frame %s, len %d, id %d\033[0m\n", buff, len, frame_id);
return false; // Do not unbind
}
void main()
{
int i;
int msgid;
int len;
char buff[100];
// Set up the TinyFrame library
TF_Init(1); // 1 = master, 0 = slave
printf("------ Simulate sending a message --------\n");
// Send a message
// args - payload, length (0 = strlen), listener, id_ptr (for storing the frame ID)
// (see the .h file for details)
TF_Send("Hello TinyFrame", 0, NULL, NULL);
// This builds the frame in an internal buffer and sends it to
// TF_WriteImpl()
printf("------ Simulate receiving a message --------\n");
// Adding global listeners
// Listeners can listen to any frame (fallback listeners),
// or to a specific Frame Type (AddTypeListener). There are
// also ID listeners that can be bound automatically in TF_Send().
//
// Type listeners are matched by the first character of the payload,
// ID listeners by the message ID (which is the same in the response as in the request)
TF_AddGenericListener(myListener);
//TF_AddTypeListener(0xF1, myTypeListener);
//TF_AddIdListener(msgID, myIdListener);
// This lets us compose a frame (it's also used internally by TF_Send and TF_Respond)
len = TF_Compose(buff, // Buffer to write the frame to
&msgid, // Int to store the message ID in
"ALPHA BETA", // Payload bytes
5, // Length - this will cut it at "ALPHA" (showing that it works)
// For string, we can use "0" to use strlen() internally
TF_NEXT_ID); // Message ID - we could specify a particular ID if we were
// trying to build a response frame, which has the same ID
// as the request it responds to.
printf("The frame we'll receive is:\n");
dumpFrame(buff, len);
// Accept the frame
// You will normally call this method in the UART IRQ handler etc
TF_Accept(buff, len);
}