diff --git a/docs/doc/framework/lian.md b/docs/doc/framework/lian.md index b585025..91c352b 100644 --- a/docs/doc/framework/lian.md +++ b/docs/doc/framework/lian.md @@ -3,9 +3,9 @@ 多数嵌入式操作系统,应具备传输多种网络协议数据的能力,但是网络协议种类繁多,为每种协议都开放单独的接口,势必会增加操作系统使用者的开发负担,亦不利于嵌入式操作系统的普及与推广。 XiUOS网络框架采用以网络适配器为中心的抽象方式,发送与接收数据时,只需要像Linux socket网络通信一样,仅关注发送与接收的数据,而不用把重点放在所使用的具体协议上。这种抽象方式有效屏蔽了种类繁多的网络协议细节,对外提供统一的网络接口,简化了基于嵌入式操作系统的网络开发。网络框架对各类协议的网络设备进行了抽象: -* 一个网络协议设备,被抽象为一个xs_Adapter +* 一个网络协议设备,被抽象为一个Adapter -xs_Adapter可以被设计为采用类似面向对象的方法,针对不同的网络协议,扩展其数据成员与接口,从而为种类繁多的网络协议实现统一的管理架构。在网络应用开发的过程中,只需要使用对应网络协议的xs_Adapter实例,而无需关心网络协议的硬件细节,从而实现了网络数据收发功能与底层硬件的解耦。 +Adapter可以被设计为采用类似面向对象的方法,针对不同的网络协议,扩展其数据成员与接口,从而为种类繁多的网络协议实现统一的管理架构。在网络应用开发的过程中,只需要使用对应网络协议的Adapter实例,而无需关心网络协议的硬件细节,从而实现了网络数据收发功能与底层硬件的解耦。
@@ -15,156 +15,288 @@ xs_Adapter可以被设计为采用类似面向对象的方法,针对不同的 ## 1. XiUOS网络框架关键数据结构定义和解析 -* struct xs_Adapter结构 +* struct Adapter结构 + ```c -struct xs_Adapter +struct Adapter { -    const char name[XS_NAME_MAX];  /* name of the adapter instance */ -    enum xs_AdapterType type;       /* type of adapter, such as lora adapter */ -    xs_AdapterInfo info;    /* adapter model info, such as vendor name and model name */ -    struct xs_AdapterOps ops;  /* socket-like APIs for data transferring */ -    struct xs_AdapterInterface interface;  /* physical interface for transferring data */ -    struct XS_DOUBLE_LINKLIST_NODE link;  /* link list node */ + char name[NAME_NUM_MAX]; + int fd; + + int product_info_flag; + struct AdapterProductInfo *info; + ATAgentType agent; + + struct Socket socket; + + int net_role_id; + enum NetProtocolType net_protocol; + enum NetRoleType net_role; + enum AdapterStatus adapter_status; + + char buffer[ADAPTER_BUFFSIZE]; + + void *done; + void *adapter_param; + + struct DoublelistNode link; }; ``` -name成员是一个可读的名字,用于唯一标识一个xs_Adapter结构。type成员表示该xs_Adapter所使用的网络协议,用一个枚举变量表示: +name成员是一个可读的名字,用于唯一标识一个Adapter结构。fd成员是一个标识符编号,用于唯一标识此网络设备所用串口。product_info_flag用于根据型号给设备进行分类。AdapterProductInfo结构体包含该网络设备的一些信息,如厂家名vendor与型号product_model。 ```c -enum xs_AdapterType { -    XS_ADAPTER_LORA = 0,  /* Lora */ -    XS_ADAPTER_4G ,       /* 4G */ -    /* ...... */ -    XS_ADAPTER_WIFI ,     /* Wifi */ +struct AdapterProductInfo +{ + uint32_t functions; + char vendor_name[NAME_NUM_MAX]; + char model_name[NAME_NUM_MAX]; + uint32_t work_mode; + + void *model_done; }; ``` -info成员包含此网络设备的基础信息,如厂家名vendor与型号product_model。 +其中model_done成员包含统一的API,用于对特定网络适配器进行实际的数据读写。model_done成员有IpProtocolDone/PrivProtocolDone两套接口,根据网络适配器种类而定,两套接口都具有的基础API如下。在使用一个网络适配器前后需要打开(open)/关闭(close)该网络适配器,打开适配器后需要配置(ioctl)其属性,setup和setdown用于使能/关闭网络传输功能,setaddr/setdns/setdhcp/ping/netstat为一些基础打网络调试接口,send/recv分别用于从网络适配器接收数据与向网络适配器发送数据,connect/disconnect用于建立/断开一个网络连接。 ```c -struct xs_AdapterInfo{ -    const char *vendor; -    const char *product_model; +struct IpProtocolDone/PrivProtocolDone +{ + int (*open)(struct Adapter *adapter); + int (*close)(struct Adapter *adapter); + int (*ioctl)(struct Adapter *adapter, int cmd, void *args); + int (*setup)(struct Adapter *adapter); + int (*setdown)(struct Adapter *adapter); + int (*setaddr)(struct Adapter *adapter, const char *ip, const char *gateway, const char *netmask); + int (*setdns)(struct Adapter *adapter, const char *dns_addr, uint8 dns_count); + int (*setdhcp)(struct Adapter *adapter, int enable); + int (*ping)(struct Adapter *adapter, const char *destination); + int (*netstat)(struct Adapter *adapter); + int (*connect)(struct Adapter *adapter, enum NetRoleType net_role, const char *ip, const char *port, enum IpType ip_type); + int (*send)(struct Adapter *adapter, const void *buf, size_t len); + int (*recv)(struct Adapter *adapter, void *buf, size_t len); + int (*disconnect)(struct Adapter *adapter); }; ``` -ops成员包含统一的、类似文件系统的API,用于对网络适配器进行实际的数据读写。在使用一个网络适配器前后需要打开(open)/关闭(close)该网络适配器,send、receive分别用于从网络适配器接收数据与向网络适配器发送数据,ioctl用于配置Adapter属性: +agent结构体是串口收发数据结构,用于辅助串口通信。网络设备通过agent通信,具有两个缓冲区分别用于向CPU接收和发送信息。 ```c -struct xs_AdapterOps { -    int (*open)(struct xs_Adapter *sadapter); -    void (*close)(struct xs_Adapter *sadapter); -    int (*join)(struct xs_Adapter *sadapter,int net_type, int dev_type, int net_number); -    int (*send)(struct xs_Adapter *sadapter, const char* data, int len, int des_dev, int time_out, bool block, int delay); -    int (*receive)(struct xs_Adapter *sadapter, char* rev_buffer, int buffer_len, int time_out, bool block); -    int (*ioctl)(struct xs_Adapter *sadapter, int cmd, void *arg); +struct ATAgent +{ + char agent_name[64]; + int fd; + + char *maintain_buffer; + uint32 maintain_len; + uint32 maintain_max; + + int lock; + + ATReplyType reply; + char reply_lr_end; + char reply_end_last_char; + char reply_end_char; + uint32 reply_char_num; + int rsp_sem; + + pthread_t at_handler; + + #define ENTM_RECV_MAX 256 + char entm_recv_buf[ENTM_RECV_MAX]; + uint32 entm_recv_len; + enum ReceiveMode receive_mode; + int entm_rx_notice; }; +typedef struct ATAgent *ATAgentType; ``` -其中需要注意的是,join接口的所使用的net_type和dev_type参数,分别来自枚举: +socket成员用于实现上层通信协议。建立多个安全稳定的tcp/udp套接字通信。 ```c -enum xs_net_type{ -    XS_CENTRALIZATION = 0, -    XS_ADHOC, -}; - -enum xs_dev_type{ -    XS_CLIENT = 0, -    XS_GATEWAY, +struct Socket +{ + uint8_t type; /* socket type:DGRAM->UDP,STREAM->TCP */ + uint8_t protocal; /* udp or tcp */ + unsigned short listen_port; /* 0-65535 */ + uint8_t socket_id; + uint8_t recv_control; + uint8_t af_type; /* IPv4 or IPv6 */ + char *src_ip_addr; /* source ip address */ + char *dst_ip_addr; /* destination IP address */ }; ``` -net_type代表的含义是,使用传统的中心化网络或者自组网络。dev_type代表的含义是,此设备是普通设备或者网关设备。 -最后,在系统中每种网络协议的xs_Adapter被分别组织成不同双链表,如Lora的xs_Adapter链表、4G的xs_Adapter链表等,使用的链表节点即为link成员。 +net_protocol成员用于指示此网络设备支持的协议,IP_PROTOCOL类型表示支持IP层相关协议,PRIVATE_PROTOCOL表示此网络设备支持额外的协议。net_role_id用于辅助net_protocol,用于标识区分该协议下支持的多个设备。 + +```c +enum NetProtocolType +{ + PRIVATE_PROTOCOL = 1, + IP_PROTOCOL, + PROTOCOL_NONE, +}; +``` + +net_role成员用于设置此网络设备通信过程中的模式和角色,包括主、从、路由、终端等。 + +```c +enum NetRoleType +{ + CLIENT = 1, + SERVER, + MASTER, + SLAVE, + COORDINATOR, + ROUTER, + END_DEVICE, + ROLE_NONE, +}; +``` + +adapter_status成员用来指示网络设备注册状态。buffer/done/adapter_param成员均为预留给adapter使用的数据缓冲区和用户数据接口。 + +```c +enum AdapterStatus +{ + REGISTERED = 1, + UNREGISTERED, + INSTALL, + UNINSTALL, +}; +``` + +最后,在系统中每种网络协议的Adapter被分别组织成不同双链表,如Lora的Adapter链表、4G的Adapter链表等,使用的链表节点即为link成员。 ## 2. XiUOS网络框架驱动开发 -以Lora网络适配器为例。网络框架针对每个具体的网络适配器将xs_Adapter进行扩充,采用类似面向对象的手段添加其他必要成员,如: +以WiFi网络适配器为例。网络框架针对每个具体的网络适配器填充Adapter的数据成员项,如协议类型、设备名称、厂商信息等。数据成员填充完后,将其注册。 ```c -struct xs_AdapterLora { -    struct xs_Adapter parent; /* inherit from xs_Adapter */ -    const char *deve_ui;  /* Lora specific value */ -    const char *app_key;  /* Lora specific value */ -}; -``` +int AdapterWifiRegister(struct Adapter *adapter); -实现xs_AdapterOps中的数据通信API,具体实现细节取决于所使用网络协议,无法实现的API可以置为NULL: +#define ADAPTER_WIFI_NAME "wifi" -```c -struct xs_AdapterOps lora_example_ops = { -    .open = lora_example_open; -    .close = lora_example_close; -    .send = lora_example_send; -    .receive = NULL; -    .ioctl = lora_example_ioctl; -}; -``` - -填充xs_AdapterLora,并将其注册。 - -```c -int xs_AdapterRegister(struct xs_Adapter *sadapter); - -extern struct xs_AdapterOps lora_example_ops; -/* declare xs_AdapterLora */ -struct xs_AdapterLora lora_example_adapter; - -void register_lora_adapter() +static int AdapterWifiRegister(struct Adapter *adapter) { -    /* initialize and register the xs_Adapter object */ -    memset(&lora_example_adapter, 0, sizeof(lora_example_adapter)); -    lora_example_adapter.parent.name = "adapter1"; -    lora_example_adapter.parent.type = XS_ADAPTER_LORA; -    lora_example_adapter.parent.info.vendor = "xxx"; -    lora_example_adapter.parent.info.product_model = "yyy"; -    lora_example_adapter.parent.ops = &lora_example_ops; -    lora_example_adapter.parent.interface.bus_device = xs_DeviceFind("uart1"); -    lora_example_adapter.deve_ui = "mmm"; -    lora_example_adapter.app_key = "nnn"; -    xs_AdapterRegister(&lora_example_adapter); + int ret = 0; + + strncpy(adapter->name, ADAPTER_WIFI_NAME, 32); + + adapter->net_protocol = IP_PROTOCOL; + adapter->adapter_status = UNREGISTERED; + + ret = AdapterDeviceRegister(adapter); + if (ret < 0) { + printf("AdapterWifi register error\n"); + return -1; + } + + return ret; +} +``` + +WiFi设备协议类型为IP_PROTOCOL,故使用IpProtocolDone接口注册到model_done。实现model_done中的数据通信API,具体实现细节取决于所使用网络协议,无法实现的API可以置为NULL: + +```c +static const struct IpProtocolDone hfa21_done = +{ + .open = Hfa21Open, + .close = Hfa21Close, + .ioctl = Hfa21Ioctl, + .setup = Hfa21SetUp, + .setdown = Hfa21SetDown, + .setaddr = Hfa21SetAddr, + .setdns = NULL, + .setdhcp = NULL, + .ping = Hfa21Ping, + .netstat = Hfa21Netstat, + .connect = Hfa21Connect, + .send = Hfa21Send, + .recv = Hfa21Receive, + .disconnect = NULL, +}; +``` + +将hfa21_done接口注册到model_done: + +```c +AdapterProductInfoType Hfa21WifiAttach(struct Adapter *adapter) +{ + struct AdapterProductInfo *product_info = PrivMalloc(sizeof(struct AdapterProductInfo)); + if (!product_info) { + printf("Hfa21WifiAttach Attach malloc product_info error\n"); + PrivFree(product_info); + return NULL; + } + + strcpy(product_info->model_name, ADAPTER_WIFI_HFA21); + + product_info->model_done = (void *)&hfa21_wifi_done; + + return product_info; } ``` ## 3. XiUOS网络框架的使用实例 -网络应用开发者使用网络框架提供的API操作网络适配器,网络适配器API可以分为通用API与协议特有API。通用API用于网络适配器的获取、打开与关闭,协议特有API用于特定协议的数据采样。以Lora网络适配器为例: +网络应用开发者根据自己的需求,将网络框架提供的API加上一些逻辑,封装为一套应用层API,使用该套API操作网络适配器,应用层API可以分为通用API与协议特有API。通用API用于网络适配器的打开、关闭、参数配置以及网络测试功能,协议特有API用于特定协议的配置以及数据收发。以Wifi网络适配器为例: ```c -/* generic API: find a adapter instance by its name */ -struct xs_Adapter *xs_AdapterFind(const char *name); - /* generic API: open/close a adapter instance */ -int xs_AdapterOpen(struct xs_Adapter *adapter); -void xs_AdapterClose(struct xs_Adapter *adapter); -/* Lora API: get current Lora adapter reading */ -uint32_t xs_AdapterReceive(struct xs_Adapter *adapter, char* rev_buffer, int buffer_len,int time_out, bool block); +int AdapterDeviceOpen(struct Adapter *adapter); +int AdapterDeviceClose(struct Adapter *adapter); + +/* generic API: configure a adapter instance */ +int AdapterDeviceControl(struct Adapter *adapter, int cmd, void *args); + +/* generic API: network interface */ +int AdapterDeviceSetAddr(struct Adapter *adapter, const char *ip, const char *gateway, const char *netmask); +int AdapterDeviceSetDns(struct Adapter *adapter, const char *dns_addr, uint8 dns_count); +int AdapterDeviceSetDhcp(struct Adapter *adapter, int enable); +int AdapterDevicePing(struct Adapter *adapter, const char *destination); +int AdapterDeviceNetstat(struct Adapter *adapter); + +/* Wifi API: get current Wifi adapter reading and receiving */ +ssize_t AdapterDeviceSend(struct Adapter *adapter, const void *src, size_t len); +ssize_t AdapterDeviceRecv(struct Adapter *adapter, void *dst, size_t len); ``` -在获取数据前,需要先获取并打开要使用的网络适配器;网络适配器打开后可以随时对网络适配器数据进行读取;使用完毕后,须关闭网络适配器。完整的使用过程示例如下: +在获取数据前,需要先打开要使用的网络适配器;网络适配器打开后对其进行相关参数如波特率等的配置,接着配置相关网络参数后,对网络适配器数据可以随时进行读取;使用完毕后,须关闭网络适配器。完整的使用过程示例如下: ```c -#define BUFFER_MAX 512 -int main(int argc, char *argv[]) +int AdapterWifiTest(void) { -int ret; -    char rev_buffer[BUFFER_MAX]; + char cmd[64]; + int baud_rate = BAUD_RATE_57600; -    struct xs_Adapter *adapter; -    struct xs_AdapterLora *lora_adapter; + struct Adapter* adapter = AdapterDeviceFindByName(ADAPTER_WIFI_NAME); -    /* get the Lora adapter instance */ -    adapter = xs_AdapterFind("lora_1"); -    XS_ASSERT(adapter->type == XS_ADAPTER_LORA); -    /* open the Lora adapter instance */ -    lora_adapter = (struct xs_AdapterLora *)adapter; -    ret = xs_AdapterOpen(adapter); -    XS_ASSERT(ret == XS_EOK); -   -    xs_AdapterReceive(adapter, rev_buffer, BUFFER_MAX, 0, true); -    xs_kprintf("Data read from lora_adapter is %s \n", rev_buffer); -    xs_AdapterClose(adapter); -    return 0; + AdapterDeviceOpen(adapter); + AdapterDeviceControl(adapter, OPE_INT, &baud_rate); + + AdapterDeviceSetUp(adapter); + AdapterDeviceSetAddr(adapter, "192.168.66.253", "255.255.255.0", "192.168.66.1"); + AdapterDevicePing(adapter, "36.152.44.95"); + AdapterDeviceNetstat(adapter); + + const char *ip = "192.168.66.211"; + const char *port = "12345"; + enum NetRoleType net_role = CLIENT; + enum IpType ip_type = IPV4; + AdapterDeviceConnect(adapter, net_role, ip, port, ip_type); + + const char *wifi_msg = "LiuKai Test"; + int len = strlen(wifi_msg); + for(int i = 0;i < 10; ++i) { + AdapterDeviceSend(adapter, wifi_msg, len); + PrivTaskDelay(4000); + } + + char wifi_recv_msg[128]; + while (1) { + AdapterDeviceRecv(adapter, wifi_recv_msg, 128); + } + } ```