看了下zephyr所支持的开发板,有一个TI公司的,CC3200。低功耗wifi芯片,淘宝了一下,200出头,可以接受。当即买了一块,先弄TCP/IP再学6LowPan会好些。现在等开发板到货。
开发环境已经装好,ubuntu下开发,请参考大牛写的:
http://iot-fans.xyz/zephyr/doc/v1.6.0/getting_started/installation_linux.html
最好对照原文:
https://www.zephyrproject.org/doc/getting_started/installation_linux.html
开发板没到,先搞些基础工作,从简单的入手吧。先分析几个基础数据结构。首先就是单向链表slist。
slist.h文件存在于zephyr / include / misc文件夹下,全部使用内联函数,无相应的.c文件。slist为单向非循环链表,具备头指针和尾指针,下面说说它的常用函数:
static
inline
void sys_slist_init(sys_slist_t *list)
初始化链表,其实就是将头指针和尾指针置空。
static
inline
bool sys_slist_is_empty(sys_slist_t *list)
判断list是否为空链表,返回true为空,false为非空。
static
inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
返回list的头节点。
static
inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
返回list的尾节点
static
inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
返回node的下一个节点,注意,必须已确定node不为空。此函数是不检查node是否为空的,所以速度会快些
static
inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node)
和上一个函数功能相同,在无法确定node是否为空的情况下使用。如果node为空,则返回NULL。
static
inline
void sys_slist_append(sys_slist_t *list,
sys_snode_t *node)
将节点node追加至list链表的尾部
static
inline
void sys_slist_prepend(sys_slist_t *list,
sys_snode_t *node)
将节点node添加至list链表的头部,成为头节点。链表有这样的功能估计是为将来成为栈或队列作准备的。
static
inline
void sys_slist_append_list(sys_slist_t *list,
void *head,
void *tail)
{
if (!list->tail)
{
list->head = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
else
{
list->tail->next = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
}
参数list:源链表
参数head:要追加链表的头节点
参数tail:要追加链表的尾节点
函数功能:将头节点为head、尾节点为tail的链表追加到源链表list后面。
static
inline
void sys_slist_merge_slist(sys_slist_t *list,
sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append->head,
list_to_append->tail);
sys_slist_init(list);
}
将链表list和链表list_to_append合并,list_to_append追加至list尾部。添加完后,list被清空。
这里有些看不懂,故将源码放上。list被清空,新链表就找不到了,因为list_to_append指向的还是追加前的链表,追加后的链表再也找不到。除非原本另有指针指向list的头尾节点。个人感觉,被清空的应该是list_to_append。
static
inline
void sys_slist_insert(sys_slist_t *list,
sys_snode_t *prev,
sys_snode_t *node)
在链表list的prev节点后插入新节点node。
static
inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list)
删除链表的头节点,必须确定list不为空链表才能使用此函数。
static
inline sys_snode_t *sys_slist_get(sys_slist_t *list)
跟上个函数一样,删除链表头节点,list可以为空链表。
static
inline
void sys_slist_remove(sys_slist_t *list,
sys_snode_t *prev_node,
sys_snode_t *node)
在链表list中删除节点node。必须给出node的上一个节点prev_node作为参数。如果不想给出上一个节点,请使用下面这个函数。
static
inline
void sys_slist_find_and_remove(sys_slist_t *list,
sys_snode_t *node)
在链表list中删除节点node。
下面是几个遍历用的宏:
#ifndef __SLIST_H__
#define __SLIST_H__
/** * @brief 遍历整张链表 * Note: 循环不安全,因此__sn不能被,简而言之就是不能用于删除操作。 * * 用户必须自行添加大括号以指定循环体 * * SYS_SLIST_FOR_EACH_NODE(l, n) { * <user code> * } * * @param __sl 指向sys_slist_t类型的指针,表示将进行迭代的链表 * @param __sn sys_snode_t类型指针,用于遍历链表中的每个节点 */
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
for (__sn = sys_slist_peek_head(__sl); __sn; \
__sn = sys_slist_peek_next(__sn))
/** * @brief 从链表指定节点处遍历到结尾 * Note: 循环不安全,因此__sn不能被删除,简而言之就是不能用于删除操作。 * * 用户自行加大括号 * * SYS_SLIST_ITERATE_FROM_NODE(l, n) { * <user code> * } * * 和SYS_SLIST_FOR_EACH_NODE()一样, 但如__sn指定为链表中的一个节点, * 则遍历从__sn的下一个节点开始。如果__sn为空,则从头节点开始遍历。 * * @param __sl 指向sys_slist_t类型的指针,表示将进行迭代的链 * @param __sn sys_snode_t类型指针,指定的开始节点,为空则从头开始 */
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \
: sys_slist_peek_head(__sl); \
__sn; \
__sn = sys_slist_peek_next(__sn))
/** * @brief 安全地遍历整个链表 * Note: __sn可被删除, 它不会打断循环. * * 用户必须自行添加大括号: * * SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) { * <user code> * } * * @param __sl sys_slist_t类型指针,指向被遍历链表 * @param __sn sys_snode_t类型指针,依次等于链表中的每个节点 * @param __sns sys_snode_t类型指针,用于安全遍历 */
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
for (__sn = sys_slist_peek_head(__sl), \
__sns = sys_slist_peek_next(__sn); \
__sn; __sn = __sns, \
__sns = sys_slist_peek_next(__sn))
上面两个遍历一般用不到,只是为下两个遍历提供服务
/** * @brief 提供根据容器建立的链表的遍历原语 * Note: 此循环不安全,因此不能被删除 * * 用户必须自行加大括号: * * SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) { * <user code> * } * * @param __sl sys_slist_t指针,将遍历此链表 * @param __cn 用于遍历链表元素的临时指针变量,为容器类型 * @param __n sys_node_t在容器结构体中的类型名称 */
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \
__cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
下面这个是安全遍历
/** * @brief 提供根据容器建立的链表的安全遍历原语 * Note: __cn 可以被删除,不会打断循环. * * User 用户必须自行添加大括号: * * SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) { * <user code> * } * * @param __sl sys_slist_t类型指针,将遍历此链表 * @param __cn 用于遍历链表元素的临时指针变量,为容器类型 * @param __cns 用于安全遍历的临时变量,和__cn同类型 * @param __n sys_node_t在容器结构体中的类型名称 */
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
__cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \
__cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
读完代码写程序,这时才发现使用CCS进行TI-RTOS是一件多么幸福的事情,用VS开发C#那简直是在天堂了。开发环境没搭太好,qemu又不懂如何关闭,总之各种折磨。总算写完,看来得花时间找找有什么办法心善下开发环境。
先上代码:
[cpp]
view plain
copy
#include <zephyr.h> #include <misc/printk.h> #include <misc/slist.h> static sys_slist_t list; struct container_node { sys_snode_t node; int id; }; void PrintList(sys_slist_t *list) { struct container_node *container; printk("print list node:\n"); SYS_SLIST_FOR_EACH_CONTAINER(list, container, node) { printk("node%d ", container->id); } printk("\n\n"); } void main(void) { struct container_node node1, node2, node3, node4, node5; node1.id = 1; node2.id = 2; node3.id = 3; node4.id = 4; node5.id = 5; sys_slist_init(&list); sys_slist_append(&list, &node1.node); sys_slist_append(&list, &node2.node); sys_slist_append(&list, &node3.node); sys_slist_append(&list, &node4.node); sys_slist_append(&list, &node5.node); PrintList(&list); printk("move node3 to head\n"); sys_slist_find_and_remove(&list, &node3.node); sys_slist_prepend(&list, &node3.node); PrintList(&list); printk("switch node4 and node2\n"); sys_slist_find_and_remove(&list, &node4.node); sys_slist_insert(&list, &node1.node, &node4.node); PrintList(&list); }
先记下环境变量设置命令,方便以后回来对照:
export ZEPHYR_GCC_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk
cd zephyr-project/
source zephyr-env.sh
由于关闭不了qemu,每编译一次都要打一轮。之后再解决这个问题
(
经tidyjiang大神指点,已解决qemu关闭问题:先按Ctrl+a,再按x退出。不要忘记他的博客,上篇日志提到过:
http://blog.csdn.net/tidyjiang/article/details/51622186)
然后通过以下命令在qemu上执行程序:
make BOARD=qemu_x86 qemu
所有命令及运行结果如下图所示:
本例演示了slist的添加、删除、插入及遍历操作。要使用链表,必须在链表所存储元素所使用结构体中添加一个sys_snode_t类型成员,这个结构体被为容器(container)。这样使用比较麻烦,在这点上contiki中的链表比zephyr更先进、好用些。另外我始终认为链表如果进出操作太多,会产生大量零碎空间,应当慎用。C#中基本没见哪个地方使用链表,有使用的地方基本都用静态链表代替。
引用:
http://blog.csdn.net/abatei/article/details/66970546