rel_1.6.0 init

This commit is contained in:
guocheng.kgc 2020-06-18 20:06:52 +08:00 committed by shengdong.dsd
commit 27b3e2883d
19359 changed files with 8093121 additions and 0 deletions

View file

@ -0,0 +1,175 @@
# AliOS Things SAL Porting Guide
在AliOS Things移植过程中如果需要支持外接Wifi/BLE等模且TCP/IP协议栈运行模组侧则需要SAL和底层模组控制模块进行对接。SAL功能对上层提供标准socket接口使上层应用不感知TCP/IP协议栈运行在MCU侧还是通讯模组侧。AliOS Things SAL的接口定义请查看头文件[sal.h](https://github.com/alibaba/AliOS-Things/blob/master/device/sal/include/sal.h)。
本文将讲述AliOS Things 中SAL移植要点。
## 1、SAL模块重要数据结构
首先先了解一下AliOS Things中跟SAL相关的两个个重要的数据结构: `sal_op_t``sal_conn_t`两个结构体。SAL依赖底层的相关操作和接口封装都在`sal_op_t`这个结构体中;`sal_conn_t`结构体为建立连接时SAL传给底层模组控制模块的相关参数。两个结构体相关定义在文件[sal.h](https://github.com/alibaba/AliOS-Things/blob/master/device/sal/include/sal.h)中。
```
typedef struct sal_op_s {
char *version;
int (*init)(void);
int (*start)(sal_conn_t *c);
int (*send)(int fd, uint8_t *data, uint32_t len,
char remote_ip[16], int32_t remote_port);
int (*domain_to_ip)(char *domain, char ip[16]);
int (*close)(int fd, int32_t remote_port);
int (*deinit)(void);
int (*register_netconn_data_input_cb)(netconn_data_input_cb_t cb);
} sal_op_t;
```
```
typedef struct {
int fd;
CONN_TYPE type;
char *addr;
int32_t r_port;
int32_t l_port;
uint32_t tcp_keep_alive;
} sal_conn_t;
```
## 2、SAL接口的实现
在具体的平台移植过程中用户需要分别实现SAL模块结构体中对应的接口函数。AliOS Things对SAL层接口有一层封装参见`device/sal/sal.c`文件。具体的接口实现一般在`device/sal/xxx/`中,其中`xxx`代表模组类型。参考实现:[mk3060.c](https://github.com/alibaba/AliOS-Things/blob/master/device/sal/wifi/mk3060/mk3060.c)。下面对每个接口做一些说明:
### `init`
该接口需要对通信模组进行相关初始化,使通信模组达到可以工作的状态。
### `deinit`
如果有需要,该接口需要提供对通信模组的去初始化操作。
### `start`
该接口需要模组启动一次连接。SAL传给底层的参数为一个结构体指针`sal_conn_t`,该结构体参数说明如下:
> fd: 每个连接对应SAL socket层的句柄
>
> type: 建立连接的类型,数据定义参见枚举`CONN_TYPE`
>
> addr: 对端ip或者域名例如“192.168.1.1”或者“www.taobao.com”
>
> r_port: 对端端口号
>
> l_port: 本地端口号
>
> tcp_keep_alive: tcp keep alive的时间
因此底层模组控制模块需要维护一套SAL socket 句柄和底层链路的对应关系。可以在发送/关闭连接时可以通过SAL socket句柄查找到对应的底层连接在接收底层数据时可以根据底层连接找到对应的SAL socket句柄。
### `close`
该接口关闭模组的一个连接。入参说明如下:
> fd: 需要关闭的socket句柄
>
> remote_port: 对端端口号该参数为可选参数小于0时为无效参数
### `send`
该接口通过模块发送数据的接口,该接口为阻塞接口,直到模组通知底层控制模块数据发送成功才会返回。入参说明如下:
> fd: 发送数据所操作的句柄
>
> data: 待发送数据的指针
>
> len: 待发送数据的长度
>
> remote_ip[16], 对端ip地址该参数为可选参数入参为NULL时无效
>
> remote_port: 对端端口号该参数为可选参数小于0时为无效参数
### `domain_to_ip`
该接口提供获取对应域名ip地址的功能注意1、即使该域名对应多个ip也只会返回一个Ip地址2、目前该接口只需要支持ipv4。入参说明如下
> domain: 域名信息
>
> ip[16]: 点格式的ip字符串目前只支持ipv4例如:192.168.111.111
### `register_netconn_data_input_cb`
该接口提供一个SAL数据接收函数的回调功能底层模组控制模块在收到数据后调用该接口上送到SAL中SAL会在其中对每个句柄的数据进行管理。SAL提供的数据上送接口实现请见`sal_packet_input`
> SAL提供的数据上送接口回调typedef int (*netconn_data_input_cb_t)(int fd, void *data, size_t len, ip_addr_t *addr, u16_t port);
>
> 参数说明如下:
>
> fd: 数据上送需要操作的句柄
>
> data: 接收到的数据(该部分内存由底层自行释放)
>
> len: 接收到的数据长度
>
> addr: 该数据的源地址为可选参数可以传入NULL该部分内存由底层自行释放
>
> port: 该数据的源端口为可选参数可以传入0
## 3、模组注册和初始化SAL
在完成SAL接口对接实现后定义一个 `sal_op_t`结构体,将各个接口和回调的实现地址赋值给结构体中对应的域。例如:
```
sal_op_t sal_op = {
.version = "1.0.0",
.init = sal_wifi_init,
.start = sal_wifi_start,
.send = sal_wifi_send,
.domain_to_ip = sal_wifi_domain_to_ip,
.close = sal_wifi_close,
.deinit = sal_wifi_deinit,
.register_netconn_data_input_cb = sal_wifi_packet_input_cb_register,
};
```
底层模组控制模块需要实现一个函数调用`sal_module_register`对SAL进行模块注册。例如
```
int mk3060_sal_init(void)
{
return sal_module_register(&sal_op);
}
```
该模块注册函数需要在[device.c](https://github.com/alibaba/AliOS-Things/blob/master/device/sal/sal_device.c)的`sal_device_init`中进行调用。例如:
```
int sal_device_init()
{
int ret = 0;
#ifdef DEV_SAL_MK3060
ret = mk3060_sal_init();
#endif
if (ret){
LOGE(TAG, "device init fail ret is %d\n", ret);
}
return ret;
}
```
## 4、编译底层模组控制模块
在完成底层模组与SAL接口对接后该部分代码建议的放置路径为`device/sal/xxx/yyy`。其中`xxx`为模组类型例如wifi、ble、lora等`yyy`为模组型号例如mk3060。例如mk3060的wifi模组代码放置路径为`device/sal/wifi/mk3060/`。对应模组控制模块代码makefile名称需与模组型号一致为`yyy.mk`例如mk3060的makefile文件名为:`mk3060.mk`
编译时请注意在正常的编译命令后需要指定编译sal和所使用的通信模组信息例如`aos make alinkapp@b_l475e sal=1 module=wifi.mk3060` ,其中`sal=1`表示需要编译sal`module=wifi.mk3060`
表示所需要连接的模组类型为`wifi.mk3060`此时AliOS Things的Makefile 体系会自动调用devcie/sal/wifi/mk3060/mk3060.mk 将模组控制模块代码编译进来。

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _ATCMD_CONFIG_MODULE
#define _ATCMD_CONFIG_MODULE
#include <hal/soc/uart.h>
/**
* AT related platform-dependent things are here, including:
* 1. AT command;
* 2. AT response code;
* 3. AT delimiter;
* 4. AT event;
* 5. Uart port used by AT;
* 6. ...
*/
// AT command
#define AT_CMD_ENET_SEND "AT+ENETRAWSEND"
#define AT_CMD_ENTER_ENET_MODE "AT+ENETRAWMODE=ON"
#define AT_CMD_EHCO_OFF "AT+UARTE=OFF"
#define AT_CMD_TEST "AT"
// Delimiter
#define AT_RECV_PREFIX "\r\n"
#define AT_RECV_SUCCESS_POSTFIX "OK\r\n"
#define AT_RECV_FAIL_POSTFIX "ERROR\r\n"
#define AT_SEND_DELIMITER "\r"
// AT event
#define AT_EVENT_ENET_DATA "+ENETEVENT:"
// uart config
#define AT_UART_BAUDRATE 115200
#define AT_UART_DATA_WIDTH DATA_WIDTH_8BIT
#define AT_UART_PARITY NO_PARITY
#define AT_UART_STOP_BITS STOP_BITS_1
#define AT_UART_FLOW_CONTROL FLOW_CONTROL_DISABLED
#define AT_UART_MODE MODE_TX_RX
#endif

View file

@ -0,0 +1,833 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <aos/aos.h>
#include <atparser.h>
#include <sal_arch.h>
#include <sal_ipaddr.h>
#include <sal.h>
#define TAG "sim800_gprs_module"
#define SIM800_AT_CMD_SUCCESS_RSP "OK"
#define SIM800_AT_CMD_FAIL_RSP "ERROR"
#define AT_CMD_TEST "AT\r\n"
#define AT_CMD_TEST_RESULT "\r\nOK\r\n"
#define AT_CMD_ECHO_OFF "ATE0"
#define AT_CMD_BAUDRATE_SET "AT+IPR"
#define AT_CMD_FLOW_CONTROL "AT+IFC"
#define AT_CMD_SAVE_CONFIG "AT&W"
#define AT_CMD_SIM_PIN_CHECK "AT+CPIN?"
#define AT_CMD_SIGNAL_QUALITY_CHECK "AT+CSQ"
#define AT_CMD_NETWORK_REG_CHECK "AT+CREG?"
#define AT_CMD_GPRS_ATTACH_CHECK "AT+CGATT?"
#define AT_CMD_GPRS_PDP_DEACTIVE "AT+CIPSHUT"
#define AT_CMD_MULTI_IP_CONNECTION "AT+CIPMUX"
#define AT_CMD_TCPIP_MODE "AT+CIPMODE"
#define AT_CMD_SEND_DATA_PROMPT_SET "AT+CIPSPRT"
#define AT_CMD_RECV_DATA_FORMAT_SET "AT+CIPSRIP"
#define AT_CMD_DOMAIN_TO_IP "AT+CDNSGIP"
#define AT_CMD_DOMAIN_RSP "\r\n+CDNSGIP: "
#define AT_CMD_START_TASK "AT+CSTT"
#define AT_CMD_BRING_UP_GPRS_CONNECT "AT+CIICR"
#define AT_CMD_GOT_LOCAL_IP "AT+CIFSR"
#define AT_CMD_START_CLIENT_CONN "AT+CIPSTART"
#define AT_CMD_START_TCP_SERVER "AT+CIPSERVER"
#define AT_CMD_CLIENT_CONNECT_OK "CONNECT OK\r\n"
#define AT_CMD_CLIENT_CONNECT_FAIL "CONNECT FAIL\r\n"
#define AT_CMD_STOP_CONN "AT+CIPCLOSE"
#define AT_CMD_SEND_DATA "AT+CIPSEND"
#define AT_CMD_DATA_RECV "\r\n+RECEIVE,"
#define SIM800_DEFAULT_CMD_LEN 64
#define SIM800_DEFAULT_RSP_LEN 64
#define SIM800_MAX_LINK_NUM 6
#define SIM800_DOMAIN_MAX_LEN 256
#define SIM800_DOMAIN_RSP_MAX_LEN 512
#define SIM800_DOMAIN_CMD_LEN (sizeof(AT_CMD_DOMAIN_TO_IP) + SIM800_DOMAIN_MAX_LEN + 1)
#define SIM800_CONN_CMD_LEN (SIM800_DOMAIN_MAX_LEN + SIM800_DEFAULT_CMD_LEN)
/* Change to include data slink for each link id respectively. <TODO> */
typedef struct link_s {
int fd;
aos_sem_t sem_start;
aos_sem_t sem_close;
} link_t;
static uint8_t inited = 0;
static link_t g_link[SIM800_MAX_LINK_NUM];
static aos_mutex_t g_link_mutex;
static aos_mutex_t g_domain_mutex;
static aos_sem_t g_domain_sem;
static char *g_pcdomain_rsp = NULL;
static netconn_data_input_cb_t g_netconn_data_input_cb;
static int fd_to_linkid(int fd)
{
int link_id;
if (aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "Failed to lock mutex (%s).", __func__);
return -1;
}
for (link_id = 0; link_id < SIM800_MAX_LINK_NUM; link_id++) {
if (g_link[link_id].fd == fd)
break;
}
aos_mutex_unlock(&g_link_mutex);
return link_id;
}
static void sim800_gprs_domain_rsp_callback(void *arg, char *rspinfo, int rsplen)
{
if (NULL == rspinfo || rsplen == 0){
LOGE(TAG, "invalid input at %s \r\n", __func__);
return;
}
if (NULL == g_pcdomain_rsp){
LOGE(TAG, "domain rsp is %s but buffer is NULL \r\n", rspinfo);
return;
}
printf("get domain rsp %s \r\n", rspinfo);
memcpy(g_pcdomain_rsp, rspinfo, rsplen);
aos_sem_signal(&g_domain_sem);
return;
}
static void sim800_gprs_module_socket_data_handle(void *arg, char *rspinfo, int rsplen)
{
unsigned char uclinkid = 0;
unsigned char unusesymbol = 0;
unsigned char datalen[6] = {0};
unsigned char ipaddr[16] = {0};
unsigned char port[6] = {0};
int i = 0;
int j = 0;
int len = 0;
int remoteport = 0;
int linkid = 0;
char *recvdata = NULL;
at.read(&uclinkid, 1);
linkid = uclinkid - '0';
if (linkid < 0 || linkid >= SIM800_MAX_LINK_NUM){
LOGE(TAG, "Invalid link id 0x%02x !!!\r\n", linkid);
return;
}
/*eat , char*/
at.read(&unusesymbol, 1);
/* get data len */
i = 0;
do {
at.read(&datalen[i], 1);
if (datalen[i] == ',') break;
if (i >= sizeof(datalen)) {
LOGE(TAG, "Too long length of data.datalen is %s \r\n", datalen);
return;
}
if (datalen[i] > '9' || datalen[i] < '0') {
LOGE(TAG, "Invalid len string!!!, datalen is %s \r\n", datalen);
return;
}
i++;
} while (1);
/* len: string to number */
for (j = 0; j < i; j++) {
len = len * 10 + datalen[j] - '0';
}
/*get ip addr and port*/
i = 0;
do {
at.read(&ipaddr[i], 1);
if (ipaddr[i] == ':') break;
if (i >= sizeof(ipaddr)) {
LOGE(TAG, "Too long length of ipaddr.ipaddr is %s \r\n", ipaddr);
return;
}
if (!((ipaddr[i] <= '9' && ipaddr[i] >= '0') || ipaddr[i] == '.')) {
LOGE(TAG, "Invalid ipaddr string!!!, ipaddr is %s \r\n", ipaddr);
return;
}
i++;
} while (1);
ipaddr[i] = 0;
i = 0;
do {
at.read(&port[i], 1);
if (port[i] == '\r') break;
if (i >= sizeof(port)) {
LOGE(TAG, "Too long length of remote port.port is %s \r\n", port);
return;
}
if (port[i] > '9' || port[i] < '0') {
LOGE(TAG, "Invalid ipaddr string!!!, port is %s \r\n", port);
return;
}
i++;
} while (1);
port[i] = 0;
/*eat \n char*/
at.read(&unusesymbol, 1);
for (j = 0; j < i; j++) {
remoteport = remoteport * 10 + port[j] - '0';
}
//printf("link %d get data from %s %s ,len %s \r\n", linkid, ipaddr, port, datalen);
/* Prepare socket data */
recvdata = (char *)aos_malloc(len + 1);
if (!recvdata) {
LOGE(TAG, "Error: %s %d out of memory.", __func__, __LINE__);
return;
}
memset(recvdata, 0, len + 1);
at.read(recvdata, len);
if (g_netconn_data_input_cb && (g_link[linkid].fd >= 0)){
if (g_netconn_data_input_cb(g_link[linkid].fd, recvdata, len, ipaddr, remoteport)){
LOGE(TAG, " %s socket %d get data len %d fail to post to sal, drop it\n",
__func__, g_link[linkid].fd, len);
}
}
LOGD(TAG, "%s socket data on link %d with length %d posted to sal\n",
__func__, linkid, len);
aos_free(recvdata);
return;
}
static void at_start_test(void* psttimer,void *command)
{
int ret = 0;
static int flag = 0;
if (flag == 0){
printf("send at command %s \r\n", command);
flag = 1;
}
ret = at.write(command, strlen(command));
if (ret < 0){
LOGE(TAG, "uart send command %s at %s %d failed ret is %d \r\n", command, __FILE__, __LINE__, ret);
}
}
int sim800_uart_selfadaption(const char *command, const char *rsp, uint32_t rsplen)
{
char *buffer = NULL;
int ret = 0;
aos_timer_t test_timer;
if (NULL == command || NULL == rsp || 0 == rsplen){
LOGE(TAG, "invalid input %s %d\r\n", __FILE__, __LINE__);
return -1;
}
buffer = aos_malloc(rsplen * 3 + 1);
if (NULL == buffer){
LOGE(TAG, "fail to malloc memory size %d at %s %d \r\n", rsplen * 3, __FILE__, __LINE__);
return -1;
}
memset(buffer, 0, rsplen * 3 + 1);
aos_timer_new(&test_timer, at_start_test, command, 10, 1);
aos_timer_start(&test_timer);
while(true){
ret = at.read(buffer, rsplen * 3);
if(ret > 0 && (strstr(buffer, rsp) != NULL)){
break;
}
}
aos_timer_stop(&test_timer);
aos_timer_free(&test_timer);
aos_free(buffer);
return 0;
}
static int sim800_uart_init(void)
{
int ret = 0;
char cmd[SIM800_DEFAULT_CMD_LEN] = {0};
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
/* uart baudrate self adaption*/
ret = sim800_uart_selfadaption(AT_CMD_TEST, AT_CMD_TEST_RESULT, strlen(AT_CMD_TEST_RESULT));
if (ret){
LOGE(TAG, "sim800_uart_selfadaption fail \r\n");
return ret;
}
/*turn off echo*/
at.send_raw(AT_CMD_ECHO_OFF, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
/*set baudrate 115200*/
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d", AT_CMD_BAUDRATE_SET, AT_UART_BAUDRATE);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
memset(cmd, 0, SIM800_DEFAULT_CMD_LEN);
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
/*turn off flow control*/
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d,%d", AT_CMD_FLOW_CONTROL, 0, 0);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
/*save configuration */
at.send_raw(AT_CMD_SAVE_CONFIG, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
return 0;
}
static int sim800_gprs_status_check(void)
{
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
/*sim card status check*/
at.send_raw(AT_CMD_SIM_PIN_CHECK, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
/*Signal quaility check*/
at.send_raw(AT_CMD_SIGNAL_QUALITY_CHECK, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
LOGI(TAG, "signal quality is %s \r\n", rsp);
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
/*network registration check*/
at.send_raw(AT_CMD_NETWORK_REG_CHECK, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
LOGI(TAG, "network registration is %s \r\n", rsp);
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
/*GPRS attach check*/
at.send_raw(AT_CMD_GPRS_ATTACH_CHECK, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
LOGI(TAG, "gprs attach check %s \r\n", rsp);
return 0;
}
static int sim800_gprs_ip_init(void)
{
char cmd[SIM800_DEFAULT_CMD_LEN] = {0};
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
/*Deactivate GPRS PDP Context*/
at.send_raw(AT_CMD_GPRS_PDP_DEACTIVE, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
/*set multi ip connection mode*/
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d", AT_CMD_MULTI_IP_CONNECTION, 1);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
#if 0
/*set tcpip mode in normal mode*/
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
memset(cmd, 0, SIM800_DEFAULT_CMD_LEN);
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d", AT_CMD_TCPIP_MODE, 0);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed \r\n", __func__, __LINE__);
return -1;
}
#endif
/*not prompt echo > when sending data*/
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
memset(cmd, 0, SIM800_DEFAULT_CMD_LEN);
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d", AT_CMD_SEND_DATA_PROMPT_SET, 0);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
/*Show Remote ip and port when receive data*/
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
memset(cmd, 0, SIM800_DEFAULT_CMD_LEN);
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d", AT_CMD_RECV_DATA_FORMAT_SET, 1);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
return 0;
}
static void sim800_get_ip_delayed_action(void *arg)
{
printf("post got ip event \r\n");
aos_post_event(EV_WIFI, CODE_WIFI_ON_GOT_IP, 0xdeaddead);
}
static int sim800_gprs_got_ip(void)
{
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
/*start gprs stask*/
at.send_raw(AT_CMD_START_TASK, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
return -1;
}
/*bring up wireless connectiong with gprs*/
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
at.send_raw(AT_CMD_BRING_UP_GPRS_CONNECT, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
//return -1;
}
/*try to got ip*/
memset(rsp, 0, SIM800_DEFAULT_RSP_LEN);
at.send_raw_self_define_respone_formate(AT_CMD_GOT_LOCAL_IP, rsp, SIM800_DEFAULT_RSP_LEN,
NULL, AT_RECV_PREFIX, NULL);
if (strstr(rsp, SIM800_AT_CMD_FAIL_RSP) != NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
//return -1;
}
printf("sim800 got ip %s \r\n", rsp);
/*delay 5 seconds to post got ip event*/
aos_post_delayed_action(5000, sim800_get_ip_delayed_action, NULL);
return 0;
}
static int sim800_gprs_module_init(void)
{
int ret = 0;
uint32_t linknum = 0;
if (inited) {
LOGI(TAG, "sim800 gprs module have already inited \r\n");
return 0;
}
g_pcdomain_rsp = aos_malloc(SIM800_DOMAIN_RSP_MAX_LEN);
if (NULL == g_pcdomain_rsp){
LOGE(TAG, "%s %d failed \r\n", __func__, __LINE__);
goto err;
}
memset(g_pcdomain_rsp , 0, SIM800_DOMAIN_RSP_MAX_LEN);
if (0 != aos_mutex_new(&g_link_mutex)) {
LOGE(TAG, "Creating link mutex failed (%s %d).", __func__, __LINE__);
goto err;
}
if (0 != aos_mutex_new(&g_domain_mutex)) {
LOGE(TAG, "Creating link mutex failed (%s %d).", __func__, __LINE__);
goto err;
}
if (0 != aos_sem_new(&g_domain_sem, 0)) {
LOGE(TAG, "Creating domain mutex failed (%s %d).", __func__, __LINE__);
goto err;
}
memset(g_link, 0, sizeof(g_link));
for(linknum = 0; linknum < SIM800_MAX_LINK_NUM; linknum++){
g_link[linknum].fd = -1;
}
ret = sim800_uart_init();
if (ret){
LOGE(TAG, "%s %d failed \r\n", __func__, __LINE__);
goto err;
}
ret = sim800_gprs_status_check();
if (ret){
LOGE(TAG, "%s %d failed \r\n", __func__, __LINE__);
goto err;
}
ret = sim800_gprs_ip_init();
if (ret){
LOGE(TAG, "%s %d failed \r\n", __func__, __LINE__);
goto err;
}
/* reg oob for domain and packet input*/
at.oob(AT_CMD_DOMAIN_RSP, AT_RECV_PREFIX, SIM800_DOMAIN_RSP_MAX_LEN,
sim800_gprs_domain_rsp_callback, NULL);
at.oob(AT_CMD_DATA_RECV, NULL, 0, sim800_gprs_module_socket_data_handle, NULL);
ret = sim800_gprs_got_ip();
if (ret){
LOGE(TAG, "%s %d failed \r\n", __func__, __LINE__);
goto err;
}
inited = 1;
return 0;
err:
if (g_pcdomain_rsp != NULL){
aos_free(g_pcdomain_rsp);
g_pcdomain_rsp = NULL;
}
if (aos_mutex_is_valid(&g_link_mutex)){
aos_mutex_free(&g_link_mutex);
}
if (aos_mutex_is_valid(&g_domain_mutex)){
aos_mutex_free(&g_domain_mutex);
}
if (aos_sem_is_valid(&g_domain_sem)){
aos_sem_free(&g_domain_sem);
}
return -1;
}
static int sim800_gprs_module_deinit()
{
if(!inited){
return 0;
}
aos_mutex_free(&g_link_mutex);
inited = 0;
return 0;
}
static int sim800_gprs_module_domain_to_ip(char *domain, char ip[16])
{
char *pccmd = NULL;
char *head = NULL;
char *end = NULL;
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
if (!inited){
LOGE(TAG, "%s sim800 gprs module haven't init yet \r\n", __func__);
return -1;
}
if (NULL == domain || NULL == ip){
LOGE(TAG, "invalid input at %s \r\n", __func__);
return -1;
}
if (strlen(domain) > SIM800_DOMAIN_MAX_LEN){
LOGE(TAG, "domain length oversize at %s \r\n", __func__);
return -1;
}
pccmd = aos_malloc(SIM800_DOMAIN_CMD_LEN);
if (NULL == pccmd){
LOGE(TAG, "fail to malloc memory %d at %s \r\n", SIM800_DOMAIN_CMD_LEN, __func__);
return -1;
}
memset(pccmd, 0, SIM800_DOMAIN_CMD_LEN);
snprintf(pccmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%s", AT_CMD_DOMAIN_TO_IP, domain);
aos_mutex_lock(&g_domain_mutex, AOS_WAIT_FOREVER);
at.send_raw(pccmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
goto err;
}
/*TODO wait for reponse for ever for now*/
aos_sem_wait(&g_domain_sem, AOS_WAIT_FOREVER);
/*
* formate is :
+CDNSGIP: 1,"www.baidu.com","183.232.231.173","183.232.231.172"
or :
+CDNSGIP: 0,8
*/
if ((head = strstr(g_pcdomain_rsp, domain)) == NULL) {
LOGE(TAG, "invalid domain rsp %s at %d\r\n", g_pcdomain_rsp, __LINE__);
goto err;
}
head += (strlen(domain) + 3);
if ((end = strstr(head, "\"")) == NULL){
LOGE(TAG, "invalid domain rsp head is %s at %d\r\n", head, __LINE__);
goto err;
}
if ((end - head) > 15 || (end - head) < 7){
LOGE(TAG, "invalid domain rsp head is %s at %d\r\n", head, __LINE__);
goto err;
}
/* We find a good IP, save it. */
memcpy(ip, head, end - head);
ip[end-head] = '\0';
memset(g_pcdomain_rsp, 0, SIM800_DOMAIN_RSP_MAX_LEN);
aos_mutex_unlock(&g_domain_mutex);
printf("domain %s get ip %s \r\n", domain ,ip);
return 0;
err:
aos_free(pccmd);
memset(g_pcdomain_rsp, 0, SIM800_DOMAIN_RSP_MAX_LEN);
aos_mutex_unlock(&g_domain_mutex);
return -1;
}
static int sim800_gprs_module_conn_start(sal_conn_t *conn)
{
int linkid = 0;
char *pccmd = NULL;
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
if (!inited){
LOGE(TAG, "%s sim800 gprs module haven't init yet \r\n", __func__);
return -1;
}
if (!conn || !conn->addr){
LOGE(TAG, "%s %d - invalid input \r\n", __func__, __LINE__);
return -1;
}
#if 0
/*if input addr is a domain, then turn it into ip addr */
if (sim800_gprs_module_domain_to_ip(conn->addr, ipaddr) != 0){
if (strlen(conn->addr) >= sizeof(ipaddr)){
LOGE(TAG, "%s invalid server addr %s \r\n", __func__, conn->addr);
return -1;
}
strcpy(ipaddr, conn->addr);
}
#endif
aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER);
for (linkid = 0; linkid < SIM800_MAX_LINK_NUM; linkid++){
if (g_link[linkid].fd >= 0){
continue;
}
g_link[linkid].fd = conn->fd;
break;
}
aos_mutex_unlock(&g_link_mutex);
if (linkid >= SIM800_MAX_LINK_NUM) {
LOGE(TAG, "No link available for now, %s failed. \r\n", __func__);
return -1;
}
pccmd = aos_malloc(SIM800_CONN_CMD_LEN);
if (NULL == pccmd){
LOGE(TAG, "fail to malloc %d at %s \r\n", SIM800_CONN_CMD_LEN, __func__);
goto err;
}
memset(pccmd, 0, SIM800_CONN_CMD_LEN);
switch(conn->type){
case TCP_SERVER:
snprintf(pccmd, SIM800_CONN_CMD_LEN - 1, "%s=%d,%d", AT_CMD_START_TCP_SERVER, 1, conn->l_port);
at.send_raw(pccmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL){
LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
goto err;
}
break;
case TCP_CLIENT:
snprintf(pccmd, SIM800_CONN_CMD_LEN - 1, "%s=%d,\"TCP\",\"%s\",%d", AT_CMD_START_CLIENT_CONN, linkid, conn->addr, conn->r_port);
at.send_raw_self_define_respone_formate(pccmd, rsp, SIM800_DEFAULT_RSP_LEN,
NULL, AT_CMD_CLIENT_CONNECT_OK, AT_CMD_CLIENT_CONNECT_FAIL);
if (strstr(rsp, AT_CMD_CLIENT_CONNECT_FAIL) != NULL){
LOGE(TAG, "pccmd %s fail, rsp %s \r\n", pccmd, rsp);
goto err;
}
break;
case UDP_UNICAST:
snprintf(pccmd, SIM800_CONN_CMD_LEN - 1, "%s=%d,\"UDP\",\"%s\",%d", AT_CMD_START_CLIENT_CONN, linkid, conn->addr, conn->r_port);
at.send_raw_self_define_respone_formate(pccmd, rsp, SIM800_DEFAULT_RSP_LEN,
NULL, AT_CMD_CLIENT_CONNECT_OK, AT_CMD_CLIENT_CONNECT_FAIL);
if (strstr(rsp, AT_CMD_CLIENT_CONNECT_FAIL) != NULL){
LOGE(TAG, "pccmd %s fail, rsp %s \r\n", pccmd, rsp);
goto err;
}
break;
case SSL_CLIENT:
case UDP_BROADCAST:
default:
LOGE(TAG, "sim800 gprs module connect type %d not support \r\n", conn->type);
goto err;
}
aos_free(pccmd);
return 0;
err:
aos_free(pccmd);
aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER);
g_link[linkid].fd = -1;
aos_mutex_unlock(&g_link_mutex);
return -1;
}
static int sim800_gprs_module_conn_close(int fd, int32_t remote_port)
{
int linkid = 0;
int ret = 0;
char cmd[SIM800_DEFAULT_CMD_LEN] = {0};
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
if (!inited){
LOGE(TAG, "%s sim800 gprs module haven't init yet \r\n", __func__);
return -1;
}
linkid = fd_to_linkid(fd);
if (linkid >= SIM800_MAX_LINK_NUM) {
LOGE(TAG, "No connection found for fd (%d) in %s \r\n", fd, __func__);
return -1;
}
snprintf(cmd, SIM800_DEFAULT_CMD_LEN -1, "%s=%d", AT_CMD_STOP_CONN, linkid);
at.send_raw(cmd, rsp, SIM800_DEFAULT_RSP_LEN);
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL){
LOGE(TAG, "cmd %s rsp is %s \r\n", cmd, rsp);
ret = -1;
}
aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER);
g_link[linkid].fd = -1;
aos_mutex_unlock(&g_link_mutex);
return ret;
}
static int sim800_gprs_module_send(int fd,uint8_t *data,uint32_t len,
char remote_ip[16], int32_t remote_port)
{
int linkid;
char cmd[SIM800_DEFAULT_CMD_LEN] = {0};
char rsp[SIM800_DEFAULT_RSP_LEN] = {0};
if (!inited){
LOGE(TAG, "%s sim800 gprs module haven't init yet \r\n", __func__);
return -1;
}
linkid = fd_to_linkid(fd);
if (linkid >= SIM800_MAX_LINK_NUM) {
LOGE(TAG, "No connection found for fd (%d) in %s \r\n", fd, __func__);
return -1;
}
snprintf(cmd, SIM800_DEFAULT_CMD_LEN - 1, "%s=%d,%d", AT_CMD_SEND_DATA, linkid, len);
/*TODO data send fail rsp is SEND FAIL*/
at.send_data_2stage((const char *)cmd, (const char *)data, len, rsp, sizeof(rsp));
if (strstr(rsp, SIM800_AT_CMD_SUCCESS_RSP) == NULL) {
LOGE(TAG, "cmd %s rsp %s at %s %d failed \r\n", cmd, rsp, __func__, __LINE__);
return -1;
}
return 0;
}
static int sim800_gprs_packet_input_cb_register(netconn_data_input_cb_t cb)
{
if (cb)
g_netconn_data_input_cb = cb;
return 0;
}
sal_op_t sim800_sal_opt = {
.version = "1.0.0",
.init = sim800_gprs_module_init,
.start = sim800_gprs_module_conn_start,
.send = sim800_gprs_module_send,
.domain_to_ip = sim800_gprs_module_domain_to_ip,
.close = sim800_gprs_module_conn_close,
.deinit = sim800_gprs_module_deinit,
.register_netconn_data_input_cb = sim800_gprs_packet_input_cb_register,
};
int sim800_sal_init(void)
{
return sal_module_register(&sim800_sal_opt);
}

View file

@ -0,0 +1,12 @@
NAME := device_sal_sim800
GLOBAL_DEFINES += DEV_SAL_SIM800
$(NAME)_COMPONENTS += yloop
ifneq (1, $(at_adapter))
$(NAME)_COMPONENTS += sal atparser
$(NAME)_SOURCES += sim800.c
endif
GLOBAL_INCLUDES += ./

View file

@ -0,0 +1,27 @@
src =Split('''
''')
component =aos_component('device_sal_sim800', src)
dependencis =Split('''
kernel/yloop
''')
for i in dependencis:
component.add_comp_deps(i)
global_includes =Split('''
./
''')
for i in global_includes:
component.add_global_includes(i)
global_macros =Split('''
DEV_SAL_SIM800
''')
for i in global_macros:
component.add_global_macros(i)
at_adapter = aos_global_config.get('at_adapter')
if at_adapter == 1:
component.add_comp_deps('device/sal')
component.add_comp_deps('framework/atparser')
src.add_sources('sim800.c')

View file

@ -0,0 +1,356 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _SAL_ARCH_INTERNAL_H_
#define _SAL_ARCH_INTERNAL_H_
#include <aos/aos.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup sys_time
* Returns the current time in milliseconds,
* may be the same as sys_jiffies or at least based on it.
*/
uint32_t sys_now(void);
//#define EVENT_SIMPLE
#define SAL_ARCH_TIMEOUT 0xffffffffUL
/** sys_mbox_tryfetch() returns SAL_MBOX_EMPTY if appropriate.
* For now we use the same magic value, but we allow this to change in future.
*/
#define SAL_MBOX_EMPTY SAL_ARCH_TIMEOUT
#define SAL_SEM_NULL NULL
#define SAL_LIGHTWEIGHT_PROT 1
#define SAL_DEFAULT_INPUTMBOX_SIZE 8
#define SAL_DEFAULT_OUTPUTMBOX_SIZE 8
typedef aos_sem_t sal_sem_t;
#define sal_sem_valid(sem) aos_sem_is_valid(sem)
#define sal_sem_set_invalid(sem) do { if(sem != NULL) { (sem)->hdl = NULL; }}while(0)
typedef uint32_t sal_prot_t;
typedef aos_mutex_t sal_mutex_t;
#define sal_mutex_valid(mutex) aos_mutex_is_valid(mutex)
#define sal_mutex_set_invalid(mutex) do { if(mutex != NULL) { (mutex)->hdl = NULL; }}while(0)
typedef aos_queue_t sal_mbox_t;
#define sal_mbox_valid(mbox) aos_queue_is_valid(mbox)
#define sal_mbox_set_invalid(mbox) do { if(mbox != NULL) { (mbox)->hdl = NULL; }}while(0)
typedef void *sal_thread_t;
/**
* @ingroup sal_mutex
* Create a new mutex.
* Note that mutexes are expected to not be taken recursively by the lwIP code,
* so both implementation types (recursive or non-recursive) should work.
* @param mutex pointer to the mutex to create
* @return ERR_OK if successful, another err_t otherwise
*/
err_t sal_mutex_new(sal_mutex_t *mutex);
/**
* @ingroup sal_mutex
* Lock a mutex
* @param mutex the mutex to lock
*/
void sal_mutex_lock(sal_mutex_t *mutex);
/**
* @ingroup sal_mutex
* Unlock a mutex
* @param mutex the mutex to unlock
*/
void sal_mutex_unlock(sal_mutex_t *mutex);
/**
* @ingroup sal_mutex
* Delete a semaphore
* @param mutex the mutex to delete
*/
void sal_mutex_free(sal_mutex_t *mutex);
#ifndef sal_mutex_valid
/**
* @ingroup sal_mutex
* Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid
*/
int sal_mutex_valid(sal_mutex_t *mutex);
#endif
#ifndef sal_mutex_set_invalid
/**
* @ingroup sal_mutex
* Set a mutex invalid so that sal_mutex_valid returns 0
*/
void sal_mutex_set_invalid(sal_mutex_t *mutex);
#endif
/* Semaphore functions: */
/**
* @ingroup sal_sem
* Create a new semaphore
* @param sem pointer to the semaphore to create
* @param count initial count of the semaphore
* @return ERR_OK if successful, another err_t otherwise
*/
err_t sal_sem_new(sal_sem_t *sem, uint8_t count);
/**
* @ingroup sal_sem
* Signals a semaphore
* @param sem the semaphore to signal
*/
void sal_sem_signal(sal_sem_t *sem);
/**
* @ingroup sal_sem
* Wait for a semaphore for the specified timeout
* @param sem the semaphore to wait for
* @param timeout timeout in milliseconds to wait (0 = wait forever)
* @return time (in milliseconds) waited for the semaphore
* or SAL_ARCH_TIMEOUT on timeout
*/
uint32_t sal_arch_sem_wait(sal_sem_t *sem, uint32_t timeout);
/**
* @ingroup sal_sem
* Delete a semaphore
* @param sem semaphore to delete
*/
void sal_sem_free(sal_sem_t *sem);
/** Wait for a semaphore - forever/no timeout */
#define sal_sem_wait(sem) sal_arch_sem_wait(sem, 0)
#ifndef sal_sem_valid
/**
* @ingroup sal_sem
* Check if a semaphore is valid/allocated: return 1 for valid, 0 for invalid
*/
int sal_sem_valid(sal_sem_t *sem);
#endif
#ifndef sal_sem_set_invalid
/**
* @ingroup sal_sem
* Set a semaphore invalid so that sal_sem_valid returns 0
*/
void sal_sem_set_invalid(sal_sem_t *sem);
#endif
#ifndef sal_sem_valid_val
/**
* Same as sal_sem_valid() but taking a value, not a pointer
*/
#define sal_sem_valid_val(sem) sal_sem_valid(&(sem))
#endif
#ifndef sal_sem_set_invalid_val
/**
* Same as sal_sem_set_invalid() but taking a value, not a pointer
*/
#define sal_sem_set_invalid_val(sem) sal_sem_set_invalid(&(sem))
#endif
/* sal_mutex_arch_init() must be called before anything else. */
void sal_mutex_arch_init(void);
void sal_mutex_arch_free(void);
/* Mailbox functions. */
/**
* @ingroup sys_mbox
* Create a new mbox of specified size
* @param mbox pointer to the mbox to create
* @param size (minimum) number of messages in this mbox
* @return ERR_OK if successful, another err_t otherwise
*/
err_t sal_mbox_new(sal_mbox_t *mbox, int size);
/**
* @ingroup sys_mbox
* Post a message to an mbox - may not fail
* -> blocks if full, only used from tasks not from ISR
* @param mbox mbox to posts the message
* @param msg message to post (ATTENTION: can be NULL)
*/
void sal_mbox_post(sal_mbox_t *mbox, void *msg);
/**
* @ingroup sys_mbox
* Try to post a message to an mbox - may fail if full or ISR
* @param mbox mbox to posts the message
* @param msg message to post (ATTENTION: can be NULL)
*/
err_t sal_mbox_trypost(sal_mbox_t *mbox, void *msg);
/**
* @ingroup sys_mbox
* Wait for a new message to arrive in the mbox
* @param mbox mbox to get a message from
* @param msg pointer where the message is stored
* @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever)
* @return time (in milliseconds) waited for a message, may be 0 if not waited
or SYS_ARCH_TIMEOUT on timeout
* The returned time has to be accurate to prevent timer jitter!
*/
u32_t sal_arch_mbox_fetch(sal_mbox_t *mbox, void **msg, u32_t timeout);
/* Allow port to override with a macro, e.g. special timeout for sys_arch_mbox_fetch() */
#ifndef sal_arch_mbox_tryfetch
/**
* @ingroup sys_mbox
* Wait for a new message to arrive in the mbox
* @param mbox mbox to get a message from
* @param msg pointer where the message is stored
* @return 0 (milliseconds) if a message has been received
* or SAL_MBOX_EMPTY if the mailbox is empty
*/
u32_t sal_arch_mbox_tryfetch(sal_mbox_t *mbox, void **msg);
#endif
/**
* For now, we map straight to sys_arch implementation.
*/
#define sal_mbox_tryfetch(mbox, msg) sal_arch_mbox_tryfetch(mbox, msg)
/**
* @ingroup sys_mbox
* Delete an mbox
* @param mbox mbox to delete
*/
void sal_mbox_free(sal_mbox_t *mbox);
#define sal_mbox_fetch(mbox, msg) sal_arch_mbox_fetch(mbox, msg, 0)
#ifndef sal_mbox_valid
/**
* @ingroup sys_mbox
* Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid
*/
int sal_mbox_valid(sal_mbox_t *mbox);
#endif
#ifndef sal_mbox_set_invalid
/**
* @ingroup sys_mbox
* Set an mbox invalid so that sys_mbox_valid returns 0
*/
void sal_mbox_set_invalid(sal_mbox_t *mbox);
#endif
#ifndef sal_mbox_valid_val
/**
* Same as sys_mbox_valid() but taking a value, not a pointer
*/
#define sal_mbox_valid_val(mbox) sal_mbox_valid(&(mbox))
#endif
#ifndef sal_mbox_set_invalid_val
/**
* Same as sys_mbox_set_invalid() but taking a value, not a pointer
*/
#define sal_mbox_set_invalid_val(mbox) sal_mbox_set_invalid(&(mbox))
#endif
/**
* @ingroup sal_time
* Returns the current time in milliseconds,
* may be the same as sal_jiffies or at least based on it.
*/
uint32_t sal_now(void);
/* Critical Region Protection */
/* These functions must be implemented in the sal_arch.c file.
In some implementations they can provide a more light-weight protection
mechanism than using semaphores. Otherwise semaphores can be used for
implementation */
#ifndef SAL_ARCH_PROTECT
/** SAL_LIGHTWEIGHT_PROT
* define SAL_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
* for certain critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#if SAL_LIGHTWEIGHT_PROT
/**
* @ingroup sal_prot
* SAL_ARCH_DECL_PROTECT
* declare a protection variable. This macro will default to defining a variable of
* type sal_prot_t. If a particular port needs a different implementation, then
* this macro may be defined in sal_arch.h.
*/
#define SAL_ARCH_DECL_PROTECT(lev) sal_prot_t lev
/**
* @ingroup sal_prot
* SAL_ARCH_PROTECT
* Perform a "fast" protect. This could be implemented by
* disabling interrupts for an embedded system or by using a semaphore or
* mutex. The implementation should allow calling SAL_ARCH_PROTECT when
* already protected. The old protection level is returned in the variable
* "lev". This macro will default to calling the sal_arch_protect() function
* which should be implemented in sal_arch.c. If a particular port needs a
* different implementation, then this macro may be defined in sal_arch.h
*/
#define SAL_ARCH_PROTECT(lev) lev = sal_arch_protect()
/**
* @ingroup sal_prot
* SAL_ARCH_UNPROTECT
* Perform a "fast" set of the protection level to "lev". This could be
* implemented by setting the interrupt level to "lev" within the MACRO or by
* using a semaphore or mutex. This macro will default to calling the
* sal_arch_unprotect() function which should be implemented in
* sal_arch.c. If a particular port needs a different implementation, then
* this macro may be defined in sal_arch.h
*/
#define SAL_ARCH_UNPROTECT(lev) sal_arch_unprotect(lev)
sal_prot_t sal_arch_protect(void);
void sal_arch_unprotect(sal_prot_t pval);
#else
#define SAL_ARCH_DECL_PROTECT(lev)
#define SAL_ARCH_PROTECT(lev)
#define SAL_ARCH_UNPROTECT(lev)
#endif /* SAL_LIGHTWEIGHT_PROT */
#endif /* SAL_ARCH_PROTECT */
/*
* Macros to set/get and increase/decrease variables in a thread-safe way.
* Use these for accessing variable that are used from more than one thread.
*/
#ifndef SAL_ARCH_INC
#define SAL_ARCH_INC(var, val) do { \
SAL_ARCH_DECL_PROTECT(old_level); \
SAL_ARCH_PROTECT(old_level); \
var += val; \
SAL_ARCH_UNPROTECT(old_level); \
} while(0)
#endif /* SAL_ARCH_INC */
#ifndef SAL_ARCH_DEC
#define SAL_ARCH_DEC(var, val) do { \
SAL_ARCH_DECL_PROTECT(old_level); \
SAL_ARCH_PROTECT(old_level); \
var -= val; \
SAL_ARCH_UNPROTECT(old_level); \
} while(0)
#endif /* SAL_ARCH_DEC */
#ifndef SAL_ARCH_GET
#define SAL_ARCH_GET(var, ret) do { \
SAL_ARCH_DECL_PROTECT(old_level); \
SAL_ARCH_PROTECT(old_level); \
ret = var; \
SAL_ARCH_UNPROTECT(old_level); \
} while(0)
#endif /* SAL_ARCH_GET */
#ifndef SAL_ARCH_SET
#define SAL_ARCH_SET(var, val) do { \
SAL_ARCH_DECL_PROTECT(old_level); \
SAL_ARCH_PROTECT(old_level); \
var = val; \
SAL_ARCH_UNPROTECT(old_level); \
} while(0)
#endif /* SAL_ARCH_SET */
#ifdef __cplusplus
}
#endif
#endif /*_SAL_ARCH_H_*/

