853 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			853 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * Change Logs:
 | |
|  * Date           Author       Notes
 | |
|  * 2014-07-31     aozima       the first version
 | |
|  * 2014-09-18     aozima       update command & response.
 | |
|  * 2017-07-28     armink       fix auto reconnect feature
 | |
|  */
 | |
| 
 | |
| #include <rtthread.h>
 | |
| #include <drivers/spi.h>
 | |
| 
 | |
| #include <netif/ethernetif.h>
 | |
| #include <netif/etharp.h>
 | |
| #include <lwip/icmp.h>
 | |
| #include "lwipopts.h"
 | |
| 
 | |
| #define WIFI_DEBUG_ON
 | |
| // #define ETH_RX_DUMP
 | |
| // #define ETH_TX_DUMP
 | |
| 
 | |
| #ifdef WIFI_DEBUG_ON
 | |
| #define WIFI_DEBUG         rt_kprintf("[RW009] ");rt_kprintf
 | |
| //#define SPI_DEBUG         rt_kprintf("[SPI] ");rt_kprintf
 | |
| #define SPI_DEBUG(...)
 | |
| #else
 | |
| #define WIFI_DEBUG(...)
 | |
| #define SPI_DEBUG(...)
 | |
| #endif /* #ifdef WIFI_DEBUG_ON */
 | |
| 
 | |
| /********************************* RW009 **************************************/
 | |
| #include "spi_wifi_rw009.h"
 | |
| 
 | |
| /* tools */
 | |
| #define node_entry(node, type, member) \
 | |
|     ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
 | |
| #define member_offset(type, member) \
 | |
|     ((unsigned long)(&((type *)0)->member))
 | |
| 
 | |
| #define MAX_SPI_PACKET_SIZE     (member_offset(struct spi_data_packet, buffer) + SPI_MAX_DATA_LEN)
 | |
| #define MAX_SPI_BUFFER_SIZE     (sizeof(struct spi_response) + MAX_SPI_PACKET_SIZE)
 | |
| #define MAX_ADDR_LEN 6
 | |
| 
 | |
| struct rw009_wifi
 | |
| {
 | |
|     /* inherit from ethernet device */
 | |
|     struct eth_device parent;
 | |
| 
 | |
|     struct rt_spi_device *rt_spi_device;
 | |
| 
 | |
|     /* interface address info. */
 | |
|     rt_uint8_t  dev_addr[MAX_ADDR_LEN];         /* hw address   */
 | |
|     rt_uint8_t  active;
 | |
| 
 | |
|     struct rt_mempool spi_tx_mp;
 | |
|     struct rt_mempool spi_rx_mp;
 | |
| 
 | |
|     struct rt_mailbox spi_tx_mb;
 | |
|     struct rt_mailbox eth_rx_mb;
 | |
| 
 | |
|     int spi_tx_mb_pool[SPI_TX_POOL_SIZE + 1];
 | |
|     int eth_rx_mb_pool[SPI_RX_POOL_SIZE + 1];
 | |
| 
 | |
|     int rw009_cmd_mb_pool[3];
 | |
|     struct rt_mailbox rw009_cmd_mb;
 | |
|     uint32_t last_cmd;
 | |
| 
 | |
|     rt_align(4)
 | |
|     rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
 | |
|     rt_align(4)
 | |
|     rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_RX_POOL_SIZE];
 | |
| 
 | |
|     rt_align(4)
 | |
|     uint8_t spi_hw_rx_buffer[MAX_SPI_BUFFER_SIZE];
 | |
| 
 | |
|     /* status for RW009 */
 | |
|     rw009_ap_info ap_info;  /* AP info for conn. */
 | |
|     rw009_ap_info *ap_scan; /* AP list for SCAN. */
 | |
|     uint32_t ap_scan_count;
 | |
| };
 | |
| static struct rw009_wifi rw009_wifi_device;
 | |
| static struct rt_event spi_wifi_data_event;
 | |
| 
 | |
| static void resp_handler(struct rw009_wifi *wifi_device, struct rw009_resp *resp)
 | |
| {
 | |
|     struct rw009_resp *resp_return = RT_NULL;
 | |
| 
 | |
|     switch (resp->cmd)
 | |
|     {
 | |
|     case RW009_CMD_INIT:
 | |
|         WIFI_DEBUG("resp_handler RW009_CMD_INIT\n");
 | |
|         resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init)); //TODO:
 | |
