打印

VSF的组件化开发示例

[复制链接]
1582|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Simon21ic|  楼主 | 2016-6-28 15:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Simon21ic 于 2016-6-28 15:49 编辑

之前的一个关于MCU组件化开发方式的帖子里提到了,这里就用VSF中的一个demo介绍一下组件化的开发方式。


代码在这里:
https://github.com/versaloon/vsf ... example/vsfusbd_eda


主要代码在main.c中
功能如下:
USB设备,实现3个设备,分别为CDC,MSC和RNDIS。
MSC实现的是模拟U盘,RNDIS实现网络连接,并且可以通过telnetd对外提供命令行接口

一些代码的说明:
        .mal.fakefat32.sector_size                                = 512,
        .mal.fakefat32.sector_number                        = 0x00001000,
        .mal.fakefat32.sectors_per_cluster                = 8,
        .mal.fakefat32.volume_id                                = 0x0CA93E47,
        .mal.fakefat32.disk_id                                        = 0x12345678,
        .mal.fakefat32.root[0].memfile.file.name= "ROOT",
        .mal.fakefat32.root[0].memfile.d.child        = (struct vsfile_memfile_t *)fakefat32_root_dir,
这个是虚拟的FAT32文件系统的属性设置,无非就是设置一些扇区大小、数量,每簇扇区数,一些ID,和更目录结构位置。

        .usbd.rndis.param.CDCACM.CDC.ep_notify        = 1,
        .usbd.rndis.param.CDCACM.CDC.ep_out                = 2,
        .usbd.rndis.param.CDCACM.CDC.ep_in                = 2,
        .usbd.rndis.param.mac.size                                = 6,
        .usbd.rndis.param.mac.addr.s_addr64                = 0x0605040302E0,
        .usbd.rndis.param.cb.param                                = &app,
        .usbd.rndis.param.cb.on_connect                        = app_rndis_on_connect,
        .usbd.cdc.param.CDC.ep_notify                        = 3,
        .usbd.cdc.param.CDC.ep_out                                = 4,
        .usbd.cdc.param.CDC.ep_in                                = 4,
        .usbd.cdc.param.CDC.stream_tx                        = (struct vsf_stream_t *)&app.usbd.cdc.stream_tx,
        .usbd.cdc.param.CDC.stream_rx                        = (struct vsf_stream_t *)&app.usbd.cdc.stream_rx,
        .usbd.cdc.param.line_coding.bitrate                = 115200,
        .usbd.cdc.param.line_coding.stopbittype        = 0,
        .usbd.cdc.param.line_coding.paritytype        = 0,
        .usbd.cdc.param.line_coding.datatype        = 8,
        .usbd.cdc.stream_tx.stream.op                        = &fifostream_op,
        .usbd.cdc.stream_tx.mem.buffer.buffer        = (uint8_t *)&app.usbd.cdc.txbuff,
        .usbd.cdc.stream_tx.mem.buffer.size                = sizeof(app.usbd.cdc.txbuff),
        .usbd.cdc.stream_rx.stream.op                        = &fifostream_op,
        .usbd.cdc.stream_rx.mem.buffer.buffer        = (uint8_t *)&app.usbd.cdc.rxbuff,
        .usbd.cdc.stream_rx.mem.buffer.size                = sizeof(app.usbd.cdc.rxbuff),
        .usbd.msc.param.ep_in                                        = 5,
        .usbd.msc.param.ep_out                                        = 5,
        .usbd.msc.param.scsi_dev                                = &app.mal.scsi_dev,
        .usbd.ifaces[0].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_RNDISControl_class,
        .usbd.ifaces[0].protocol_param                        = &app.usbd.rndis.param,
        .usbd.ifaces[1].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_RNDISData_class,
        .usbd.ifaces[1].protocol_param                        = &app.usbd.rndis.param,
        .usbd.ifaces[2].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_CDCACMControl_class,
        .usbd.ifaces[2].protocol_param                        = &app.usbd.cdc.param,
        .usbd.ifaces[3].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_CDCACMData_class,
        .usbd.ifaces[3].protocol_param                        = &app.usbd.cdc.param,
        .usbd.ifaces[4].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_MSCBOT_class,
        .usbd.ifaces[4].protocol_param                        = &app.usbd.msc.param,
        .usbd.config[0].num_of_ifaces                        = dimof(app.usbd.ifaces),
        .usbd.config[0].iface                                        = app.usbd.ifaces,
        .usbd.device.num_of_configuration                = dimof(app.usbd.config),
        .usbd.device.config                                                = app.usbd.config,
        .usbd.device.desc_filter                                = (struct vsfusbd_desc_filter_t *)USB_descriptors,
        .usbd.device.device_class_iface                        = 0,
        .usbd.device.drv                                                = (struct interface_usbd_t *)&core_interfaces.usbd,
        .usbd.device.int_priority                                = 0,
