1i7 (1i7) wrote,
1i7
1i7

Categories:

ChipKIT: подключение к Вайфай

Начинаем подготовку к выпуску наших роботов в Сеть делать там разные интересные вещи, но для начала придется разобраться с необходимой стартовой рутиной: напишем программу, которая подключает плату ChipKIT к беспроводной сети WiFi - открытой или защищенной паролем.

ChipKIT WF32 подключение к беспроводной сети WiFi from 1i7 on Vimeo.



Подключенный к плате ChipKIT WF32 светодиод показывает статус беспроводного подключения: он горит, когда плата подключена к вайфай, и не горит, когда плата не подключена. Как видно из видео, реакция на события включения/выключения точки со стороны платы требует некоторого времени (10-15 секунд), но в целом все работает достаточно надежно.

В роли точки доступа выступает Ётафон, раздающий вайфай в режиме модема (эта функция доступна на любом смартфоне с Андроид); вместо него подойдет обычная домашняя точка доступа или iPhone, который тоже умеет раздавать интернет через WiFi.

В Андроиде Настройки > Ещё... > Режим модема



Android modem config.png

Android-WiFi point config.png




Оборудование

В серии ChipKIT с WiFi умеют работать платы:

ChipKIT Wi-FIRE (судя по всему уже поступила в продажу)
chipKIT-WiFIRE.png

ChipKIT WF32
chipKIT_WF32.png

ChipKIT Uno32 с WiFi Shield
chipKIT-WiFi-Shield.jpg


Библиотеки и документация

Среду разработки MPIDE для плат ChipKIT для Linux/Mac/Windows нужно качать на сайте chipkit.net. Для работы с WiFi также потребуются дополнительные библиотеки - их можно найти например на странице платы ChipKIT WF32 в магазине Digilent (см список закачек Support Documents внизу старницы: архив chipKIT Network and USB Libs-xxx.zip). В этом же архиве содержится необходимая документация и инструкции по установке (в Linux архив нужно распаковать в ~/Documents/mpide-sketches/libraries, в Windows - в папку "C:\Users\MyName\Documents\mpide\libraries").

Замечание: Библиотека для работы с WiFi на платах ChipKIT представляет собой простую C++ обертку над стеком Tcp и WiFi для процессоров PIC32 от Microchip (он входит в состав пакета MLA - Microchip libraries for applications), поэтому этот код не является переносимым внутри всей платформы Arduino - он будет работать только на платах серии ChipKIT. Во-первых, насколько мне известно, в платформе Arduino не предусмотрен стандартный API для работы с WiFi, поэтому WiFi-шилды для обычных Ардуин используют свои вызовы; во-вторых, код стека Tcp и WiFi, написанный для PIC32, будет проблематично запустить на процессорах AVR на обычной Arduino из-за чисто технических причин и особенностей архитектур; в-третьих, это все равно нельзя делать, тк. библиотеки MLA Microchip публикует под проприетарной лицензией - хотя исходный код стека доступен и его можно модифицировать под нужды проекта, лицензия не позволяет запускать его на чипах других производителей (в частности, AVR).

Алгоритм
Программа постоянно ищет сеть WiFi с заданным именем (lasto4ka). Если сеть найдена, пытается к ней подключиться с заданным типом безопасности: используя пароль (WPA2) или как к открытой сети без пароля. Если подключение удалось, программа зажигает лампочку статуса и печатает сообщение "WiFi is ON, do something with network" в отладочный порт Serial UART раз в 5 секунд. Если подключение теряется, программа гасит лампочку переходит в режим поиска сети с заданными параметрами.

Отладочные сообщения о ходе выполнения программы на плате можно посмотреть в MPIDE в окне Tools/Serial Monitor.

mpide_serial_monitor_wifi.png


Замечание: Имя сети, тип подключения (открытая сеть/пароль WPA2) и сам пароль (в случае WPA2) задаются жестко в коде прошивки, иначе нам пришлось бы дополнительно придумывать, каким образом доставлять их на плату.


Собственно код

Вся прошивка умещаяется в одном файле chipkit_wifi.pde.

Подключим необходимые библиотеки:


