2022/02/27

Ejemplo de ESP32 con lectura de DHT11

Extendiendo los pasos de primer contacto con ESP32, va tipo receta con anotaciones sin mayores explicaciones, la idea es terminar con una carpeta con el proyecto armado.

 

Instalación de dependencias

 

sudo apt install git wget flex bison gperf python3 python3-pip python3-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0


Mi entorno suele ser una virtual, por comodidad también hago:

sudo apt install vim kdiff3 dirdiff

 

Estructura de archivos

 

mkdir esp http_request

 

~/esp/esp-idf
      esp-idf-lib
      http_request

 

Aunque he puesto el ejemplo http_request a la par de los repositorios, puede estar en cualquier lado.

 

Repositorios y setup herramientas

 

El primer repo te provee un montón de dispositivos, nos interesa el componente dht11.

git clone https://github.com/UncleRus/esp-idf-lib.git

git clone -b v4.4 --recursive https://github.com/espressif/esp-idf.git

 

El segundo es la adaptación de FreeRTOS a extensa de expresif.

 

cd esp-idf

./install.sh esp32 

 

Eso te instaló lo que haga falta para ESP32. Tanto acá como en pasos posteriores, donde dice esp32 puede ir esp32c3 o esp32s2, pero por ahora sólo probé con esp32, no debería en general pero pueden haber diferencias sutiles con los pines en estos ejemplos básicos.

 

El código


cd ../http_request

. ../esp-idf/export.sh

Esto es para que funcione el entorno de build.

 

El código es copia del ejemplo http_request:

cp -r ../esp-idf/examples/protocols/http_request/ .

Ajuste del proyecto a esp32:

idf.py set-target esp32

Sería un buen momento para hacer funcionar el ejemplo así como está, pero vamos directo al ejemplo completo.

 

Dependencias de código

 

En CMakeFiles.txt, agregá la dependencia a esp-idf-lib:

set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common $ENV{IDF_PATH}/../esp-idf-lib/components)

Menuconfig

idf.py menuconfig

Si está versionando, no te olvides de NO VERSIONAR sdkconfig una vez que hayas puesto los valores de conexión de la WiFi. Lo que hago yo es:

idf.py menuconfig -> Save

git add sdkconfig

git commit -m "xxx"

idf.py menuconfig

Example Connection Configuration --->
  [*] connect using WiFi interface
  (xxxxxxx) WiFi SSID
  (xxxxxxx) WiFi Password

Pero si tenés otros valores secretos se empieza a complicar. De un modo u otro, repito, NO VERSIONES SECRETOS.

 

Ajustes del código

 

Tomamos como base esp-idf-lib/examples/dht/main/main.c

includes

#include <stdio.h>
#include "dht.h"

constants

static const dht_sensor_type_t sensor_type = DHT_TYPE_DHT11;
static const gpio_num_t dht_gpio = 17;

La URL

#define WEB_SERVER "example.com" -> la IP que uses
#define WEB_PORT "80" -> el puerto que uses
#define WEB_PATH "/" -> según mi ejemplo "/collect.php"

static char *REQUEST_GET =
        "GET " WEB_PATH "/?t=%d&h=%d HTTP/1.0\r\n"...

La idea es reemplazar esos dos %d con sprintf(), para eso incluí <stdio.h>, con los valores leídos.

Las variables

char send_buf[256];

int16_t temperature = 0;
int16_t humidity = 0;

La lectura del sensor