View file

@ -0,0 +1,200 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _SAL_PCB_H_
#define _SAL_PCB_H_
#ifdef __cplusplus
extern "C" {
#endif
#if SAL_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif
/** Main packet buffer struct */
struct pbuf {
/** next pbuf in singly linked pbuf chain */
struct pbuf *next;
/** pointer to the actual data in the buffer */
void *payload;
/**
* total length of this buffer and all next buffers in chain
* belonging to the same packet.
*
* For non-queue packet chains this is the invariant:
* p->tot_len == p->len + (p->next? p->next->tot_len: 0)
*/
u16_t tot_len;
/** length of this buffer */
u16_t len;
/** pbuf_type as u8_t instead of enum to save space */
u8_t /*pbuf_type*/ type;
/** misc flags */
u8_t flags;
#if SAL_XR_EXT_MBUF_SUPPORT
/** new flags for mbuf */
u8_t mb_flags;
/** decrease its size to u8_t */
u8_t ref;
#else /* SAL_XR_EXT_MBUF_SUPPORT */
/**
* the reference count always equals the number of pointers
* that refer to this pbuf. This can be pointers from an application,
* the stack itself, or pbuf->next pointers from a chain.
*/
u16_t ref;
#endif
};
/** This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB \
/* ip addresses in network byte order */ \
ip_addr_t local_ip; \
ip_addr_t remote_ip; \
/* Socket options */ \
u8_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
struct ip_pcb {
/* Common members of all PCB types */
IP_PCB;
};
struct tcp_pcb;
typedef void (*tcp_recv_fn)(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
const ip_addr_t *addr, u16_t port);
/**
* members common to struct tcp_pcb and struct tcp_listen_pcb
*/
#define TCP_PCB_COMMON(type) \
type *next; /* for the linked list */ \
void *callback_arg; \
u8_t prio; \
/* ports are in host byte order */ \
u16_t local_port
/** the TCP protocol control block */
struct tcp_pcb {
/** common PCB members */
IP_PCB;
/** protocol specific PCB members */
TCP_PCB_COMMON(struct tcp_pcb);
/* ports are in host byte order */
u16_t remote_port;
/** receive callback function */
tcp_recv_fn recv;
/* user-supplied argument for the recv callback */
void *recv_arg;
};
struct udp_pcb;
/** Function prototype for udp pcb receive callback functions
* addr and port are in same byte order as in the pcb
* The callback is responsible for freeing the pbuf
* if it's not used any more.
*
* ATTENTION: Be aware that 'addr' might point into the pbuf 'p' so freeing this pbuf
* can make 'addr' invalid, too.
*
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @param port the remote port from which the packet was received
*/
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
const ip_addr_t *addr, u16_t port);
/** the UDP protocol control block */
struct udp_pcb {
/** Common members of all PCB types */
IP_PCB;
/* Protocol specific PCB members */
struct udp_pcb *next;
u8_t flags;
/** ports are in host byte order */
u16_t local_port, remote_port;
#if SAL_MULTICAST_TX_OPTIONS
/** outgoing network interface for multicast packets */
ip_addr_t multicast_ip;
/** TTL for outgoing multicast packets */
u8_t mcast_ttl;
#endif /* SAL_MULTICAST_TX_OPTIONS */
#if SAL_UDPLITE
/** used for UDP_LITE only */
u16_t chksum_len_rx, chksum_len_tx;
#endif /* SAL_UDPLITE */
/** receive callback function */
udp_recv_fn recv;
/** user-supplied argument for the recv callback */
void *recv_arg;
};
struct raw_pcb;
/** Function prototype for raw pcb receive callback functions.
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
const ip_addr_t *addr);
/** the RAW protocol control block */
struct raw_pcb {
/* Common members of all PCB types */
IP_PCB;
struct raw_pcb *next;
u8_t protocol;
/** receive callback function */
raw_recv_fn recv;
/* user-supplied argument for the recv callback */
void *recv_arg;
#if SAL_IPV6
/* fields for handling checksum computations as per RFC3542. */
u16_t chksum_offset;
u8_t chksum_reqd;
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* __AOS_EVENTFD_H__ */

View file

@ -0,0 +1,270 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _SAL_SOCKETS_INTERNAL_H_
#define _SAL_SOCKETS_INTERNAL_H_
#include <sys/time.h>
#include <stdlib.h>
#include <aos/aos.h>
#include "vfs_conf.h"
#include "sal_arch.h"
#include "sal_def.h"
#include "sal_ipaddr.h"
#include "sal_err.h"
#include "sal_pcb.h"
#include "sal_arch_internal.h"
#include "sal.h"
#include "sal_sockets.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MEMP_NUM_NETCONN 5//(MAX_SOCKETS_TCP + MAX_LISTENING_SOCKETS_TCP + MAX_SOCKETS_UDP)
#define SAL_TAG "sal"
#ifdef SAL_USE_DEBUG
#define SAL_DEBUG(format, ...) LOGD(SAL_TAG, format, ##__VA_ARGS__)
#else
#define SAL_DEBUG(format, ...)
#endif
#define SAL_ERROR(format, ...) LOGE(SAL_TAG, format, ##__VA_ARGS__)
#define SAL_ASSERT(msg, assertion) do { if (!(assertion)) { \
LOGE(SAL_TAG, msg);} \
} while (0)
/** IPv4 only: set the IP address given as an u32_t */
#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
/** IPv4 only: get the IP address as an u32_t */
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
/* Helpers to process several netconn_types by the same code */
#define NETCONNTYPE_GROUP(t) ((t)&0xF0)
#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0)
#if SAL_NETCONN_SEM_PER_THREAD
#define SELECT_SEM_T sal_sem_t*
#define SELECT_SEM_PTR(sem) (sem)
#else /* SAL_NETCONN_SEM_PER_THREAD */
#define SELECT_SEM_T sal_sem_t
#define SELECT_SEM_PTR(sem) (&(sem))
#endif /* SAL_NETCONN_SEM_PER_THREAD */
/* Flags for struct netconn.flags (u8_t) */
/** Should this netconn avoid blocking? */
#define NETCONN_FLAG_NON_BLOCKING 0x02
/** Was the last connect action a non-blocking one? */
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_set_nonblocking(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
// #if defined(AOS_CONFIG_VFS_DEV_NODES)
// #define SAL_SOCKET_OFFSET AOS_CONFIG_VFS_DEV_NODES
// #endif
#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1)
typedef struct sal_netbuf{
void *payload;
u16_t len;
ip_addr_t addr;
u16_t port;
}sal_netbuf_t;
typedef struct sal_outputbuf{
void *payload;
u16_t len;
u16_t remote_port;
char remote_ip[16];
}sal_outputbuf_t;
/** Description for a task waiting in select */
struct sal_select_cb {
/** Pointer to the next waiting task */
struct sal_select_cb *next;
/** Pointer to the previous waiting task */
struct sal_select_cb *prev;
/** readset passed to select */
fd_set *readset;
/** writeset passed to select */
fd_set *writeset;
/** unimplemented: exceptset passed to select */
fd_set *exceptset;
/** don't signal the same semaphore twice: set to 1 when signalled */
int sem_signalled;
/** semaphore to wake up a task waiting for select */
SELECT_SEM_T sem;
};
/** Current state of the netconn. Non-TCP netconns are always
* in state NETCONN_NONE! */
enum netconn_state {
NETCONN_NONE,
NETCONN_WRITE,
NETCONN_LISTEN,
NETCONN_CONNECT,
NETCONN_CLOSE
};
/* Flags for struct netconn.flags (u8_t) */
/** Should this netconn avoid blocking? */
#define NETCONN_FLAG_NON_BLOCKING 0x02
/** Was the last connect action a non-blocking one? */
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
/** If a nonblocking write has been rejected before, poll_tcp needs to
check if the netconn is writable again */
#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
/** If this flag is set then only IPv6 communication is allowed on the
netconn. As per RFC#3493 this features defaults to OFF allowing
dual-stack usage by default. */
#define NETCONN_FLAG_IPV6_V6ONLY 0x20
/** @ingroup netconn_common
* Protocol family and type of the netconn
*/
enum netconn_type {
NETCONN_INVALID = 0,
/** TCP IPv4 */
NETCONN_TCP = 0x10,
#if SAL_IPV6
/** TCP IPv6 */
NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */,
#endif /* SAL_IPV6 */
/** UDP IPv4 */
NETCONN_UDP = 0x20,
/** UDP IPv4 lite */
NETCONN_UDPLITE = 0x21,
/** UDP IPv4 no checksum */
NETCONN_UDPNOCHKSUM = 0x22,
#if SAL_IPV6
/** UDP IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */
NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */,
/** UDP IPv6 lite (dual-stack by default, unless you call @ref netconn_set_ipv6only) */
NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */,
/** UDP IPv6 no checksum (dual-stack by default, unless you call @ref netconn_set_ipv6only) */
NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */,
#endif /* SAL_IPV6 */
/** Raw connection IPv4 */
NETCONN_RAW = 0x40
#if SAL_IPV6
/** Raw connection IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */
, NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */
#endif /* SAL_IPV6 */
};
struct sal_netconn;
/** A callback prototype to inform about events for a netconn */
typedef void (* netconn_callback)(struct sal_netconn *conn, enum netconn_evt, u16_t len);
/** A netconn descriptor */
typedef struct sal_netconn {
int socket;
/** type of the netconn (TCP, UDP or RAW) */
enum netconn_type type;
/** current state of the netconn */
enum netconn_state state;
/** the SAL internal protocol control block */
union {
struct ip_pcb *ip;
struct tcp_pcb *tcp;
struct udp_pcb *udp;
struct raw_pcb *raw;
} pcb;
/** the last error this netconn had */
err_t last_err;
/** mbox where received packets are stored until they are fetched
by the neconn application thread. */
sal_mbox_t recvmbox;
sal_mbox_t sendmbox;
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
u8_t flags;
/** timeout to wait for sending data (which means enqueueing data for sending
in internal buffers) in milliseconds */
s32_t send_timeout;
/** timeout in milliseconds to wait for new data to be received
(or connections to arrive for listening netconns) */
int recv_timeout;
#if SAL_RCVBUF
/** maximum amount of bytes queued in recvmbox
not used for TCP: adjust TCP_WND instead! */
int recv_bufsize;
/** number of bytes currently in recvmbox to be received,
tested against recv_bufsize to limit bytes on recvmbox
for UDP and RAW, used for FIONREAD */
int recv_avail;
#endif /* SAL_RCVBUF */
/** A callback function that is informed about events for this netconn */
netconn_callback callback;
} sal_netconn_t;
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_set_nonblocking(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
#define SAL_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U))
#define SAL_SOCKET_MAX_PAYLOAD_SIZE 1512
#define SAL_SOCKET_IP4_ANY_ADDR "0.0.0.0"
#define SAL_SOCKET_IP4_ADDR_LEN 16
void sal_deal_event(int s, enum netconn_evt evt);
#define API_EVENT_SIMPLE(s,e) sal_deal_event(s,e)
#define EAI_NONAME 200
#define EAI_SERVICE 201
#define EAI_FAIL 202
#define EAI_MEMORY 203
#define EAI_FAMILY 204
#define HOST_NOT_FOUND 210
#define NO_DATA 211
#define NO_RECOVERY 212
#define TRY_AGAIN 213
/* input flags for struct addrinfo */
#define AI_PASSIVE 0x01
#define AI_CANONNAME 0x02
#define AI_NUMERICHOST 0x04
#define AI_NUMERICSERV 0x08
#define AI_V4MAPPED 0x10
#define AI_ALL 0x20
#define AI_ADDRCONFIG 0x40
struct sockaddr_storage {
u8_t s2_len;
sa_family_t ss_family;
char s2_data1[2];
u32_t s2_data2[3];
#if LWIP_IPV6
u32_t s2_data3[3];
#endif /* LWIP_IPV6 */
};
#ifdef __cplusplus
}
#endif
#endif /* __AOS_EVENTFD_H__ */

View file

@ -0,0 +1,225 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _SAL_H_
#define _SAL_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SAL_PACKET_SEND_MODE_ASYNC 1
typedef enum {
/* WiFi */
TCP_SERVER,
TCP_CLIENT,
SSL_CLIENT,
UDP_BROADCAST,
UDP_UNICAST,
/*WiFi end */
/* Add others hereafter */
} CONN_TYPE;
/* Fill necessary fileds according to the socket type. */
typedef struct {
int fd; /* fd that are used in socket level */
CONN_TYPE type;
char *addr; /* remote ip or domain */
int32_t r_port; /* remote port (set to -1 if not used) */
int32_t l_port; /* local port (set to -1 if not used) */
uint32_t tcp_keep_alive; /* tcp keep alive value (set to 0 if not used) */
} sal_conn_t;
/* Socket data state indicator. */
typedef enum netconn_evt {
NETCONN_EVT_RCVPLUS,
NETCONN_EVT_RCVMINUS,
NETCONN_EVT_SENDPLUS,
NETCONN_EVT_SENDMINUS,
NETCONN_EVT_ERROR
} netconn_evt_t;
typedef int (*netconn_data_input_cb_t)(int fd, void *data, size_t len, char remote_ip[16], uint16_t remote_port);
typedef struct sal_op_s {
char *version; /* Reserved for furture use. */
/**
* Module low level init so that it's ready to setup socket connection.
*
* @return 0 - success, -1 - failure
*/
int (*init)(void);
/**
* Start a socket connection via module.
*
* @param[in] c - connect parameters which are used to setup
* the socket connection.
*
* @return 0 - success, -1 - failure
*/
int (*start)(sal_conn_t *c);
/**
* Send data via module.
* This function does not return until all data sent.
*
* @param[in] fd - the file descripter to operate on.
* @param[in] data - pointer to data to send.
* @param[in] len - length of the data.
* @param[in] remote_ip - remote ip address (optional).
* @param[in] remote_port - remote port number (optional).
* @param[in] timeout - packet send timeout (ms)
* @return 0 - success, -1 - failure
*/
int (*send)(int fd, uint8_t *data, uint32_t len,
char remote_ip[16], int32_t remote_port, int32_t timeout);
int (*recv)(int fd, uint8_t *data, uint32_t len,
char remote_ip[16], int32_t remote_port);
/**
* Get IP information of the corresponding domain.
* Currently only one IP string is returned (even when the domain
* coresponses to mutliple IPs). Note: only IPv4 is supported.
*
* @param[in] domain - the domain string.
* @param[out] ip - the place to hold the dot-formatted ip string.
*
* @return 0 - success, -1 - failure
*/
int (*domain_to_ip)(char *domain, char ip[16]);
/**
* Close the socket connection.
*
* @param[in] fd - the file descripter to operate on.
* @param[in] remote_port - remote port number (optional).
*
* @return 0 - success, -1 - failure
*/
int (*close)(int fd, int32_t remote_port);
/**
* Destroy SAL or exit low level state if necessary.
*
* @return 0 - success, -1 - failure
*/
int (*deinit)(void);
/**
* Register network connection data input function
* Input data from module.
* This callback should be called when the data is received from the module
* It should tell the sal where the data comes from.
* @param[in] fd - the file descripter to operate on.
* @param[in] data - the received data.
* @param[in] len - expected length of the data when IN,
* and real read len when OUT.
* @param[in] addr - remote ip address. Caller manages the
memory (optional).
* @param[in] port - remote port number (optional).
*
* @return 0 - success, -1 - failure
*/
int (*register_netconn_data_input_cb)(netconn_data_input_cb_t cb);
} sal_op_t;
/**
* Register a module instance to the SAL
*
* @param[in] module the module instance
**/
int sal_module_register(sal_op_t *module);
/**
* Module low level init so that it's ready to setup socket connection.
*
* @return 0 - success, -1 - failure
*/
int sal_module_init(void);
/**
* Start a socket connection via module.
*
* @param[in] conn - connect parameters which are used to setup
* the socket connection.
*
* @return 0 - success, -1 - failure
*/
int sal_module_start(sal_conn_t *conn);
/**
* Send data via module.
* This function does not return until all data sent.
*
* @param[in] fd - the file descripter to operate on.
* @param[in] data - pointer to data to send.
* @param[in] len - length of the data.
* @param[in] remote_ip - remote port number (optional).
* @param[in] remote_port - remote port number (optional).
*
* @return 0 - success, -1 - failure
*/
int sal_module_send(int fd, uint8_t *data, uint32_t len, char remote_ip[16],
int32_t remote_port, int32_t timeout);
/**
* Get IP information of the corresponding domain.
* Currently only one IP string is returned (even when the domain
* coresponses to mutliple IPs). Note: only IPv4 is supported.
*
* @param[in] domain - the domain string.
* @param[out] ip - the place to hold the dot-formatted ip string.
*
* @return 0 - success, -1 - failure
*/
int sal_module_domain_to_ip(char *domain, char ip[16]);
/**
* Close the socket connection.
*
* @param[in] fd - the file descripter to operate on.
* @param[in] remote_port - remote port number (optional).
*
* @return 0 - success, -1 - failure
*/
int sal_module_close(int fd, int32_t remote_port);
/**
* Destroy SAL or exit low level state if necessary.
*
* @return 0 - success, -1 - failure
*/
int sal_module_deinit(void);
/**
* Register network connection data input function
* Input data from module.
* This callback should be called when the data is received from the module
* It should tell the sal where the data comes from.
* @param[in] fd - the file descripter to operate on.
* @param[in] data - the received data.
* @param[in] len - expected length of the data when IN,
* and real read len when OUT.
* @param[in] addr - remote ip address. Caller manages the
memory (optional).
* @param[in] port - remote port number (optional).
*
* @return 0 - success, -1 - failure
*/
int sal_module_register_netconn_data_input_cb(netconn_data_input_cb_t cb);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef SAL_ARCH_H
#define SAL_ARCH_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif
/* Define generic types used in sal */
#if !SAL_NO_STDINT_H
#include <stdint.h>
typedef uint8_t u8_t;
typedef int8_t s8_t;
typedef uint16_t u16_t;
typedef int16_t s16_t;
typedef uint32_t u32_t;
typedef int32_t s32_t;
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef SAL_DEF_H
#define SAL_DEF_H
#ifdef __cplusplus
extern "C" {
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define sal_htons(x) (x)
#define sal_ntohs(x) (x)
#define sal_htonl(x) (x)
#define sal_ntohl(x) (x)
#else
#define sal_htons(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
#define sal_ntohs(x) sal_htons(x)
#define sal_htonl(x) ((((x) & 0xff) << 24) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff0000UL) >> 8) | \
(((x) & 0xff000000UL) >> 24))
#define sal_ntohl(x) sal_htonl(x)
#endif
#define htons(x) sal_htons(x)
#define ntohs(x) sal_ntohs(x)
#define htonl(x) sal_htonl(x)
#define ntohl(x) sal_ntohl(x)
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,185 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _ERR_H_
#define _ERR_H_
#include <stdint.h>
typedef int8_t err_t;
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#ifndef errno
extern int errno;
#endif
/** Definitions for error constants. */
typedef enum {
/** No error, everything OK. */
ERR_OK = 0,
/** Out of memory error. */
ERR_MEM = -1,
/** Buffer error. */
ERR_BUF = -2,
/** Timeout. */
ERR_TIMEOUT = -3,
/** Routing problem. */
ERR_RTE = -4,
/** Operation in progress */
ERR_INPROGRESS = -5,
/** Illegal value. */
ERR_VAL = -6,
/** Operation would block. */
ERR_WOULDBLOCK = -7,
/** Address in use. */
ERR_USE = -8,
/** Already connecting. */
ERR_ALREADY = -9,
/** Conn already established.*/
ERR_ISCONN = -10,
/** Not connected. */
ERR_CONN = -11,
/** Low-level netif error */
ERR_IF = -12,
/** Connection aborted. */
ERR_ABRT = -13,
/** Connection reset. */
ERR_RST = -14,
/** Connection closed. */
ERR_CLSD = -15,
/** Illegal argument. */
ERR_ARG = -16
} err_enum_t;
const char *sal_strerr(err_t err);
int err_to_errno(err_t err);
#endif

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _SAL_IPADDR_H_
#define _SAL_IPADDR_H_
#ifdef __cplusplus
extern "C" {
#endif
/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED
to prevent this code from redefining it. */
#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED)
typedef u32_t in_addr_t;
#endif
struct in_addr {
in_addr_t s_addr;
};
struct in6_addr {
union {
u32_t u32_addr[4];
u8_t u8_addr[16];
} un;
#define s6_addr un.u8_addr
};
enum sal_ip_addr_type {
/** IPv4 */
IPADDR_TYPE_V4 = 0U,
/** IPv6 */
IPADDR_TYPE_V6 = 6U,
/** IPv4+IPv6 ("dual-stack") */
IPADDR_TYPE_ANY = 46U
};
typedef struct ip4_addr {
u32_t addr;
} ip4_addr_t;
typedef struct ip6_addr {
u32_t addr[4];
} ip6_addr_t;
typedef struct _ip_addr {
union {
ip6_addr_t ip6;
ip4_addr_t ip4;
} u_addr;
/** @ref sal_ip_addr_type */
u8_t type;
} ip_addr_t;
/** 255.255.255.255 */
#define IPADDR_NONE ((u32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((u32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
/** 255.255.255.255 */
#define IPADDR_NONE ((u32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((u32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
/** 255.255.255.255 */
#define INADDR_NONE IPADDR_NONE
/** 127.0.0.1 */
#define INADDR_LOOPBACK IPADDR_LOOPBACK
/** 0.0.0.0 */
#define INADDR_ANY IPADDR_ANY
/** 255.255.255.255 */
#define INADDR_BROADCAST IPADDR_BROADCAST
#define IPADDR_BROADCAST_STRING "255.255.255.255"
in_addr_t ipaddr_addr(const char *cp);
int ip4addr_aton(const char *cp, ip4_addr_t *addr);
char *ip4addr_ntoa(const ip4_addr_t *addr);
#define inet_addr(cp) ipaddr_addr(cp)
#define inet_aton(cp,addr) ip4addr_aton(cp,(ip4_addr_t*)addr)
#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr))
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,325 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _SAL_SOCKET_H_
#define _SAL_SOCKET_H_
#include <stddef.h> /* for size_t */
#include <sys/time.h>
#include <sys/select.h>
#ifdef __cplusplus
extern "C" {
#endif
#define AF_UNSPEC 0
#define AF_INET 2
#define AF_INET6 10
#define PF_INET AF_INET
#define PF_INET6 AF_INET6
#define PF_UNSPEC AF_UNSPEC
#define IPPROTO_IP 0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
/* Socket protocol types (TCP/UDP/RAW) */
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define IP_MULTICAST_TTL 5
#define IP_MULTICAST_IF 6
#define IP_MULTICAST_LOOP 7
/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED
to prevent this code from redefining it. */
#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED)
typedef u8_t sa_family_t;
#endif
/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED
to prevent this code from redefining it. */
#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED)
typedef u16_t in_port_t;
#endif
#define DNS_MAX_NAME_LENGTH 256
struct sockaddr {
u8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
/* members are in network byte order */
struct sockaddr_in {
u8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
#define SIN_ZERO_LEN 8
char sin_zero[SIN_ZERO_LEN];
};
struct sockaddr_in6 {
u8_t sin6_len; /* length of this structure */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* Transport layer port # */
u32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
u32_t sin6_scope_id; /* Set of interfaces for scope */
};
/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED
to prevent this code from redefining it. */
#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED)
typedef u32_t socklen_t;
#endif
struct hostent {
char *h_name; /* Official name of the host. */
char **h_aliases; /* A pointer to an array of pointers to alternative
host names, terminated by a null pointer. */
int h_addrtype; /* Address type. */
int h_length; /* The length, in bytes, of the address. */
char **h_addr_list; /* A pointer to an array of pointers to network
addresses (in network byte order) for the host,
terminated by a null pointer. */
#define h_addr h_addr_list[0] /* for backward compatibility */
};
struct addrinfo {
int ai_flags; /* Input flags. */
int ai_family; /* Address family of socket. */
int ai_socktype; /* Socket type. */
int ai_protocol; /* Protocol of socket. */
socklen_t ai_addrlen; /* Length of socket address. */
struct sockaddr *ai_addr; /* Socket address of socket. */
char *ai_canonname; /* Canonical name of service location. */
struct addrinfo *ai_next; /* Pointer to next in list. */
};
#define SOL_SOCKET 0xfff /* options for socket level */
#define IPPROTO_IP 0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define IPPROTO_IPV6 41
#define IPPROTO_ICMPV6 58
#define IPPROTO_UDPLITE 136
#define IPPROTO_RAW 255
/* Flags we can use with send and recv. */
#define MSG_PEEK 0x01 /* Peeks at an incoming message */
#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */
#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */
#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */
#define MSG_MORE 0x10 /* Sender will send more */
#define MEMP_NUM_NETCONN 5//(MAX_SOCKETS_TCP + MAX_LISTENING_SOCKETS_TCP + MAX_SOCKETS_UDP)
#ifndef SAL_SOCKET_OFFSET
#define SAL_SOCKET_OFFSET 0
#endif
/* FD_SET used for event_select */
#ifndef FD_SET
#undef FD_SETSIZE
/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */
#define FD_SETSIZE MEMP_NUM_NETCONN
#define FDSETSAFESET(n, code) do { \
if (((n) - SAL_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - SAL_SOCKET_OFFSET) >= 0)) { \
code; }} while(0)
#define FDSETSAFEGET(n, code) (((n) - SAL_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - SAL_SOCKET_OFFSET) >= 0) ?\
(code) : 0)
#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-SAL_SOCKET_OFFSET)/8] |= (1 << (((n)-SAL_SOCKET_OFFSET) & 7)))
#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-SAL_SOCKET_OFFSET)/8] &= ~(1 << (((n)-SAL_SOCKET_OFFSET) & 7)))
#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-SAL_SOCKET_OFFSET)/8] & (1 << (((n)-SAL_SOCKET_OFFSET) & 7)))
#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p)))
typedef struct fd_set {
unsigned char fd_bits [(FD_SETSIZE * 2 + 7) / 8];
} fd_set;
#elif SAL_SOCKET_OFFSET
#error SAL_SOCKET_OFFSET does not work with external FD_SET!
#else
#include <fcntl.h>
#endif /* FD_SET */
/*
* Options and types related to multicast membership
*/
#define IP_ADD_MEMBERSHIP 3
#define IP_DROP_MEMBERSHIP 4
#define IP_MULTICAST_TTL 5
#define IP_MULTICAST_IF 6
#define IP_MULTICAST_LOOP 7
typedef struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
} ip_mreq;
/*
* Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
*/
#define SO_REUSEADDR 0x0004 /* Allow local address reuse */
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*
* Additional options, not kept in so_options.
*/
#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
#define SO_LINGER 0x0080 /* linger on close if data present */
#define SO_DONTLINGER ((int)(~SO_LINGER))
#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */
#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */
#define SO_RCVBUF 0x1002 /* receive buffer size */
#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */
#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */
#define SO_SNDTIMEO 0x1005 /* send timeout */
#define SO_RCVTIMEO 0x1006 /* receive timeout */
#define SO_ERROR 0x1007 /* get error status and clear */
#define SO_TYPE 0x1008 /* get socket type */
#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */
#define SO_NO_CHECK 0x100a /* don't create UDP checksum */
const void *ur_adapter_get_default_ipaddr(void);
const void *ur_adapter_get_mcast_ipaddr(void);
int sal_select(int maxfdp1, fd_set *readset, fd_set *writeset,
fd_set *exceptset, struct timeval *timeout);
int sal_socket(int domain, int type, int protocol);
int sal_write(int s, const void *data, size_t size);
int sal_connect(int s, const struct sockaddr *name, socklen_t namelen);
int sal_bind(int s, const struct sockaddr *name, socklen_t namelen);
int sal_eventfd(unsigned int initval, int flags);
int sal_setsockopt(int s, int level, int optname,
const void *optval, socklen_t optlen);
int sal_getsockopt(int s, int level, int optname,
void *optval, socklen_t *optlen);
struct hostent *sal_gethostbyname(const char *name);
int sal_close(int s);
int sal_init(void);
int sal_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
int sal_send(int s, const void *data, size_t size, int flags);
int sal_shutdown(int s, int how);
int sal_recvfrom(int s, void *mem, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
int sal_recv(int s, void *mem, size_t len, int flags);
int sal_read(int s, void *mem, size_t len);
void sal_freeaddrinfo(struct addrinfo *ai);
int sal_getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
void sal_freeaddrinfo(struct addrinfo *ai);
int sal_shutdown(int s, int how);
int sal_getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
int sal_fcntl(int s, int cmd, int val);
#define select(maxfdp1,readset,writeset,exceptset,timeout) \
sal_select(maxfdp1,readset,writeset,exceptset,timeout)
#define write(s,data,size) \
sal_write(s,data,size)
#define socket(domain,type,protocol) \
sal_socket(domain,type,protocol)
#define connect(s,name,namelen) \
sal_connect(s,name,namelen)
#define bind(s,name,namelen) \
sal_bind(s,name,namelen)
#define shutdown(s,how) \
sal_shutdown(s,how)
#define eventfd(initval,flags) \
sal_eventfd(initval,flags)
#define setsockopt(s,level,optname,optval,optlen) \
sal_setsockopt(s,level,optname,optval,optlen)
#define getsockopt(s,level,optname,optval,optlen) \
sal_getsockopt(s,level,optname,optval,optlen)
#define gethostbyname(name) \
sal_gethostbyname(name)
#define close(s) \
sal_close(s)
#define sendto(s,dataptr,size,flags,to,tolen) \
sal_sendto(s,dataptr,size,flags,to,tolen)
#define recvfrom(s,mem,len,flags,from,fromlen) \
sal_recvfrom(s,mem,len,flags,from,fromlen)
#define send(s,data,size,flags) \
sal_send(s,data,size,flags)
#define recv(s,data,size,flags) \
sal_recv(s,data,size,flags)
#define read(s,data,size) \
sal_read(s,data,size)
#define freeaddrinfo(addrinfo) sal_freeaddrinfo(addrinfo)
#define getaddrinfo(nodname, servname, hints, res) \
sal_getaddrinfo(nodname, servname, hints, res)
#define fcntl(s,cmd,val) sal_fcntl(s,cmd,val)
#define inet_ntop(af,src,dst,size) \
(((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL)
#define inet_pton(af,src,dst) \
(((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0)
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,222 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "internal/sal_sockets_internal.h"
/* Here for now until needed in other places in lwIP */
#ifndef isprint
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
#define isprint(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#endif
/**
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
* @param addr pointer to which to save the ip address in network order
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
ip4addr_aton(const char *cp, ip4_addr_t *addr)
{
u32_t val;
u8_t base;
char c;
u32_t parts[4];
u32_t *pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, 1-9=decimal.
*/
if (!isdigit(c)) {
return 0;
}
val = 0;
base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X') {
base = 16;
c = *++cp;
} else {
base = 8;
}
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else {
break;
}
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3) {
return 0;
}
*pp++ = val;
c = *++cp;
} else {
break;
}
}
/*
* Check for trailing characters.
*/
if (c != '\0' && !isspace(c)) {
return 0;
}
/*
* Concoct the address according to
* the number of parts specified.
*/
switch (pp - parts + 1) {
case 0:
return 0; /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffUL) {
return 0;
}
if (parts[0] > 0xff) {
return 0;
}
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff) {
return 0;
}
if ((parts[0] > 0xff) || (parts[1] > 0xff)) {
return 0;
}
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff) {
return 0;
}
if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {
return 0;
}
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
default:
SAL_ASSERT("unhandled", 0);
break;
}
if (addr) {
ip4_addr_set_u32(addr, sal_htonl(val));
}
return 1;
}
/**
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
*
* @param addr ip address in network order to convert
* @param buf target buffer where the string is stored
* @param buflen length of buf
* @return either pointer to buf which now holds the ASCII
* representation of addr or NULL if buf was too small
*/
char *
ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
{
u32_t s_addr;
char inv[3];
char *rp;
u8_t *ap;
u8_t rem;
u8_t n;
u8_t i;
int len = 0;
s_addr = ip4_addr_get_u32(addr);
rp = buf;
ap = (u8_t *)&s_addr;
for (n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
} while (*ap);
while (i--) {
if (len++ >= buflen) {
return NULL;
}
*rp++ = inv[i];
}
if (len++ >= buflen) {
return NULL;
}
*rp++ = '.';
ap++;
}
*--rp = 0;
return buf;
}
/**
* Convert numeric IP address into decimal dotted ASCII representation.
* returns ptr to static buffer; not reentrant!
*
* @param addr ip address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* representation of addr
*/
char *
ip4addr_ntoa(const ip4_addr_t *addr)
{
static char str[SAL_SOCKET_IP4_ADDR_LEN];
return ip4addr_ntoa_r(addr, str, SAL_SOCKET_IP4_ADDR_LEN);
}
/**
* Ascii internet address interpretation routine.
* The value returned is in network order.
*
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
* @return ip address in network order
*/
in_addr_t
ipaddr_addr(const char *cp)
{
ip4_addr_t val;
if (ip4addr_aton(cp, &val)) {
return ip4_addr_get_u32(&val);
}
return (IPADDR_NONE);
}

