Rainbow Electronics Поиск Switch to English
Продукция Горячие предложения Склад и цены Решения Статьи Разработчикам О компании Контакты Карта сайта
Главная страница
Управление офисным освещением по Wi-Fi. Часть 1: Wi-Fi модуль Atmel WINC1500 tutorial

Целью цикла является ознакомление читателей с основами работы по трем продуктам компании Atmel:

  • Микроконтроллером из серии SAMD21 с ядром Cortex-M0+
  • Wi-Fi модулем WINC1500
  • Технологией сенсорных кнопок Q-touch

Введение


В данном цикле статей речь пойдет не о DIY разработке а-ля «Умный офис» или «коробочном» продукте, который мы предлагаем купить. Целью цикла является ознакомление читателей с основами работы по трем продуктам небезызвестной компании Atmel:
  • Микроконтроллером из серии SAMD21 с ядром Cortex-M0+
  • Wi-Fi модулем WINC1500
  • Технологией сенсорных кнопок Q-touch

Только вместо привычного мигания светодиодом на отладке, мы для пущей масштабности решили помигать светильниками в нашем офисе через Wi-Fi сеть с использованием промышленного протокола ModBus TCP, а управлять будем при помощи сенсорных кнопок и слайдеров. Использовать для этого будем уже хорошо знакому нашим читателям отладочную плату SAMD21 Xplained Pro, c 2-мя подключенными к ней модулями расширения ATWINC1500-XPRO и ATQT1-XPRO. Подключив модули расширения к отладке получаем следующую конструкцию:


Немного об отладках серии Xplained Pro
Xplained Pro Kits — это серия отладочных плат среднего ценового сегмента (самыми дешевыми являются киты серии Xplained mini) на различные семейства микроконтроллеров Atmel и набор модулей расширения к ним. Причем, за счет унифицированных краевых разъемов на отладках модули расширения подходят к любой плате. Т.е. реализована концепция а-ля Arduino. На всех платах установлен отладчик EDBG. Остальная периферия на плате зависит от установленного на ней контроллера. 

Постановка задачи


У нас в офисе установлены светодиодные управляемые (читай диммируемые) светильники, работающие по протоколу DALI. Для связи с внешним миром система освещения использует шлюз ModBus-DALI нашей разработки. Шлюз может управляться как по интерфейсу RS485 (ModBus RTU), так и через Ethernet (ModBus TCP). Для решения нашей задачи будем использовать последний. Таким образом, наша конструкция подключается к локальной сети по Wi-Fi, микроконтроллер анализирует состояние сенсорных кнопок и слайдера и преобразует их в команды протокола ModBus TCP. Те, в свою очередь, преобразуются в команды DALI и отсылаются на исполнение светильникам.
Примечание: шлюз ModBus DALI не является объектом описания в данном цикле статей, а принимается как данность и единственный способ интеграции в систему управления освещением (СУО).

Подключение Wi-Fi модуля WINC1500


Atmel, как и многие другие производители полупроводниковой техники, пытается найти себе тепленькое местечко в малопонятном, но набирающем силу и популярность финансовом «пузыре» под названием Internet Of Things. Поэтому свои Wi-Fi решения Atmel позиционирует как малопотребляющие и рассчитанные на применение в устройствах интернета вещей. Рассматриваемый в сегодняшней статье модуль WINC1500 рассчитан на работу с хост контроллером по последовательному интерфейсу UART/SPI/I2C. Модуль имеет чип-антенну на борту.

 