while(1) {
  if (dht_read_data(sensor_type, dht_gpio, &humidity, &temperature) == ESP_OK) {
    ESP_LOGI(TAG,"Humidity: %d%% Temp: %dC\n", humidity, temperature);
    sprintf(send_buf, REQUEST_GET, temperature, humidity);
    ESP_LOGI(TAG,"sending: \n%s\n",send_buf);
 } else {
    ESP_LOGE(TAG,"Could not read data from sensor\n");
 }

y la escritura, al buffer lo preparamos con el sprintf() anterior.

if (write(s, send_buf, strlen(send_buf)) < 0) {...



Acá el código entero resultante con propuestas de ejercicios intercalados, no deberías necesitarlo, pero no molesta. El proyecto completo en github

 

#include <string.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "dht.h"


/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "192.168.1.102"
#define WEB_PORT "8080"
#define WEB_PATH "/collect.php"

static const dht_sensor_type_t sensor_type = DHT_TYPE_DHT11;
static const gpio_num_t dht_gpio = 17;


static const char *TAG = "temp_collector";

static char *REQUEST_GET = "GET " WEB_PATH "/?t=%d&h=%d HTTP/1.0\r\n"
    "Host: "WEB_SERVER":"WEB_PORT"\r\n"
    "User-Agent: esp-idf/1.0 esp32\r\n"
    "\r\n";

// Ejercicio: enviar POST    
// Ejercicio: enviar json

static void http_get_task(void *pvParameters)
{
    const struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
    int s, r;
    char recv_buf[64];

    char send_buf[256];

    int16_t temperature = 0;
    int16_t humidity = 0;
 
    while(1) {
        if (dht_read_data(sensor_type, dht_gpio,
                &humidity, &temperature) == ESP_OK) {
            ESP_LOGI(TAG,
    "Humidity: %d%% Temp: %dC\n", humidity / 10, temperature / 10);
            sprintf(send_buf, REQUEST_GET, temperature / 10, humidity / 10);
        ESP_LOGI(TAG,"sending: \n%s\n",send_buf);
        } else {
            ESP_LOGE(TAG,"Could not read data from sensor\n");
        // Ejercicio: enviar mensaje
        }

        int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);

        if(err != 0 || res == NULL) {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p",
                      err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }

        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s",
                        inet_ntoa(*addr));

        s = socket(res->ai_family, res->ai_socktype, 0);
        if(s < 0) {
            ESP_LOGE(TAG, "... Failed to allocate socket.");
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... allocated socket");

        if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
            ESP_LOGE(TAG,
                 "... socket connect failed errno=%d", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }

        ESP_LOGI(TAG, "... connected");
        freeaddrinfo(res);

        if (write(s, send_buf, strlen(send_buf)) < 0) {
            ESP_LOGE(TAG, "... socket send failed");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... socket send success");

        struct timeval receiving_timeout;
        receiving_timeout.tv_sec = 5;
        receiving_timeout.tv_usec = 0;
        if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
           &receiving_timeout, sizeof(receiving_timeout)) < 0) {
            ESP_LOGE(TAG,
              "... failed to set socket receiving timeout");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... set socket receiving timeout success");

        /* Read HTTP response */
        do {
            bzero(recv_buf, sizeof(recv_buf));
            r = read(s, recv_buf, sizeof(recv_buf)-1);
            for(int i = 0; i < r; i++) {
                putchar(recv_buf[i]);
            }
        } while(r > 0);

        ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);
        close(s);

        for(int countdown = 10; countdown >= 0; countdown--) {
            ESP_LOGI(TAG, "%d... ", countdown);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
        ESP_LOGI(TAG, "Starting again!");
    }
}

void app_main(void)
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    ESP_ERROR_CHECK(example_connect());

    xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, NULL);
}


Si hubieras usado el ejemplo http_request sin tocar y vez esa basura no te preocupes, es que el servidor te ha dado la respuesta comprimida, observá el Content-Encoding: gzip, no tenés error.


example.org
example.org


Errata


Me faltó mencionar que hay que conectar el sensor a algún pin, en este caso usé el 17

static const gpio_num_t dht_gpio = 17;

y no olvides poner la resistencia entre el positivo (3.3v) y el cable de datos.

2022/02/21

Talento vs KPI: Una muerte es una tragedia, un millón, estadísticas

Para lidiar con una vulnerabilidad hay que primero comprenderla, hacer una POC y que funcione, cuantificar cuál es su impacto teórico en términos de Confidencialidad, Integridad y Disponibilidad  y otras dimensiones, por ejemplo aplicando CVSS. Luego, desarrollar algún método de detección, que puede ser tan sencillo como comprobar la versión de una librería a un sofisticado script, programa o plugin de alguna herramienta de seguridad como NMAP o Metasploit que interactúe con el sistema y la explote, preferentemente sin generar efectos colaterales perjudiales. En caso de haber un payload involucrado, desde comprender su funcionamiento a desofuscarlo en caso de lenguajes interpretados hasta una dificilísima ingeniería inversa ya que se trata código de máquina, que puede estar cifrado y ofuscado y nos lleva al hostil terreno del assembly y el conocimiento íntimo del sistema operativo, sin dejar de lado un sencillo análisis de comportamiento en busca de IOCs para alimentar herramientas de detección y prevención.


