VSF的组件化开发示例

[复制链接]
1760|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对外提供命令行接口

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

  1.         .usbd.rndis.param.CDCACM.CDC.ep_notify        = 1,
  2.         .usbd.rndis.param.CDCACM.CDC.ep_out                = 2,
  3.         .usbd.rndis.param.CDCACM.CDC.ep_in                = 2,
  4.         .usbd.rndis.param.mac.size                                = 6,
  5.         .usbd.rndis.param.mac.addr.s_addr64                = 0x0605040302E0,
  6.         .usbd.rndis.param.cb.param                                = &app,
  7.         .usbd.rndis.param.cb.on_connect                        = app_rndis_on_connect,
  8.         .usbd.cdc.param.CDC.ep_notify                        = 3,
  9.         .usbd.cdc.param.CDC.ep_out                                = 4,
  10.         .usbd.cdc.param.CDC.ep_in                                = 4,
  11.         .usbd.cdc.param.CDC.stream_tx                        = (struct vsf_stream_t *)&app.usbd.cdc.stream_tx,
  12.         .usbd.cdc.param.CDC.stream_rx                        = (struct vsf_stream_t *)&app.usbd.cdc.stream_rx,
  13.         .usbd.cdc.param.line_coding.bitrate                = 115200,
  14.         .usbd.cdc.param.line_coding.stopbittype        = 0,
  15.         .usbd.cdc.param.line_coding.paritytype        = 0,
  16.         .usbd.cdc.param.line_coding.datatype        = 8,
  17.         .usbd.cdc.stream_tx.stream.op                        = &fifostream_op,
  18.         .usbd.cdc.stream_tx.mem.buffer.buffer        = (uint8_t *)&app.usbd.cdc.txbuff,
  19.         .usbd.cdc.stream_tx.mem.buffer.size                = sizeof(app.usbd.cdc.txbuff),
  20.         .usbd.cdc.stream_rx.stream.op                        = &fifostream_op,
  21.         .usbd.cdc.stream_rx.mem.buffer.buffer        = (uint8_t *)&app.usbd.cdc.rxbuff,
  22.         .usbd.cdc.stream_rx.mem.buffer.size                = sizeof(app.usbd.cdc.rxbuff),
  23.         .usbd.msc.param.ep_in                                        = 5,
  24.         .usbd.msc.param.ep_out                                        = 5,
  25.         .usbd.msc.param.scsi_dev                                = &app.mal.scsi_dev,
  26.         .usbd.ifaces[0].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_RNDISControl_class,
  27.         .usbd.ifaces[0].protocol_param                        = &app.usbd.rndis.param,
  28.         .usbd.ifaces[1].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_RNDISData_class,
  29.         .usbd.ifaces[1].protocol_param                        = &app.usbd.rndis.param,
  30.         .usbd.ifaces[2].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_CDCACMControl_class,
  31.         .usbd.ifaces[2].protocol_param                        = &app.usbd.cdc.param,
  32.         .usbd.ifaces[3].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_CDCACMData_class,
  33.         .usbd.ifaces[3].protocol_param                        = &app.usbd.cdc.param,
  34.         .usbd.ifaces[4].class_protocol                        = (struct vsfusbd_class_protocol_t *)&vsfusbd_MSCBOT_class,
  35.         .usbd.ifaces[4].protocol_param                        = &app.usbd.msc.param,
  36.         .usbd.config[0].num_of_ifaces                        = dimof(app.usbd.ifaces),
  37.         .usbd.config[0].iface                                        = app.usbd.ifaces,
  38.         .usbd.device.num_of_configuration                = dimof(app.usbd.config),
  39.         .usbd.device.config                                                = app.usbd.config,
  40.         .usbd.device.desc_filter                                = (struct vsfusbd_desc_filter_t *)USB_descriptors,
  41.         .usbd.device.device_class_iface                        = 0,
  42.         .usbd.device.drv                                                = (struct interface_usbd_t *)&core_interfaces.usbd,
  43.         .usbd.device.int_priority                                = 0,
USB设备端,3种设备的设置,3个设备中CDC和RNDIS对应2个USB的接口,所以一共是5个USB的接口。这里做了这些接口的数据结构的初始化。并且,初始化了USB的config、interface以及描述符、底层驱动等结构。

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

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

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


  1. int main(void)
  2. {
  3.         vsf_enter_critical();
  4.         vsfsm_evtq_init(&app.pendsvq);
  5.         vsfsm_evtq_set(&app.pendsvq);
  6.         vsfhal_core_pendsv_config(app_on_pendsv, &app.pendsvq);

  7.         vsfsm_init(&app.sm);

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

  1. static struct vsfsm_state_t *
  2. app_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
  3. {
  4.         switch (evt)
  5.         {
  6.         case VSFSM_EVT_INIT:
  7.                 vsfhal_core_init(NULL);
  8.                 vsfhal_tickclk_init();
  9.                 vsfhal_tickclk_start();

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

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

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

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

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

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

  29.                 // vsfip init
  30.                 {
  31.                         struct vsfip_buffer_t *buffer;
  32.                         int i;

  33.                         buffer = &app.vsfip.buffer_pool.buffer[0];
  34.                         for (i = 0; i < APPCFG_VSFIP_BUFFER_NUM; i++)
  35.                         {
  36.                                 buffer->buffer = app.vsfip.buffer_mem[i];
  37.                                 buffer++;
  38.                         }
  39.                 }
  40.                 VSFPOOL_INIT(&app.vsfip.buffer_pool, struct vsfip_buffer_t, APPCFG_VSFIP_BUFFER_NUM);
  41.                 VSFPOOL_INIT(&app.vsfip.socket_pool, struct vsfip_socket_t, APPCFG_VSFIP_SOCKET_NUM);
  42.                 VSFPOOL_INIT(&app.vsfip.tcppcb_pool, struct vsfip_tcppcb_t, APPCFG_VSFIP_TCPPCB_NUM);
  43.                 vsfip_init((struct vsfip_mem_op_t *)&app_vsfip_mem_op);

  44.                 // telnet stream innit
  45.                 STREAM_INIT(&app.vsfip.telnetd.stream_rx);
  46.                 STREAM_INIT(&app.vsfip.telnetd.stream_tx);
  47.                 vsfip_telnetd_start(&app.vsfip.telnetd.telnetd);
  48.         
  49.                 // usbd cdc init
  50.                 STREAM_INIT(&app.usbd.cdc.stream_rx);
  51.                 STREAM_INIT(&app.usbd.cdc.stream_tx);

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

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

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

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



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

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

266

主题

2597

帖子

104

粉丝
快速回复 在线客服 返回列表 返回顶部