Краткие характеристики из даташита

  • IEEE®802.11 b/g/n 20MHz (1x1) solution
  • Single spatial stream in 2.4GHz ISM band
  • Integrated PA and T/R Switch
  • Integrated PCB antenna
  • Superior Sensitivity and Range via advanced PHY signal processing
  • Advanced Equalization and Channel Estimation
  • Advanced Carrier and Timing Synchronization
  • Wi-Fi Direct and Soft-AP support
  • Supports IEEE 802.11 WEP, WPA, WPA2 Security
  • Supports China WAPI security
  • Superior MAC throughput via hardware accelerated two-level A-MSDU/A-MPDU frame aggregation and block acknowledgement
  • On-chip memory management engine to reduce host load
  • SPI, UART, and I2C host interfaces
  • 2- or 3-wire Bluetooth® coexistence interface
  • Operating temperature range of -40°C to +85°C
  • I/O operating voltage of 2.7V to 3.6V
  • Integrated Flash memory for system software
  • Power Save Modes
  • Integrated Network IP stack to minimize host CPU requirements
  • Network features TCP, UDP, DHCP, ARP, HTTP, SSL, and DNS
  • Small footprint host driver (4KB flash – less than 1KB RAM)



Подключение модуля расширения к отладке и предварительная настройка


Отладка SAMD21 Xplained имеет 3 внешних разъема для подключения плат расширения. По умолчанию проект создается из предположения, что плата расширения с WINC1500 подключена к разъему отладки EXT1. Если требуется подключить её к другому разъему нужно в файле conf_winc.h поменять порты:

 

Дефайны для использования EXT3

//  ---------- PIN settings --------- 
 
#define CONF_WINC_PIN_RESET                     PIN_PA27  
#define CONF_WINC_PIN_CHIP_ENABLE               PIN_PA28  
#define CONF_WINC_PIN_WAKE                              PIN_PB08    

//    ---------- SPI settings ---------  
#define CONF_WINC_USE_SPI                               (1)    

/** SPI pin and instance settings. */  
#define CONF_WINC_SPI_MODULE                    SERCOM2  
#define CONF_WINC_SPI_SERCOM_MUX                SPI_SIGNAL_MUX_SETTING_D  
#define CONF_WINC_SPI_PINMUX_PAD0               PINMUX_PA12C_SERCOM2_PAD0 /* out */  
#define CONF_WINC_SPI_PINMUX_PAD1               PINMUX_PA13C_SERCOM2_PAD1 /* sck  */  
#define CONF_WINC_SPI_PINMUX_PAD2               PINMUX_UNUSED /* cs driven from software */  
#define CONF_WINC_SPI_PINMUX_PAD3               PINMUX_PA15C_SERCOM2_PAD3 /* in  */  
#define CONF_WINC_SPI_CS_PIN                    PIN_PA14    

/** SPI interrupt pin. */  
#define CONF_WINC_SPI_INT_PIN                   PIN_PB09A_EIC_EXTINT9  
#define CONF_WINC_SPI_INT_MUX                   MUX_PB09A_EIC_EXTINT9  
#define CONF_WINC_SPI_INT_EIC                   (9)  


Модуль соединен с хост контроллером на отладке по SPI, кроме того к модулю идет порт ввода вывода, которым модуль «дергает» при каком-либо событии (приеме/отправке пакета). В коде настроено аппаратное прерывание при изменении уровня на этом пине. При возникновении прерывания в обработчике увеличивается счетчик событий.

Настройка дебажного вывода в COM-порт


Встроенный отладчик EDBG определяется в диспетчере устройств как отладчик и как виртуальный COM-port, на вывод в который можно настроить один из SERCOM'ов микроконтроллера. Таким образом, можно выводить отладочные сообщения в COM-порт через тот же разъем USB-micro, через который идет программирование и отладка:

 

Код функции инициализации

static void configure_console(void)  
{       
                struct usart_config usart_conf;
        
                usart_get_config_defaults(&usart_conf);         
                usart_conf.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;   
                usart_conf.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;   
                usart_conf.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;   
                usart_conf.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;   
                usart_conf.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;   
                usart_conf.baudrate    = 115200;        

                stdio_serial_init(&cdc_uart_module, EDBG_CDC_MODULE, &usart_conf);      
                usart_enable(&cdc_uart_module);  
}  



Callback'и наше всё