#include <WiFiShieldOrPmodWiFi_G.h>

#include <DNETcK.h>
#include <DWIFIcK.h>



Параметры для подключения к точке доступа: открытая или запароленная, имя сети и пароль:

// Точка доступа ВайФай
boolean USE_SECURITY_OPEN = false;

const char* wifi_ssid = "lasto4ka";
const char* wifi_wpa2_passphrase = "robotguest";



Укажем, каким образом будем получать IP-адрес - динамический (точка сама назначит по своему усмотрению в момент подключения) или статический (попросим точку назначить адрес, нужный нам):


boolean USE_STATIC_ADDRESS = true;

// статический IP-адрес для текущего хоста - если включен режим
// USE_STATIC_ADDRESS = true, то попросим у точки Wifi дать его нам
IPv4 host_ip = {192,168,43,117};



Сюда будем сохранять идентификатор активного подключения для внутренних нужд программы:


// Подключение к WiFi
int connectionId = DWIFIcK::INVALID_CONNECTION_ID;



Назначим пин для светодиода, который будет отображать текущий статус подключения:


// Пин для лампочки статуса WiFi
#define WIFI_STATUS_PIN 13



В сетапе ничего интересного - включаем последовательный порт UART для вывода отладочных сообщений по USB в MPIDE на компьютере, переводим пин для лампочки со статусом подключения к вайфай в режим вывода.


void setup() {
    Serial.begin(9600);
    Serial.println("Start wifi network connection demo");

    pinMode(WIFI_STATUS_PIN, OUTPUT);
}



Всё интересное находится в бесконечном цикле loop.

Сетевой стек для PIC32 на ChipKIT (как и стек USB) не является многопоточным - в прошивке, которую мы загрузим на плату, не будет такого секретного системного фонового потока, который бы держал связь с точкой вайфай, следил за статусом подключения, передачей данных и т.п. В нашей программе есть только один поток - loop, поэтому все эти операции должны осуществляться внутри него в промежутке между выполнением остальных полезных действий - для этого нам достаточно поместить вызов DNETcK::periodicTasks() в код так, чтобы он время от времени вызывался например раз за цикл.


void loop() {
    DNETcK::STATUS networkStatus;
    
    // Держим Tcp-стек в живом состоянии
    DNETcK::periodicTasks();
    
    ....
}



На очередной итерации проверяем, подключены ли мы к точке, при помощи вызова DWIFIcK::isConnected(): если не подключены гасим лампочку статуса и начинаем попытку подключения.


    if(!DWIFIcK::isConnected(connectionId)) {
        // Не подключены к WiFi - выключим лампочку
        digitalWrite(WIFI_STATUS_PIN, LOW);
        
        bool connectedToWifi = false;
      
        // Подключимся к сети Wifi
        Serial.println("Connecting wifi...");
    
        ....
    }



Для начала получим доступ к оборудованию WiFi при помощи системного вызова DWIFIcK::connect() с нужными параметрами (имя сети, пароль, статус возврата): если хотим подключиться к открытой сети, передаем только ее имя, если к защищенной, то вызываем вариант с паролем.


        // Сначала получим доступ к оборудованию:
        // выбрать способ подключения (открытый или с паролем)
        if(USE_SECURITY_OPEN) {
            // Подключиться к открытой сети WiFi.
            Serial.print("SSID: ");
            Serial.println(wifi_ssid);
            
            connectionId = DWIFIcK::connect(wifi_ssid, &networkStatus);
        } else {
            // Подключиться к сети WiFi, защищенной WPA2 с паролем.
            Serial.print("SSID: ");
            Serial.print(wifi_ssid);
            Serial.print(", WPA2 passphrase: ");
            Serial.println(wifi_wpa2_passphrase);
          
            connectionId = DWIFIcK::connect(wifi_ssid, wifi_wpa2_passphrase, &networkStatus);
        }



На этом этапе подключения к самой точке (проверка имени и пароля) еще не происходит - если чип WiFi установлен на плату и работает корректно, то вызов DWIFIcK::connect() почти сразу вернет корректный идентификатор подключения connectionId.


  
        if(connectionId != DWIFIcK::INVALID_CONNECTION_ID) {
            // На этом этапе подключение будет создано, даже если указанная
            // сеть Wifi недоступна или для нее задан неправильный пароль
            Serial.print("Connection created, connection id=");
            Serial.println(conectionId, DEC);

            ...
        }


