要先知道怎么工作的才好了解,移植。本文从main函数中的rf相关代码入手,顺藤摸瓜理清RF的相关操作和数据处理流程。
1. main函数中的RF相关代码
为什么从main入手,因为这里有初始化等相关代码,基本可以顺藤摸瓜搞明白里面的问题所在。
参考文件:contiki/platform/srf06-cc26xx/contiki-main.c,其中main函数里与射频相关的代码只有两句:
1 | netstack_init(); |
2. set_rf_params函数
这里先看set_rf_params()
因为函数体就定义在main函数中。核心代码:
1 | //获取设备地址,并取出16位小地址。 |
注释中可以看到,这段代码引出了NETSTACK_RADIO.set_value
函数,NETSTACK_RADIO
应该是个包含有函数指针的结构体。
在contiki/core/net/netstack.h文件中找到如下宏定义:
1 |
继续在contiki/platform/srf06-cc26xx/contiki-conf.h中找到相关代码:
1 |
嗯,好了把main函数中的set_value相关代码展开如下:
1 | ieee_mode_driver.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); |
找ieee-mode_driver,在contiki/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c文件中找到该变量。
1 | const struct radio_driver ieee_mode_driver = { |
经过查看set_value,set_object函数,发现这些操作都是在进行一些参数的配置。至此不必继续分析。只是ieee-mode中有些内部函数可以做简单说明:
- static uint8_t rf_is_on(void) 判定RF是否打开,1:处于接收模式,0:其他模式
- static uint8_t transmitting(void) 判断是否处于发送状态,1:发送,0:其他
- static uint8_t get_cca_info(void) 获取CAA信息
- static radio_value_t get_rssi(void) 获取当前信号强度,单位dBm
- static radio_value_t get_tx_power(void) 获取发送功率配置值,单位dBm
- static void set_tx_power(radio_value_t power) 配置发送功率值,单位dBm
- static uint8_t rf_radio_setup() 执行CMD_RADIO_SETUP命令完成参数配置
- static uint8_t rf_cmd_ieee_rx() 配置RF为IEEE802.15.4 RX模式,即:用将cmd_ieee_rx_buf的内容完成RF配置
- static void init_rx_buffers(void) 接收缓冲区初始化为循环链表
- static void init_rf_params(void) 完成cmd_ieee_rx_buf参数设置
- static int rx_on(void) 执行rf_cmd_ieee_rx();打开Rx
- static int rx_off(void) 给RF内核发送CMD_ABORT命令关闭RF
- static uint8_t request(void) LPM_MODULE(cc26xx_rf_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE);
- static void soft_off(void) 给RF内核发送CMD_ABORT命令关闭RF
- static uint8_t soft_on(void) 调用rx_on函数打开RF
- static uint32_t calc_last_packet_timestamp(uint32_t rat_timestamp) 计算时间戳,用于流控
3 netstack_init函数
netstack_init函数位于contiki/core/net/netstack.c中,函数体并注释展开后的代码如下:
1 | void |
其中第一个分析如下,其它几个为协议栈上的函数暂不分析,分析协议栈的时候再另起新篇吧。
4 ieee_mode_driver.init
这里调用的是init函数,函数内容:
1 | /*---------------------------------------------------------------------------*/ |
根据分析,init函数完成了接收缓冲区的清零操作,调用init_rf_params();
函数完成参数初始化,调用on函数打开RF并配置了中断函数入口地址,回调函数定时器配置ctimer_set,最后完成启动进程rf_core_process。
5. rf_core_process
该进程定义于contiki/cpu/cc26xx-cc13xx/rf-core/rf_core.c文件中。函数体:
1 | PROCESS_THREAD(rf_core_process, ev, data) |
该进程做的事情很简单,当PROCESS_EVENT_POLL事件发生的时候,调用NETSTACK_RADIO.read
函数读取接收缓冲区数据,并调用NETSTACK_RDC.input
函数通知上层协议。如果不需要协议层的支持,在这个process中调用自定义函数触发数据处理进程即可。PROCESS_EVENT_POLL事件是执行process_poll函数时触发的。上文分析在init函数中调用的on函数里调用了rf_core_setup_interrupts(poll_mode);
最终执行如下代码:
1 | HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = ENABLED_IRQS_POLL_MODE; |
看来这里只定义了poll_mode模式,还以为在中断里调用了poll呢,那么就搜索吧,执行find
命令:
1 | usercontiki:~/contiki$ find -name "*.c" | xargs grep "process_poll(&rf_core_process)" - |
原来只是没找到,rf-core.c中是在函数void cc26xx_rf_cpe0_isr(void)
中调用process_poll的,而这个函数正是中断函数。
ieee-mode.c中是在pending_packet函数中调用的,遍历接收缓冲区时,当存在缓冲区状态为DATA_ENTRY_STATUS_FINISHED时调用poll。触发数据接收。
prop-mode.c和ieee-mode.c是并列文件,其中的process_poll函数同样是在pending_start函数中调用的。
6. 自定义配置
如果想自定义配置一些参数、功能,需要对RF部分的参数有清除的掌握才行。而这些参数的定义在文件cpu/cc26xx-cc13xx/rf-core/api/ieee-cmd.h中。
6.1 CMD_IEEE_RX命令参数
1 |
|
参数配置函数:
1 | static void |
6.2 CMD_IEEE_TX命令参数
数据结构如下:
1 |
|
7. 下一步
在代码分析中有两个东西直接忽略掉了,下一步需要补上。
- LPM 相关
- ENERGEST相关