TinyFrame

授权协议 MIT License
开发语言 C/C++
所属分类 其他开源、 嵌入式操作系统
软件类型 开源软件
地区 不详
投 递 者 薛文斌
操作系统 嵌入式
开源组织
适用人群 未知
 软件概览

TinyFrame

TinyFrame is a simple library for building and parsing data frames to be sentover a serial interface (e.g. UART, telnet, socket). The code is written to build with--std=gnu99 and mostly compatible with --std=gnu89.

The library provides a high level interface for passing messages between the two peers.Multi-message sessions, response listeners, checksums, timeouts are all handled by the library.

TinyFrame is suitable for a wide range of applications, including inter-microcontrollercommunication, as a protocol for FTDI-based PC applications or for messaging throughUDP packets.

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 is generalenough to implement most communication patterns.

TinyFrame is re-entrant and supports creating multiple instances with the limitationthat their structure (field sizes and checksum type) is the same. There is a supportfor adding multi-threaded access to a shared instance using a mutex.

TinyFrame also comes with (optional) helper functions for building and parsing messagepayloads, those are provided in the utils/ folder.

Ports

TinyFrame has been ported to mutiple languages:

Please note most of the ports are experimental and may exhibit various bugs or missingfeatures. Testers are welcome :)

Functional overview

The basic functionality of TinyFrame is explained here. For particlars, such as theAPI functions, it's recommended to read the doc comments in the header file.

Structure of a frame

Each frame consists of a header and a payload. Both parts can be protected by a checksum,ensuring a frame with a malformed header (e.g. with a corrupted length field) or a corruptedpayload is rejected.

The frame header contains a frame ID and a message type. Frame ID is incremented with eachnew message. The highest bit of the ID field is fixed to 1 and 0 for the two peers,avoiding a conflict.

Frame ID can be re-used in a response to tie the two messages together. Values of thetype field are user defined.

All fields in the frame have a configurable size. By changing a field in the configfile, such as TF_LEN_BYTES (1, 2 or 4), the library seamlessly switches between uint8_t,uint16_t and uint32_t for all functions working with the field.

,-----+-----+-----+------+------------+- - - -+-------------,
| SOF | ID  | LEN | TYPE | HEAD_CKSUM | DATA  | DATA_CKSUM  |
| 0-1 | 1-4 | 1-4 | 1-4  | 0-4        | ...   | 0-4         | <- size (bytes)
'-----+-----+-----+------+------------+- - - -+-------------'

SOF ......... start of frame, usually 0x01 (optional, configurable)
ID  ......... the frame ID (MSb is the peer bit)
LEN ......... number 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 .. data checksum (left out if LEN is 0)

Message listeners

TinyFrame is based on the concept of message listeners. A listener is a callback functionwaiting for a particular message Type or ID to be received.

There are 3 listener types, in the order of precedence:

  • ID listeners - waiting for a response
  • Type listeners - waiting for a message of the given Type field
  • Generic listeners - fallback

ID listeners can be registered automatically when sending a message. All listeners canalso be registered and removed manually.

ID listeners are used to receive the response to a request. When registerign an IDlistener, it's possible to attach custom user data to it that will be made available tothe listener callback. This data (void *) can be any kind of application contextvariable.

ID listeners can be assigned a timeout. When a listener expires, before it's removed,the callback is fired with NULL payload data in order to let the user free() anyattached userdata. This happens only if the userdata is not NULL.

Listener callbacks return values of the TF_Result enum:

  • TF_CLOSE - message accepted, remove the listener
  • TF_STAY - message accepted, stay registered
  • TF_RENEW - sameas TF_STAY, but the ID listener's timeout is renewed
  • TF_NEXT - message NOT accepted, keep the listener and pass the message to the nextlistener capable of handling it.

Data buffers, multi-part frames

TinyFrame uses two data buffers: a small transmit buffer and a larger receive buffer.The transmit buffer is used to prepare bytes to send, either all at once, or in acircular fashion if the buffer is not large enough. The buffer must only contain the entireframe header, so e.g. 32 bytes should be sufficient for short messages.

Using the *_Multipart() sending functions, it's further possible to split the frameheader and payload to multiple function calls, allowing the applciation to e.g. generatethe payload on-the-fly.

In contrast to the transmit buffer, the receive buffer must be large enough to containan entire frame. This is because the final checksum must be verified before the frameis handled.

If frames larger than the possible receive buffer size are required (e.g. in embeddedsystems with small RAM), it's recommended to implement a multi-message transport mechanismat a higher level and send the data in chunks.