Habíendo superado esta etapa, evaluar en nuestro despliegue actual según la situación perimetral, la topología de la red, el valor de la información, en otras palabras, un análisis complejo de amenazas para poder determinar el potencial efecto real de esa vulnerabilidad en los distintos puntos del sistema donde puede estar presente y elegir el mejor plan de mitigación, que puede ser eliminar funcionalidades o aplicaciones, aplicar parches o actualizaciones, cambiar valores de configuración, agregar o modificar reglas de IPS, WAF, AV y FW.


A todo esto lo considero Talento, tanto desde la actuación de la gente ciberseguridad en la primera etapa como en la segunda que se suma la de gente de desarrollo, sistemas y administración de seguridad.

 
Hay otro Talento, que es del lado de la arquitectura, diseño y programación de las aplicaciones y servicios. Desde ese punto de vista, hay una inteligencia y optimización orientada a no hacer esfuerzos innecesarios, a intentar comprender. 

Entonces si el reporte de vulnerabilidades dice que hay tal componente vulnerable, correctamente, en lugar de salir corriendo a actualizarlo, este Talento dice, veamos si lo estamos usando de modo tal que la vulnerabilidad se manifieste. Por ejemplo, con Log4Shell, este Talento pregunta, ¿estamos enviando mensajes que vienen desde el usuario al log? Por que si no es así, no hay vulnerabilidad concreta, por favor no me hagas perder mi magro tiempo actualizando algo que no hace falta.
 

En la confluencia entre ambos Talentos, para que ciberseguridad pueda realmente apreciar el impacto de una vulnerabilidad en los sistemas necesita un importante esfuerzo por parte de las demás áreas técnicas.
 

Ahora, imaginemos que no tenemos una sola vulnerabilidad sino que tenemos miles, si, miles, que combinadas con nuestros activos generan combinaciones de centenares de miles de instancias, quizás millones.
 

Poco podemos conservar de la visión enunciada, es como una herida abierta esperando a infectarse, hay que limpiar y proteger, rápido, luego vemos si antibiótico, vendas, reposo. Miles de heridas.
 

Mientras aplicamos las defensas perimetrales, por madurez podríamos intentar identificar esas instancias, pues se dice que es indispensable medir… tarde, ese tiempo es tiempo cedido al atacante.
 

Las vulnerabilidades propias de nuestros sistemas descubiertas por Ethical Hacking pueden esperar un poco, apelando a una falsa seguridad por oscuridad, al atacante le puede costar encontrarlas pues debe interactuar con nuestro sistema. Pero con las que corresponden a elementos de terceros no hacen falta sutilezas, descubrirlas es simplemente correr un script sin ningún pensamiento.
 

Eternal Blue es un ciberataque que encarnado en el ransomware Wannacry es la prueba viviente. En abril de 2017 The Shadow Brokers la publicó tras habérsela robado a la NSA, que la había descubierto cerca de cinco años antes. En mayo de 2017 fue la primera oleada de ataques de la mano del ransomware Wannacry. En marzo de  2017 Microsoft publicó el patch, advertidos por NSA. Casi dos meses transcurrieron desde la disponibilidad del parche hasta su explotación masiva. Una política proactiva de actualización la hubiese convertido en Wannabe.
 

No he oido de explotaciones masivas de Log4shell, algo se ha aprendido desde Wannacy, pues hasta donde he sabido las políticas han sido más o menos:
 

  • En el perímetro se detecta y bloquea cualquier intento de explotación y postexplotación, rápido.
  • Se dan de baja aplicaciones.
  • Se actualizan las librerías.
  • Se aplican mitigaciones por configuración.

 

Estas dos últimas medidas pueden parecer quizás un tanto desprolijas, pero para hacerla correctamente hay que usar Talentos, lo cual hubiese sido un desperdicio.