USB设备端,3种设备的设置,3个设备中CDC和RNDIS对应2个USB的接口,所以一共是5个USB的接口。这里做了这些接口的数据结构的初始化。并且,初始化了USB的config、interface以及描述符、底层驱动等结构。

        .usbd.rndis.param.netif.macaddr.size                        = 6,
        .usbd.rndis.param.netif.macaddr.addr.s_addr64        = 0x0E0D0C0B0AE0,
        .usbd.rndis.param.netif.ipaddr.size                                = 4,
        .usbd.rndis.param.netif.ipaddr.addr.s_addr                = 0x01202020,
        .usbd.rndis.param.netif.netmask.size                        = 4,
        .usbd.rndis.param.netif.netmask.addr.s_addr                = 0x00FFFFFF,
        .usbd.rndis.param.netif.gateway.size                        = 4,
        .usbd.rndis.param.netif.gateway.addr.s_addr                = 0x01202020,
RNDIS设备的属性设,这个在简单不过了

        .vsfip.telnetd.telnetd.port                                                = 23,
        .vsfip.telnetd.telnetd.session_num                                = dimof(app.vsfip.telnetd.sessions),
        .vsfip.telnetd.sessions[0].stream_tx                        = (struct vsf_stream_t *)&app.vsfip.telnetd.stream_tx,
        .vsfip.telnetd.sessions[0].stream_rx                        = (struct vsf_stream_t *)&app.vsfip.telnetd.stream_rx,
        .vsfip.telnetd.stream_tx.stream.op                                = &fifostream_op,
        .vsfip.telnetd.stream_tx.mem.buffer.buffer                = (uint8_t *)&app.vsfip.telnetd.txbuff,
        .vsfip.telnetd.stream_tx.mem.buffer.size                = sizeof(app.vsfip.telnetd.txbuff),
        .vsfip.telnetd.stream_rx.stream.op                                = &fifostream_op,
        .vsfip.telnetd.stream_rx.mem.buffer.buffer                = (uint8_t *)&app.vsfip.telnetd.rxbuff,
        .vsfip.telnetd.stream_rx.mem.buffer.size                = sizeof(app.vsfip.telnetd.rxbuff),te
telnetd的属性设置,这里设置了数据收发的流,这个流的另一端就是接到命令行组件的,基于telnetd的命令行界面,几乎不用什么代码,通过这些简单的设置就能够实现

        .shell.echo                                                                = false,
        .shell.stream_tx                                                = (struct vsf_stream_t *)&app.vsfip.telnetd.stream_tx,
        .shell.stream_rx                                                = (struct vsf_stream_t *)&app.vsfip.telnetd.stream_rx,
命令行界面的属性设置,telnet的客户端会自己回显,所以不需要shell的回显功能。另外就是链接shell的输入和输出流到telnetd的流。


int main(void)
{
        vsf_enter_critical();
        vsfsm_evtq_init(&app.pendsvq);
        vsfsm_evtq_set(&app.pendsvq);
        vsfhal_core_pendsv_config(app_on_pendsv, &app.pendsvq);

        vsfsm_init(&app.sm);

        vsf_leave_critical();
        vsfsm_evtq_set(NULL);
        while (1)
        {
                // no thread runs in mainq, just sleep in main loop
                vsfhal_core_sleep(SLEEP_WFI);
        }
}
main函数,这里的while(1)里放的是非实时代码。