|         if(resp_return == RT_NULL) break;
 | |
|         rt_memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init));
 | |
| 
 | |
|         WIFI_DEBUG("sn:%-*.*s\n", sizeof(resp->resp.init.sn), sizeof(resp->resp.init.sn), resp->resp.init.sn);
 | |
|         WIFI_DEBUG("version:%-*.*s\n", sizeof(resp->resp.init.version), sizeof(resp->resp.init.version), resp->resp.init.version);
 | |
| 
 | |
|         rt_memcpy(wifi_device->dev_addr, resp->resp.init.mac, 6);
 | |
|         break;
 | |
| 
 | |
|     case RW009_CMD_SCAN:
 | |
|         if( resp->len == sizeof(rw009_ap_info) )
 | |
|         {
 | |
|             rw009_ap_info *ap_scan = rt_realloc(wifi_device->ap_scan, sizeof(rw009_ap_info) * (wifi_device->ap_scan_count + 1) );
 | |
|             if(ap_scan != RT_NULL)
 | |
|             {
 | |
|                 rt_memcpy( &ap_scan[wifi_device->ap_scan_count], &resp->resp.ap_info, sizeof(rw009_ap_info) );
 | |
| 
 | |
|                 //dump
 | |
|                 if(1)
 | |
|                 {
 | |
| #ifdef WIFI_DEBUG_ON
 | |
|                     rw009_ap_info *ap_info = &resp->resp.ap_info;
 | |
|                     WIFI_DEBUG("SCAN SSID:%-32.32s\n", ap_info->ssid);
 | |
|                     WIFI_DEBUG("SCAN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
 | |
|                                ap_info->bssid[0],
 | |
|                                ap_info->bssid[1],
 | |
|                                ap_info->bssid[2],
 | |
|                                ap_info->bssid[3],
 | |
|                                ap_info->bssid[4],
 | |
|                                ap_info->bssid[5]);
 | |
|                     WIFI_DEBUG("SCAN rssi:%ddBm\n", ap_info->rssi);
 | |
|                     WIFI_DEBUG("SCAN rate:%dMbps\n", ap_info->max_data_rate/1000);
 | |
|                     WIFI_DEBUG("SCAN channel:%d\n", ap_info->channel);
 | |
|                     WIFI_DEBUG("SCAN security:%08X\n\n", ap_info->security);
 | |
| #endif /* WIFI_DEBUG_ON */
 | |
|                 }
 | |
| 
 | |
|                 wifi_device->ap_scan_count++;
 | |
|                 wifi_device->ap_scan = ap_scan;
 | |
|             }
 | |
| 
 | |
|             return; /* wait for next ap */
 | |
|         }
 | |
|         break;
 | |
|     case RW009_CMD_JOIN:
 | |
|     case RW009_CMD_EASY_JOIN:
 | |
|         WIFI_DEBUG("resp_handler RW009_CMD_EASY_JOIN\n");
 | |
|         resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join)); //TODO:
 | |
|         if(resp_return == RT_NULL) break;
 | |
|         rt_memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join));
 | |
| 
 | |
|         if( resp->result == 0 )
 | |
|         {
 | |
|             rt_memcpy(&wifi_device->ap_info, &resp_return->resp.ap_info, sizeof(rw009_resp_join));
 | |
|             wifi_device->active = 1;
 | |
|             eth_device_linkchange(&wifi_device->parent, RT_TRUE);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             wifi_device->active = 1;
 | |
|             eth_device_linkchange(&wifi_device->parent, RT_FALSE);
 | |
|             WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
 | |
|         }
 | |
| 
 | |
|         //dupm
 | |
|         if(1)
 | |