Hay que aplicar los parches con la única consideración de que los sistemas sigan funcionando, no si hace falta. No va más “si funciona no lo toqués”, ni siquiera hay que esperar a que se detecte que un componente tiene una vulnerabilidad para actualizarlo. Hay que hacerlo permanentemente, quizás no el mismo día que sale cada parche, pero si con una frecuencia muy alta.

Eso pulirá los mecanismos de los equipos de DevOps para afrontar cualquier actualización de urgencia real.
 
Se parece un poco al sistema Chaos Monkey de Netflix, donde a propósito se voltean al azar componentes en producción para forzar a que el sistema de conjunto sea resistente a fallas.

Una deuda, razonable y con paralelismo en Kanban es la de los vulnerabilidades de bajo impacto, equivalentes a las tareas de baja prioridad. En Kanban incluso existe un mecanismo de purga del backlog con el criterio de que si pasaron tantos meses y no se han resuelto ciertas tareas de baja prioridad, entonces no deben tener tanto valor y si lo tienen, renacerán pronto. La vulnerabilidades de bajo impacto que no son resultado de la construcción de nuestro sistema, o sea, las de librerías de terceros y sistemas operativos de soporte, del mismo modo persisten meses o años, pero tienen una diferencia, si se aplica al política de actualización permanente, simplemente disminuirán drásticamente de la mano de las importantes, sin que las hayamos atacado explícitamente.

No me gustan los KPIs, pienso que son dimensiones sacadas de la galera, yo elaboro unos, otra persona otros, seguramente incompatibles e incongruentes. Representan los intereses de distintos Product Owners que quizás estén en conflicto de intereses. No importa, los podemos poner a nuestro servicio, debemos tener menos de tantas vulnerabilidades por equipo, de acuerdo aunque desde el punto de vista del Talento parece ser una muestra de ceguera atroz. Una vez que se reducen los números, podemos recuperar el Talento y comenzar a pensar como atacar las vulnerabilidades más especiales.

El uso de los KPI y la aplicación de parches aparentemente con poca inteligencia, es economía de escala.

Primer contacto real con PIC16

Tras haber asistido a un seminario introductorio a PIC16, debido a que los kits fueron entregados tras éste, me quedaron pendientes dos actividades: el blinky y ver si unas instrucciones muy específicas bcf y bsf, no serían reemplazables por unos ingeniosos ands y ors.

 

El blinky

 

Hasta donde entendí, a diferencia de los AVR, estos PIC siempre necesitan una referencia externa para el clock, hay que ponerle un cristal y unos capacitores... no tan fácil, en el curso no hay ningún diagrama de conexión, como que está asumido que vos ya sabés electrónica digital y lo que no conocés es PIC. Menciona por un lado que sólo se van a usar dos pines para programar (TX y RX) y luego dice "Comparte el control del pin MCLR", ¿mmh, qué querrá decir? Obviamente pedí el diagrama pero para hacer más interesante esta experiencia lo voy a recibir cuando haya tenido éxito o fracaso.

Entonces, al buscar diagramas relacionados a cosas como "pic16f tiny bootloader circuit diagram and usb uart adapter" lo segundo mejor que encontré fué un proyecto donde muestra que se usa RTS para pegarle a MCLR (a.k.a. RESET), pero eso es a la salida de un MAX232, la idea es usar el adaptador USB-UART provisto en el kit (dicho sea de paso, ese kit debería haber traido el cristal, los capacitores...)

 

Usando RTS para el RESET
Usando RTS para el RESET


Finalmente, llegúe a un tutorial que al final dice:

 

Download the complete project folder from the below link:
Hardware design Files and Code Library 

 

Sin RTS
Sin RTS


perfecto, es lo más sencillo posible que parecería funcionar, al reset habría que darle con el dedo.

 

Ahora, a tomar posesión del chip, lo primero es identificar las patitas:

 

Pinout colorizado por función
Pinout colorizado por función

Cada color es un puerto, en grís los mínimos necesarios para programarlo.


A pensar un poco, muy poco, el diagrama del tutorial es lo que hay que hacer.


Circuito armado
Circuito armado

A la derecha Tx y Rx al USB-TTL. Lo alimento con una fuente externa.


Antes de investigar nada más, a ver si funciona. Hay que bajar el tinybootloader para linux y probar...

 