207
Living_SDK/device/sal/sal.c Normal file
View file

@ -0,0 +1,207 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <aos/aos.h>
#include <sal_arch.h>
#include <sal_ipaddr.h>
#include <sal.h>
#define TAG "sal_module"
sal_op_t *g_sal_module = NULL;
int sal_module_register(sal_op_t *module)
{
if (NULL == module){
LOGE(TAG, "sal module register invalid input\n");
return -1;
}
if (NULL != g_sal_module){
LOGE(TAG, "sal module have already registered\n");
return -1;
}
g_sal_module = module;
return 0;
}
int sal_module_init(void)
{
int err = 0;
if (NULL == g_sal_module){
LOGI(TAG, "sal module init fail for there is no sal module registered yet \n");
return 0;
}
if (NULL == g_sal_module->init){
LOGE(TAG, "init function in sal module is null \n");
return -1;
}
/*show we deinit module at first ?*/
err = g_sal_module->init();
if (err){
LOGE(TAG, "module init fail\n");
}
return err;
}
int sal_module_deinit(void)
{
int err = 0;
if (NULL == g_sal_module){
LOGE(TAG, "sal module deinit fail for there is no sal module registered yet \n");
return -1;
}
if (NULL == g_sal_module->deinit){
LOGE(TAG, "deinit function in sal module is null \n");
return -1;
}
err = g_sal_module->deinit();
if (err){
LOGE(TAG, "module deinit fail\n");
}
return err;
}
int sal_module_start(sal_conn_t *conn)
{
int err = 0;
if (NULL == g_sal_module){
LOGE(TAG, "sal module start fail for there is no sal module registered yet \n");
return -1;
}
if (NULL == g_sal_module->start){
LOGE(TAG, "start function in sal module is null \n");
return -1;
}
if (NULL == conn){
LOGE(TAG, "invalid input\n");
return -1;
}
err = g_sal_module->start(conn);
if (err){
LOGE(TAG, "module start fail err=%d\n", err);
}
return err;
}
int sal_module_close(int fd, int32_t remote_port)
{
int err = 0;
if (NULL == g_sal_module){
LOGE(TAG, "sal module close fail for there is no sal module registered yet \n");
return -1;
}
if (NULL == g_sal_module->close){
LOGE(TAG, "close function in sal module is null \n");
return -1;
}
err = g_sal_module->close(fd, remote_port);
if (err){
LOGD(TAG, "module close fail err=%d\n", err);
}
return err;
}
int sal_module_send(int fd, uint8_t *data, uint32_t len,
char remote_ip[16], int32_t remote_port, int32_t timeout)
{
int err = 0;
if (NULL == g_sal_module){
LOGE(TAG, "sal module send fail for there is no sal module registered yet \n");
return -1;
}
if (NULL == g_sal_module->send){
LOGE(TAG, "send function in sal module is null \n");
return -1;
}
if (NULL == data){
LOGE(TAG, "invalid input\n");
return -1;
}
err = g_sal_module->send(fd, data, len, remote_ip, remote_port, timeout);
if (err){
LOGE(TAG, "module send fail err=%d\n", err);
}
return err;
}
int sal_module_domain_to_ip(char *domain, char ip[16])
{
int err = 0;
if (NULL == g_sal_module){
LOGE(TAG, "sal module domain_to_ip fail for there is no sal module registered yet \n");
return -1;
}
if (NULL == g_sal_module->domain_to_ip){
LOGE(TAG, "domai_to_ip function in sal module is null \n");
return -1;
}
if (NULL == domain){
LOGE(TAG, "invalid input\n");
return -1;
}
err = g_sal_module->domain_to_ip(domain, ip);
if (err){
LOGE(TAG, "module domain_to_ip fail err=%d\n", err);
}
return err;
}
int sal_module_register_netconn_data_input_cb(netconn_data_input_cb_t cb)
{
int err = 0;
if (NULL == g_sal_module){
LOGE(TAG, "sal module recv fail for there is no sal module registered yet \n");
return -1;
}
if (NULL == g_sal_module->register_netconn_data_input_cb){
LOGE(TAG, "recv function in sal module is null \n");
return -1;
}
err = g_sal_module->register_netconn_data_input_cb(cb);
if (err){
LOGE(TAG, "module recv fail err=%d\n", err);
}
return err;
}