Библиотека для работы с модулем WINC1500 построена по принципу Callback'ов, т.е. если мы что-то хотим от модуля (например, получить число доступных Wi-Fi сетей в радиоэфире), то мы вызываем соответствующую функцию (которая посылает нужный запрос в модуль) и модуль уходит «думать». Когда модуль сформирует результат, он изменит состояние пина INT, вызвав тем самым внешнее прерывание в микроконтроллере, обработчик которого увеличивает счетчик событий. При вызове функции m2m_wifi_handle_events(NULL); считывается количество событий и параметры (тип, необходимые данные) каждого события (в нашем примере, это завершение сканирования эфира и готовность выдать число найденных сетей) и вызывается соответствующая функция (Callback), если она инициализирована и зарегистрирована заранее.



Проверка связи с WINC1500 по SPI


Для начала работы необходимо инициализировать модуль, настроить и зарегистрировать необходимые Callback'и. Для чтения параметров модуля callback не нужен, поэтому пока его не регистрируем и не делаем.

 

Инициализация модуля и получение его параметров

int main(void)  
{       
                tstrWifiInitParam settings;     
                int8_t ret;     

                // Initialize the board.  
                system_init();          

                // Initialize the UART console.         
                configure_console();    
                printf(STRING_HEADER);          

                // Initialize the BSP.          
                nm_bsp_init();          

                // Initialize Wi-Fi parameters structure.       
                memset((uint8_t *)&settings, 0, sizeof(tstrWifiInitParam));     

                //Initialize Wi-Fi driver with data and status callbacks.       
                ret = m2m_wifi_init(&settings);         
                if (M2M_SUCCESS != ret)           
                {               
                                printf("main: m2m_wifi_init call error!(%d)\r\n", ret);                 
                                while (1);      
                }       

                // Display WINC1500 chip information.   
                printf("Chip ID : \r\t\t\t%x\r\n", (unsigned int)nmi_get_chipid());     
                printf("RF Revision ID : \r\t\t\t%x\r\n", (unsigned int)nmi_get_rfrevid());     
                printf("Done.\r\n\r\n");        

                while (1);      
                return 0;  
}  



Создание точки доступа


WINC1500 позволяет создавать точку доступа и раздавать подключившимся абонентам IP-адреса по DHCP. Начало main такое же, как в предыдущем примере, но добавляется инициализация структуры, содержащей параметры точки доступа, и создание точки доступа, а также регистрация callback перед инициализацией модуля:
// Initialize Wi-Fi parameters structure.        

                memset((uint8_t *)&settings, 0, sizeof(tstrWifiInitParam));     

                // Initialize Wi-Fi driver with data and status callbacks.      
                settings.pfAppWifiCb = wifi_cb;         
                ret = m2m_wifi_init(&settings);         
                if (M2M_SUCCESS != ret)         
                {               

                printf("main: m2m_wifi_init call error!(%d)\r\n", ret);                 
                while (1);      
                }
В режиме точки доступа WINC1500 поддерживается только и WEP шифрование (WPA не поддерживается), либо открытая Wi-Fi сеть. Так же поддерживается только 1 клиент.
Создание точки доступа. Дополнительный код

 

Код функции main:

     // Initialize AP mode parameters structure with SSID, channel and OPEN security type.           
        memset(&strM2MAPConfig, 0x00, sizeof(tstrM2MAPConfig));         
        strcpy((char *)&strM2MAPConfig.au8SSID, MAIN_WLAN_SSID);        
        strM2MAPConfig.u8ListenChannel = MAIN_WLAN_CHANNEL;     
        strM2MAPConfig.u8SecType = MAIN_WLAN_AUTH; 
        
        strM2MAPConfig.au8DHCPServerIP[0] = 192;        
        strM2MAPConfig.au8DHCPServerIP[1] = 168;        
        strM2MAPConfig.au8DHCPServerIP[2] = 1;          
        strM2MAPConfig.au8DHCPServerIP[3] = 1;    