En la versión 0.6 al bajar el .deb falla por dependencia imposible de satisfacer, python-gtk2,buscando, hallamos https://osdn.net/projects/sfnet_tinybldlin/releases/ que dice tener la versión 0.8.1, veamos... nop, tambien necesita python-gtk2

              Depends: python-gtk2 but it is not installable
              Depends: python-cairo but it is not installed
              Depends: python-gobject but it is not installed
              Depends: python-serial but it is not installable

Veamos de instalarlo basándonos en https://techviewleo.com/install-python-with-virtualenv-on-linux-mint/

sudo apt-get update

sudo apt-get upgrade

sudo add-apt-repository universe

sudo apt-get update

con algunos

apt-cache search python 

determinamos que python-cairo y python-gobject estan disponibles, hay que usar pip para el resto

curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py

sudo python2 get-pip.py

ok, pero luego no puedo hallar los paquetes faltantes con pip


Hay varios caminos: 

  • resolver las dependencias
    • es en lo que vengo fallando
  • buscar otro programa
    • no está apareciendo
  • instanciar una virtual con una distro antigua que soporte python2
    • quizás tampoco pueda resolver las dependencias
    • puede ser que mplab no funcione ahí
      • no importa, sólo la usaría para flashear
  • usar wine
    • seguramente se me complique el acceso al puerto serial
    • chicken
  • instanciar una virtual con windows
    • se me puede complicar el acceso al puerto serial
    • chicken
  • actualizar el programa a python3
    • y hacer un aporte a la humanidad...
    • pero puede ser mucho tiempo
  • evitar el bootloader
    • esto significa faltar al espíritu de la experiencia original
    • tendría que armar o comprar el programador
      • no me interesa volver a hacer nada con PIC, quizás programar otro que tengo en un cajón

o mucho mejor aun, buscar un poco más hasta encontrar que 


https://github.com/lcgamboa/tinybldlin

y un

sudo apt install python3-serial


abre el programa, pero... siempre hay un pero, dice que:


Tiny PIC BootLoader
Tiny PIC BootLoader

...no lo encuentra. Mirá fijo la captura y vas a ver que en la terminal desde donde lo abriste, dice que aprietes el reset. Esta captura no es sobre la primera iteración, donde esa terminal había quedado oculta.

Lo aprieto y nada...

Siguiento mi método de armar un mail para no mandarlo, donde fuí documentando todo lo hecho para solicitar ayuda, descubrí que había conectado mal Rx, así que a desoldar... y anda.

Situación: hay que apretar el reset ante cada operación, ok, razonable.

Puede hacer falta por única vez:

  •  Tools -> Options -> Embedded -> Build Tools -> Scan for Build Tools 

Luego, para cada proyecto:

  • New project -> Microchip Embedded -> Standalone project
  • family -> Baseline 8-bit MCUs (PIC10/12/16)
  • device -> PIC16F874A
  • tool -> simulator
  • header -> none
  • compiler -> XC8 (v2.32) o similar
  • new file -> main.c

#include <xc.h>
#include <pic16f877a.h>
#include <stdio.h>

#define _XTAL_FREQ 4000000

void main(void) {
    TRISB = 0;
    PORTB=0;
    while(1) {
        PORTBbits.RB0=0;
        PORTBbits.RB1=0;
        PORTBbits.RB7=0;
        __delay_ms(500);
        PORTBbits.RB0=1;
        PORTBbits.RB1=1;
        PORTBbits.RB7=1;
        __delay_ms(500);
    }
    return;
}

  • Build
  • copiar a tinypicbootloader la ruta tipo:

/home/carlos/Desktop/blinky.X/dist/default/production/blinky.X.production.hex

  • write flash
  • reset
Listo, el blinky funciona.

La parte ingeniosa del análisis bcf -> andwf queda para otro día,


2022/02/17

Primer contacto con ESP32

Paso a relatar los pasos que he seguido para instanciar los hello world en distintos ESP32 en el marco de colaborar en los criterios de elección de hardware para la carrera de especialización de IoT, siendo mi foco de interés sus características de seguridad, pero antes hay hacerlos andar.

