本文介绍,BabyOS组件Protocol使用;
代码连接:https://gitee.com/notrynohigh/BabyOS_Example/blob/examples/example/protocol/stm32f107/main.c
通过 USART1 接收与发送。
由外向内-代码分析
代码块1
此代码关注2处:
bTransFileInit(); // 发送文件初始化
bHalItInvoke(B_HAL_IT_UART_RX, B_HAL_UART_1, ¶m); //通过串口中断接收每个字节
int main()
{
BoardInit();
SysTick_Config(SystemCoreClock / TICK_FRQ_HZ);
NVIC_SetPriority(SysTick_IRQn, 0x0);
bInit();
bTransFileInit();
while (1)
{
bExec();
}
}
void USART1_IRQHandler()
{
uint8_t uart_dat = 0;
bHalItParam_t param;
param._uart.len = 1;
param._uart.pbuf = &uart_dat;
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
uart_dat = USART_ReceiveData(USART1);
bHalItInvoke(B_HAL_IT_UART_RX, B_HAL_UART_1, ¶m);
}
}
代码块2
//创建了 bProtoUart 结构体实例
bHAL_UART_CREATE_ATTR(bProtoUart, 1024, 100, _bProtoRevHandle, NULL);
//创建了 bProtol 结构体实例
B_PROT_SRV_CREATE_ATTR(bProtol, "bos", bProtoCallback);
//根据bProtoUart 实例参数,100ms 接收空闲中断 回调 _bProtoRevHandle
bHalUartReceiveIdle(B_HAL_UART_1, &bProtoUart);
// 查找bProtol -> name 与 b_srv_protocol 有没有匹配的,返回实例 bProtoUart 地址
sgSrvId = bProtSrvInit(&bProtol, NULL);
/*
bProtSrvId_t bProtSrvInit(bProtSrvAttr_t *attr, bProtSrvGetInfo_t func)
{
if (attr == NULL)
{
return NULL;
}
bSECTION_FOR_EACH(b_srv_protocol, bProtocolInstance_t, instance)
{
if (strcmp(instance->name, attr->name) == 0)
{
attr->attr.get_info = func;
attr->attr.package = instance->package;
attr->attr.parse = instance->parse;
break;
}
}
if (attr->attr.parse && attr->attr.package)
{
return attr;
}
return NULL;
}
*/
//b_srv_protocol.c
//bSECTION_DEF_FLASH(b_srv_protocol, bProtocolInstance_t); //68行
//b_mod_protocol.c
//bPROTOCOL_REG_INSTANCE("bos", _bProtocolParse, _bProtocolPackage); //320行
代码块3 BOS 私有通讯协议
/**
| | | | | | |
| :--- | ------------------ | ------------------- | ----- | -------- | ----- |
| Head | Device ID | Len(cmd+param) | Cmd | Param | Check |
| 0xFE | sizeof(bProtoID_t) | sizeof(bProtoLen_t) | 1Byte | 0~nBytes | 1Byte |
*/
Device ID
在这个例程中,device id = 0;
使用效果
经过上面初始化之后:
- 接收到1帧数据; //串口中断接收 (硬件外设)
- 空闲100ms; //空闲中断 (软件实现)
- 这里接收回调; //产生回调(软件实现)
static int _bProtoRevHandle(uint8_t *pbuf, uint16_t len, void *user_data)
//调用 bProtSrvParse 后
//调用_bProtocolParse 后
//解码成功会 回调 bProtoCallback
int bProtoCallback(bProtoCmd_t cmd, void *param)
{
if (cmd == B_PROTO_TRANS_FILE_INFO)
{
bProtoFileInfo_t *p = (bProtoFileInfo_t *)param;
bTransFileRunParam.fsize = p->size;
bTransFileRunParam.f_crc32 = p->fcrc32;
}
else if (cmd == B_PROTO_SET_FILE_LOCATION)
{
bProtoFileLocation_t *p = (bProtoFileLocation_t *)param;
bTransFileRunParam.dev_no = p->dev;
bTransFileRunParam.offset = p->offset;
bTransFileRunParam.rlen = 0;
}
else if (cmd == B_PROTO_FILE_DATA)
{
bProtoFileData_t *p = (bProtoFileData_t *)param;
if (bTransFileRunParam.rlen == p->offset)
{
bLseek(sgFd, bTransFileRunParam.offset + bTransFileRunParam.rlen);
bWrite(sgFd, p->dat, p->size);
bTransFileRunParam.rlen += p->size;
bSemRelease(sgSemId);
}
}
return 0;
}
文件收发
B_TASK_CREATE_ATTR(bTransFileAttr);
B_SEM_CREATE_ATTR(bTransFileSemAttr);
这个例程中使用了一个线程与一个信号量实现,此处代码不是本篇文章的重点内容。
总结
BabyOS-Protocol 提供了一套 协议解析的框架;
并提供了一套私有的bos 协议;
可以很容易嵌入其他协议,如
// proto_name \ref "bos": babyos私有协议
// "modbus", "xmodem128", "ymodem"
// callback \ref bProtSrvCallback_t
#define B_PROT_SRV_CREATE_ATTR(attr_name, proto_name, _callback) \
static bProtSrvAttr_t attr_name = { \
.name = proto_name, \
.attr.callback = _callback, \
.attr.parse = NULL, \
.attr.package = NULL, \
}
这是一个看上去很不错的框架,非常建议去了解一下这套框架;
并且在你没有对比发现比这套框架更好的代码时候,非常建议你去实际使用一下它。