static struct vsfsm_state_t *
app_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
        switch (evt)
        {
        case VSFSM_EVT_INIT:
                vsfhal_core_init(NULL);
                vsfhal_tickclk_init();
                vsfhal_tickclk_start();

                VSFPOOL_INIT(&app.vsftimer_pool, struct vsftimer_t, APPCFG_VSFTIMER_NUM);
                vsftimer_init((struct vsftimer_mem_op_t *)&vsftimer_memop);
                vsfhal_tickclk_config_cb(app_tickclk_callback_int, NULL);

                vsf_bufmgr_init(app.bufmgr_buffer, sizeof(app.bufmgr_buffer));

                // fs init: currently supported fs are non-block, so ugly pt code below
                {
                        struct vsfile_t *file;

                        VSFPOOL_INIT(&app.vfsfile_pool, struct vsfile_vfsfile_t, 2);
                        vsfile_init((struct vsfile_memop_t *)&app_vsfile_memop);

                        // create msc_root and httpd_root under root
                        app.caller_pt.state = 0;
                        vsfile_addfile(&app.caller_pt, 0, NULL, "msc_root", VSFILE_ATTR_DIRECTORY);

                        // mount fakefat32 under /msc_root
                        app.caller_pt.state = 0;
                        vsfile_getfile(&app.caller_pt, 0, NULL, "/msc_root", &file);
                        app.caller_pt.state = 0;
                        app.caller_pt.user_data = &app.mal.fakefat32;
                        vsfile_mount(&app.caller_pt, 0, (struct vsfile_fsop_t *)&fakefat32_fs_op, file);
                }

                // vsfip init
                {
                        struct vsfip_buffer_t *buffer;
                        int i;

                        buffer = &app.vsfip.buffer_pool.buffer[0];
                        for (i = 0; i < APPCFG_VSFIP_BUFFER_NUM; i++)
                        {
                                buffer->buffer = app.vsfip.buffer_mem[i];
                                buffer++;
                        }
                }
                VSFPOOL_INIT(&app.vsfip.buffer_pool, struct vsfip_buffer_t, APPCFG_VSFIP_BUFFER_NUM);
                VSFPOOL_INIT(&app.vsfip.socket_pool, struct vsfip_socket_t, APPCFG_VSFIP_SOCKET_NUM);
                VSFPOOL_INIT(&app.vsfip.tcppcb_pool, struct vsfip_tcppcb_t, APPCFG_VSFIP_TCPPCB_NUM);
                vsfip_init((struct vsfip_mem_op_t *)&app_vsfip_mem_op);

                // telnet stream innit
                STREAM_INIT(&app.vsfip.telnetd.stream_rx);
                STREAM_INIT(&app.vsfip.telnetd.stream_tx);
                vsfip_telnetd_start(&app.vsfip.telnetd.telnetd);
        
                // usbd cdc init
                STREAM_INIT(&app.usbd.cdc.stream_rx);
                STREAM_INIT(&app.usbd.cdc.stream_tx);

                vsfscsi_init(&app.mal.scsi_dev);
                vsfusbd_device_init(&app.usbd.device);

#if defined(APPCFG_BUFMGR_SIZE) && (APPCFG_BUFMGR_SIZE > 0)
                vsfshell_init(&app.shell);
#endif

                if (app.usb_pullup.port != IFS_DUMMY_PORT)
                {
                        vsfhal_gpio_init(app.usb_pullup.port);
                        vsfhal_gpio_clear(app.usb_pullup.port, 1 << app.usb_pullup.pin);
                        vsfhal_gpio_config_pin(app.usb_pullup.port,
                                                                                        app.usb_pullup.pin, GPIO_OUTPP);
                }
                app.usbd.device.drv->disconnect();
                vsftimer_create(sm, 200, 1, APP_EVT_USBPU_TO);
                break;
        case APP_EVT_USBPU_TO:
                if (app.usb_pullup.port != IFS_DUMMY_PORT)
                {
                        vsfhal_gpio_set(app.usb_pullup.port,
                                                                                1 << app.usb_pullup.pin);
                }
                app.usbd.device.drv->connect();
                break;
        }
        return NULL;
}
APP初始化,其实也就是调用各个组件的初始化代码,所有组件初始化完成后,关闭USB的上拉,然后建立200ms定时器。
之后200ms到了时候,会发送定时器事件,然后重新使能USB上拉,系统就跑起来了。

void app_rndis_on_connect(void *param)
{
        struct vsfapp_t *app = (struct vsfapp_t *)param;
        vsfip_dhcpd_start(&app->usbd.rndis.param.netif, &app->usbd.rndis.dhcpd);
}
一些回调函数,这里在RNDIS的on_connect响应中,启动dhcpd组件,并应用于usb的rndis的网络接口



其它代码,也基本上都是类似的简单代码,甚至不需要写任何USB端点初始化的代码(USB组件具备自动初始化各个端点的功能,用户只需要输入正确的描述符即可),系统就可以运行起来了。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:www.versaloon.com --- under construction

266

主题

2597

帖子

104

粉丝