View file

@ -0,0 +1,16 @@
NAME := sal
$(NAME)_TYPE := kernel
ifneq (1,$(at_adapter))
GLOBAL_DEFINES += WITH_SAL # for sal general use
$(NAME)_SOURCES := sal_sockets.c sal_err.c sal_arch.c ip4_addr.c sal.c sal_device.c
GLOBAL_INCLUDES += ./include
endif
ifeq (wifi.gt202,$(module))
$(NAME)_COMPONENTS += sal.wifi.gt202
else ifeq (wifi.mk3060,$(module))
$(NAME)_COMPONENTS += sal.wifi.mk3060
else ifeq (gprs.sim800,$(module))
$(NAME)_COMPONENTS += sal.gprs.sim800
endif

View file

@ -0,0 +1,358 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/* system includes */
#include <aos/aos.h>
#include "sal_err.h"
#include "sal_arch.h"
#include "internal/sal_arch_internal.h"
static aos_mutex_t sal_arch_mutex;
//#define NET_TASK_NUME 2
//#define NET_TASK_STACK_SIZE 1024
//ktask_t g_net_task[NET_TASK_NUME];
//cpu_stack_t g_net_task_stack[NET_TASK_NUME][NET_TASK_STACK_SIZE];
/*-----------------------------------------------------------------------------------*/
/*
err_t sal_sem_new(sal_sem_t *sem, uint8_t count)
Creates a new semaphore.
*/
err_t sal_sem_new(sal_sem_t *sem, uint8_t count)
{
err_t ret = ERR_MEM;
int stat = aos_sem_new(sem, count);
if (stat == 0) {
ret = ERR_OK;
}
return ret;
}
/*-----------------------------------------------------------------------------------*/
/*
void sal_sem_free(sal_sem_t *sem)
Deallocates a semaphore.
*/
void sal_sem_free(sal_sem_t *sem)
{
if ((sem != NULL)) {
aos_sem_free(sem);
}
}
/*-----------------------------------------------------------------------------------*/
/*
void sal_sem_signal(sal_sem_t *sem)
Signals a semaphore.
*/
void sal_sem_signal(sal_sem_t *sem)
{
aos_sem_signal(sem);
}
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds).
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SAL_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that SAL implements a function with a similar name,
sal_sem_wait(), that uses the sal_arch_sem_wait() function.
*/
uint32_t sal_arch_sem_wait(sal_sem_t *sem, uint32_t timeout)
{
uint32_t begin_ms, end_ms, elapsed_ms;
uint32_t ret;
if (sem == NULL) {
return SAL_ARCH_TIMEOUT;
}
begin_ms = sal_now();
if ( timeout != 0UL ) {
ret = aos_sem_wait(sem, timeout);
if (ret == 0) {
end_ms = sal_now();
elapsed_ms = end_ms - begin_ms;
ret = elapsed_ms;
} else {
ret = SAL_ARCH_TIMEOUT;
}
} else {
while ( !(aos_sem_wait(sem, AOS_WAIT_FOREVER) == 0));
end_ms = sal_now();
elapsed_ms = end_ms - begin_ms;
if ( elapsed_ms == 0UL ) {
elapsed_ms = 1UL;
}
ret = elapsed_ms;
}
return ret;
}
/*-----------------------------------------------------------------------------------*/
/*
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Creates an empty mailbox for maximum "size" elements.
*/
err_t sal_mbox_new(sal_mbox_t *mb, int size)
{
void *msg_start;
err_t ret = ERR_MEM;
msg_start = (void*)aos_malloc(size * sizeof(void *));
if (msg_start == NULL) {
return ERR_MEM;
}
int stat = aos_queue_new(mb,msg_start,size * sizeof(void *),sizeof(void *));
if (stat == 0) {
ret = ERR_OK;
}
return ret;
}
/*-----------------------------------------------------------------------------------*/
/*
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
*/
void sal_mbox_free(sal_mbox_t *mb)
{
void *start;
if ((mb != NULL)) {
start = aos_queue_buf_ptr(mb);
if(start != NULL)
aos_free(start);
aos_queue_free(mb);
}
}
/*-----------------------------------------------------------------------------------*/
/*
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
Posts the "msg" to the mailbox. This function have to block until the "msg" is really posted.
*/
void sal_mbox_post(sal_mbox_t *mb, void *msg)
{
aos_queue_send(mb,&msg,sizeof(void*));
}
/*
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one is full, else, ERR_OK if the "msg" is posted.
*/
err_t sal_mbox_trypost(sal_mbox_t *mb, void *msg)
{
if (aos_queue_send(mb,&msg,sizeof(void*)) != 0)
return ERR_MEM;
else
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
*/
u32_t sal_arch_mbox_fetch(sal_mbox_t *mb, void **msg, u32_t timeout)
{
u32_t begin_ms, end_ms, elapsed_ms;
u32_t len;
u32_t ret;
if (mb == NULL)
return SAL_ARCH_TIMEOUT;
begin_ms = sal_now();
if( timeout != 0UL ) {
if(aos_queue_recv(mb,timeout,msg,&len) == 0) {
end_ms = sal_now();
elapsed_ms = end_ms - begin_ms;
ret = elapsed_ms;
} else {
ret = SAL_ARCH_TIMEOUT;
}
} else {
while(aos_queue_recv(mb,AOS_WAIT_FOREVER,msg,&len) != 0);
end_ms = sal_now();
elapsed_ms = end_ms - begin_ms;
if( elapsed_ms == 0UL ) {
elapsed_ms = 1UL;
}
ret = elapsed_ms;
}
return ret;
}
/*
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
similar to sys_arch_mbox_fetch, however if a message is not present in the mailbox,
it immediately returns with the code SAL_MBOX_EMPTY.
*/
u32_t sal_arch_mbox_tryfetch(sal_mbox_t *mb, void **msg)
{
u32_t len;
if(aos_queue_recv(mb,0u,msg,&len) != 0 ) {
return SAL_MBOX_EMPTY;
} else {
return ERR_OK;
}
}
/** Create a new mutex
* @param mutex pointer to the mutex to create
* @return a new mutex
*
**/
err_t sal_mutex_new(sal_mutex_t *mutex)
{
err_t ret = ERR_MEM;
int stat = aos_mutex_new(mutex);
if (stat == 0) {
ret = ERR_OK;
}
return ret;
}
/** Lock a mutex
* @param mutex the mutex to lock
**/
void sal_mutex_lock(sal_mutex_t *mutex)
{
aos_mutex_lock(mutex, AOS_WAIT_FOREVER);
}
/** Unlock a mutex
* @param mutex the mutex to unlock */
void sal_mutex_unlock(sal_mutex_t *mutex)
{
aos_mutex_unlock(mutex);
}
/** Delete a semaphore
* @param mutex the mutex to delete
**/
void sal_mutex_free(sal_mutex_t *mutex)
{
aos_mutex_free(mutex);
}
/*
uint32_t sal_now(void)
This optional function returns the current time in milliseconds (don't care for wraparound,
this is only used for time diffs).
*/
uint32_t sal_now(void)
{
return aos_now_ms();
}
#if SAL_LIGHTWEIGHT_PROT
/*
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sal_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sal_arch_protect() is only required if your port is supporting an operating
system.
*/
sal_prot_t sal_arch_protect(void)
{
aos_mutex_lock(&sal_arch_mutex, AOS_WAIT_FOREVER);
return 0;
}
/*
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sal_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
*/
void sal_arch_unprotect(sal_prot_t pval)
{
aos_mutex_unlock(&sal_arch_mutex);
}
#endif
/*
* Prints an assertion messages and aborts execution.
*/
void sal_arch_assert(const char *file, int line)
{
}
/*
void sal_mutet_init(void)
Is called to initialize the sal_arch layer.
*/
void sal_mutex_arch_init(void)
{
aos_mutex_new(&sal_arch_mutex);
}
void sal_mutex_arch_free(void)
{
aos_mutex_free(&sal_arch_mutex);
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <aos/aos.h>
#define TAG "SAL_DEVICE"
#ifdef DEV_SAL_MK3060
extern int mk3060_sal_init(void);
#endif
int sal_device_init()
{
int ret = 0;
#ifdef DEV_SAL_MK3060
ret = mk3060_sal_init();
#endif
#ifdef DEV_SAL_GT202
ret = gt202_sal_init();
#endif
#ifdef DEV_SAL_SIM800
extern int sim800_sal_init(void);
ret = sim800_sal_init();
#endif
if (ret){
LOGE(TAG, "device init fail ret is %d\n", ret);
}
return ret;
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "sal_err.h"
/** Table to quickly map an sal error (err_t) to a socket error
* by using -err as an index */
static const int err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ALREADY -9 Already connecting. */
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
ENOTCONN, /* ERR_CONN -11 Not connected. */
-1, /* ERR_IF -12 Low-level netif error */
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
ECONNRESET, /* ERR_RST -14 Connection reset. */
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
EIO /* ERR_ARG -16 Illegal argument. */
};
#ifdef SAL_DEBUG
static const char *err_strerr[] = {
"Ok.", /* ERR_OK 0 */
"Out of memory error.", /* ERR_MEM -1 */
"Buffer error.", /* ERR_BUF -2 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Routing problem.", /* ERR_RTE -4 */
"Operation in progress.", /* ERR_INPROGRESS -5 */
"Illegal value.", /* ERR_VAL -6 */
"Operation would block.", /* ERR_WOULDBLOCK -7 */
"Address in use.", /* ERR_USE -8 */
"Already connecting.", /* ERR_ALREADY -9 */
"Already connected.", /* ERR_ISCONN -10 */
"Not connected.", /* ERR_CONN -11 */
"Low-level netif error.", /* ERR_IF -12 */
"Connection aborted.", /* ERR_ABRT -13 */
"Connection reset.", /* ERR_RST -14 */
"Connection closed.", /* ERR_CLSD -15 */
"Illegal argument." /* ERR_ARG -16 */
};
/**
* Convert an lwip internal error to a string representation.
*
* @param err an lwip internal err_t
* @return a string representation for err
*/
const char *
sal_strerr(err_t err)
{
if ((err > 0) || (-err >= (err_t)sizeof(err_strerr))) {
return "Unknown error.";
}
return err_strerr[-err];
}
#endif
int
err_to_errno(err_t err)
{
if ((err > 0) || (-err >= (err_t)sizeof(err_to_errno_table))) {
return EIO;
}
return err_to_errno_table[-err];
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
src = Split('''
sal_sockets.c
sal_err.c
sal_arch.c
ip4_addr.c
sal.c
sal_device.c
''')
component = aos_component('sal', src)
component.add_comp_deps('device/sal/wifi/mk3060')
component.add_global_includes('include')
component.add_global_macros('WITH_SAL')

View file

@ -0,0 +1,7 @@
NAME := sal_modulue_gt202
#$(NAME)_COMPONENTS += atparser
$(NAME)_SOURCES += gt202_sal.c
GLOBAL_DEFINES += DEV_SAL_GT202

View file

@ -0,0 +1,405 @@
#include <stdio.h>
#include <stddef.h>
#include <aos/kernel.h>
#include "qcom_api.h"
#include "sal.h"
#define CONN_LIST_MAX (10)
#define QCOM_SELECT_TIMEOUT (10)
// Convert IP address in uint32_t to comma separated bytes
#define UINT32_IPADDR_TO_CSV_BYTES(a) (((a) >> 24) & 0xFF), (((a) >> 16) & 0xFF), (((a) >> 8) & 0xFF), ((a)&0xFF)
// Convert comma separated bytes to a uint32_t IP address
#define CSV_BYTES_TO_UINT32_IPADDR(a0, a1, a2, a3) (((uint32_t)(a0)&0xFF) << 24) | (((uint32_t)(a1)&0xFF) << 16) | (((uint32_t)(a2)&0xFF) << 8) | ((uint32_t)(a3)&0xFF)
typedef struct {
int fd;
int qcom_socket;
}SocketFDMap;
static SocketFDMap sock_list[CONN_LIST_MAX];
static netconn_data_input_cb_t g_netconn_data_input_cb;
static int sal_qcom_init(void)
{
return 0;
}
static int remove_sock_form_list_by_fd(int fd)
{
int i;
for(i=0; i<CONN_LIST_MAX; i++)
{
if(sock_list[i].fd == fd)
{
sock_list[i].fd = -1;
sock_list[i].qcom_socket = -1;
}
}
return 0;
}
static int remove_sock_form_list_by_qsock(int socket)
{
int i;
for(i=0; i<CONN_LIST_MAX; i++)
{
if(sock_list[i].qcom_socket == socket)
{
sock_list[i].fd = -1;
sock_list[i].qcom_socket = -1;
}
}
return 0;
}
static int add_sock_to_list(int fd, int sock)
{
int i;
for(i=0; i<CONN_LIST_MAX; i++)
{
if(sock_list[i].qcom_socket < 0)
{
sock_list[i].fd = fd;
sock_list[i].qcom_socket = sock;
return 0;
}
}
return 1;
}
static int fd_to_socket(int fd)
{
int i;
for(i=0; i<CONN_LIST_MAX; i++)
{
if(sock_list[i].fd == fd)
{
return sock_list[i].qcom_socket;
}
}
return -1;
}
static int socket_to_fd(int socket)
{
int i;
for(i=0; i<CONN_LIST_MAX; i++)
{
if(sock_list[i].qcom_socket == socket)
{
return sock_list[i].fd;
}
}
return -1;
}
static int sal_qcom_domain_to_ip(char *domain, char ip[16])
{
uint32_t addr = 0;
A_STATUS status;
PRINTF("DNS Request %s\r\n", domain);
if (strcmp(domain, "public.iot-as-mqtt.cn-shanghai.aliyuncs.com") == 0) {
/* Workaround DNS */
PRINTF("Work around DNS\r\n");
strcpy(ip, "139.196.135.135");
return 0;
}
if (strcmp(domain, "iotx-ota.oss-cn-shanghai.aliyuncs.com") == 0) {
PRINTF("Work around DNS\r\n");
strcpy(ip, "106.14.228.182");
return 0;
}
// NOTE: This function returns the address in reverse byte order
status = qcom_dnsc_get_host_by_name((char *)domain, &addr);
PRINTF("DNS Resolve %d, status = %d\r\n", addr, status);
if (status == 0)
{
int len = snprintf(ip, 16, "%d.%d.%d.%d", UINT32_IPADDR_TO_CSV_BYTES(addr));
ip[len] = 0;
PRINTF("Looked up %s as %d.%d.%d.%d\r\n", domain, UINT32_IPADDR_TO_CSV_BYTES(addr));
}
return status;
}
int sal_qcom_start(sal_conn_t *c)
{
int sock, ret;
SOCKADDR_T l_addr, r_addr;
memset(&l_addr, 0, sizeof(l_addr));
memset(&r_addr, 0, sizeof(r_addr));
A_STATUS status;
if(!c || !c->addr)
{
PRINTF("sal_qcom_start paramter error\r\n");
return 1;
}
PRINTF("sal_qcom_start %s\r\n", c->addr);
// NOTE: This function returns the address in reverse byte order
status = qcom_dnsc_get_host_by_name(c->addr, (uint32_t*)&r_addr.sin_addr.s_addr);
if(status != A_OK)
{
/*domain resolve failed, try to use IP directly */
int a0, a1, a2, a3;
ret = sscanf(c->addr, "%d.%d.%d.%d", &a0, &a1, &a2, &a3);
if(ret == 4)
{
r_addr.sin_addr.s_addr = CSV_BYTES_TO_UINT32_IPADDR(a0, a1, a2, a3);
}
else
{
return 1;
}
}
switch(c->type)
{
case TCP_CLIENT:
case TCP_SERVER:
sock = qcom_socket(ATH_AF_INET, SOCK_STREAM_TYPE, 0);
PRINTF("QCOM TCP SOCKET = %d\r\n", sock);
break;
case UDP_UNICAST:
case UDP_BROADCAST:
sock = qcom_socket(ATH_AF_INET, SOCK_DGRAM_TYPE, 0);
PRINTF("QCOM UDP SOCKET = %d\r\n", sock);
break;
default:
return 1;
break;
}
if(sock < 0)
{
return 1;
}
if(c->type == TCP_CLIENT || c->type == SSL_CLIENT)
{
r_addr.sin_port = c->r_port;
r_addr.sin_family = ATH_AF_INET;
status = (A_STATUS)qcom_connect(sock, (struct sockaddr *)&r_addr, sizeof(r_addr));
if(status != A_OK)
{
return 1;
}
}
if(c->type == TCP_SERVER)
{
l_addr.sin_port = c->l_port;
l_addr.sin_family = ATH_AF_INET;
l_addr.sin_addr.s_addr = CSV_BYTES_TO_UINT32_IPADDR(0, 0, 0, 0);
status = (A_STATUS)qcom_bind(sock, (struct sockaddr *)(&l_addr), sizeof(l_addr));
if(status != A_OK)
{
qcom_socket_close(sock);
return 1;
}
status = qcom_listen(sock, 1);
if(status != A_OK)
{
qcom_socket_close(sock);
return 1;
}
}
if(c->type == UDP_UNICAST || c->type == UDP_BROADCAST)
{
l_addr.sin_port = c->l_port;
l_addr.sin_family = ATH_AF_INET;
l_addr.sin_addr.s_addr = CSV_BYTES_TO_UINT32_IPADDR(0, 0, 0, 0);
status = (A_STATUS)qcom_bind(sock, (struct sockaddr *)(&l_addr), sizeof(l_addr));
if(status != A_OK)
{
qcom_socket_close(sock);
return 1;
}
}
PRINTF("sal_qcom_start c->fd = %d, socket = %d\r\n", c->fd, sock);
add_sock_to_list(c->fd, sock);
return 0;
}
static int sal_qcom_send(int fd, uint8_t *data, uint32_t len, char remote_ip[16], int32_t remote_port, int32_t timeout)
{
volatile int sent;
int qcom_socket = 0;
/* qcom driver enable ZERO_COPY, then must use custom_alloc */
uint8_t *send_buf = custom_alloc(len);
PRINTF("sal_qcom_send fd = %d, size = %d\r\n",fd, len);
qcom_socket = fd_to_socket(fd);
if(send_buf == NULL)
{
PRINTF("sal_qcom_send allocation failed\r\n");
return 1;
}
memcpy(send_buf, data, len);
/* if remote_ip, regard it as TCP send */
if(remote_ip == NULL)
{
sent = qcom_send(qcom_socket, (char*)send_buf, len, 0);
PRINTF("TCP Send return %d\r\n", sent);
}
else /* UDP send */
{
int a0, a1, a2, a3;
sscanf(remote_ip, "%d.%d.%d.%d", &a0, &a1, &a2, &a3);
SOCKADDR_T r_addr;
r_addr.sin_family = ATH_AF_INET;
r_addr.sin_port = remote_port;
r_addr.sin_addr.s_addr = CSV_BYTES_TO_UINT32_IPADDR(a0, a1, a2, a3);
PRINTF("UDP Send, %d-%d-%d-%d:%d\r\n", a0,a1,a2,a3,remote_port);
sent = qcom_sendto(qcom_socket, (char*)send_buf, len, 0, (struct sockaddr *)&r_addr, sizeof(SOCKADDR_T));
PRINTF("UDP Send return %d\r\n", sent);
}
custom_free(send_buf);
return 0;
}
static int sal_qcom_close(int fd, int32_t remote_port)
{
int sock;
sock = fd_to_socket(fd);
if (sock == -1) {
/* SOCKET close by remote */
return 0;
}
PRINTF("sal_qcom_close fd = %d, socket =%d\r\n", fd, sock);
qcom_socket_close(sock);
remove_sock_form_list_by_fd(fd);
return 0;
}
static int sal_qcom_register_netconn_data_input_cb(netconn_data_input_cb_t cb)
{
PRINTF("sal_qcom_register_netconn_data_input_cb\r\n");
if (cb)
g_netconn_data_input_cb = cb;
return 0;
}
static int sal_qcom_deinit(void)
{
return 0;
}
void sal_recv_task(void *param)
{
int i, rev_len, timeout, sock, fd;
char *recv_buf;
SOCKADDR_T r_addr;
socklen_t r_addr_len;
PRINTF("sal_recv_task starting... \r\n");
while(1)
{
for(i=0; i<CONN_LIST_MAX; i++)
{
if(sock_list[i].qcom_socket > 0)
{
sock = sock_list[i].qcom_socket;
QCA_CONTEXT_STRUCT *enetCtx = wlan_get_context();
switch(t_select(enetCtx, sock, QCOM_SELECT_TIMEOUT))
{
case A_SOCK_INVALID: /* socket err */
PRINTF("CLOSE BY REMOTE\r\n");
remove_sock_form_list_by_qsock(sock);
continue;
case A_OK:
recv_buf = NULL;
rev_len = qcom_recvfrom(sock, &recv_buf, 1400, 0, (struct sockaddr *)&r_addr, &r_addr_len);
if(rev_len >= 0)
{
fd = socket_to_fd(sock);
PRINTF("qcom_recvfrom get data %d, fd = %d, sock = %d\r\n", rev_len, fd, sock);
g_netconn_data_input_cb(fd, recv_buf, rev_len, NULL, 0);
zero_copy_free(recv_buf);
continue;
}
break;
case A_ERROR: /* timeout */
continue;
default:
break;
}
}
}
A_MDELAY(1);
}
}
static ktask_t *g_sal_task = NULL;
sal_op_t gt202_sal_op;
#define WIFI_SAL_STACK_SIZE 256
int gt202_sal_init()
{
kstat_t status;
int i = 0;
gt202_sal_op.version = "1.0.0";
gt202_sal_op.init = sal_qcom_init;
gt202_sal_op.start = sal_qcom_start;
gt202_sal_op.send = sal_qcom_send;
gt202_sal_op.deinit = sal_qcom_deinit;
gt202_sal_op.close = sal_qcom_close;
gt202_sal_op.domain_to_ip = sal_qcom_domain_to_ip;
gt202_sal_op.register_netconn_data_input_cb = sal_qcom_register_netconn_data_input_cb;
PRINTF("gt202_sal_init\r\n");
while (i < CONN_LIST_MAX) {
sock_list[i].fd = -1;
sock_list[i].qcom_socket = -1;
i++;
}
status = krhino_task_dyn_create(&g_sal_task, "WIFI SAL", 0, (AOS_DEFAULT_APP_PRI - 9), 0,
WIFI_SAL_STACK_SIZE, (task_entry_t)sal_recv_task, 1);
if(status != RHINO_SUCCESS)
{
PRINTF("WIFI SAL Task creation failed %d\r\n", status);
return 1;
}
sal_module_register(&gt202_sal_op);
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _ATCMD_CONFIG_MODULE
#define _ATCMD_CONFIG_MODULE
#include <hal/soc/soc.h>
/**
* AT related platform-dependent things are here, including:
* 1. AT command;
* 2. AT response code;
* 3. AT delimiter;
* 4. AT event;
* 5. Uart port used by AT;
* 6. ...
*/
// AT command
#define AT_CMD_ENET_SEND "AT+ENETRAWSEND"
#define AT_CMD_ENTER_ENET_MODE "AT+ENETRAWMODE=ON"
#define AT_CMD_EHCO_OFF "AT+UARTE=OFF"
#define AT_CMD_TEST "AT"
// Delimiter
#define AT_RECV_PREFIX "\r\n"
#define AT_RECV_SUCCESS_POSTFIX "OK\r\n"
#define AT_RECV_FAIL_POSTFIX "ERROR\r\n"
#define AT_SEND_DELIMITER "\r"
// AT event
#define AT_EVENT_ENET_DATA "+ENETEVENT:"
// uart config
#define AT_UART_BAUDRATE 115200
#define AT_UART_DATA_WIDTH DATA_WIDTH_8BIT
#define AT_UART_PARITY NO_PARITY
#define AT_UART_STOP_BITS STOP_BITS_1
#define AT_UART_FLOW_CONTROL FLOW_CONTROL_DISABLED
#define AT_UART_MODE MODE_TX_RX
#endif

View file

@ -0,0 +1,786 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <aos/aos.h>
#include <hal/hal.h>
#include <atparser.h>
#include <sal.h>
#define TAG "sal_wifi"
#define CMD_SUCCESS_RSP "OK"
#define CMD_FAIL_RSP "ERROR"
#define MAX_DATA_LEN 4096
#define MAX_DOMAIN_LEN 256
#define DATA_LEN_MAX 10
#define LINK_ID_MAX 5
#define STOP_CMD "AT+CIPSTOP"
#define STOP_CMD_LEN (sizeof(STOP_CMD)+1+1+5+1)
#define STOP_AUTOCONN_CMD "AT+CIPAUTOCONN"
#define STOP_AUTOCONN_CMD_LEN (sizeof(STOP_AUTOCONN_CMD)+1+1+5+1)
#define AT_RESET_CMD "AT"
typedef int (*at_data_check_cb_t)(char data);
/* Change to include data slink for each link id respectively. <TODO> */
typedef struct link_s {
int fd;
aos_sem_t sem_start;
aos_sem_t sem_close;
} link_t;
static link_t g_link[LINK_ID_MAX];
static aos_mutex_t g_link_mutex;
static netconn_data_input_cb_t g_netconn_data_input_cb;
static char localipaddr[16];
static void handle_tcp_udp_client_conn_state(uint8_t link_id)
{
char s[32] = {0};
at.read(s, 6);
if (strstr(s, "CLOSED") != NULL) {
LOGI(TAG, "Server closed event.");
if (aos_sem_is_valid(&g_link[link_id].sem_close)) {
LOGD(TAG, "sem is going to be waked up: 0x%x", &g_link[link_id].sem_close);
aos_sem_signal(&g_link[link_id].sem_close); // wakeup send task
}
LOGI(TAG, "Server conn (%d) closed.", link_id);
} else if (strstr(s, "CONNEC") != NULL){
LOGI(TAG, "Server conn (%d) successful.", link_id);
at.read(s, 3);
if (aos_sem_is_valid(&g_link[link_id].sem_start)) {
LOGD(TAG, "sem is going to be waked up: 0x%x", &g_link[link_id].sem_start);
aos_sem_signal(&g_link[link_id].sem_start); // wakeup send task
}
} else if (strstr(s, "DISCON") != NULL) {
LOGI(TAG, "Server conn (%d) disconnected.", link_id);
at.read(s, 6);
} else {
LOGW(TAG, "No one handle this unkown event!!!");
}
}
static void handle_client_conn_state()
{
}
static int socket_data_len_check(char data)
{
if (data > '9' || data < '0') {
return -1;
}
return 0;
}
static int socket_ip_info_check(char data)
{
if ((data > '9' || data < '0') && data != '.') {
return -1;
}
return 0;
}
static int socket_data_info_get(char *buf, uint32_t buflen, at_data_check_cb_t valuecheck)
{
uint32_t i = 0;
if (NULL == buf || 0 ==buflen){
return -1;
}
do {
at.read(&buf[i], 1);
if (buf[i] == ',') {
buf[i] = 0;
break;
}
if (i >= buflen) {
LOGE(TAG, "Too long length of data.reader is %s \r\n", buf);
return -1;
}
if (NULL != valuecheck){
if (valuecheck(buf[i])){
LOGE(TAG, "Invalid string!!!, reader is %s \r\n", buf);
return -1;
}
}
i++;
} while (1);
return 0;
}
static void handle_socket_data()
{
int link_id = 0;
int ret = 0;
uint32_t len = 0;
char reader[16] = {0};
char *recvdata = NULL;
/* Eat the "OCKET," */
at.read(reader, 6);
if (memcmp(reader, "OCKET,", strlen("OCKET,")) != 0) {
LOGE(TAG, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x invalid event format!!!\r\n",
reader[0], reader[1], reader[2], reader[3], reader[4], reader[5]);
return;
}
memset(reader, 0, sizeof(reader));
ret = socket_data_info_get(reader, 1, &socket_data_len_check);
if (ret){
LOGE(TAG, "Invalid link id 0x%02x !!!\r\n", reader[0]);
return;
}
link_id = reader[0] - '0';
memset(reader, 0, sizeof(reader));
/* len */
ret = socket_data_info_get(reader, sizeof(reader), &socket_data_len_check);
if (ret){
LOGE(TAG, "Invalid datalen %s !!!\r\n", reader);
return;
}
len = atoi(reader);
if (len > MAX_DATA_LEN){
LOGE(TAG, "invalid input socket data len %d \r\n", len);
return;
}
/* Prepare socket data */
recvdata = (char *)aos_malloc(len + 1);
if (!recvdata) {
LOGE(TAG, "Error: %s %d out of memory, len is %d. \r\n", __func__, __LINE__, len);
return;
}
at.read(recvdata, len);
recvdata[len] = '\0';
LOGD(TAG, "The socket data is %s", recvdata);
if (g_netconn_data_input_cb && (g_link[link_id].fd >= 0)){
/* TODO get recv data src ip and port*/
if (g_netconn_data_input_cb(g_link[link_id].fd, recvdata, len, NULL, 0)){
LOGE(TAG, " %s socket %d get data len %d fail to post to sal, drop it\n",
__func__, g_link[link_id].fd, len);
}
}
LOGD(TAG, "%s socket data on link %d with length %d posted to sal\n",
__func__, link_id, len);
aos_free(recvdata);
}
static void handle_udp_broadcast_data()
{
uint32_t len = 0;
uint32_t remoteport = 0;
int32_t linkid = 0;
int32_t ret = 0;
char reader[16] = {0};
char ipaddr[16] = {0};
char *recvdata = NULL;
/* Eat the "DP_BROADCAST," */
at.read(reader, 13);
if (memcmp(reader, "DP_BROADCAST,", strlen("DP_BROADCAST,")) != 0) {
LOGE(TAG, "%s invalid event format!!!\r\n",
reader[0], reader[1], reader[2], reader[3], reader[4], reader[5]);
return;
}
/* get ip addr */
ret = socket_data_info_get(ipaddr, sizeof(ipaddr), &socket_ip_info_check);
if (ret){
LOGE(TAG, "Invalid ip addr %s !!!\r\n", ipaddr);
return;
}
LOGD(TAG, "get broadcast form ip addr %s \r\n", ipaddr);
/* get ip port */
memset(reader, 0, sizeof(reader));
ret = socket_data_info_get(reader, sizeof(reader), &socket_data_len_check);
if (ret){
LOGE(TAG, "Invalid ip addr %s !!!\r\n", reader);
return;
}
LOGD(TAG, "get broadcast form ip port %s \r\n", reader);
remoteport = atoi(reader);
memset(reader, 0, sizeof(reader));
ret = socket_data_info_get(reader, 1, &socket_data_len_check);
if (ret){
LOGE(TAG, "Invalid link id 0x%02x !!!\r\n", reader[0]);
return;
}
linkid = reader[0] - '0';
LOGD(TAG, "get udp broadcast linkid %d \r\n", linkid);
/* len */
memset(reader, 0, sizeof(reader));
ret = socket_data_info_get(reader, sizeof(reader), &socket_data_len_check);
if (ret){
LOGE(TAG, "Invalid datalen %s !!!\r\n", reader);
return;
}
len = atoi(reader);
if (len > MAX_DATA_LEN){
LOGE(TAG, "invalid input socket data len %d \r\n", len);
return;
}
/* Prepare socket data */
recvdata = (char *)aos_malloc(len + 1);
if (!recvdata) {
LOGE(TAG, "Error: %s %d out of memory, len is %d. \r\n", __func__, __LINE__, len);
return;
}
at.read(recvdata, len);
recvdata[len] = '\0';
if (strcmp(ipaddr, localipaddr) != 0) {
if (g_netconn_data_input_cb && (g_link[linkid].fd >= 0)){
if (g_netconn_data_input_cb(g_link[linkid].fd, recvdata, len, ipaddr, remoteport)){
LOGE(TAG, " %s socket %d get data len %d fail to post to sal, drop it\n",
__func__, g_link[linkid].fd, len);
}
}
} else {
LOGD(TAG, "drop broadcast packet len %d \r\n", len);
}
aos_free(recvdata);
}
static void mk3060_get_local_ip_addr()
{
int ret = 0;
hal_wifi_ip_stat_t ip_stat = {0};
at_wevent_handler(NULL, NULL, 0);
ret = hal_wifi_get_ip_stat(NULL, &ip_stat, STATION);
if (ret){
printf("fail to get local ip addr \r\n");
return ;
}
LOGD(TAG, "local ip is %s \r\n", ip_stat.ip);
strcpy(localipaddr, ip_stat.ip);
}
/*
* Wifi station event handler. include:
* +WEVENT:AP_UP
* +WEVENT:AP_DOWN
* +WEVENT:STATION_UP
* +WEVENT:STATION_DOWN
*/
static void mk3060wifi_event_handler(void *arg, char *buf, int buflen)
{
char eventhead[4] = {0};
char eventotal[16] = {0};
at.read(eventhead, 3);
if (strcmp(eventhead, "AP_") == 0) {
at.read(eventotal, 2);
if (strcmp(eventotal, "UP") == 0){
} else if (strcmp(eventotal, "DO") == 0){
/*eat WN*/
at.read(eventotal, 2);
} else {
LOGE(TAG, "!!!Error: wrong WEVENT AP string received. %s\r\n", eventotal);
return;
}
}else if (strcmp(eventhead, "STA") == 0){
at.read(eventotal, 7);
if (strcmp(eventotal, "TION_UP") == 0){
aos_loop_schedule_work(0, mk3060_get_local_ip_addr, NULL, NULL, NULL);
} else if (strcmp(eventotal, "TION_DO") == 0){
/*eat WN*/
at.read(eventotal, 2);
memset(localipaddr, 0, sizeof(localipaddr));
} else {
LOGE(TAG, "!!!Error: wrong WEVENT STATION string received. %s\r\n", eventotal);
return;
}
}else {
LOGE(TAG, "!!!Error: wrong WEVENT string received. %s\r\n", eventhead);
return;
}
return;
}
/**
* Network connection state event handler. Events includes:
* 1. +CIPEVENT:id,SERVER,CONNECTED
* 2. +CIPEVENT:id,SERVER,CLOSED
* 3. +CIPEVENT:CLIENT,CONNECTED,ip,port
* 4. +CIPEVENT:CLIENT,CLOSED,ip,port
* 5. +CIPEVENT:id,UDP,CONNECTED
* 6. +CIPEVENT:id,UDP,CLOSED
* 7. +CIPEVENT:SOCKET,id,len,data
* 8. +CIPEVENT:UDP_BROADCAST,ip,port,id,len,data
*/
static void net_event_handler(void *arg, char *buf, int buflen)
{
char c;
char s[32] = {0};
LOGD(TAG, "%s entry.", __func__);
at.read(&c, 1);
if (c >= '0' && c < ('0' + LINK_ID_MAX)) {
int link_id = c - '0';
at.read(&c, 1);
if (c != ',') {
LOGE(TAG, "!!!Error: wrong CIPEVENT string. 0x%02x\r\n", c);
return;
}
at.read(&c, 1);
if (c == 'S') {
LOGD(TAG, "%s server conn state event, linkid: %d.", __func__, link_id);
/* Eat the "ERVER," */
at.read(s, 6);
if (memcmp(s, "ERVER,", strlen("ERVER,")) != 0) {
LOGE(TAG, "invalid event format 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
s[0], s[1], s[2], s[3], s[4], s[5]);
return;
}
handle_tcp_udp_client_conn_state(link_id);
} else if (c == 'U') {
LOGD(TAG, "%s UDP conn state event.", __func__);
/* Eat the "DP," */
at.read(s, 3);
if (memcmp(s, "DP,", strlen("DP,")) != 0) {
LOGE(TAG, "%s invalid event format 0x%02x 0x%02x 0x%02x \r\n", __FUNCTION__, s[0], s[1], s[2]);
return;
}
handle_tcp_udp_client_conn_state(link_id);
} else {
LOGE(TAG, "!!!Error: wrong CIPEVENT string 0x%02x at line %d\r\n", c, __LINE__);
return ;
}
} else if (c == 'S') {
LOGD(TAG, "%s socket data event.", __func__);
handle_socket_data();
} else if (c == 'C') {
LOGD(TAG, "%s client conn state event.", __func__);
handle_client_conn_state();
} else if (c == 'U') {
LOGD(TAG, "%s udp broadcast data event.", __func__);
handle_udp_broadcast_data();
}
else {
LOGE(TAG, "!!!Error: wrong CIPEVENT string received. 0x%02x\r\n", c);
return;
}
LOGD(TAG, "%s exit.", __func__);
}
// turn off AT echo
static void mk3060_uart_echo_off()
{
char out[64] = {0};
at.send_raw(AT_CMD_EHCO_OFF, out, sizeof(out));
LOGD(TAG, "The AT response is: %s", out);
if (strstr(out, CMD_FAIL_RSP) != NULL) {
LOGE(TAG, "%s %d failed", __func__, __LINE__);
}
return;
}
static uint8_t inited = 0;
#define NET_OOB_PREFIX "+CIPEVENT:"
#define WIFIEVENT_OOB_PREFIX "+WEVENT:"
static int sal_wifi_init(void)
{
int link;
char cmd[STOP_AUTOCONN_CMD_LEN] = {0};
char out[64] = {0};
if (inited) {
LOGW(TAG, "sal component is already initialized");
return 0;
}
if (0 != aos_mutex_new(&g_link_mutex)) {
LOGE(TAG, "Creating link mutex failed (%s %d).", __func__, __LINE__);
return -1;
}
mk3060_uart_echo_off();
memset(g_link, 0, sizeof(g_link));
for (link = 0; link < LINK_ID_MAX; link++) {
g_link[link].fd = -1;
/*close all link */
snprintf(cmd, STOP_CMD_LEN - 1, "%s=%d", STOP_CMD, link);
LOGD(TAG, "%s %d - AT cmd to run: %s", __func__, __LINE__, cmd);
at.send_raw(cmd, out, sizeof(out));
LOGD(TAG, "The AT response is: %s", out);
if (strstr(out, CMD_FAIL_RSP) != NULL) {
LOGD(TAG, "%s %d failed", __func__, __LINE__);
//return -1;
}
memset(cmd, 0, sizeof(cmd));
/*close all link auto reconnect */
snprintf(cmd, STOP_AUTOCONN_CMD_LEN - 1, "%s=%d,0", STOP_AUTOCONN_CMD, link);
LOGD(TAG, "%s %d - AT cmd to run: %s", __func__, __LINE__, cmd);
at.send_raw(cmd, out, sizeof(out));
LOGD(TAG, "The AT response is: %s", out);
if (strstr(out, CMD_FAIL_RSP) != NULL) {
LOGE(TAG, "%s %d failed", __func__, __LINE__);
//return -1;
}
memset(cmd, 0, sizeof(cmd));
}
at.oob(NET_OOB_PREFIX, NULL, 0, net_event_handler, NULL);
at.oob(WIFIEVENT_OOB_PREFIX, NULL, 0, mk3060wifi_event_handler, NULL);
inited = 1;
return 0;
}
static int sal_wifi_deinit(void)
{
if (!inited) return 0;
// at.exitoob(NET_OOB_PREFIX); // <TODO>
aos_mutex_free(&g_link_mutex);
return 0;
}
#define START_CMD "AT+CIPSTART"
#define START_CMD_LEN (sizeof(START_CMD)+1+1+13+1+MAX_DOMAIN_LEN+1+5+1+5+1)
static char *start_cmd_type_str[] = {"tcp_server", "tcp_client", \
"ssl_client", "udp_broadcast", "udp_unicast"};
int sal_wifi_start(sal_conn_t *c)
{
int link_id;
char cmd[START_CMD_LEN] = {0};
char out[256] = {0};
if (!c || !c->addr) {
LOGE(TAG, "%s %d - invalid argument", __func__, __LINE__);
return -1;
}
if (aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "Failed to lock mutex (%s).", __func__);
return -1;
}
for (link_id = 0; link_id < LINK_ID_MAX; link_id++) {
if (g_link[link_id].fd >= 0)
continue;
else {
g_link[link_id].fd = c->fd;
if (aos_sem_new(&g_link[link_id].sem_start, 0) != 0){
LOGE(TAG, "failed to allocate semaphore %s", __func__);
g_link[link_id].fd = -1;
return -1;
}
if (aos_sem_new(&g_link[link_id].sem_close, 0) != 0){
LOGE(TAG, "failed to allocate semaphore %s", __func__);
aos_sem_free(&g_link[link_id].sem_start);
g_link[link_id].fd = -1;
return -1;
}
break;
}
}
aos_mutex_unlock(&g_link_mutex);
// The caller should deal with this failure
if (link_id >= LINK_ID_MAX) {
LOGI(TAG, "No link available for now, %s failed.", __func__);
return -1;
}
LOGD(TAG, "Creating %s connection ...", start_cmd_type_str[c->type]);
switch (c->type) {
case TCP_SERVER:
snprintf(cmd, START_CMD_LEN - 1, "%s=%d,%s,%d,",
START_CMD, link_id, start_cmd_type_str[c->type], c->l_port);
break;
case TCP_CLIENT:
case SSL_CLIENT:
snprintf(cmd, START_CMD_LEN - 5 - 1, "%s=%d,%s,%s,%d",
START_CMD, link_id, start_cmd_type_str[c->type],
c->addr, c->r_port);
if (c->l_port >= 0)
snprintf(cmd + strlen(cmd), 7, ",%d", c->l_port);
break;
case UDP_BROADCAST:
case UDP_UNICAST:
snprintf(cmd, START_CMD_LEN - 1, "%s=%d,%s,%s,%d,%d",
START_CMD, link_id, start_cmd_type_str[c->type],
c->addr, c->r_port, c->l_port);
break;
default:
LOGE(TAG, "Invalid connection type.");
goto err;
}
LOGD(TAG, "\r\n%s %d - AT cmd to run: %s \r\n", __func__, __LINE__, cmd);
at.send_raw(cmd, out, sizeof(out));
LOGD(TAG, "The AT response is: %s", out);
if (strstr(out, CMD_FAIL_RSP) != NULL) {
LOGE(TAG, "%s %d failed", __func__, __LINE__);
goto err;
}
if (aos_sem_wait(&g_link[link_id].sem_start, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "%s sem_wait failed", __func__);
goto err;
}
LOGD(TAG, "%s sem_wait succeed.", __func__);
return 0;
err:
if (aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "Failed to lock mutex (%s).", __func__);
return -1;
}
if (aos_sem_is_valid(&g_link[link_id].sem_start)){
aos_sem_free(&g_link[link_id].sem_start);
}
if (aos_sem_is_valid(&g_link[link_id].sem_close)){
aos_sem_free(&g_link[link_id].sem_close);
}
g_link[link_id].fd = -1;
aos_mutex_unlock(&g_link_mutex);
return -1;
}
static int fd_to_linkid(int fd)
{
int link_id;
if (aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "Failed to lock mutex (%s).", __func__);
return -1;
}
for (link_id = 0; link_id < LINK_ID_MAX; link_id++) {
if (g_link[link_id].fd == fd)
break;
}
aos_mutex_unlock(&g_link_mutex);
return link_id;
}
#define SEND_CMD "AT+CIPSEND"
#define SEND_CMD_LEN (sizeof(SEND_CMD)+1+1+5+1+DATA_LEN_MAX+1)
static int sal_wifi_send(int fd,
uint8_t *data,
uint32_t len,
char remote_ip[16],
int32_t remote_port,
int32_t timeout)
{
int link_id;
char cmd[SEND_CMD_LEN] = {0}, out[128] = {0};
if (!data) return -1;
LOGD(TAG, "%s on fd %d", __func__, fd);
link_id = fd_to_linkid(fd);
if (link_id >= LINK_ID_MAX) {
LOGE(TAG, "No connection found for fd (%d) in %s", fd, __func__);
return -1;
}
/* AT+CIPSEND=id, */
snprintf(cmd, SEND_CMD_LEN - 1, "%s=%d,", SEND_CMD, link_id);
/* [remote_port,] */
if (remote_port >= 0)
snprintf(cmd + strlen(cmd), 7, "%d,", remote_port);
/* data_length */
snprintf(cmd + strlen(cmd), DATA_LEN_MAX + 1, "%d", len);
LOGD(TAG, "\r\n%s %d - AT cmd to run: %s\r\n", __func__, __LINE__, cmd);
at.send_data_2stage((const char *)cmd, (const char *)data, len, out, sizeof(out));
LOGD(TAG, "\r\nThe AT response is: %s\r\n", out);
if (strstr(out, CMD_FAIL_RSP) != NULL) {
LOGD(TAG, "%s %d failed", __func__, __LINE__);
return -1;
}
return 0;
}
#define DOMAIN_RSP "+CIPDOMAIN:"
#define DOMAIN_CMD "AT+CIPDOMAIN"
#define DOMAIN_CMD_LEN (sizeof(DOMAIN_CMD)+MAX_DOMAIN_LEN+1)
/* Return the first IP if multiple found. */
static int sal_wifi_domain_to_ip(char *domain,
char ip[16])
{
char cmd[DOMAIN_CMD_LEN] = {0}, out[256] = {0}, *head, *end;
snprintf(cmd, DOMAIN_CMD_LEN - 1, "%s=%s", DOMAIN_CMD, domain);
LOGD(TAG, "%s %d - AT cmd to run: %s", __func__, __LINE__, cmd);
at.send_raw(cmd, out, sizeof(out));
LOGD(TAG, "The AT response is: %s", out);
if (strstr(out, at._default_recv_success_postfix) == NULL) {
LOGE(TAG, "%s %d failed", __func__, __LINE__);
return -1;
}
/**
* +CIPDOMAIN:1\r\n
* 180.97.33.108\r\n
*
* OK\r\n
*/
if ((head = strstr(out, DOMAIN_RSP)) == NULL) {
LOGE(TAG, "No IP info found in result string %s \r\n.", out);
return -1;
}
/* Check the format */
head += strlen(DOMAIN_RSP);
if (head[0] < '0' && head[0] >= ('0' + LINK_ID_MAX)){
LOGE(TAG, "%s %d failed", __func__, __LINE__);
goto err;
}
head++;
if (memcmp(head, at._default_recv_prefix, at._recv_prefix_len) != 0){
LOGE(TAG, "%s %d failed", __func__, __LINE__);
goto err;
}
/* We find the IP head */
head += at._recv_prefix_len;
end = head;
while (((end - head) < 15) && (*end != at._default_recv_prefix[0])) end++;
if (((end - head) < 6) || ((end -head) > 15)) goto err;
/* We find a good IP, save it. */
memcpy(ip, head, end - head);
ip[end-head] = '\0';
LOGD(TAG, "get domain %s ip %s \r\n", domain, ip);
return 0;
err:
LOGE(TAG, "Failed to get IP due to unexpected result string %s \r\n.", out);
return -1;
}
static int sal_wifi_close(int fd,
int32_t remote_port)
{
int link_id;
char cmd[STOP_CMD_LEN] = {0}, out[64];
link_id = fd_to_linkid(fd);
if (link_id >= LINK_ID_MAX) {
LOGE(TAG, "No connection found for fd (%d) in %s", fd, __func__);
return -1;
}
snprintf(cmd, STOP_CMD_LEN - 1, "%s=%d", STOP_CMD, link_id);
LOGD(TAG, "%s %d - AT cmd to run: %s", __func__, __LINE__, cmd);
at.send_raw(cmd, out, sizeof(out));
LOGD(TAG, "The AT response is: %s", out);
if (strstr(out, CMD_FAIL_RSP) != NULL) {
LOGE(TAG, "%s %d failed", __func__, __LINE__);
goto err;
}
if (aos_sem_wait(&g_link[link_id].sem_close, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "%s sem_wait failed", __func__);
goto err;
}
LOGD(TAG, "%s sem_wait succeed.", __func__);
err:
if (aos_mutex_lock(&g_link_mutex, AOS_WAIT_FOREVER) != 0) {
LOGE(TAG, "Failed to lock mutex (%s).", __func__);
return -1;
}
if (aos_sem_is_valid(&g_link[link_id].sem_start)){
aos_sem_free(&g_link[link_id].sem_start);
}
if (aos_sem_is_valid(&g_link[link_id].sem_close)){
aos_sem_free(&g_link[link_id].sem_close);
}
g_link[link_id].fd = -1;
aos_mutex_unlock(&g_link_mutex);
return -1;
}
static int mk3060_wifi_packet_input_cb_register(netconn_data_input_cb_t cb)
{
if (cb)
g_netconn_data_input_cb = cb;
return 0;
}
sal_op_t sal_op = {
.version = "1.0.0",
.init = sal_wifi_init,
.start = sal_wifi_start,
.send = sal_wifi_send,
.domain_to_ip = sal_wifi_domain_to_ip,
.close = sal_wifi_close,
.deinit = sal_wifi_deinit,
.register_netconn_data_input_cb = mk3060_wifi_packet_input_cb_register,
};
int mk3060_sal_init(void)
{
return sal_module_register(&sal_op);
}

View file

@ -0,0 +1,13 @@
NAME := device_sal_mk3060
$(NAME)_SOURCES += wifi_atcmd.c
GLOBAL_DEFINES += DEV_SAL_MK3060
$(NAME)_COMPONENTS += yloop
ifneq (1, $(at_adapter))
$(NAME)_COMPONENTS += sal atparser
$(NAME)_SOURCES += mk3060.c
endif
GLOBAL_INCLUDES += ./

View file

@ -0,0 +1,13 @@
src = Split('''
wifi_atcmd.c
mk3060.c
''')
component = aos_component('device_sal_mk3060', src)
component.add_comp_deps('framework/atparser')
component.add_comp_deps('kernel/yloop')
component.add_global_includes('.')
component.add_global_macros('DEV_SAL_MK3060')

View file

@ -0,0 +1,302 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hal/base.h>
#include <hal/wifi.h>
#include "atparser.h"
#define TAG "wifi_port"
#define AT_RSP_SUCCESS "OK"
#define AT_RSP_FAIL "ERROR"
static int get_mac_helper(char *mac);
static int get_ip_stat_helper(hal_wifi_ip_stat_t *result);
static void fetch_ip_stat(void *arg)
{
hal_wifi_ip_stat_t ip_stat = {0};
hal_wifi_module_t *m;
if (!arg) {
LOGE(TAG, "%s failed, invalid argument\r\n", __func__);
return;
}
m = (hal_wifi_module_t *)arg;
get_ip_stat_helper(&ip_stat);
if (m->ev_cb->ip_got != NULL) {
m->ev_cb->ip_got(m, &ip_stat, NULL);
}
}
void at_wevent_handler(void *arg, char *buf, int buflen)
{
hal_wifi_module_t *m;
if (NULL == arg){
m = hal_wifi_get_default_module();
} else {
m = (hal_wifi_module_t *)arg;
}
if (NULL == m) {
return;
}
if (m->ev_cb->stat_chg != NULL) {
m->ev_cb->stat_chg(m, NOTIFY_STATION_UP, NULL);
}
fetch_ip_stat(m);
}
static int wifi_init(hal_wifi_module_t *m)
{
LOGI(TAG, "wifi init success!!\n");
return 0;
};
#define MAC_STR_LEN 12
// str: char[12], mac: hex[6]
static void mac_str_to_hex(char *str, uint8_t *mac)
{
int i;
char c;
uint8_t j;
if (!str || !mac) return;
memset(mac, 0, MAC_STR_LEN >> 1);
for (i = 0; i < MAC_STR_LEN; i++) {
c = str[i];
if (c >= '0' && c <= '9') j = c - '0';
else if (c >= 'A' && c <= 'F') j = c - 'A' + 0xa;
else if (c >= 'a' && c <= 'f') j = c - 'a' + 0xa;
else j = c % 0xf;
j <<= i & 1 ? 0 : 4;
mac[i>>1] |= j;
}
}
// mac - hex[6]
static void wifi_get_mac_addr(hal_wifi_module_t *m, uint8_t *mac)
{
char mac_str[MAC_STR_LEN+1] = {0};
if (!mac) return;
(void)m;
LOGD(TAG, "wifi_get_mac_addr!!\n");
get_mac_helper(mac_str);
mac_str_to_hex(mac_str, mac);
LOGI(TAG, "mac in hex: %02x%02x%02x%02x%02x%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
};
#define AT_CMD_CONNECT_AP "AT+WJAP"
static int wifi_start(hal_wifi_module_t *m, hal_wifi_init_type_t *init_para)
{
char in[128] = {0};
char out[128] = {0};
(void)init_para;
if (strcmp(init_para->wifi_key, "open") == 0) {
snprintf(in, sizeof(in), AT_CMD_CONNECT_AP"=%s",
init_para->wifi_ssid);
} else {
snprintf(in, sizeof(in), AT_CMD_CONNECT_AP"=%s,%s",
init_para->wifi_ssid, init_para->wifi_key);
}
LOGI(TAG, "Will connect via at cmd: %s\r\n", in);
if (at.send_raw(in, out, sizeof(out)) == 0)
LOGI(TAG, "AT command %s succeed, rsp: %s\r\n", in, out);
else
LOGE(TAG, "AT command %s failed\r\n", in);
if (strstr(out, AT_RSP_FAIL)) {
LOGE(TAG, "Connect wifi failed\r\n");
return -1;
}
return 0;
}
static int wifi_start_adv(hal_wifi_module_t *m, hal_wifi_init_type_adv_t *init_para_adv)
{
(void)init_para_adv;
return 0;
}
#define AT_CMD_OBTAIN_MAC "AT+WMAC?"
// mac string, e.g. "BF01ADE2F5CE"
static int get_mac_helper(char *mac)
{
char out[128] = {0};
if (!mac) return -1;
if (at.send_raw(AT_CMD_OBTAIN_MAC, out, sizeof(out)) == 0) {
LOGI(TAG, "AT command %s succeed, rsp: %s", AT_CMD_OBTAIN_MAC, out);
} else {
LOGE(TAG, "AT command %s failed\r\n", AT_CMD_OBTAIN_MAC);
return -1;
}
if (strstr(out, AT_RSP_FAIL)) {
LOGE(TAG, "Command %s executed with ERROR.", AT_CMD_OBTAIN_MAC);
return -1;
}
sscanf(out, "%*[^:]:%[^\r]", mac);
LOGI(TAG, "mac result: %s\r\n", mac);
return 0;
}
#define AT_CMD_OBTAIN_IP "AT+WJAPIP?"
static int get_ip_stat_helper(hal_wifi_ip_stat_t *result)
{
char out[128] = {0};
int ret = 0;
if (!result) return -1;
if (at.send_raw(AT_CMD_OBTAIN_IP, out, sizeof(out)) == 0) {
LOGI(TAG, "AT command %s succeed, rsp: %s", AT_CMD_OBTAIN_IP, out);
} else {
LOGE(TAG, "AT command %s failed\r\n", AT_CMD_OBTAIN_IP);
return -1;
}
if (strstr(out, AT_RSP_FAIL)) {
LOGE(TAG, "Command %s executed with ERROR", AT_CMD_OBTAIN_IP);
return -1;
}
sscanf(out, "%*[^:]:%[^,],%[^,],%[^,],%[^\r]",
result->ip, result->mask, result->gate, result->dns);
LOGD(TAG, "result: %s %s %s %s\r\n",
result->ip, result->mask, result->gate, result->dns);
ret = get_mac_helper(result->mac);
return ret;
}
static int get_ip_stat(hal_wifi_module_t *m, hal_wifi_ip_stat_t *out_net_para, hal_wifi_type_t wifi_type)
{
(void)wifi_type;
(void)m;
get_ip_stat_helper(out_net_para);
return 0;
}
static int get_link_stat(hal_wifi_module_t *m, hal_wifi_link_stat_t *out_stat)
{
return 0;
}
static void start_scan(hal_wifi_module_t *m)
{
}
static void start_scan_adv(hal_wifi_module_t *m)
{
}
static int power_off(hal_wifi_module_t *m)
{
return 0;
}
static int power_on(hal_wifi_module_t *m)
{
return 0;
}
static int suspend(hal_wifi_module_t *m)
{
return 0;
}
static int suspend_station(hal_wifi_module_t *m)
{
return 0;
}
static int suspend_soft_ap(hal_wifi_module_t *m)
{
return 0;
}
static int set_channel(hal_wifi_module_t *m, int ch)
{
return 0;
}
static void start_monitor(hal_wifi_module_t *m)
{
}
static void stop_monitor(hal_wifi_module_t *m)
{
}
static void register_monitor_cb(hal_wifi_module_t *m, monitor_data_cb_t fn)
{
}
static void register_wlan_mgnt_monitor_cb(hal_wifi_module_t *m, monitor_data_cb_t fn)
{
}
static int wlan_send_80211_raw_frame(hal_wifi_module_t *m, uint8_t *buf, int len)
{
return 0;
}
hal_wifi_module_t aos_wifi_module_mk3060 = {
.base.name = "aos_wifi_module_mk3060",
.init = wifi_init,
.get_mac_addr = wifi_get_mac_addr,
.start = wifi_start,
.start_adv = wifi_start_adv,
.get_ip_stat = get_ip_stat,
.get_link_stat = get_link_stat,
.start_scan = start_scan,
.start_scan_adv = start_scan_adv,
.power_off = power_off,
.power_on = power_on,
.suspend = suspend,
.suspend_station = suspend_station,
.suspend_soft_ap = suspend_soft_ap,
.set_channel = set_channel,
.start_monitor = start_monitor,
.stop_monitor = stop_monitor,
.register_monitor_cb = register_monitor_cb,
.register_wlan_mgnt_monitor_cb = register_wlan_mgnt_monitor_cb,
.wlan_send_80211_raw_frame = wlan_send_80211_raw_frame
};