Процесс подключения к точке происходит дальше - при старте инициализации IP-стека. Вызываем нужный вариант DNETcK::begin() для подключения с динамическим или статическим IP-адресом.


            // Теперь попробуем подключиться к самой точке доступа - инициализируем Ip-стек
            Serial.print("Initializing IP stack...");
            
            if(USE_STATIC_ADDRESS) {
                // подключимся со статическим ip-адресом
                DNETcK::begin(host_ip);
            } else {
                // подключиться с динамическим ip-адресом
                DNETcK::begin();
            }    


Как уже говорилось выше, сетевой стек на ChipKIT реализован для работы в однопоточных системах, поэтому большинство вызовов не являются блокирующими. В том числе вызов DNETcK::begin() вернется почти сразу не дожидаясь результатов подключения к точке, поэтому дождемся их самостоятельно внутри несложного цикла, который завершит работу в двух случаях: если мы успешно подключились к точке доступа и получили IP-адрес или если попытка подключения завершилась с ошибкой (не найдена сеть с нужным именем, не подошел пароль и т.п.):


            // К открытой сети может подключиться с первой попытки, к сети с паролем
            // может потребоваться несколько циклов (если пароль для сети неправильный,
            // то ошибка вылезет тоже на этом этапе).
            bool initializing = true;
            while(initializing) {
                // Вызов isInitialized заблокируется до тех пор, пока стек не будет
                // инициализирован или не истечет время ожидания (по умолчанию 15 секунд).
                // Если сеть не подключится до истечения таймаута и при этом не произойдет
                // ошибка, isInitialized просто вернет FALSE без кода ошибки, при необходимости
                // можно вызвать его повторно до успеха или ошибки.
                if(DNETcK::isInitialized(&networkStatus)) {
                    // Стек IP инициализирован
                    connectedToWifi = true;
                    
                    initializing = false;
                } else if(DNETcK::isStatusAnError(networkStatus)) {
                    // Стек IP не инициализирован из-за ошибки,
                    // в этом месте больше не пробуем
                    initializing = false;
                }
            }
        }


Подключились успешно, зажигаем статусную лампочку:


        if(connectedToWifi) {
            // Подключились к Wifi
            Serial.println("Connected to wifi");
            printNetworkStatus();
            
            // включим лампочку
            digitalWrite(WIFI_STATUS_PIN, HIGH);
        }



Не получилось подключиться - отправим в отладочный порт код ошибки, корректно завершим работу сетевого стека и через 4 секунды попробуем всё заново на следующей итерации:


        } else {
            // Так и не получилось подключиться
            Serial.print("Failed to connect wifi, status: ");
            printDNETcKStatus(networkStatus);
            Serial.println();
            
            // Нужно корректно завершить весь стек IP и Wifi, чтобы
            // иметь возможность переподключиться на следующей итерации
            DNETcK::end();
            DWIFIcK::disconnect(conectionId);
            conectionId = DWIFIcK::INVALID_CONNECTION_ID;
            
            // Немного подождем и попробуем переподключиться на следующей итерации
            Serial.println("Retry after 4 seconds...");
            delay(4000);
        }


На этом блок подключения к точке WiFi закончен. В случае неудачи программа ждет 4 секунды и повторяет попытку на следующей итерации. В случае удачного подключения на следующей итерации управление передается следующему блоку, который будет или принимать входящие сетевые подключения или сам выходить в сеть на внешние ресурсы или делать что-то еще - об этом в следующих лабах.


void loop() {
    ...
        
    if(!DWIFIcK::isConnected(conectionId)) {
        ...

    } else {
        // Подключены к WiFi - здесь можно делать любые операции, для которых необходима сеть
        Serial.println("WiFi is ON, do something with network");
        delay(5000);
    }
}



ChipKIT WiFi connected.jpg



исходники прошивки, подсветка синтаксиса.
Tags: chipkit, типовые задачи
Subscribe

  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 2 comments