#if USE_WEP     
        strcpy((char *)&strM2MAPConfig.au8WepKey, MAIN_WLAN_WEP_KEY);   
        strM2MAPConfig.u8KeySz = strlen(MAIN_WLAN_WEP_KEY);     
        strM2MAPConfig.u8KeyIndx = MAIN_WLAN_WEP_KEY_INDEX;  

#endif          
        
        /* Bring up AP mode with parameters structure. */       
        ret = m2m_wifi_enable_ap(&strM2MAPConfig);      
        if (M2M_SUCCESS != ret)         
        {               
        
        printf("main: m2m_wifi_enable_ap call error!\r\n");             
        while (1);      
        
        }       

        printf("AP mode started. You can connect to %s.\r\n", (char *)MAIN_WLAN_SSID);          

        while (1)       
        {               

                while (m2m_wifi_handle_events(NULL) != M2M_SUCCESS);            
                // Handle pending events from network controller.  
        }           

// Код callback   
static void wifi_cb(uint8_t u8MsgType, void *pvMsg)  
{       
                switch (u8MsgType) {    
                case M2M_WIFI_RESP_CON_STATE_CHANGED:   
                {               
                        
                        tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg;              
                        if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED) {                 
                        } else if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED) {                       
                                printf("Station disconnected\r\n");             
                        }               

                        break;          

        }       

                case M2M_WIFI_REQ_DHCP_CONF:    
        {               

                uint8_t *pu8IPAddress = (uint8_t *)pvMsg;               
                printf("Station connected\r\n");                
                printf("Station IP is %u.%u.%u.%u\r\n",                                 
                                pu8IPAddress[0], pu8IPAddress[1], pu8IPAddress[2], pu8IPAddress[3]);            
                
                break;          

        }       

        default:        
        {               
                break;          
        }       

        }  
}      


Файл main.h: 
/** Security mode */  
#define USE_WEP                                  (1) /*< Set to (1) to use WEP, and (0) to use OPEN */    

/** AP mode Settings */  
#define MAIN_WLAN_SSID           "WINC1500_AP" /* < SSID */  
#if USE_WEP  
#define MAIN_WLAN_AUTH           M2M_WIFI_SEC_WEP /* < Security manner */  
#define MAIN_WLAN_WEP_KEY        "1234567890" /* < Security Key in WEP Mode */  
#define MAIN_WLAN_WEP_KEY_INDEX  (1)  
#else  #define MAIN_WLAN_AUTH           M2M_WIFI_SEC_OPEN /* < Security manner */  
#endif  
#define MAIN_WLAN_CHANNEL        (6) /* < Channel number */  


Работа в режиме точки доступа, в связи с озвученными ограничениями, не является основным режимом работы WINC1500, а служит в основном для реализации механизма подключения к сторонней точке доступа. Например, если в Вашем устройстве нет интерфейса для того, чтобы задать параметры сети (SSID и пароль), к которой необходимо подключиться, можно сначала создать собственную точку доступа и подключившись к ней передать каким-либо способом данные о целевой сети.
Кстати в модуле уже реализован этот механизм: специальной командой можно помимо старта собственной точки доступа, можно запустить встроенный в модуль WEB-сервер и подключившись к нему браузером задать параметры подключения к целевой сети.

Получение списка доступных сетей


Теперь просканируем эфир на предмет наличия Wi-Fi сетей и выведем их список в отладочный порт.
Для запуска сканирования достаточно вызвать функцию m2m_wifi_request_scan(M2M_WIFI_CH_ALL), сразу после инициализации модуля
 /* Initialize Wi-Fi parameters structure. */   
        memset((uint8_t *)&settings, 0, sizeof(tstrWifiInitParam));     
        /* Initialize Wi-Fi driver with data and status callbacks. */   
        settings.pfAppWifiCb = wifi_cb;         
        ret = m2m_wifi_init(&settings);         
        if (M2M_SUCCESS != ret)          
        {               

        printf("main: m2m_wifi_init call error!(%d)\r\n", ret);                 
        while (1);      
        
        }       
        /* Request scan. */     
        m2m_wifi_request_scan(M2M_WIFI_CH_ALL);  