Para comenzar, me ha costado comprender la taxonomía de los ESP32, en algún momento medio que lo había logrado pero por falta de refrescarlo lo perdí. En esta oportunidad no sé si he tenido mejor suerte o ha mejorado la información de espressif. Como sea, a partir de una comparativa pude hacerme el siguiente resumen.

Si ves en github podés ver con blame que existe desde hace 15 meses, yo había tenido mi primer contacto con ESP8266 hace 20 meses e intenté entender poco despues así que quizás me la perdí.

Desde ahí te bajás la datasheet de cada familia o serie y te queda algo como esto:
 

  • ESP32
    • ESP32-D0WD-V3
    • ESP32-D0WDQ6-V3
    • ESP32-D0WD
    • ESP32-D0WDQ6
    • ESP32-D2WD
    • ESP32-S0WD
    • ESP32-U4WDH
    • ESP-WROOM-32
  • ESP32-S2
    • ESP32-S2
      • WROVER-1
      • MINI-1
    • ESP32-S2FH2
    • ESP32-S2FH4
  • ESP32-S3
    • ESP32-S3
    • ESP32-S3FN8
    • ESP32-S3R2
    • ESP32-S3R8
    • ESP32-S3R8V
  • ESP32-C3
    • ESP32-C3
      • ESP32-C3-WROOM-02
    • ESP32-C3FN4
    • ESP32-C3FH4

En negrita marqué los que tengo, en el primer caso lo dejé colgando, eso es lo que me confunde un poco. Lo que me importa es dada una plaquita, poder identificar que tiene, a ver si me sirve en particular para el dictado de la materia Ciberseguridad de IoT para mostrar secure boot. Ese safer than ESP32 significa que ESP32 es vulnerable a algunos ataques, no importa, es un tanto irrelevante al mostrar como funciona.

 

Compartiva familias ESP32
Compartiva familias ESP32

Bien, ¿qué hay que hacer? Pues bajar la SDK, evitando sufrir todo lo sufrido con ESP8266.

Curioseás un rato por Libraries and Frameworks, Resources, ponés freertos en el buscador, nada. Recordás que existe https://github.com/espressif/ESP8266_RTOS_SDK y suponés que existe algo tipo ESP32_RTOS_SDK, pero no, no existe. Buscás en los repos y aparece uno que dice:


ESP31B SDK based on FreeRTOS.
For ESP32 please see http://github.com/espressif/esp-idf

 

Ok, pese a que acá relaciona FreeRTOS con el SDK luego... no importa, no fue tan difícil.

Lo primero que te dice es que si querés soporte para todas las familias, elijas la versión apropiada. Luego dice que hay documentación para cada release combinando para cada serie, vamos por la V4.4. que cubre todo, la que me falta, ESP32-S3, ya vendrá.

 

Pasos


Abrimos en tres ventanas esp32, esp32s2 y esp32c3 y los operamos en simultáneo a ver las diferencias.

Voy a usar un VirtualBox con Linux Mint 20.3 xfce, 8GB RAM, 2 cores, guest additions para poder copiar y pegar.

 

Step 1: Install prerequisites, linux only

Sin misterios, es lo mismo para cualquier serie.

sudo apt-get install git wget flex bison gperf python3 python3-pip python3-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0


Step 2: Get ESP-IDF

Sin misterios, son 1.2 GB, el v4.4 corresponde al release que habíamos elegido antes.

git clone -b v4.4 --recursive https://github.com/espressif/esp-idf.git


Step 3: Set up the tools, linux only

./install.sh esp32,esp32s2,esp32c3

Dice que

Selected targets are: esp32c3, esp32s2, esp32
Installing tools: xtensa-esp32-elf, xtensa-esp32s2-elf, riscv32-esp-elf, esp32ulp-elf, esp32s2ulp-elf, openocd-esp32

 

Ese riscv32-esp-elf debe ser para el esp32c3.

 

Step 4: Set up the environment variables


. ./export.sh

Te dice con buen criterio que no lo incluyas en el .bashrc para que no se active en cada terminal, es razonable pues no vas a tener 20 terminales en la que estés compilando.

 

Step 5: Start a project

Te dice que te ubiques afuera de ~/esp/esp-idf, copies el hello world, nada misterioso.


Step 7: Configure


idf.py set-target [esp32|esp32s2|eps32c3]
idf.py menuconfig