|         {
 | |
| #ifdef WIFI_DEBUG_ON
 | |
|             rw009_ap_info *ap_info = &resp->resp.ap_info;
 | |
|             WIFI_DEBUG("JOIN SSID:%-32.32s\n", ap_info->ssid);
 | |
|             WIFI_DEBUG("JOIN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
 | |
|                        ap_info->bssid[0],
 | |
|                        ap_info->bssid[1],
 | |
|                        ap_info->bssid[2],
 | |
|                        ap_info->bssid[3],
 | |
|                        ap_info->bssid[4],
 | |
|                        ap_info->bssid[5]);
 | |
|             WIFI_DEBUG("JOIN rssi:%ddBm\n", ap_info->rssi);
 | |
|             WIFI_DEBUG("JOIN rate:%dMbps\n", ap_info->max_data_rate/1000);
 | |
|             WIFI_DEBUG("JOIN channel:%d\n", ap_info->channel);
 | |
|             WIFI_DEBUG("JOIN security:%08X\n\n", ap_info->security);
 | |
| #endif /* WIFI_DEBUG_ON */
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|     case RW009_CMD_RSSI:
 | |
|         // TODO: client RSSI.
 | |
|     {
 | |
|         rw009_ap_info *ap_info = &resp->resp.ap_info;
 | |
|         wifi_device->ap_info.rssi = ap_info->rssi;
 | |
|         WIFI_DEBUG("current RSSI: %d\n", wifi_device->ap_info.rssi);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|     case RW009_CMD_SOFTAP:
 | |
|     {
 | |
|         if( resp->result == 0 )
 | |
|         {
 | |
|             ;
 | |
|             wifi_device->active = 1;
 | |
|             eth_device_linkchange(&wifi_device->parent, RT_TRUE);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
 | |
|         }
 | |
| 
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|     default:
 | |
|         WIFI_DEBUG("resp_handler %d\n", resp->cmd);
 | |
|         break;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     if(resp->cmd == wifi_device->last_cmd)
 | |
|     {
 | |
|         rt_mb_send(&wifi_device->rw009_cmd_mb, (rt_uint32_t)resp_return);
 | |
|         return;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         rt_free(resp_return);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static rt_err_t rw009_cmd(struct rw009_wifi *wifi_device, uint32_t cmd, void *args)
 | |
| {
 | |
|     rt_err_t result = RT_EOK;
 | |
|     rt_int32_t timeout = RW009_CMD_TIMEOUT;
 | |
| 
 | |
|     struct spi_data_packet *data_packet;
 | |
|     struct rw009_cmd *wifi_cmd = RT_NULL;
 | |
|     struct rw009_resp *resp = RT_NULL;
 | |
| 
 | |
|     wifi_device->last_cmd = cmd;
 | |
| 
 | |
|     data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
 | |
|     wifi_cmd = (struct rw009_cmd *)data_packet->buffer;
 | |
| 
 | |
|     wifi_cmd->cmd = cmd;
 | |
|     wifi_cmd->len = 0;
 | |
| 
 | |
|     if( cmd == RW009_CMD_INIT )
 | |
|     {
 | |
|         wifi_cmd->len = sizeof(rw009_cmd_init);
 | |
|     }
 | |
|     else if( cmd == RW009_CMD_SCAN )
 | |
|     {
 | |
|         wifi_cmd->len = 0;
 | |
|         timeout += RT_TICK_PER_SECOND*10;
 | |
| 
 | |
|         if(wifi_device->ap_scan)
 | |
|         {
 | |
|             rt_free(wifi_device->ap_scan);
 | |
|             wifi_device->ap_scan = RT_NULL;
 | |
|             wifi_device->ap_scan_count = 0;
 | |
|         }
 | |
|     }
 | |
|     else if( cmd == RW009_CMD_JOIN )
 | |
|     {
 | |
|         wifi_cmd->len = sizeof(rw009_cmd_join);
 | |
|     }
 | |
|     else if( cmd == RW009_CMD_EASY_JOIN )
 | |
|     {
 | |
|         wifi_cmd->len = sizeof(rw009_cmd_easy_join);
 | |
|         timeout += RT_TICK_PER_SECOND*5;
 | |
|     }
 | |
|     else if( cmd == RW009_CMD_RSSI )
 | |
|     {
 | |
|         wifi_cmd->len = sizeof(rw009_cmd_rssi);
 | |
|     }
 | |
|     else if( cmd == RW009_CMD_SOFTAP )
 | |
|     {
 | |
|         wifi_cmd->len = sizeof(rw009_cmd_softap);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         WIFI_DEBUG("unkown RW009 CMD %d\n", cmd);
 | |
|         result = -RT_ENOSYS;
 | |
|         rt_mp_free(data_packet);
 | |
|         data_packet = RT_NULL;
 | |
|     }
 | |
| 
 | |
|     if(data_packet == RT_NULL)
 | |
|     {
 | |
|         goto _exit;
 | |
|     }
 | |
| 
 | |
|     if(wifi_cmd->len)
 | |
|         rt_memcpy(&wifi_cmd->params, args, wifi_cmd->len);
 | |
| 
 | |
|     data_packet->data_type = data_type_cmd;
 | |
|     data_packet->data_len = member_offset(struct rw009_cmd, params) + wifi_cmd->len;
 | |
| 
 | |
|     rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
 | |
|     rt_event_send(&spi_wifi_data_event, 1);
 | |
| 
 | |
|     result = rt_mb_recv(&wifi_device->rw009_cmd_mb,
 | |
|                         (rt_uint32_t *)&resp,
 | |
|                         timeout);
 | |
| 
 | |
|     if ( result != RT_EOK )
 | |
|     {
 | |
|         WIFI_DEBUG("CMD %d error, resultL %d\n", cmd, result );
 | |
|     }
 | |
| 
 | |
|     if(resp != RT_NULL)
 | |
|         result = resp->result;
 | |
| 
 | |
| _exit:
 | |
|     wifi_device->last_cmd = 0;
 | |
|     if(resp) rt_free(resp);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| static rt_err_t spi_wifi_transfer(struct rw009_wifi *dev)
 | |
| {
 | |
|     struct pbuf *p = RT_NULL;
 | |
|     struct spi_cmd_request cmd;
 | |
|     struct spi_response resp;
 | |
| 
 | |
|     rt_err_t result;
 | |
|     const struct spi_data_packet *data_packet = RT_NULL;
 | |
| 
 | |
|     struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
 | |
|     struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
 | |
| 
 | |
|     spi_wifi_int_cmd(0);
 | |
|     while (spi_wifi_is_busy());
 | |
|     SPI_DEBUG("sequence start!\n");
 | |
| 
 | |
|     rt_memset(&cmd, 0, sizeof(struct spi_cmd_request));
 | |
|     cmd.magic1 = CMD_MAGIC1;
 | |
|     cmd.magic2 = CMD_MAGIC2;
 | |
| 
 | |
|     cmd.flag |= CMD_FLAG_MRDY;
 | |
| 
 | |
|     result = rt_mb_recv(&wifi_device->spi_tx_mb,
 | |
|                         (rt_uint32_t *)&data_packet,
 | |
|                         0);
 | |
|     if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
 | |
|     {
 | |
|         cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
 | |
|         //SPI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len);
 | |
|     }
 | |
| 
 | |
|     rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
 | |
|     while (spi_wifi_is_busy());
 | |
| 
 | |
|     {
 | |
|         struct rt_spi_message message;
 | |
|         uint32_t max_data_len = 0;
 | |
| 
 | |
|         /* setup message */
 | |
|         message.send_buf = RT_NULL;
 | |
|         message.recv_buf = &resp;
 | |
|         message.length = sizeof(resp);
 | |
|         message.cs_take = 1;
 | |
|         message.cs_release = 0;
 | |
| 
 | |
|         rt_spi_take_bus(rt_spi_device);
 | |
| 
 | |
|         /* transfer message */
 | |
|         rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
 | |
| 
 | |
|         if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
 | |
|         {
 | |
|             SPI_DEBUG("bad resp magic, abort!\n");
 | |
|             goto _bad_resp_magic;
 | |
|         }
 | |
| 
 | |
|         if (resp.flag & RESP_FLAG_SRDY)
 | |
|         {
 | |
|             SPI_DEBUG("RESP_FLAG_SRDY\n");
 | |
|             max_data_len = cmd.M2S_len;
 | |
|         }
 | |
| 
 | |
|         if (resp.S2M_len)
 | |
|         {
 | |
|             SPI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len);
 | |
|             if (resp.S2M_len > MAX_SPI_PACKET_SIZE)
 | |
|             {
 | |
|                 SPI_DEBUG("resp.S2M_len %d > %d(MAX_SPI_PACKET_SIZE), drop!\n", resp.S2M_len, MAX_SPI_PACKET_SIZE);
 | |
|                 resp.S2M_len = 0;//drop
 | |
|             }
 | |
| 
 | |
|             if (resp.S2M_len > max_data_len)
 | |
|                 max_data_len = resp.S2M_len;
 | |
|         }
 | |
| 
 | |
|         if (max_data_len == 0)
 | |
|         {
 | |
|             SPI_DEBUG("no rx or tx data!\n");
 | |
|         }
 | |
| 
 | |
|         //SPI_DEBUG("max_data_len = %d\n", max_data_len);
 | |
| 
 | |
| _bad_resp_magic:
 | |
|         /* setup message */
 | |
|         message.send_buf = data_packet;//&tx_buffer;
 | |
|         message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer;
 | |
|         message.length = max_data_len;
 | |
|         message.cs_take = 0;
 | |
|         message.cs_release = 1;
 | |
| 
 | |
|         /* transfer message */
 | |
|         rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
 | |
| 
 | |
|         rt_spi_release_bus(rt_spi_device);
 | |
| 
 | |
|         if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY))
 | |
|         {
 | |
|             rt_mp_free((void *)data_packet);
 | |
|         }
 | |
| 
 | |
|         if ((resp.S2M_len) && (resp.S2M_len <= MAX_SPI_PACKET_SIZE))
 | |
|         {
 | |
|             data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
 | |
|             if (data_packet->data_type == data_type_eth_data)
 | |
|             {
 | |
| 
 | |
|                 if (wifi_device->active)
 | |
|                 {
 | |
|                     p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
 | |
|                     pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
 | |
| 
 | |
|                     rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
 | |
|                     eth_device_ready((struct eth_device *)dev);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     SPI_DEBUG("!active, RX drop.\n");
 | |
|                 }
 | |
|             }
 | |
|             else if (data_packet->data_type == data_type_resp)
 | |
|             {
 | |
|                 SPI_DEBUG("data_type_resp\n");
 | |
|                 resp_handler(dev, (struct rw009_resp *)data_packet->buffer);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 SPI_DEBUG("data_type: %d, %dbyte\n",
 | |
|                           data_packet->data_type,
 | |
|                           data_packet->data_len);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     spi_wifi_int_cmd(1);
 | |
| 
 | |
|     SPI_DEBUG("sequence finish!\n\n");
 | |
| 
 | |
|     if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
 | |
|     {
 | |
|         return -RT_ERROR;
 | |
|     }
 | |
| 
 | |
|     return RT_EOK;
 | |
| }
 | |
| 
 | |
| #if defined(ETH_RX_DUMP) ||  defined(ETH_TX_DUMP)
 | |
| static void packet_dump(const char *msg, const struct pbuf *p)
 | |
| {
 | |
|     const struct pbuf* q;
 | |
|     rt_uint32_t i,j;
 | |
|     rt_uint8_t *ptr = p->payload;
 | |
| 
 | |
|     rt_kprintf("%s %d byte\n", msg, p->tot_len);
 | |
| 
 | |
|     i=0;
 | |
|     for(q=p; q != RT_NULL; q= q->next)
 | |
|     {
 | |
|         ptr = q->payload;
 | |
| 
 | |
|         for(j=0; j<q->len; j++)
 | |
|         {
 | |
|             if( (i%8) == 0 )
 | |
|             {
 | |
|                 rt_kprintf("  ");
 | |
|             }
 | |
|             if( (i%16) == 0 )
 | |
|             {
 | |
|                 rt_kprintf("\r\n");
 | |
|             }
 | |
|             rt_kprintf("%02x ",*ptr);
 | |
| 
 | |
|             i++;
 | |
|             ptr++;
 | |
|         }
 | |
|     }
 | |
|     rt_kprintf("\n\n");
 | |
| }
 | |
| #endif /* dump */
 | |
| 
 | |
| /********************************* RT-Thread Ethernet interface begin **************************************/
 | |
| static rt_err_t rw009_wifi_init(rt_device_t dev)
 | |
| {
 | |
|     return RT_EOK;
 | |
| }
 | |
| 
 | |
| static rt_err_t rw009_wifi_open(rt_device_t dev, rt_uint16_t oflag)
 | |
| {
 | |
|     return RT_EOK;
 | |
| }
 | |
| 
 | |
| static rt_err_t rw009_wifi_close(rt_device_t dev)
 | |
| {
 | |
|     return RT_EOK;
 | |
| }
 | |
| 
 | |
| static rt_ssize_t rw009_wifi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
 | |
| {
 | |
|     rt_set_errno(-RT_ENOSYS);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static rt_ssize_t rw009_wifi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
 | |
| {
 | |
|     rt_set_errno(-RT_ENOSYS);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static rt_err_t rw009_wifi_control(rt_device_t dev, int cmd, void *args)
 | |
| {
 | |
|     struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
 | |
|     rt_err_t result = RT_EOK;
 | |
| 
 | |
|     if (cmd == NIOCTL_GADDR)
 | |
|     {
 | |
|         rt_memcpy(args, wifi_device->dev_addr, 6);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         result = rw009_cmd(wifi_device, cmd, args);
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| /* transmit packet. */
 | |
| rt_err_t rw009_wifi_tx(rt_device_t dev, struct pbuf *p)
 | |
| {
 | |
|     rt_err_t result = RT_EOK;
 | |
|     struct spi_data_packet *data_packet;
 | |
|     struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
 | |
| 
 | |
|     if (!wifi_device->active)
 | |
|     {
 | |
|         WIFI_DEBUG("!active, TX drop!\n");
 | |
|         return RT_EOK;
 | |
|     }
 | |
| 
 | |
|     /* get free tx buffer */
 | |
|     data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
 | |
|     if (data_packet != RT_NULL)
 | |
|     {
 | |
|         data_packet->data_type = data_type_eth_data;
 | |
|         data_packet->data_len = p->tot_len;
 | |
| 
 | |
|         pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
 | |
| 
 | |
|         rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
 | |
|         rt_event_send(&spi_wifi_data_event, 1);
 | |
|     }
 | |
|     else
 | |
|         return -RT_ERROR;
 | |
| 
 | |
| #ifdef ETH_TX_DUMP
 | |
|     packet_dump("TX dump", p);
 | |
| #endif /* ETH_TX_DUMP */
 | |
| 
 | |
|     /* Return SUCCESS */
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| /* reception packet. */
 | |
| struct pbuf *rw009_wifi_rx(rt_device_t dev)
 | |
| {
 | |
|     struct pbuf *p = RT_NULL;
 | |
|     struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
 | |
| 
 | |
|     if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK)
 | |
|     {
 | |
|         return RT_NULL;
 | |
|     }
 | |
| 
 | |
| #ifdef ETH_RX_DUMP
 | |
|     if(p)
 | |
|         packet_dump("RX dump", p);
 | |
| #endif /* ETH_RX_DUMP */
 | |
| 
 | |
|     return p;
 | |
| }
 | |
| /********************************* RT-Thread Ethernet interface end **************************************/
 | |
| 
 | |
| static void spi_wifi_data_thread_entry(void *parameter)
 | |
| {
 | |
|     rt_uint32_t e;
 | |
|     rt_err_t result;
 | |
| 
 | |
|     while (1)
 | |
|     {
 | |
|         /* receive first event */
 | |
|         if (rt_event_recv(&spi_wifi_data_event,
 | |
|                           1,
 | |
|                           RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
 | |
|                           RT_WAITING_FOREVER,
 | |
|                           &e) != RT_EOK)
 | |
|         {
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         result = spi_wifi_transfer(&rw009_wifi_device);
 | |
| 
 | |
|         if (result == RT_EOK)
 | |
|         {
 | |
|             rt_event_send(&spi_wifi_data_event, 1);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #ifdef RT_USING_DEVICE_OPS
 | |
| const static struct rt_device_ops rw009_ops =
 | |
| {
 | |
|     rw009_wifi_init,
 | |
|     rw009_wifi_open,
 | |
|     rw009_wifi_close,
 | |
|     rw009_wifi_read,
 | |
|     rw009_wifi_write,
 | |
|     rw009_wifi_control
 | |
| };
 | |
| #endif
 | |
| 
 | |
| rt_err_t rt_hw_wifi_init(const char *spi_device_name, wifi_mode_t mode)
 | |
| {
 | |
|     /* align and struct size check. */
 | |
|     RT_ASSERT( (SPI_MAX_DATA_LEN & 0x03) == 0);
 | |
|     RT_ASSERT( sizeof(struct rw009_resp) <= SPI_MAX_DATA_LEN);
 | |
| 
 | |
|     rt_memset(&rw009_wifi_device, 0, sizeof(struct rw009_wifi));
 | |
| 
 | |
|     rw009_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
 | |
| 
 | |
|     if (rw009_wifi_device.rt_spi_device == RT_NULL)
 | |
|     {
 | |
|         SPI_DEBUG("spi device %s not found!\r\n", spi_device_name);
 | |
|         return -RT_ENOSYS;
 | |
|     }
 | |
| 
 | |
|     /* config spi */
 | |
|     {
 | |
|         struct rt_spi_configuration cfg;
 | |
|         cfg.data_width = 8;
 | |
|         cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */
 | |
|         cfg.max_hz = 15 * 1000000; /* 10M */
 | |
|         rt_spi_configure(rw009_wifi_device.rt_spi_device, &cfg);
 | |
|     }
 | |
| 
 | |
| #ifdef RT_USING_DEVICE_OPS
 | |
|     rw009_wifi_device.parent.parent.ops        = &rw009_ops;
 | |
| #else
 | |
|     rw009_wifi_device.parent.parent.init       = rw009_wifi_init;
 | |
|     rw009_wifi_device.parent.parent.open       = rw009_wifi_open;
 | |
|     rw009_wifi_device.parent.parent.close      = rw009_wifi_close;
 | |
|     rw009_wifi_device.parent.parent.read       = rw009_wifi_read;
 | |
|     rw009_wifi_device.parent.parent.write      = rw009_wifi_write;
 | |
|     rw009_wifi_device.parent.parent.control    = rw009_wifi_control;
 | |
| #endif
 | |
|     rw009_wifi_device.parent.parent.user_data  = RT_NULL;
 | |
| 
 | |
|     rw009_wifi_device.parent.eth_rx     = rw009_wifi_rx;
 | |
|     rw009_wifi_device.parent.eth_tx     = rw009_wifi_tx;
 | |
| 
 | |
|     rt_mp_init(&rw009_wifi_device.spi_tx_mp,
 | |
|                "spi_tx",
 | |
|                &rw009_wifi_device.spi_tx_mempool[0],
 | |
|                sizeof(rw009_wifi_device.spi_tx_mempool),
 | |
|                sizeof(struct spi_data_packet));
 | |
| 
 | |
|     rt_mp_init(&rw009_wifi_device.spi_rx_mp,
 | |
|                "spi_rx",
 | |
|                &rw009_wifi_device.spi_rx_mempool[0],
 | |
|                sizeof(rw009_wifi_device.spi_rx_mempool),
 | |
|                sizeof(struct spi_data_packet));
 | |
| 
 | |
|     rt_mb_init(&rw009_wifi_device.spi_tx_mb,
 | |
|                "spi_tx",
 | |
|                &rw009_wifi_device.spi_tx_mb_pool[0],
 | |
|                SPI_TX_POOL_SIZE,
 | |
|                RT_IPC_FLAG_PRIO);
 | |
| 
 | |
|     rt_mb_init(&rw009_wifi_device.eth_rx_mb,
 | |
|                "eth_rx",
 | |
|                &rw009_wifi_device.eth_rx_mb_pool[0],
 | |
|                SPI_TX_POOL_SIZE,
 | |
|                RT_IPC_FLAG_PRIO);
 | |
| 
 | |
|     rt_mb_init(&rw009_wifi_device.rw009_cmd_mb,
 | |
|                "wifi_cmd",
 | |
|                &rw009_wifi_device.rw009_cmd_mb_pool[0],
 | |
|                sizeof(rw009_wifi_device.rw009_cmd_mb_pool) / 4,
 | |
|                RT_IPC_FLAG_PRIO);
 | |
|     rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
 | |
| 
 | |
|     spi_wifi_hw_init();
 | |
| 
 | |
|     {
 | |
|         rt_thread_t tid;
 | |
| 
 | |
| 
 | |
|         tid = rt_thread_create("wifi",
 | |
|                                spi_wifi_data_thread_entry,
 | |
|                                RT_NULL,
 | |
|                                2048,
 | |
|                                RT_THREAD_PRIORITY_MAX - 2,
 | |
|                                20);
 | |
| 
 | |
|         if (tid != RT_NULL)
 | |
|             rt_thread_startup(tid);
 | |
|     }
 | |
| 
 | |
|     /* init: get mac address */
 | |
|     {
 | |
|         rw009_cmd_init init;
 | |
|         init.mode = mode;
 | |
|         WIFI_DEBUG("wifi_control RW009_CMD_INIT\n");
 | |
|         rw009_wifi_control((rt_device_t)&rw009_wifi_device,
 | |
|                            RW009_CMD_INIT,
 | |
|                            (void *)&init); // 0: firmware, 1: STA, 2:AP
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /* register eth device */
 | |
|     eth_device_init(&(rw009_wifi_device.parent), "w0");
 | |
|     eth_device_linkchange(&rw009_wifi_device.parent, RT_FALSE);
 | |
| 
 | |
|     return RT_EOK;
 | |
| }
 | |
| 
 | |
| void spi_wifi_isr(int vector)
 | |
| {
 | |
|     /* enter interrupt */
 | |
|     rt_interrupt_enter();
 | |
| 
 | |
|     SPI_DEBUG("spi_wifi_isr\n");
 | |
|     rt_event_send(&spi_wifi_data_event, 1);
 | |
| 
 | |
|     /* leave interrupt */
 | |
|     rt_interrupt_leave();
 | |
| }
 | |
| 
 | |
| /********************************* RW009 tools **************************************/
 | |
| rt_err_t rw009_join(const char * SSID, const char * passwd)
 | |
| {
 | |
|     rt_err_t result;
 | |
|     rt_device_t wifi_device;
 | |
|     rw009_cmd_easy_join easy_join;
 | |
| 
 | |
|     wifi_device = rt_device_find("w0");
 | |
|     if(wifi_device == RT_NULL)
 | |
|         return -RT_ENOSYS;
 | |
| 
 | |
|     strncpy( easy_join.ssid, SSID, sizeof(easy_join.ssid) );
 | |
|     strncpy( easy_join.passwd, passwd, sizeof(easy_join.passwd) );
 | |
| 
 | |
|     result = rt_device_control(wifi_device,
 | |
|                                RW009_CMD_EASY_JOIN,
 | |
|                                (void *)&easy_join);
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel)
 | |
| {
 | |
|     rt_err_t result;
 | |
|     rt_device_t wifi_device;
 | |
|     rw009_cmd_softap softap;
 | |
| 
 | |
|     wifi_device = rt_device_find("w0");
 | |
|     if(wifi_device == RT_NULL)
 | |
|         return -RT_ENOSYS;
 | |
| 
 | |
|     strncpy( softap.ssid, SSID, sizeof(softap.ssid) );
 | |
|     strncpy( softap.passwd, passwd, sizeof(softap.passwd) );
 | |
| 
 | |
|     softap.security = security;
 | |
|     softap.channel = channel;
 | |
|     result = rt_device_control(wifi_device,
 | |
|                                RW009_CMD_SOFTAP,
 | |
|                                (void *)&softap);
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| int32_t rw009_rssi(void)
 | |
| {
 | |
|     rt_err_t result;
 | |
|     struct rw009_wifi * wifi_device;
 | |
| 
 | |
|     wifi_device = (struct rw009_wifi *)rt_device_find("w0");
 | |
| 
 | |
|     if(wifi_device == RT_NULL)
 | |
|         return 0;
 | |
| 
 | |
|     if(wifi_device->active == 0)
 | |
|         return 0;
 | |
| 
 | |
|     // SCAN
 | |
|     result = rt_device_control((rt_device_t)wifi_device,
 | |
|                                RW009_CMD_RSSI,
 | |
|                                RT_NULL);
 | |
| 
 | |
|     if(result == RT_EOK)
 | |
|     {
 | |
|         return wifi_device->ap_info.rssi;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #ifdef RT_USING_FINSH
 | |
| #include <finsh.h>
 | |
| 
 | |
| static rt_err_t rw009_scan(void)
 | |
| {
 | |
|     rt_err_t result;
 | |
|     struct rw009_wifi * wifi_device;
 | |
| 
 | |
|     wifi_device = (struct rw009_wifi *)rt_device_find("w0");
 | |
| 
 | |
|     rt_kprintf("\nCMD RW009_CMD_SCAN \n");
 | |
|     result = rt_device_control((rt_device_t)wifi_device,
 | |
|                                RW009_CMD_SCAN,
 | |
|                                RT_NULL);
 | |
| 
 | |
|     rt_kprintf("CMD RW009_CMD_SCAN result:%d\n", result);
 | |
| 
 | |
|     if(result == RT_EOK)
 | |
|     {
 | |
|         uint32_t i;
 | |
|         rw009_ap_info *ap_info;
 | |
| 
 | |
|         for(i=0; i<wifi_device->ap_scan_count; i++)
 | |
|         {
 | |
|             ap_info = &wifi_device->ap_scan[i];
 | |
|             rt_kprintf("AP #%02d SSID: %-32.32s\n", i, ap_info->ssid );
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| FINSH_FUNCTION_EXPORT(rw009_scan, SACN and list AP.);
 | |
| FINSH_FUNCTION_EXPORT(rw009_join, RW009 join to AP.);
 | |
| FINSH_FUNCTION_EXPORT(rw009_rssi, get RW009 current AP rssi.);
 | |
| 
 | |
| #endif // RT_USING_FINSH
 |