本帖最后由 Simon21ic 于 2016-3-22 04:33 编辑
应用举例:app_blink,此模块功能为注册一个命令行界面的命令,可以通过这个命令来控制一个IO口以设置的间隔反转,类似LED的blink效果。
- #include "vsf.h"
- #include "../../vsfos/vsfos.h"
- struct app_blink_t
- {
- struct interface_gpio_pin_t pin;
- uint32_t interval;
- };
首先需要include基本的系统头文件,并且定义blink需要的结构:一个GPIO引脚和一个时间间隔属性。
下面我们先掠过应用代码,说明一下模块的载入和退出代码:
- vsf_err_t app_blink_modexit(struct vsf_module_t *module)
- {
- vsf_bufmgr_free(module->ifs);
- module->ifs = NULL;
- return VSFERR_NONE;
- }
- vsf_err_t app_blink_modinit(struct vsf_module_t *module,
- struct app_hwcfg_t const *cfg)
- {
- struct vsfshell_handler_t *handlers;
- handlers = vsf_bufmgr_malloc(2 * sizeof(struct vsfshell_handler_t));
- if (!handlers) return VSFERR_FAIL;
- memset(handlers, 0, sizeof(*handlers));
- handlers[0] = (struct vsfshell_handler_t){"blink", app_blink};
- vsfshell_register_handlers(&vsfos->shell, handlers);
- module->ifs = handlers;
- return VSFERR_NONE;
- }
模块的载入,就是动态分配模块的内存,并且设置为模块的接口(module->ifs)。
app_blink里,没有专用的模块接口,只是使用了vsfshell_handler_t的数组,动态分配内存并且初始化handlers之后,就调用vsfshell_register_handlers注册blink命令。
当在命令行界面中,运行blink后,就会调用到执行的命令处理函数app_blink:
- static vsf_err_t app_blink(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
- {
- struct vsfshell_handler_param_t *param =
- (struct vsfshell_handler_param_t *)pt->user_data;
- struct vsfsm_pt_t *outpt = param->output_pt;
- struct app_blink_t *blink = (struct app_blink_t *)param->priv;
- vsfsm_pt_begin(pt);
- if (param->argc != 4)
- {
- vsfshell_printf(outpt, "format: %s PORT PIN INTERVAL"VSFSHELL_LINEEND,
- param->argv[0]);
- goto end;
- }
- param->priv = vsf_bufmgr_malloc(sizeof(struct app_blink_t));
- if (NULL == param->priv)
- {
- vsfshell_printf(outpt, "not enough resources"VSFSHELL_LINEEND);
- goto end;
- }
- blink = (struct app_blink_t *)param->priv;
- blink->pin.port = strtoul(param->argv[1], NULL, 0);
- blink->pin.pin = strtoul(param->argv[2], NULL, 0);
- blink->interval = strtoul(param->argv[3], NULL, 0);
- vsfshell_printf(outpt, "blinking on GPIO%d.%d"VSFSHELL_LINEEND,
- blink->pin.port, blink->pin.pin);
- // switch to background thread
- vsfshell_handler_release_io(param);
- vsfhal_gpio_init(blink->pin.port);
- vsfhal_gpio_config_pin(blink->pin.port, blink->pin.pin, GPIO_OUTPP);
- while (1)
- {
- vsfhal_gpio_clear(blink->pin.port, 1 << blink->pin.pin);
- vsfsm_pt_delay(pt, blink->interval);
- vsfhal_gpio_set(blink->pin.port, 1 << blink->pin.pin);
- vsfsm_pt_delay(pt, blink->interval);
- }
- end:
- vsfshell_handler_exit(param);
- vsfsm_pt_end(pt);
- return VSFERR_NONE;
- }
这里就是blink的功能函数了。命令处理函数基本都类似,先得到vsfshell_handler_param_t的参数指针param,并且从这个结构中,得到outpt用于信息输出。param->argc和param->argv就是命令行中输入的参数,参数以空格分开,也可以使用双引号把带空格的字符串作为一个参数。vsfshell_printf就是类似printf的功能,只是第一个参数需要是outpt。检查完毕后,就分配app_blink_t,并且解析参数得到需要控制的IO口以及翻转的毫秒间隔。之后调用vsfshell_handler_release_io后,本任务转入后台运行,命令行界面可以继续输入命令。后台运行的任务就是初始化IO口后,在while(1)中,以设置的毫秒间隔翻转IO口。最后,如果命令处理函数退出的话,要调用一次vsfshell_handler_exit。
在之前的那个任务运行的时候,还可以再次运行blink命令,控制其他的IO口翻转,vsfshell中的命令处理函数,都是动态分配的独立任务,返回会释放资源,不返回则可以一直独立运行。
VSFOS内置的命令都在vsf\example\appldr\module\vsfos\vsfos_busybox.c中,这里有更多的示例代码。
如果模块可以提供接口给其他模块使用,最简单的可以参考vsf\tool\crc中的CRC模块的代码。
如果模块依赖某个硬件接口库,那么需要在使用这个硬件接口之前,判断硬件接口是否可用:
- if (!vsfhal_hcd_if)
- {
- vsfshell_printf(outpt, "hcd interface not available"VSFSHELL_LINEEND);
- goto end;
- }
如果模块依赖其他模块,那么在模块的入口函数里,需要调用vsf_module_get来判断依赖的模块是否存在:
- if (vsf_module_get(VSFIP_MODNAME) != NULL)
- {
- handlers[idx++] = (struct vsfshell_handler_t){"ipconfig", vsfos_busybox_ipconfig, ctx};
- handlers[idx++] = (struct vsfshell_handler_t){"arp", vsfos_busybox_arp, ctx};
- handlers[idx++] = (struct vsfshell_handler_t){"ping", vsfos_busybox_ping, ctx};
- if (vsf_module_get(VSFIP_HTTPD_MODNAME) != NULL)
- {
- handlers[idx++] = (struct vsfshell_handler_t){"httpd", vsfos_busybox_httpd, ctx};
- }
- if (vsf_module_get(VSFIP_DNSC_MODNAME) != NULL)
- {
- handlers[idx++] = (struct vsfshell_handler_t){"dns", vsfos_busybox_dns, ctx};
- vsfip_dnsc_init();
- }
- }
|