ESP8266 FreeRTOS Autodiscover

Fornisco in questo articolo un piccolo esempio di come protrebbe essere implementato l'autodiscover sul ESP8266.à

La versione di freeRTOS, si riferisce a questa versione e spiego come installare la toolchain su Ubuntu e su Fedora

Non ho utilizzato alcun protocollo particolare, esempio il protocollo usato dal cromecast.

Ho preferito invece utilizzare un pachetto UDP, broadcast, su una porta inventata. L'esempio utilizza LWIP ovviamente.

#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "private_ssid_config.h"
#include "esp8266.h"
#include "task.h"

#include "assert.h"
#include "stdio.h"
#include "stdlib.h"
#include "lwip/opt.h"
#include "lwip/api.h"

#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"

#include <stdint.h>
#include <string.h>

#include "espressif/esp_common.h"
#include "esp/uart.h"

#define REPETE_TIME 1200 // ms
#define DISCOVER_PORT 7766

#define vTaskDelayMs(delay) vTaskDelay(delay/portTICK_PERIOD_MS)

struct AutoDiscover_msg {
    uint32_t inc;
    uint32_t reset;
};

void Task_DiscoverUDP(void *pvParameters) {
    const unsigned int broadcastPermission = 1;
    const char broadcastIP[] = "255.255.255.255";
    const unsigned int broadcastPort = DISCOVER_PORT;
    
    struct sockaddr_in broadcastAddr;
    struct AutoDiscover_msg msg;
    int sock;

    while(true) { 
        
        // Wait connection
        if(sdk_wifi_station_get_connect_status() != STATION_GOT_IP) {
            printf("[Error] Station not connected\n");
            vTaskDelayMs(REPETE_TIME);
            continue;
        }

        sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        
        if (sock < 0) {
            printf("[Error] Impossible allocate socket\r\n");
            vTaskDelayMs(REPETE_TIME);
            continue;
        }

        if ((setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (void*)&broadcastPermission,
                    sizeof(broadcastPermission))) < 0) {
            printf("[Error] Impossible setup socket settings\r\n");

            close(sock);
            vTaskDelayMs(REPETE_TIME);
            continue;
        }
        
        
        memset(&broadcastAddr, 0, sizeof(broadcastAddr));
        broadcastAddr.sin_family = AF_INET;
        broadcastAddr.sin_addr.s_addr = inet_addr(broadcastIP);
        broadcastAddr.sin_port = htons(broadcastPort);
        break;
    }

    /* Init AutoDiscover_msg */
    msg.inc = 0;
    msg.reset = 1;
    
    while (true) {
        int len_to_send;
        unsigned int len_sendt;

        len_to_send = sizeof(msg);
    
        /* Send message over UDP */
        len_sendt = sendto(sock, &msg, len_to_send, 0, (struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr));

        if (len_sendt != len_to_send) {
            printf("[Error] Sendto error, impossible send\r\n");
            close(sock);
            vTaskDelayMs(REPETE_TIME);
            break;
        }
        
        printf("Send broadcast inc:%d, reset:%d\n", msg.inc, msg.reset);

        msg.inc++;
        msg.reset = 0;
        
        vTaskDelayMs(REPETE_TIME);
    }
    // Never done
    close(sock);
}

void user_init(void) {
    uart_set_baud(0, 115200);
    printf("SDK version:%s\n", sdk_system_get_sdk_version());

    struct sdk_station_config config = {
        .ssid     = WIFI_SSID,
        .password = WIFI_PASS,
    };

    /* required to call wifi_set_opmode before station_set_config */
    sdk_wifi_set_opmode(STATION_MODE);
    sdk_wifi_station_set_config(&config);

    xTaskCreate(Task_DiscoverUDP, "UPD discover", 4096, NULL, 1, NULL);
}

Implementazione di un ricevitore in python, per autodiscover

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from socket import *
import time
import select
import thread
import struct 

broad_cast_port = 7766
time_out = 5

active_address = {}

def recive_broadcast(argc, argv):
    global active_address

    s = socket(AF_INET, SOCK_DGRAM)
    s.bind(('0.0.0.0', broad_cast_port))
    
    last_inc_value = -1
    while True:
        ready = select.select([s],[], [], time_out)
        if ready[0]:
            recv = s.recvfrom(1024)
            
            m = struct.unpack("<II", recv[0])
            inc = m[0]
            reset = m[1]
            send_ip = recv[1][0]

            active_address.update({send_ip:(inc, time.time())})
            
            if reset == 1:
                last_inc_value = -1

            last_inc_value = inc

        for key in list(active_address):
            elm_time = active_address[key][1]
            if (time.time() - elm_time > 5):
                del active_address[key]
                print("deleted:%s" % key)

                print("Active IP:")
                for k in active_address:
                    print("    %s" % k)
            
def main():
    thread.start_new_thread(recive_broadcast, ("Thread #: Broadcast Recv", 1)) 
    while True:
        print("Active IP:")
        for k in active_address:
            print("    %s" % k)
        time.sleep(1)

if __name__ == "__main__":
    main()