Но при этом нужно предусмотреть соответствующую обработку событий по сканированию в callback wifi_cb


Код wifi_cb для сканирования
static void wifi_cb(uint8_t u8MsgType, void *pvMsg)  
{       

        switch (u8MsgType) {    
        case M2M_WIFI_RESP_SCAN_DONE:   
        {               

                tstrM2mScanDone *pstrInfo = (tstrM2mScanDone *)pvMsg;           
                scan_request_index = 0;                 
                if (pstrInfo->u8NumofCh >= 1)                   
                {                       

                        m2m_wifi_req_scan_result(scan_request_index);                   
                        scan_request_index++;           
                }               
                else            
                {                       
                        m2m_wifi_request_scan(M2M_WIFI_CH_ALL);                 
                }               

                break;          

        }       

        case M2M_WIFI_RESP_SCAN_RESULT:         
        {               

                tstrM2mWifiscanResult *pstrScanResult = (tstrM2mWifiscanResult *)pvMsg;                 
                uint16_t demo_ssid_len;                 
                uint16_t scan_ssid_len = strlen((const char *)pstrScanResult->au8SSID);                 

                /* display founded AP. */               
                printf("[%d] SSID:%s\r\n", scan_request_index, pstrScanResult->au8SSID);                

                num_founded_ap = m2m_wifi_get_num_ap_found();           
                if (scan_ssid_len) {                    

                        /* check same SSID. */                          
                        demo_ssid_len = strlen((const char *)MAIN_WLAN_SSID);                   
                        if(     (demo_ssid_len == scan_ssid_len) &&     (!memcmp(pstrScanResult->au8SSID, (uint8_t *)MAIN_WLAN_SSID, demo_ssid_len)))                           
                        {                               
                                /* A scan result matches an entry in the preferred AP List.                              
                                * Initiate a connection request.                                 
                                */                              
                                printf("Found %s \r\n", MAIN_WLAN_SSID);                                
                                m2m_wifi_connect((char *)MAIN_WLAN_SSID,sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH,(void *)MAIN_WLAN_PSK,M2M_WIFI_CH_ALL);                                  
                                        break;                          
                        }               
                }               

                if (scan_request_index < num_founded_ap)                
                {                       
                        m2m_wifi_req_scan_result(scan_request_index);                   
                        scan_request_index++;           
                }               
                else            
                {                       
                        printf("can not find AP %s\r\n", MAIN_WLAN_SSID);                       
                        m2m_wifi_request_scan(M2M_WIFI_CH_ALL);                 
                }               

                break;          

        }       
        case M2M_WIFI_RESP_CON_STATE_CHANGED:   
        {               
                tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg;              
                if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED)                   
                {                       
                        m2m_wifi_request_dhcp_client();                 
                }                  
                else if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED)                 
                {                       
                        printf("Wi-Fi disconnected\r\n");                       

                        /* Request scan. */                     
                        m2m_wifi_request_scan(M2M_WIFI_CH_ALL);                 
                }               
                break;          
        }
        
        case M2M_WIFI_REQ_DHCP_CONF:    
        {               
                uint8_t *pu8IPAddress = (uint8_t *)pvMsg;               
                printf("Wi-Fi connected\r\n");                  
                printf("Wi-Fi IP is %u.%u.%u.%u\r\n", pu8IPAddress[0], pu8IPAddress[1], pu8IPAddress[2], pu8IPAddress[3]);              
                break;          
        }       

        default:        
        {               
                break;          
        }       
        }  
}  


Отлаживать соединение и передачу данных по UDP/TCP и вообще дебажить очень удобно Геркулесом)
Дебажный вывод результата сканирования:



