本帖最后由 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();
}
}
|