蓝牙----CC2640中的ICall模块与TI RTOS

用TI的CC2640蓝牙有一段时间了,平时是做应用层的开发,没太关注ICall模块,但读完这篇文章,我收获很大,结合一些其他的学习资料,做一些总结。

1.ICall模块介绍

ICall是实现TI蓝牙芯片功能中应用程序和协议栈的不可缺的一部分。

TI蓝牙芯片的程序框图
ICALL 模块实现包含应用程序和 BLE协议栈通信,实现多任务间消息传递,发送方申请内存,接收方释放内存,上面这句话总体概括了ICall模块的作用:
1.消息传递和线程同步
 1.1一个客户端实体和一个服务器实体,通过ICall实现协议栈的消息传递
 1.2 ICall 通过任务在消息队列给另一任务发送一个阻塞消息完成线程同步
2.堆分配与管理
 ICall 为应用提供了全局堆管理的 API 用以动态内存分配

2.ICall 模块初试化

ICall 初始化,在 main 函数中调用 ICall_init()。该函数初始化 ICall 初级服务,例如堆栈管理器,调用 ICall_createRemoteTasks()创建但不启动蓝牙协议栈任务。使用 ICall 之前,必须要先注册 ICall。
在这里插入图片描述

  ICall_init();                /* 初始化 ICall 模块 */ 
  ICall _createRemoteTasks ();/* 将协议栈作作为任务创建 */ 

在使用ICall 协议服务之前,服务器和客户端分别完成登记和注册

 / * ICALL 服务端登记* / 
/* BLE协议使用 ICALL_SERVICE_CLASS_BLE 做蓝牙协议栈 ICALL的消息交互的标识*/
ICall _enrollService (ICALL _SERVICE_CLASS_BLE ,NULL ,&entity ,&syncHandle );
 / * ICALL 客户端注册* / 
/*ICALL服务端通过两个变量来进行消息传递。
syncEvent 参数表示事件标识,
selfEntity 表示处理消息的目的任务,也是客户端实体以后通信的源地址。
注册 ICALL 的客户端使用唯一 syncEvent和selfEntity 。*/
   ICall _registerApp (&selfEntity ,&syncEvent); 

3.ICall 线程同步

ICALL 使用 TI-RTOS 的事件用以线程同步。

ICall 消息队列保留了特定事件标志位
#define ICALL_MSG_EVENT_ID Event_Id_31

客户端或服务端在收到消息前保持阻塞状态,ICall 使用阻塞型 API 保持任务阻塞状态直到关联的信号量被 Post

Event_pend 函数表示阻塞当前任务等待某一事件标志位发生。

UInt Event_pend(Event_Handle handle, UInt andMask, UInt orMask, UInt32 timeout);
	handle 是构造的 Event_Handle 事件句柄(标识符)。
	andMask 和 orMask 为用户选择要阻塞/挂起的事件标志。
	timeout 是以毫秒为单位的超时周期。如果在此超时时间范围内后事件尚未被Post,该函数将返回。 

Event_post 用以客户端/服务端将某个任务阻塞任务激活成运行状态

void Event_post(Event_Handle handle,UInt eventMask);

上面的事件句柄 handle 由服务端 ICall _enrollService()和 ICall _registerApp()调用后获得。

4.ICall 的消息流程分析

1.ICall服务端创建
在这里插入图片描述

有关协议栈任务实体:TI软件架构的区分
独立镜像方式是通过工具自动计算首地址作为协议栈的任务的入口地址,
静态链接库方式是直接链接协议栈的入口地址作为协议栈任务的任务实体。

2.服务端登记

ICALL_SERVICE_CLASS_BLE_MSG 作为服务端的源地址
ICall_enrollService(ICALL_SERVICE_CLASS_BLE_MSG,ICall_ServiceFunc) osal_service_entry,
&osal_entity,&osal_syncHandle)

3.客户端注册,

selfEntity 作为客户端 Icall 通信的源地址
ICall_registerApp(&selfEntity, &syncEvent);

4.应用程序发送消息

所有应用程序 Icall 消息发送都是封装在 icall_directAPI 函数中。
4.1icall_direct将要传递的消息封装
在这里插入图片描述

4.1调用ICall_sendServiceMsg

Call_sendServiceMsg(ICall_getEntityId(),service,ICALL_MSG_FORMAT_DIRECT_API_ID,&(liteMsg.msg));ICall_getEntityId():调用API的应用程序的任务标识
	▪ service:为ICALL_SERVICE_CLASS_BLE_MSG
	▪ ICall_sendServiceMsg的函数原型
		○ ICall_sendServiceMsg(ICall_EntityID src, ICall_ServiceEnum dest,ICall_MSGFormat format, void *msg)
		○ ICall_EntityID客户端地址,调用API的应用程序
		○ ICall_ServiceEnum服务器端地址,协议栈的

