NuMaker-IIoT-NUC980
测评之网络 USB 打印机测试
功能模块的硬件介绍
新唐NuMaker-IIoT-NUC980开发板核心搭载了NUC980DR61YC 的ARM9处理器,主频最高300M,并且芯片集成了64 MB的DRAM,外设接口包由物联网常用的数据通讯接口,比如以太网接口、USB 2.0高速接口、RS-485总线、CAN 总线、SPI接口、通用GPIO、硬件加速等等,开发板官方也支持许多操作系统,比如rt-thread、linux、freertos、openwrt等等,资料文档也非常齐全。
功能模块的使用说明
开发板包装非常简约,里面打开了就可以看到主板本体
随便找了根usb micro的数据线,接到开发板的烧写端口(板子上一共有2 个 micro usb 接口,一个用于是连接到 nuc980 usb,可以用于给 nuc980 下载固件,还有一个USB是连接到板子上的 USB 转 TTL,可以用于调试,把NUC980 设置为 USB 启动进入下载模式)
此时电脑出现usb设备发现,但是缺少驱动的提示
安装WinUSB4NuVCOM.exe
打开NuWriterNuWriterReleaseNuWriter.exe 这样就可以对开发板进行各种类型的烧写了
打开RT-Thread Stduio,安装980开发板相对应的开发包,新建工程进行编译
开发板的主板sw1跳线到usb启动,使用nuwiter进行下载
成功运行rt-thread
RT-Thread开发 1、参考linux的usb打印机驱动,移植进rt-thread,增加配置项
可以成功发现识别usb打印机
2、编写tcp server透传数据给打印机 /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2022-03-15 Tuber first version */
#include #include #include #include #include #include #include
#define PRINTER_BUF_SIZE 1024 #define PRINTER_TCP_PORT 9100
rt_err_t printer_tcp_server_one_job() { char *buf; socklen_t sin_size; int server, client, bytes_received; struct sockaddr_in server_addr, client_addr; int ret; int optval; int nrecv = 0; rt_device_t printer_dev; struct timeval timeout = { 0, 1 };
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == -1) { rt_kprintf("Socket error\n"); return -RT_ERROR; }
optval = 1; ret = setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (ret == -1) { rt_kprintf("Setsockopt error\n"); closesocket(server); return -RT_ERROR; }
server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PRINTER_TCP_PORT); server_addr.sin_addr.s_addr = INADDR_ANY; rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
ret = bind(server, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)); if (ret == -1) { rt_kprintf("Unable to bind %d %d\n", ret, rt_get_errno()); closesocket(server); return -RT_ERROR; }
if (listen(server, 5) == -1) { rt_kprintf("Listen error\n"); closesocket(server); return -RT_ERROR; }
rt_kprintf("Prnd Server Waiting for client on port 9100\n");
sin_size = sizeof(struct sockaddr_in); client = accept(server, (struct sockaddr *) &client_addr, &sin_size); if (client < 0) { rt_kprintf("accept connection failed! errno = %d\n", errno); closesocket(server); return -RT_ERROR; }
ret = closesocket(server);
// set timeout ret = setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); if (ret == -1) { closesocket(client); return -RT_ERROR; }
rt_kprintf("I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
//open printer and write data printer_dev = rt_device_find("prn1"); if (!printer_dev) { rt_kprintf("find %s failed!\n", "prn1"); closesocket(client); return -RT_ERROR; }
ret = rt_device_open(printer_dev, RT_DEVICE_OFLAG_RDWR); if (ret != RT_EOK) { rt_kprintf("could not open printer\n"); closesocket(client); return -RT_ERROR; }
buf = rt_malloc(PRINTER_BUF_SIZE); if (buf == NULL) { rt_kprintf("malloc buf failed\n"); closesocket(client); return -RT_ENOMEM; }
while (1) { //read from printer // bytes_received = rt_device_read(printer_dev, 0, buf, PRINTER_BUF_SIZE); // if (bytes_received <= 0 && rt_get_errno() != RT_EOK) // { // break; // } // else if (bytes_received > 0) // { // rt_kprintf("usb recv[%d]\n", bytes_received); // send(client, buf, bytes_received, 0); //write to tcp client // }
//read data from tcp server bytes_received = recv(client, buf, PRINTER_BUF_SIZE, 0); if (bytes_received <= 0 && rt_get_errno() != 18) { break; } else if (bytes_received > 0) { rt_kprintf("client recv[%d]\n", bytes_received); rt_device_write(printer_dev, 0, buf, bytes_received); //write to printer nrecv += bytes_received; } }
rt_kprintf("\n nrecv %d = %d \r\n", nrecv);
rt_free(buf);
rt_device_close(printer_dev);
closesocket(client);
return RT_EOK; }
void printer_tcp_server_task(void *arg) { while (1) { if (printer_tcp_server_one_job() == RT_EOK) { continue; }; rt_thread_mdelay(100); } }
int printer_tcp_server_init(void) { rt_thread_t thread = rt_thread_create("prnd", printer_tcp_server_task, RT_NULL, 2048, 15, 20); if (thread == RT_NULL) { rt_kprintf("start printer tcp server failed\n"); }
rt_thread_startup(thread); return 0; } INIT_APP_EXPORT(printer_tcp_server_init);
功能演示
心得体会 1、芯片的BSP涉及到usb host部分目前遇到bug:某些高速设备进行枚举的时候,会get full configuration descriptor failed,经研究发现当配置描述大于64字节的时候,rtt的usbh协议栈打开的pipo会使用最大每次64字节读一次的方式进行读取,但是bsp则会依据第一次setup传输记录的请求长度进行获取,结果直接返回大于64字节的数据包,导致错误。(https://github.com/RT-Thread/rt-thread/issues/5675)
2、设备驱动框架很好的解耦和用户态和内核态之间的调用,基本和linux的架构差不多,初学者也很方便上手。
3、tcp方面是支持sal层的,可以很方便的移植linux下面的socket程序,api也大体一致,学习成本非常低。
|