概述
stm32 ECM 驱动ME909成功了,先庆祝一下
TFQ 先说一下参考资料:
1. 网上广为流传的RNDIS,最早是国外了lrndis-master.zip,我下载下来看了下,感觉很复杂,关键是不知道干什么用的,只是弄明白了这个使用的是USB DEVICE, 好像模拟了一个网卡, 以这个为祖师,在这个基础上做出RNDIS的就很多了,比如RTTHREAD也把RNDIS也在RTT基础上发布了一版本, 安富莱的硬汉也搞起来了, 最初的lrndis-master.zip是裸机运行的。说明这个RNDIS还是很有吸引人的。
2. USB协议相关 USB2.0协议英文原版(全).pdf
基于USB+CDC的虚拟以太网接口研究与设计.pdf
USB CDC相关的资料
3,linux 原码中有关ECM CDC的c 文件
只看协议会感觉很空洞,如果只看代码的会使人眩晕,只有协议与代码结合着看,才会使人清晰,
调试过程中遇到空难无数,最终一个一个解决了,
理论指导,所有的工作都是在理念的指导下完成的,下面这个图给我提供了最直接的理论指导:
上面详细说明了NDIS的过程,首先PC(STM32) 给4G模块发送拨号命令 echo "AT^NDISDUP=1,1">/dev/ttyUSB0, 也就是发起数据业务请求,4G模块收到请求后,会向无线网络请求IP地址与DNS,
然后PC(STM32)通过DHCP 客户端请求IP地址,这个过程,4G模块并没有与无线网络交互,完全是在PC与4G模块之间进行的,PC请求到的IP地址也是“发起业务”阶段4G模块向无线网络申请的IP地址。
下面的ARP其实就是PING程序吧,我的理解,但实际上我PING不通DHCP获得的IP地址。有时候却可以PING通网关。
数据传输阶段,其实4G模块大部分时候工作在这个阶段,这个阶段,4G模块完全就是起到一个以太网数据帧中继的作用,PC(STM32)把以太网数据发送给4G模块,4G模块再把以太网数据原封不动发到无线网络上; 同样无线网络上的数据4G模块也会原封不动 的转发给PC(STM32),
最后就是释放业务,这个我没有试。echo "AT^NDISDUP=1,0">/dev/ttyUSB0, 应该是这个命令吧, 由PC发起请求中止数据业务。
理论上是这样的,我调试的过程中,实际也是这样的,尤其是DHCP阶段,因为在LINUX上调试4G模块时,根本就不会去调用DHCP(可能linux后台会自动的调用DHCP来获得IP),但在STM32上时,必须人为的调用DHCP来获得IP地址,其实获得的这个IP地址就是第一阶段4G模块向无线网络申请的IP地址。
移植过程中遇到的几个难点。
1,USB协议栈 匹配
2. MAC地址的获得。
MAC地址的获得真是一点一点的啃出来的,因为无从参考,在RNDDIS中,MAC地址是设置死的,而4G模块无论是ME909 还是EC20这些正规厂家生产的4G模块,它的MAC地址应该是全球唯一的吧,不应该随便设置,即使可以随便设置,但ME909内部却存在真实的MAC地址,如果2都不一样,数据会发出去吗?我表示怀疑。因此必须把MAC地址给弄出来。
于是我参考linux内核中mac地址的获得办法。在cdc_ether.c中是有获得MAC地址的代码的。
int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status;
struct cdc_state *info = (void *) &dev->data;
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
< sizeof(struct cdc_state)));
status = usbnet_generic_cdc_bind(dev, intf);
if (status < 0)
return status;
status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress);
if (status < 0) {
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver_of(intf), info->data);
return status;
}
return 0;
}
这名程序usbnet_get_ethernet_addr(dev, info->ether->iMACAddress);获得MAC地址。
int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
{
int tmp = -1, ret;
unsigned char buf [13];
ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf);
if (ret == 12)
tmp = hex2bin(dev->net->dev_addr, buf, 6);
if (tmp < 0) {
dev_dbg(&dev->udev->dev,
"bad MAC string %d fetch, %dn", iMACAddress, tmp);
if (ret >= 0)
ret = -EINVAL;
return ret;
}
return 0;
}
程序很清楚的的说明了,MAC地址是通过string descriptor 获得的, 但是MAC地址的 string descriptor index是多少呢,还得把程序再往前翻,
string descriptor index在这个结构体中,
/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
struct usb_cdc_ether_desc {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 iMACAddress;
__le32 bmEthernetStatistics;
__le16 wMaxSegmentSize;
__le16 wNumberMCFilters;
__u8 bNumberPowerFilters;
} __attribute__ ((packed));
这个描述符之前没有听说过,应该是不常用, 常用的是的设备描述符, 配置描述符,接口描述符,端点描述符, Functional Descriptor这是什么鬼, 功能描述符? 暂时就称作功能描述符吧,但是它存在哪呢?
/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */这句话说明了这个结构体在CDC的协议中是有定义的。
CS_INTERFACE 协议中有定义为0X24,
Ethernet Networking functional descriptor也有定义为0X0F
在CDC120.PDF 有定义
虽然找到了MAC地址的 string descriptor index的位置,但是还不确定在哪能获得到index,这个地方走了很多弯路,其实也是因为自己对USB协议认识不彻底的原因,我想当然的就认为这个struct usb_cdc_ether_desc是通过 GET INTERFACE DESCRIPTOR来获得的,并在程序中付诸实施了,但一个偶然的发现,我单步调试的过程中发现在接口描述符的后面,端点描述符的前面,还有几个未知描述符,突然发现这几个描述符的类型刚好就是0X24,灵感来了, MAC地址的 string descriptor index 就这么找到了。 MAC 字符串描述符也就获得了。
注: ME909或者说是4G模块的MAC地址应该不重要, 本来就是ppp模式点对点通讯方式, 要MAC地址干什么?
最后
以上就是无限毛衣为你收集整理的stm32 ECM 驱动ME909 成功的全部内容,希望文章能够帮你解决stm32 ECM 驱动ME909 成功所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复