Подключение по DHCP


По умолчанию WINC подключается по DHCP, и по намекам в разных комментариях и документах Atmel, они хотят прекрыть возможность подключаться со статическим IP. 

При подключении по DHCP код callback должен обрабатывать соответствующее событие.

 

Код wifi_cb при использовании DHCP

static void wifi_cb(uint8_t u8MsgType, void *pvMsg)  
{       

        switch (u8MsgType) {    
        case M2M_WIFI_RESP_CON_STATE_CHANGED:   
        {               

                tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg;              
                if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED)                 
                {                       

                printf("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: CONNECTED\r\n");                      
                m2m_wifi_request_dhcp_client();                 
                }                  
                else if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED)                  
                {                       
                        printf("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: DISCONNECTED\r\n");                   
                        wifi_connected = 0;                     
                        m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL);               
                        }               

                break;          
        }       
        case M2M_WIFI_REQ_DHCP_CONF:    
        {               
                        uint8_t *pu8IPAddress = (uint8_t *)pvMsg;               
                        wifi_connected = 1;             
                        printf("wifi_cb: M2M_WIFI_REQ_DHCP_CONF: IP is %u.%u.%u.%u\r\n",pu8IPAddress[0], pu8IPAddress[1], pu8IPAddress[2], pu8IPAddress[3]);            
                        break;          
        }
                
        default:        
        {               
                        break;          
        }       
        }  
}



Подключение со статическим адресом


Для подключения со статическим адресом сначала надо запретить автоматическое подключение по dhcp в main после инициализации модуля:
 m2m_wifi_enable_dhcp(0);  

И соответствующим образом изменить callback:

Код wifi_cb при использовании статического IP

static void wifi_cb(uint8_t u8MsgType, void *pvMsg)  
{               

        printf("wifi_cb: u8MsgType= %d\n",u8MsgType);   
        switch (u8MsgType) {    
        case M2M_WIFI_RESP_CON_STATE_CHANGED:   
        {               
                tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg;              
                if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED)                   
                {                       
                        printf("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: CONNECTED\r\n");
                                                        
                        tstrM2MIPConfig ip_client;                      
                        ip_client.u32StaticIP = _htonl(0xc0a8142d); //corresponds to 192.168.20.45                      
                        ip_client.u32DNS = _htonl(0xc0a80266); //corresponds to 192.168.2.102                   
                        ip_client.u32SubnetMask =_htonl(0xFFFFFF00); //corresponds to 255.255.255.0                     
                        ip_client.u32Gateway = _htonl(0xc0a81401);  //corresponds to 192.168.20.1                       
                        m2m_wifi_set_static_ip(&ip_client);                                     

                        wifi_connected = 1;             
                }               
                else            
                {                       
                        if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED)                        
                        {                          
                                printf("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: DISCONNECTED\r\n");                      
                                wifi_connected = 0;                        
                                m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL);                       
                        }               
                }               
                break;          
        }       
        default:                
                break;          
        }  
}  


Работа с TCP/IP стеком


Большинство API для работы с TCP/IP стеком через WINC1500 реализованы по аналогии с сокетам Беркли.
Беркли API WINC API Server/Client TCP/UDP Описание
socket socket Both Both Создает новый сокет
connect connect Client TCP Устанавливает TCP соединение с удаленным сервером
bind bind Server Both Биндит сокет с IP адресом и портом
listen listen Server TCP Создает TCP сервер
send send Both Both Отправляет данные в сокет
sendto sendto Both UDP Посылает пакет по UDP
recv recv Both Both Получает пакет
recvfrom recvfrom Both Both Получает пакет
close close Both Both Закрывает соединение и освобождает ресурсы
gethostbyname gethostbyname Both Both Получает IP адрес по имени хоста
setsockopt setsockopt Both Both Устанавливает опции сокета
htons/ntohs htons/ntohs Both Both Меняет порядок байт в 2-байтовых целых из представления хоста в сетевое и наоборот
htonl/ntohl htonl/ntohl Both Both Меняет порядок байт в 4-байтовых целых из представления хоста в сетевое и наоборот
Примечание: API функции Беркли write, read, gethostbyaddr, select, poll, getsockopt в WINC1500 не поддерживаются.