Con set-target le decís a cada proyecto en que familia será desplegado.

En este punto te recomiendo un:

sudo apt install kdiff3 dirdiff

Luego  te hacés algo como esto mediante copias sucesivas:

hello_world
hello_world_esp32
hello_world_esp32c3
hello_world_esp32s2

Entrás en cada  *_esp32* y ejecutás el set-target correspondiente.

Te genera una carpeta build y el archivo sdkconfig. En éste, podés ver las opciones de configuración para menuconfig y con kdiff3 podrás apreciar las diferencias, muy divertido e ilustrativo:

kdiff3 hello_world_esp32s2/sdkconfig \
    hello_world_esp32c3/sdkconfig

 

Comparación sdkconfig
Comparación sdkconfig

 

Para comparar los archivos de build la tentación es usar esto:

dirdiff hello_world_esp32s2/build/ \
   hello_world_esp32c3/build/

Usalo, pero tené en cuenta que en la carpeta esp-idf hay varias carpetas con nombres correspondientes a la familia, lo cual mete ruido. Igual no me fijé si amerita mirar mucho por este lado.

Cuando llegues al menuconfig, esta bueno tomar nota del baud rate:

Serial Flasher Config ->
'idf.py monitor' baud rate (115200 bps)

Pese a que dice: "set up project specific variables, e.g. Wi-Fi network name and password, the processor speed,..." y habiendo aprendido que con "/" te muestra todas las variables, no lo puedo encontrar. Luego, tras explorar un ratito y quizás recordar de la experiencia anterior, hay variables que son locales a cada proyecto, eso lo ves en main/Kconfig.projbuild. Lo de la clave de Wi-Fi está en el ejemplo ./esp-idf/examples/wifi/getting_started/station.

 

Step 6: Connect device


Esta bueno decirle a virtualbox que siempre conecte la placa a la virtual, asi no tenés que estar recordando hacerlo cada vez que reconectás o se resetea:


Conexión USB con filtro
Conexión USB con filtro

No domino esta funcionalidad, me parece que hay que hacerlo con cada dispositivo, no alcanza cada tipo, tampoco es tan importante.

 

Step 8: Build the project


idf.py build

Paciencia...


Mientras podés saltarte unos pasos y ejecutar 

idf.py -p /dev/ttyUSB0 monitor

para ver que trae la placa ya flasheado.

 

Step 9: Flash onto the device


idf.py -p /dev/ttyUSB0 flash


Step 10: Monitor 

 

Ya te lo había dicho:

idf.py -p /dev/ttyUSB0 monitor

Te agrego que se sale con control ]

 

Resultados

 

El ESP-WROOM-32 dijo que:

Failed to connect to ESP32: Wrong boot mode detected (0x13)!

Se corrije apretando el botón que dice "100" o parecido mientras 

Serial port /dev/ttyUSB0
Connecting.........

Los otros, de una.

 

Remapeo

 

Mirando la traza al fashear cada plaquita, puedo identificar mejor qué es qué, verde significa que le había acertado, amarillo que estaba cerca:

 

  • ESP32
    • ESP32-D0WD-V3
    • ESP32-D0WDQ6-V3
    • ESP32-D0WD
    • ESP32-D0WDQ6
      • ESP-WROOM-32
    • ESP32-D2WD
    • ESP32-S0WD
    • ESP32-U4WDH
  • ESP32-S2
    • ESP32-S2
      • WROVER-1
    • ESP32-S2FH2
    • ESP32-S2FH4
      • MINI-1
  • ESP32-S3
    • ESP32-S3
    • ESP32-S3FN8
    • ESP32-S3R2
    • ESP32-S3R8
    • ESP32-S3R8V
  • ESP32-C3
    • ESP32-C3
        • ESP32-C3-WROOM-02 
    • ESP32-C3FN4
    • ESP32-C3FH4

 

No te prometo que en breve publique la parte de seguridad, mientras, le pego un sensor de temperatura y lo mando por Internet.

2022/02/08

Rescatando un scanner de la calle

