更新联框架文档描述

This commit is contained in:
Liu_Kai 2021-11-25 12:30:10 +04:30
parent 32a2e231da
commit c83dcfecbf
1 changed files with 237 additions and 105 deletions

View File

@ -3,9 +3,9 @@
多数嵌入式操作系统,应具备传输多种网络协议数据的能力,但是网络协议种类繁多,为每种协议都开放单独的接口,势必会增加操作系统使用者的开发负担,亦不利于嵌入式操作系统的普及与推广。 多数嵌入式操作系统,应具备传输多种网络协议数据的能力,但是网络协议种类繁多,为每种协议都开放单独的接口,势必会增加操作系统使用者的开发负担,亦不利于嵌入式操作系统的普及与推广。
XiUOS网络框架采用以网络适配器为中心的抽象方式发送与接收数据时只需要像Linux socket网络通信一样仅关注发送与接收的数据而不用把重点放在所使用的具体协议上。这种抽象方式有效屏蔽了种类繁多的网络协议细节对外提供统一的网络接口简化了基于嵌入式操作系统的网络开发。网络框架对各类协议的网络设备进行了抽象 XiUOS网络框架采用以网络适配器为中心的抽象方式发送与接收数据时只需要像Linux socket网络通信一样仅关注发送与接收的数据而不用把重点放在所使用的具体协议上。这种抽象方式有效屏蔽了种类繁多的网络协议细节对外提供统一的网络接口简化了基于嵌入式操作系统的网络开发。网络框架对各类协议的网络设备进行了抽象
* 一个网络协议设备,被抽象为一个xs_Adapter * 一个网络协议设备被抽象为一个Adapter
xs_Adapter可以被设计为采用类似面向对象的方法针对不同的网络协议扩展其数据成员与接口从而为种类繁多的网络协议实现统一的管理架构。在网络应用开发的过程中只需要使用对应网络协议的xs_Adapter实例而无需关心网络协议的硬件细节从而实现了网络数据收发功能与底层硬件的解耦。 Adapter可以被设计为采用类似面向对象的方法针对不同的网络协议扩展其数据成员与接口从而为种类繁多的网络协议实现统一的管理架构。在网络应用开发的过程中只需要使用对应网络协议的Adapter实例而无需关心网络协议的硬件细节从而实现了网络数据收发功能与底层硬件的解耦。
<center> <center>
@ -15,156 +15,288 @@ xs_Adapter可以被设计为采用类似面向对象的方法针对不同的
## 1. XiUOS网络框架关键数据结构定义和解析 ## 1. XiUOS网络框架关键数据结构定义和解析
* struct xs_Adapter结构 * struct Adapter结构
```c ```c
struct xs_Adapter struct Adapter
{ {
    const char name[XS_NAME_MAX];  /* name of the adapter instance */ char name[NAME_NUM_MAX];
    enum xs_AdapterType type;       /* type of adapter, such as lora adapter */ int fd;
    xs_AdapterInfo info;    /* adapter model info, such as vendor name and model name */
    struct xs_AdapterOps ops;  /* socket-like APIs for data transferring */ int product_info_flag;
    struct xs_AdapterInterface interface;  /* physical interface for transferring data */ struct AdapterProductInfo *info;
    struct XS_DOUBLE_LINKLIST_NODE link;  /* link list node */ 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 ```c
enum xs_AdapterType { struct AdapterProductInfo
    XS_ADAPTER_LORA = 0,  /* Lora */ {
    XS_ADAPTER_4G ,       /* 4G */ uint32_t functions;
    /* ...... */ char vendor_name[NAME_NUM_MAX];
    XS_ADAPTER_WIFI ,     /* Wifi */ 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 ```c
struct xs_AdapterInfo{ struct IpProtocolDone/PrivProtocolDone
    const char *vendor; {
    const char *product_model; 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 ```c
struct xs_AdapterOps { struct ATAgent
    int (*open)(struct xs_Adapter *sadapter); {
    void (*close)(struct xs_Adapter *sadapter); char agent_name[64];
    int (*join)(struct xs_Adapter *sadapter,int net_type, int dev_type, int net_number); int fd;
    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); char *maintain_buffer;
    int (*ioctl)(struct xs_Adapter *sadapter, int cmd, void *arg); 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 ```c
enum xs_net_type{ struct Socket
    XS_CENTRALIZATION = 0, {
    XS_ADHOC, uint8_t type; /* socket type:DGRAM->UDP,STREAM->TCP */
}; uint8_t protocal; /* udp or tcp */
unsigned short listen_port; /* 0-65535 */
enum xs_dev_type{ uint8_t socket_id;
    XS_CLIENT = 0, uint8_t recv_control;
    XS_GATEWAY, 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网络框架驱动开发 ## 2. XiUOS网络框架驱动开发
以Lora网络适配器为例。网络框架针对每个具体的网络适配器将xs_Adapter进行扩充采用类似面向对象的手段添加其他必要成员 WiFi网络适配器为例。网络框架针对每个具体的网络适配器填充Adapter的数据成员项如协议类型、设备名称、厂商信息等。数据成员填充完后将其注册。
```c ```c
struct xs_AdapterLora { int AdapterWifiRegister(struct Adapter *adapter);
    struct xs_Adapter parent; /* inherit from xs_Adapter */
    const char *deve_ui;  /* Lora specific value */
    const char *app_key;  /* Lora specific value */
};
```
实现xs_AdapterOps中的数据通信API具体实现细节取决于所使用网络协议无法实现的API可以置为NULL #define ADAPTER_WIFI_NAME "wifi"
```c static int AdapterWifiRegister(struct Adapter *adapter)
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()
{ {
    /* initialize and register the xs_Adapter object */ int ret = 0;
    memset(&lora_example_adapter, 0, sizeof(lora_example_adapter));
    lora_example_adapter.parent.name = "adapter1"; strncpy(adapter->name, ADAPTER_WIFI_NAME, 32);
    lora_example_adapter.parent.type = XS_ADAPTER_LORA;
    lora_example_adapter.parent.info.vendor = "xxx"; adapter->net_protocol = IP_PROTOCOL;
    lora_example_adapter.parent.info.product_model = "yyy"; adapter->adapter_status = UNREGISTERED;
    lora_example_adapter.parent.ops = &lora_example_ops;
    lora_example_adapter.parent.interface.bus_device = xs_DeviceFind("uart1"); ret = AdapterDeviceRegister(adapter);
    lora_example_adapter.deve_ui = "mmm"; if (ret < 0) {
    lora_example_adapter.app_key = "nnn"; printf("AdapterWifi register error\n");
    xs_AdapterRegister(&lora_example_adapter); 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网络框架的使用实例 ## 3. XiUOS网络框架的使用实例
网络应用开发者使用网络框架提供的API操作网络适配器网络适配器API可以分为通用API与协议特有API。通用API用于网络适配器的获取、打开与关闭协议特有API用于特定协议的数据采样。以Lora网络适配器为例 网络应用开发者根据自己的需求将网络框架提供的API加上一些逻辑封装为一套应用层API使用该套API操作网络适配器应用层API可以分为通用API与协议特有API。通用API用于网络适配器的打开、关闭、参数配置以及网络测试功能协议特有API用于特定协议的配置以及数据收发。以Wifi网络适配器为例:
```c ```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 */ /* generic API: open/close a adapter instance */
int xs_AdapterOpen(struct xs_Adapter *adapter); int AdapterDeviceOpen(struct Adapter *adapter);
void xs_AdapterClose(struct xs_Adapter *adapter); int AdapterDeviceClose(struct Adapter *adapter);
/* Lora API: get current Lora adapter reading */
uint32_t xs_AdapterReceive(struct xs_Adapter *adapter, char* rev_buffer, int buffer_lenint time_out, bool block); /* 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 ```c
#define BUFFER_MAX 512 int AdapterWifiTest(void)
int main(int argc, char *argv[])
{ {
int ret; char cmd[64];
    char rev_buffer[BUFFER_MAX]; int baud_rate = BAUD_RATE_57600;
    struct xs_Adapter *adapter; struct Adapter* adapter = AdapterDeviceFindByName(ADAPTER_WIFI_NAME);
    struct xs_AdapterLora *lora_adapter;
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);
}
    /* 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;
} }
``` ```