Usage Hints

  • All TinyFrame functions, typedefs and macros start with the TF_ prefix.
  • Both peers must include the library with the same config parameters
  • See TF_Integration.example.c and TF_Config.example.c for reference how to configure and integrate the library.
  • DO NOT modify the library files, if possible. This makes it easy to upgrade.
  • Start by calling TF_Init() with TF_MASTER or TF_SLAVE as the argument. This creates a handle.Use TF_InitStatic() to avoid the use of malloc().
  • If multiple instances are used, you can tag them using the tf.userdata / tf.usertag field.
  • 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.
  • Use TF_AcceptChar(tf, byte) to give read data to TF. TF_Accept(tf, bytes, count) will accept mulitple bytes.
  • If you wish to use timeouts, periodically call TF_Tick(). The calling period determinesthe length of 1 tick. This is used to time-out the parser in case it gets stuckin 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 asan ID listener and wait for a response.
  • Use the *_Multipart() variant of the above sending functions for payloads generated inmultiple function calls. The payload is sent afterwards by calling TF_Multipart_Payload()and the frame is closed by TF_Multipart_Close().
  • If custom checksum implementation is needed, select TF_CKSUM_CUSTOM8, 16 or 32 andimplement the three checksum functions.
  • To reply to a message (when your listener gets called), use TF_Respond()with the msg object you received, replacing the data pointer (and len) with a response.
  • At any time you can manually reset the message parser using TF_ResetParser(). It can alsobe reset automatically after a timeout configured in the config file.

Gotchas to look out for

  • If any userdata is attached to an ID listener with a timeout, when the listener times out,it will be called with NULL msg->data to let the user free the userdata. Thereforeit's needed to check msg->data before proceeding to handle the message.
  • If a multi-part frame is being sent, the Tx part of the library is locked to preventconcurrent access. The frame must be fully sent and closed before attempting to sendanything else.
  • If multiple threads are used, don't forget to implement the mutex callbacks to avoidconcurrent access to the Tx functions. The default implementation is not entirely threadsafe, as it can't rely on platform-specific resources like mutexes or atomic access.Set TF_USE_MUTEX to 1 in the config file.

Examples

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 asynchronousRx and Tx. If you can't run the demos, the source files are still good as examples.

  • 摘要:TinyFrame是一个简单的用于解析串口(如 UART、telnet、套接字等)通信数据帧的库。 本文分享自华为云社区《LiteOS组件尝鲜—玩转TinyFrame》,作者:Lionlace。 基本介绍 TinyFrame是一个简单的用于解析串口(如 UART、telnet、套接字等)通信数据帧的库。它可以灵活处理通信双方之间的消息会话、响应侦听者、校验及超时问题。该库允许注册侦听器(以回

  • 在上一篇中,我列举了框架的整体结构,下面我们将一一说明: 首先需要说明的是TinyFrame.Data。 它主要用于处理数据库底层操作。包含EF CodeFirst,Repository,Unitofwork三个部分。 其中,DomainModel主要是用来存放实体类的: 1: namespace TinyFrame.Data.DomainModel 2: { 3:

  • 我自己的框架中,UOW是可以通过反射提取具体的Repository的,也可以调用Commit方法。 但是正确的应用方式应该是: Using(var uow = new UnitOfWork()) {    // code here }   或者是 当UOW通过IOC注册完毕后,可以通过如下代码进行事务操作:   uow.BeginTrans(); //code here uow.Commit();

  • TinyFrame开篇:基于CodeFirst的ORM TinyFrame续篇:整合Spring IOC实现依赖注入 TinyFrame再续篇:整合Spring AOP实现日志拦截 TinyFrame尾篇:整合Spring AOP实现用户认证   点击这里下载源代码 上面只是我第一次搭建项目的时候,做的一个设想,后来在实际项目中,我扩充了这个框架,并在实际项目中使用,效果还可以: TinyFram

  • 在上一篇,我们打造了自己的数据访问部分,这篇,我们准备讲解如何打造逻辑访问部分。 在上一篇中,我们利用Repository模式构建了基于泛型的操作合集。由于这些操作的合集都是原子性的操作,也就是针对单表的操作,我们有必要为每个单表做增删改查操作,所以这里我们最好将泛型包装一下: 这里是IBook接口部分,它继承自IRepository接口,并承载了Book实体类 1: using Tiny

  • 在这个框架中,我们使用Autofac作为IOC容器,来实现控制反转,依赖注入的目的。 在程序加载的时候,我需要将系统中所有用到的接口与之对应的实现进行装载。由于用户交互部分是在TinyFrame.Web中,并且请求入口是在Application_Start方法中,所以我在这里进行了注入: 1: private void RegisterDependency() 2:

相关阅读

相关文章

相关问答

相关文档