Como quizás hayas visto antes con un touchpad y un dvr, tengo una cierta compulsión por adoptar componentes obsoletos de hardware abandonados en la calle, aunque ello se cruce con mis proyectos menos inútiles y alguna vez me obligue a purgar. Hay gente que tienen algo parecido con perros y gatos. Tengo como ventaja que aunque juntan mugre mis cosas, no la generan y además sólo ocupa espacio estático. Es verdad que no les puedo hablar y si lo hiciera no lo evidenciaría por escrito.

En esta ocasión, una impresora multifunción con todos sus cables, lo que me cuenta que el motivo de su abandono probablemente esté ligado al agotamiento de sus insumos o un alto costo de reposición y bajo retorno o alguna falla. Mmh, qué brillante, ¿queda alguna otra posibilidad?. Lo normal es que algo con fuente venga sin fuente y ha venido incluso con el cable USB.

El primer impulso obviamente es conectarla a ver si anda, pero hay que tener cuidado, estamos suponiendo los motivos del abandono sin conocerlos a ciencia cierta. ¿Y si tenía una falla electrónica y al conectarla me vuela un puerto USB?

Por suerte, así como el dinero atrae al dinero y una mano ayuda a la otra, tengo en el montón de basura alguna netbook que funciona.

Como impresora impresora, no me interesa, la operación hasta ahora ha tenido como único costo enfrentar la resistencia de las personas de mi hogar a la introducción del componente ajeno. Para saber si funciona, debería comprar cartuchos y si no llega a funcionar, ese sí que sería un costo considerable sin ningún tipo de beneficio, sólo un "te lo dije".

Es interesante el scanner, aunque con poca frecuencia, algunas veces necesito digitalizar alguna superficie y aunque el celular suele alcanzar, no es muy cómodo y siempre quedan sombras y distorsiones (¡ay, qué vergüenza! acabo de escribir distorciones, eso me pasa por juntarme con electrónicos).


Debería tambien contemplar algún fallo de alimentación seguido de un corto que haga saltar la térmica y me apague esta máquina y pierda parte de lo escrito, pero voy a confiar en la zapatilla y prender una velita virtual para que todo salga bien.

Esta bueno que haya venido con la fuente pues tiene un conector loco que nunca había visto y me hubiese obligado a investigar y aprender algo que no me interesa ni sirve para nada más que ejercer mi ingenio y este artículo no hubiera ocurrido y la impresora habría quedado para la próxima purga. Queda pendiente sin embargo ver que provee esa fuente, si fuera un 5v + 12v, sería muy útil para otros usos.

Es HP Deskjet 3050 y según su hoja de datos... no me interesa. Por inspección visual veo que no tiene lo que más querría, un puerto Ethernet o WiFi... ¡ups! la acabo de prender y no sólo los tapones siguen en su lugar sino que veo un led titilante y al lado una etiqueta que dice "inalámbrico" y en el display "puerta abierta", no sé que significa, voy a tener que ver el manual. Igual no fué tan difícil, un linux mint 17 la vió instantáneamente.

Mint 17 la vió al toque
Mint 17 la vió al toque

 

Hora de conectarla a una virtual con algo más actual e investigar si se le puede usar el scanner aunque el sensor esté fallando, pues eso es lo que ocurre y aunque me dan muchas ganas de desarmarla para corregir el sensor, a menos que impida el funcionamiento del scanner, no me aporta gran cosa.

El UART/USB que tendría que usar para programar el PIC
El UART/USB que tendría que usar para programar el PIC

 

Piece of cake, simple-scan lo vió de una, casi que me dá vergüenza haber documentado esto, pero la verdad es que cuando empecé no sabía que sería tan fácil. Pudo haber sido más oportuno, hace un casi justo un año lidié con otro scanner, me pude haber ahorrado unos pesitos..


Lo útil de esta entrada es sólo tener en cuenta la metodología para interactuar con hardware en estado desconocido, primero conectar a la pieza más barata posible que determine que es seguro seguir conectando.


No prometo nada, pero podría:

  • algún día arreglar el sensor al menos para que no aparezca el mensaje, tinta tiene pero no sé si funcionará, si se ha secado.
  • acceder vía WiFi al scanner así la puedo poner más lejos y compartirla
  • ver de reemplazar el firmware, eso sí que sería algo meritorio, convertirla en un microcontrolador con WiFi y los GPIO que debe tener