4.2调用 ICall_send
ICall_send 直接将消息放入了目的 Icall 消息实体的消息队列中,并且触发事件通知该任务唤醒解析处理消息

ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg);ICALL_SYNC_HANDLE_POST(ICall_entities[dest].task->syncHandle);# `

5.ICall 的调用过程

协议栈对应用程序的触发概括而言就是:回调函数,消息入队,异步事件,阻塞停止
下面以GATT层的事件接受为例
1.回调函数定义

static void SimplePeripheral_charValueChangeCB(uint8_t paramId)
{
  uint8_t *pValue = ICall_malloc(sizeof(uint8_t));
  if (pValue)
  {
    *pValue = paramId;
    if (SimplePeripheral_enqueueMsg(SP_CHAR_CHANGE_EVT, pValue) != SUCCESS)
    {
      ICall_free(pValue);
    }
  }
}
static simpleProfileCBs_t SimplePeripheral_simpleProfileCBs =
{
  SimplePeripheral_charValueChangeCB // Simple GATT Characteristic value change callback
};

2.绑定回调函数

  SimpleProfile_RegisterAppCBs(&SimplePeripheral_simpleProfileCBs);

3.当GATT层收到蓝牙数据后,SP_CHAR_CHANGE_EVT入队,app任务唤醒后执行

if (events)
    {
      ICall_EntityID dest;
      ICall_ServiceEnum src;
      ICall_HciExtEvt *pMsg = NULL;
      // 优先检查协议栈消息
      if (ICall_fetchServiceMsg(&src, &dest,
                                (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
      {
        uint8 safeToDealloc = TRUE;
        if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
        {
          ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;
          if (pEvt->signature != 0xffff)
          {
            safeToDealloc = SimplePeripheral_processStackMsg((ICall_Hdr *)pMsg);
          }
        }
        if (pMsg && safeToDealloc)
        {
          ICall_freeMsg(pMsg);
        }
      }

      // 判断APP消息
      if (events & SP_QUEUE_EVT)
      {
        while (!Queue_empty(appMsgQueueHandle))
        {
          spEvt_t *pMsg = (spEvt_t *)Util_dequeueMsg(appMsgQueueHandle);
          if (pMsg)
          {
            SimplePeripheral_processAppMsg(pMsg);
            ICall_free(pMsg);
          }
        }
      }
    }

4.在协议栈任务确定是蓝牙哪一层的任务

static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg)
{
  switch (pMsg->event)
  {
    case GAP_MSG_EVENT:
      SimplePeripheral_processGapMessage((gapEventHdr_t*) pMsg);
      break;

    case GATT_MSG_EVENT:
      // Process GATT message
      safeToDealloc = SimplePeripheral_processGATTMsg((gattMsgEvent_t *)pMsg);
      break;

    case HCI_GAP_EVENT_EVENT:
    {
      // Process HCI message
     ************
           break;
    }

    default:
      // do nothing
      break;
  }

5.在GATT层任务中完成最终事件的处理

static uint8_t SimplePeripheral_processGATTMsg(gattMsgEvent_t *pMsg)
{
  if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
  {
    // Display the opcode of the message that caused the violation.
    Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
  }
  else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
  {
    // MTU size updated
    Display_printf(dispHandle, SP_ROW_STATUS_1, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU);
  }

  // Free message payload. Needed only for ATT Protocol messages
  GATT_bm_free(&pMsg->msg, pMsg->method);

  // It's safe to free the incoming message
  return (TRUE);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TI-RTOS是德州仪器公司针对其微控制器系列开发的一个实时操作系统。由于TI-RTOS在嵌入式领域应用广泛,因此针对其的开放教程和文资料也是存在的。 首先,TI-RTOS的官方网站(www.ti.com)上提供了详细的开发教程和相关文档,可以通过注册和登录获取相关资料。在官方网站上,可以找到针对不同系列的TI微控制器的开发教程和技术文档。这些文档包括了TI-RTOS的概述、使用方法、编程接口、示例代码等内容,对于初学者和进阶者都有很实用的指导。 此外,互联网上也有很多独立的公开资源提供TI-RTOS文资料。例如,各种学习论坛、技术博客、视频教程等都提供了关于TI-RTOS的学习资料。在这些平台上,你可以找到人们的实际项目经验、案例分析、开发技巧等等,这些资料对于深入了解和应用TI-RTOS非常有帮助。 此外,德州仪器公司也会定期举办TI-RTOS的培训课程和技术研讨会。这些会议通常会提供面对面的指导和交流机会,你可以在现场和其他开发者一起学习TI-RTOS的使用和最佳实践。此外,这些会议还提供了问答环节,可以解答你在使用TI-RTOS过程遇到的问题。 综上所述,TI-RTOS的开放教程和文资料是非常丰富的。通过官方网站、互联网上的公开资源以及参加相关培训,你可以获得关于TI-RTOS全面而深入的学习资料,从而更好地掌握和应用这一实时操作系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值