UDP и TCP


Для работы по UDP и TCP необходимо создать соответствующие сокеты, инициализировать их, открыть, написать и зарегистрировать callback для обработки приема/передачи данных. Не будем подробно останавливаться на каждом случае (UDP отправка/прием, TCP клиент/сервер), рассмотрим основные моменты.
Инициализация параметров сокета осуществляется с помощью соответствующей структуры. В ней нужно задать тип подключения, порт, IP сервера (в виде 0xc0a814ff, например для 192.168.20.255)
struct sockaddr_in src_addr;     

        addr.sin_family = AF_INET;      
        addr.sin_port = _htons(MAIN_WIFI_M2M_SERVER_PORT);      
        addr.sin_addr.s_addr = _htonl(MAIN_WIFI_M2M_SERVER_IP);  

Инициализируем сокет и callback к нему, а также подключаемся к сети с заданными ранее параметрами в структуре addr:
 socketInit();   
        registerSocketCallback(socket_cb, NULL);        

        // Connect to router.   
        m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL);       
        printf("m2m_wifi_connect!\r\n");  

В основном цикле создаем сокет и биндим его и реализовываем поддержку соединения (в случае отключения переподключение). И для UDP и для TCP эту процедуры аналогичны за исключением типа подключения (SOCK_DGRAM UDP, SOCK_STREAM TCP). 
SOCKET rx_socket = -1;  
В while(1):     
        if (rx_socket < 0)          
        {                  
                if ((rx_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)                      
                {                         
                printf("main: failed to create RX UDP Client socket error!\r\n");                         
                continue;                  
                }                  
                // Socket bind                     
                bind(rx_socket, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_in));      

        }       
        if (wifi_connected == M2M_WIFI_CONNECTED)       
        {               
                // Open client socket.                  
                if (rx_socket < 0)              
                {                       
                        if ((rx_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)                          
                        {                               
                                printf("main: failed to create TCP client socket error!\r\n");                                  
                                continue;                       
                        }                       
                        // Connect server                                                      
                        printf("socket_number new connection: %d\r\n", rx_socket);                     
                        ret=connect(rx_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));                  
                        printf("ret value: %d\r\n", ret);                         
                        connected = FALSE;                     
                        if (ret < 0)                   
                        {                                       
                                close(rx_socket);                                       
                                rx_socket = -1;                         
                        }               
                }       
        }  


Callback должен обрабатывать события подключения/бинда, приема, передачи данных и для сервера TCP: listen, accept.

Пример callback для одновременной работы то UDP (rx_socket) и TCP (tcp_client_socket):

socket_cb для UDP и TCP
static void socket_cb(SOCKET sock, uint8_t u8Msg, void *pvMsg)  
{       

        // Check for socket event on RX socket.         
        if (sock == rx_socket)          
        {               
                if (u8Msg == SOCKET_MSG_BIND)                   
                {                       
                        tstrSocketBindMsg *pstrBind = (tstrSocketBindMsg *)pvMsg;                       
                        if (pstrBind && pstrBind->status == 0)                          
                        {                               
                                // Prepare next buffer reception.                               
                                sock_bind_state = 1;                            
                                recv(sock, udp_data_rx, MAIN_WIFI_M2M_BUFFER_SIZE, 0);                          
                        }                       
                        else                    
                        {                               
                                printf("socket_cb: bind error!\r\n");                   
                        }               
                }               
                else if (u8Msg == SOCKET_MSG_RECVFROM)                  
                {                       
                        tstrSocketRecvMsg *pstrRx = (tstrSocketRecvMsg *)pvMsg;                         
                        if (pstrRx->pu8Buffer && pstrRx->s16BufferSize)                         
                        {                               
                                delay = 0;                              
                                sock_rx_state = pstrRx->s16BufferSize;                                  
                                printf("socket_cb udp recv!\r\n");                              
                                printf("rx packet length= %d\n",pstrRx->s16BufferSize);                         
                        }                       
                        else                    
                        {                               
                                if (pstrRx->s16BufferSize == SOCK_ERR_TIMEOUT)                                  
                                {                                       
                                        // Prepare next buffer reception.                                      
                                        recv(sock, udp_data_rx, MAIN_WIFI_M2M_BUFFER_SIZE, 0);                                  
                                }                       
                        }               
                }               
                if (u8Msg == SOCKET_MSG_SENDTO)                 
                {                       
                        recv(sock, udp_data_rx, MAIN_WIFI_M2M_BUFFER_SIZE, 0);                          
                        sock_tx_state = 1;              
                }       
        }       
        if (sock == tcp_client_socket)          
        {                          
                switch (u8Msg)             
                {                  
                        // Socket connected                
                        case SOCKET_MSG_CONNECT:                   
                        {                     
                                tstrSocketConnectMsg *pstrConnect = (tstrSocketConnectMsg *)pvMsg;                        
                                        if (pstrConnect && pstrConnect->s8Error >= 0)                     
                                        {                                 
                                                printf("socket_cb tcp connect!\r\n");                             
                                                tcp_ready_to_send=1;                      
                                        }                         
                                        else                      
                                        {                                 
                                                close(tcp_client_socket);                                 
                                                tcp_client_socket = -1;                           
                                        }                 
                                }                 
                                break;                    

                                // Message send                   
                                case SOCKET_MSG_SEND:             
                                {                          
                                        printf("socket_cb tcp send!\r\n");                        
                                        recv(tcp_client_socket, tcp_data_rx, sizeof(tcp_data_rx), 0);                     
                                        tcp_tx_ready=1;                   
                                }                 
                                break;                    

                                // Message receive                
                                case SOCKET_MSG_RECV:             
                                {                                                 

                                        tstrSocketRecvMsg *pstrRecv = (tstrSocketRecvMsg *)pvMsg;                         
                                        if (pstrRecv && pstrRecv->s16BufferSize > 0)                      
                                        {                                 
                                                tcp_rx_ready=pstrRecv->s16BufferSize;                     
                                        }                         
                                        else                      
                                        {                                 
                                                close(tcp_client_socket);                                 
                                                tcp_client_socket = -1;                           
                                        }                 
                                }                 
                                break;                    

                                default:                    
                                break;             
                        }                       
                }  
}  


При этом важно не забывать вызывать в while(1) функцию обработки событий от модуля:
m2m_wifi_handle_events(NULL);  

Заключение

Теперь, используя полученные знания мы уже можем подключиться по локальной сети к нашему ModBus-DALI шлюзу. Шлюз является TCP сервером на 502 порту. Но об этом в третьей части цикла, который мы посвятим реализации протокола ModBus TCP поверх нашей локальной сети. Во второй части рассмотрим подключение и использование сенсорных кнопок в качестве интерфейса управления. До новых встреч.

версия для печати

Наверх
главная страница | продукция | горячее предложение | склад и цены | решения | статьи | разработчикам | о компании | контакты | карта сайта
Предприятия, компании и выставки России и СНГ

Rainbow Electronics, 2003-2024
https://betonmobile.ru/mobile-liga-stavok
Разработка сайта FlyNet
prev next list
rand
Rambler's Top100

RadioTOP-рейтинг радиотехнических сайтов
Гипермаркет Shop.Sec.Ru
Поиск электронныхкомпонентов
Поиск электронных компонентов по складам поставщиков России и СНГ.
Поиск электронных компонентов Индекс популярности микроконтроллеров на mcu.caxapa.ru
Справочник по микросхемам
на Русском языке