2020/06/24

Primer contacto con ESP8266

En el marco de la cursada de CEIoT, en mi trabajo práctico que cuando termine compartiré, debo implementar unos sensores y actuadores con un microcontrolador. Ya he hecho algo parecido con una EDU-CIAA-NXP en germinómetro con SAPI y ando en regular la velocidad de unos coolers con un ATMega328p con ArduinoIDE  uno de estos días.
 



Esta vez debo agregarle conexión por WiFi y MQTT y aunque la EDU-CIAA-NXP con un módulo WiFi ESP-01 me serviría, prefiero algo más compacto. Además mi idea es instalar muchos más y la EDU-CIAA-NXP es un poco carita y me sirve para otras cosas.

El ATMega328p está regalado en términos de precio pero tambien tengo que agregarle un modulo WiFi ESP-01 y armar la placa, quizás más adelante.

Decidí usar una ESP-12x con FreeRTOS, relato acá mis desventuras para regocijo y utilidad tuya.

Lo primero es comprender qué es, por que miré bastante por ahí y hallé que hay un plugin para ArduinoIDE, que hay algo de Lua, que hay un firmware.

Si vas al sitio que dice el chip http://en.doit.am/, es todo un ecosistema y por más que sean los Doctors of Intelligence & Technology, no lo son de UX.

Hay dos links interesantes, LuaNode y en el desplegable NodeMCU, NodeMCU Start, vamos por el segundo, que nos lleva a https://smartarduino.gitbooks.io/user-manual-for-esp-12e-devkit/content/ que dice:

ESP-12E DevKit is already built-in Lua fireware with AP mode y que te tiene que aparecer un Access Point con una clave 12345678, triste, y una IP donde se supone que hay un servidor que te permite prender y apagar los leds.

Mmmh, ¿será esto lo que viene precargado como firmware? Parecido, la red se llama ESP_3d3d65, no tiene clave, me asigna la ip 192.168.4.3 y nadie escucha en 192.168.4.1.

Tengo otro microcontrolador de otra compra, los resultados son similares, tenemos un Access Point sin alma.

De todos modos no me interesa, como diría la Zorra al no alcanzar las Uvas.

Si vamos por el link de LuaNode, llegamos a https://github.com/Nicholas3388/LuaNode, que sin ser ninguna Zorra esta vez, me puede llegar a interesar otro día, hoy no por que no es mi camino de FreeRTOS.

Por el lado de ArduinoIDE, https://naylampmechatronics.com/blog/56_usando-esp8266-con-el-ide-de-arduino.html nos muestra como hacer el blinky pero antes aclara un poco el ecosistema esp8266, no lo voy a repetir acá, tambien está en https://en.wikipedia.org/wiki/ESP8266, que es donde debí haber comenzado, pero no sé por qué se me ocurrió tomar este acercamiento tangencial.

Finalmente, http://esp8266.net/, de ahí a:

git clone https://github.com/espressif/ESP8266_RTOS_SDK.git

El README.md dice de bajar la toolchain, luego vas al hello world, hacés make menuconfig, que te dice que te faltan un montón de cosas

~/ESP8266_RTOS_SDK/examples/get-started/hello_world$ make
...
setuptools
click>=5.0
pyserial>=3.0
future>=0.15.2
cryptography>=2.1.4
pyparsing>=2.0.3,<2.4.0
pyelftools>=0.22
...

y sugiere y acepto ejecutar:

/usr/bin/python -m pip install --user \
-r /home/ceiot/Desktop/ESP8266_RTOS_SDK/requirements.txt

pero antes

sudo apt install python-pip python-setuptools

Ahora make dice que falta curses.h, no problemo,

sudo apt install libncurses5-dev

falta gperf...

sudo apt install gperf

Y por fin..


esp_rtos_sdk


¡Esto se va a descontrolar! Hacía como diez o quince años que no veía uno de estos diálogos así, cuando tenía que compilar el kernel. En realidad que no interactuaba, estoy seguro que para algo de algún embebido vi algo el año pasado.


Y ahora make, que falla por que no encontró xtensa-lx106-elf-gcc, completamente razonable pues a esos paths que se mencionan no tienen nada que ver, les debe haber quedado la documentación sin actualizar, no importa, buscás donde descomprimiste:

export PATH=/home/ceiot/Desktop/xtensa-lx106-elf/bin:$PATH

Si te encontrás con estos errores, metiste la pata igual que yo, frená un momento y pensá...


ESP8266_RTOS_SDK/components/esp8266/driver/ir_rx.c: In function 'ir_rx_intr_handler': 
ESP8266_RTOS_SDK/components/esp8266/driver/ir_rx.c:59:5: error: missing braces around
 initializer [-Werror=missing-braces]
      static ir_rx_nec_data_t ir_data = {0};

que está reportado en https://github.com/espressif/ESP8266_RTOS_SDK/issues/761. Se "arregla" con:

static ir_rx_nec_data_t ir_data = {{0}}; 


Y ahí te das cuenta que te faltó un:

git checkout release/v3.3

para lo cual tenés que reclonear por que choca con los git pull sobre los components.

Y sigue sin funcionar, ahora dice:


ESP8266_RTOS_SDK/components/esp8266/source/esp_err_to_name.c:391:29: error: unknown type name 'esp_err_t'
 const char *esp_err_to_name(esp_err_t code)

Y finalmente te das cuenta que leiste el README.md de master, no el de release/v3.3 y te bajaste la toolchain equivocada, lo arreglás y ni te molestás en probarlo, te vás directo a:

~ESP8266_RTOS_SDK/examples/protocols/esp-mqtt/tcp$ make menuconfig


En Example configuration, que en la imagen anterior no está, ponés los datos de tu acceso a la WiFi:

Example Configuration  --->  
() WiFi SSID
() WiFi Password
(mqtt://iot.eclipse.org) Broker URL

Luego compilás, flasheas y te colgás del serial:


~ESP8266_RTOS_SDK/examples/protocols/esp-mqtt/tcp$ make all flash monitor
...
Connecting....
Chip is ESP8266EX
Features: WiFi
MAC: cc:50:e3:xx:xx:xx
...

Primer boot



ahí tenés la IP y la MAC y funciona todo ok.

Si no hubiera código mostrando la IP, como en el proceso de flash te dijo la MAC, la podés buscar así:

$arp -a |  grep cc:50
? (192.168.1.110) at cc:50:e3:xx:xx:xx [ether] on enp0s3

Si quisiera usar otro programa de terminal, por algún perverso motivo baudrate es 74880, lo pesqué con un git grep -i baud y probé los valores obtenidos.


Se cambia con make menuconfig  en la opción serial flasher config -> make monitor baud rate


Habiendo tomado el control del hello wold, me doy por satisfecho, cuando reporte el trabajo práctico completo mostraré más detalles, dame unos meses... quizás antes si surge algo interesante.

 


2020/06/14

Ayudas para gestionar archivos duplicados.

Una de mis tantas tareas postergadas que #quedateencasa me está permitiendo encarar, es limpiar un poco mi máquina de cosas repetidas, el tiempo pasa y a veces bajo algo otra vez pues no recuerdo haberlo hecho antes, tengo un proyecto al que le hice una copia por backup, tengo un proyecto que ha estado en distintas máquinas y cuando estoy por reformatear una copio a la principal y así. Mi disco tiene una selva parecida a esto:

Documentos
inbox
descargado
la datasheet

 anterior
Documentos
anterior
proyectos
precursor del proyecto

la datasheet

 inbox
clasificar
datashets
la datasheet

proyectos
precursor del proyecto

Desktop
repositorios
assembla
github
cpantel
el proyecto

doc
la datasheet

rescate
pendrive01
Desktop
el proyecto

la datasheet
 

Y lo mismo con instaladores, papers, libros, manuales, código mío y ajeno.

Me imagino que tendrás algo parecido.

Mas por salud mental que por el espacio ocupado, es mejorcito ordenar y limpiar.

Dado que en mi máquina por momentos pueden haber muchos, muchos archivos, no es una tarea sencilla y me he armado una serie de trucos/scripts para facilitarla.

Un millón y medio es un montón:

sudo find /home -type f | wc -l
790790

sudo find / -mount -type f | wc -l
718397

sudo es por que tu usuario no puede ver todo, de ahora en más hay uno implícito.

-type f es por que no queremos contar cosas que no son archivos.

-mount es para que no se escape de la partición y vuelva a contar a /home.

No recuerdo si herramientas forenses como Encase tienen alguna funcionalidad para detectar duplicados, porbablemente si pues una de sus funciones básicas es asociar un hash a cada archivo.

No me estoy metiendo con archivos de un sistema ajeno, son los míos, los conozco, esto es un complemento, no un sistema de gestión de archivos duplicados.

Si te preocupa el espacio, find te ayuda a encontrar los archivos grandes, sea cual sea tu criterio de grande:

find / -type f -size +1G -exec ls {} \; > 1g.txt

-size +1G significa mayores a un gigabyte

-exec significa ejecutá el siguiente comando hasta \; reemplazando {} con cada elemento hallado. Ojo que se va a ejecutar cada vez, si obtuviste mil archivos, van a haber mil ls, te aviso para cuando pongas un comando más pesadito.

Antes de cualquier limpieza está bueno medir:

df  / /home -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 276G 41G 221G 16% /
/dev/sda6 612G 574G 7,4G 99% /home

-h significa mostrame los bytes con K, M, G

1% de disco libre puede parecer poco, pero tené en cuenta que hay varias carpetas por ahí que se llaman "*BORRABLE*", en realidad tengo %10 libre.

Pero había dicho que lo que importa es la salud, no es espacio, vamos a buscar duplicados.

Nombres



Asociar por nombres tiene problemas, hay archivos que los he bajado y les he cambiado el nombre, por lo general papers, que vienen con un código que no me sirve de nada, o las datasheets que bajan todas con el mismo nombre.


A veces me agarra la loca y al nombre de la datasheet le agrego una descripción.

Esta linea sirve para obtener todos los normbres de los archivos, contando las repeticiones:


find / -type f | rev | cut -d "/" -f 1 | rev  | sort | uniq -c | sort -n

rev lo necesito para el próximo paso, invierte el sentido del texto

cut corta en pedacitos separados por el delimitador...

-d "/" barra y me da el pedacito...

-f 1 primero. Esto es para quedarme con el nombre de archivo, lo que era lo último

rev necesito que esté al derecho otra vez

sort ordena alfabéticamente para juntar los iguales

uniq descarta duplicados mientras...

-c  cuenta cuantos duplicados hubo

sort nuevamente ordenamos según el número de repeticiones

-n numéricamente



Me pudiste haber preguntado por que no usar:

find / -type f -exec basename {} \; | sort | uniq -c | sort -nr

Recordá que antes te dije que -exec no es precisamente eficiente, el tiempo de ejecución paso de 11 segundos a... me aburrí de esperar, mientras hago otras cosa dejé escrito despues esto así me entero.

aplay /usr/share/sounds/speech-dispatcher/dummy-message.wav

aplay tira al sistema de audio el archivo de audio que le dés, ojo que no soporta cualquier cosa.


Hashes



Mejor buscar por hash, con md5 estamos bien, no estamos ante un adversario.

Recordemos que es un hash y que ocurre cuando hay un adversario de por medio.

Un hash es una función que se le aplica a un dato tal que "lo comprime" a un tamaño fijo, perdiendo un montón de información, pero con la característica de que distintos datos dan distintos hashes, hasta cierto punto.

La idea es que si dos archivos tienen la misma firma es problable que sean iguales.

Lo que tiene md5 es que el tamaño es un tanto reducido y que además no es seguro criptográficamente hablando, se pueden tomar atajos en las cuentas, no lo uses entonces si hay un adversario de por medio.

Puede haber usado sha1sum, sha2sum, etc, pero para lo que quiero, md5 alcanza y sobra.

find / -type f -iname "*.pdf" -o "*.epub" | while read BOOK; do
  md5sum "$BOOK"
done
-iname es para que busque cosas que terminen en pdf

-o es o lo siguiente

while toma cada linea y se la da a a read

read lee cada linea y la pone en la variable de nombre BOOK

md5sum calcula el hash md5 del archivo apuntado por $BOOK

Casi cuatro horas lleva esto...


Inspección


Como método complementario queda la inspección manual, tiene mucho de recuerdos, asociaciones, ver en que carpeta está cada cosa y qué lo rodea.


Ejemplo concreto


Primero un listado parcial de nombres de archivos con su frecuencia:

 3 Esapi-datasheet.pdf
2 msp430fr569xx_datasheet.pdf
2 BK-913-datasheet.pdf
1 spms376e_Tiva-TM4C123GH6PM_datasheet.pdf
1 sg90_datasheet.pdf
1 pic16f73-4-6-7-datasheet.pdf
1 msp430fr59x_69x_datasheet.pdf
1 e16g301_datasheet.pdf
1 datasheet.pdf
1 atmel-2586-avr-8-bit-microc....iny85_datasheet.pdf
1 atmel-2586-avr-8-bit-microc....iny85_Datasheet.pdf
1 AD9523-1_datasheet.pdf
1 utc uln2003 DARLINGTON SINK DRIVER.pdf
1 utc uln2003.pdf
Ahi hay dos pares de archivos probablemente el mismo con distintos nombres.

Estos son los hashes, todo recortado para que se vea bien:

c23db  /PlanDeEstu...uments/msp430fr569xx_datasheet.pdf
dbad8 /PlanDeEstu...sheets/AD9523/AD9523-1_datasheet.pdf
af564 /PlanDeEstu...2018/parallella/docs/e16g301_datasheet.pdf
b04c2 /INBOX/pasa...dspecs/atmel-2586-avr-8-bit-microco...iny85_datasheet.pdf
7f1c9 /INBOX/ANTE...ATABLE/robot/datasheet.pdf
f6e40 /INBOX/ANTE...ATABLE/robot/utc uln2003.pdf
c23db /REPO/githu...bricante/TI/msp430fr59x_69x_datasheet.pdf
bf45f /REPO/githu...AA_K60/Datasheets/BK-913-datasheet.pdf
bf45f /REPO/githu...EDU-NXP/Datasheets/BK-913-datasheet.pdf
c23db /SORT/free/...atasheet/TI/msp430fr569xx_datasheet.pdf
b04c2 /REPO/githu...h_cooler/doc/Atmel-2586-AVR-8-bit-Microco...iny85_Datasheet.pdf
a08eb /SORT/free/.../sg90_datasheet.pdf
f6e40 /SORT/free/.../components/utc uln2003 DARLINGTON SINK DRIVER.pdf
7a8ac /SORT/Secur...aining April 16th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac /SORT/Secur...g/OWASP Default Training/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac /SORT/Secur...aining May 28th 2010/OWASP ESAPI/Esapi-datasheet.pdf
fa658 /formacion/...sembly/spms376e_Tiva-TM4C123GH6PM_datasheet.pdf
aa14a /research/m...ntroller/pic/pic16f73-4-6-7-datasheet.pdf
Fijate que coincide la sumatoria del primer listado con la longitud de éste.

Ordenando por hashes, saltan los iguales:


7a8ac  /SORT/Secur...aining April 16th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac  /SORT/Secur...aining May 28th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac  /SORT/Secur...g/OWASP Default Training/OWASP ESAPI/Esapi-datasheet.pdf
7f1c9  /INBOX/ANTERIOR/RESCATABLE/robot/datasheet.pdf
a08eb  /SORT/free/.../sg90_datasheet.pdf
aa14a  /research/m...ntroller/pic/pic16f73-4-6-7-datasheet.pdf
af564  /PlanDeEstu...2018/parallella/docs/e16g301_datasheet.pdf
b04c2  /INBOX/pasa...dspecs/atmel-2586-avr-8-bit-microco...iny85_datasheet.pdf
b04c2 /REPO/githu...h_cooler/doc/Atmel-2586-AVR-8-bit-Microco...iny85_Datasheet.pdf
bf45f  /REPO/githu...AA_K60/Datasheets/BK-913-datasheet.pdf
bf45f  /REPO/githu...EDU-NXP/Datasheets/BK-913-datasheet.pdf
c23db  /PlanDeEstu...uments/msp430fr569xx_datasheet.pdf
c23db  /REPO/githu...bricante/TI/msp430fr59x_69x_datasheet.pdf
c23db  /SORT/free/...atasheet/TI/msp430fr569xx_datasheet.pdf
dbad8  /PlanDeEstu...sheets/AD9523/AD9523-1_datasheet.pdf
f6e40 /INBOX/ANTE...ATABLE/robot/utc uln2003.pdf
f6e40 /SORT/free/.../components/utc uln2003 DARLINGTON SINK DRIVER.pdf
fa658  /formacion/...sembly/spms376e_Tiva-TM4C123GH6PM_datasheet.pdf


<interrupción>

Se activó aplay ¡28 minutos y medio! termino el find con -exec, te recuerdo que del otro modo fueron 11 segundos.

</interrupción>


Finalmente, análisis manual:

7f1c9  /INBOX/ANTERIOR/RESCATABLE/robot/datasheet.pdf
es equivalente a

f6e40  /INBOX/ANTE...ATABLE/robot/utc uln2003.pdf
f6e40 /SORT/free/.../components/utc uln2003 DARLINGTON SINK DRIVER.pdf

¡Qué trabajito!, ¿no? Multiplicalo por mil.


Duplicados legítimos


Hay archivos que están duplicados y es legítimo, por ejemplo documentación del mismo componente en distintos repositorios. O esto:

35...c8  Vivado/2015.2/.../mig_7series_v1_9/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2015.2/.../mig_7series_v1_9/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2015.2/.../mig_7series_v1_8/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2015.2/.../mig_7series_v1_8/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2015.2/.../mig_7series_v1_7/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2015.2/.../mig_7series_v1_7/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2018.2/.../mig_7series_v1_9/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2018.2/.../mig_7series_v1_9/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2018.2/.../mig_7series_v1_8/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2018.2/.../mig_7series_v1_8/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2018.2/.../mig_7series_v1_7/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2018.2/.../mig_7series_v1_7/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2015.4/.../mig_7series_v1_9/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2015.4/.../mig_7series_v1_9/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2015.4/.../mig_7series_v1_8/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2015.4/.../mig_7series_v1_8/.../ug586_7Series_MIS.pdf
35...c8  Vivado/2015.4/.../mig_7series_v1_7/.../redirect/ug586_7Series_MIS.pdf
35...c8  Vivado/2015.4/.../mig_7series_v1_7/.../ug586_7Series_MIS.pdf

18 archivos iguales, mala suerte, no se pueden borrar.

Me dirías que esos son parte de programas, no es asunto mío, no debería ni buscar por fuera de /home. Pués si lo es, por que hay programas y programas. Lo que están instalados por la distribución ok, es verdad que no importan, pero muchos otros como los de xilinx son independientes de la distribución, o pueden ser resultado de la compilación de un repositorio.

Como sea, nos encontramos con que hay "falsos positivos" como partes de programas, clones de versionamiento, carpetas tipo "BORRAR".

Lo que podría hacer es algo tipo

grep -v -f whitelist.txt

-v es que invierta la selección, esto es que me traiga lo que NO cumple

-f es una lista de rutas

Pero si me interesa cuando la duplicación se produce entre estos falsos positivos y lo que está fuera de esas rutas, puedo tener el archivo ug586_7Series_MIS.pdf
incluido en un curso, lo conservo. O puede estar en ~/Downloads, puedo borrarlo.



Ayuda al análisis manual

Hasta acá estas son mis reglas:

  • Hay paths que corresponden a aplicaciones, no me interesan los hallazgos a menos que coincidan con elementos fuera de esos paths.
  • Si están versionados, no me interesan los hallazgos a menos que coincidan con elementos fuera de esos paths.
  • Mejor ver de conjunto para detectar grupos de duplicación, producto de backups, snapshots, rescates y sincronizaciones.

Para ayudarme en este análisis, me he hecho un script en awk, un lenguaje extremadamente interesante, suele estar asociado a la herramienta sed que viene a ser algo así como automatizar las operaciones del programa vi, que es un editor de texto.

No te puedo contar el tiempo que me llevó escribir el siguiente script pues me dá vergüenza decir que fueron dos horas, es bastante básico pero aunque tengo experiencia con awk, tiene algunas sutilezas que voy a comentar. No soy experto pero lo vengo usándo hace décadas de modo esporádico, cuando hice este programa choqué con varias cosas y eso me indujo a escribir este post.

El programa lo que hace es:
  • Carga una lista de falsos positivos.
  • Recibe linea por linea algo del tipo "hash ruta" ordenado por hash.
  • Descarta ocurrencias simples de hash.
  • Señala los casos correspondientes a la lista de falsos positivos.

Comento el código señalando la resolución a las dificultades que tuve y lo que me llama la atención del lenguaje pensando que venís de C y bash.

awk soporta funciones pero sus returns no devuelven tipos complejos, no arrays, aunque se pueden usar globales mejor por referencia:

function load_whitelist(file, whitelist) {
   while (1) {
      status = getline record < file
      if (status == -1) {
         print "falla " file;
         exit 1;
      }
      if (status == 0) break;
      whitelist[++count] = record
   }
   close(file);
}

Atención, index devuelve la posición, no el desplazamiento...

function check_in_whitelist(path, whitelist) {
  for ( elem in whitelist ) {
    if ( index(path, whitelist[elem]) == 35 ) {
      return 1;
    }
  }
  return 0
}
function print_checked(line, whitelist) {
  if ( check_in_whitelist(line, whitelist) ) {
    print "XXX " line
  } else {
    print "    " line
  }
}

Recordemos que lo que esté en el bloque BEGIN se ejecuta una sola vez al comienzo del programa, viene a ser como el setup() en ArduinoIDE

BEGIN {
  state = "state_first"
  load_whitelist("whitelist.txt", whitelist)
}

He utilizado una FSM como lo relatado en ...

Las instrucciones estas se ejecutan para cada linea leida por STDIN, a la que se le aplica el pattern. Normalmente se hace mucho con esos patterns, pero en este caso que las lineas son todas homogéneas con esto alcanza.

Recordá que cada pattern y su bloque correspondiente se van evaluando y ejecutando en orden, con next podés pasar a procesar la siguiente linea de entrada sin aplicar las reglas restantes.

Recuerdo, estoy seguro, que en los patterns no se pueden usar variables.

/.*/ {
  switch (state) {
    case "state_first":
       linea_anterior = $0
       md5_anterior   = $1
       state = "state_head"
    break;
    case "state_head":
      if ($1 == md5_anterior) {
        print_checked(linea_anterior, whitelist)
        linea_anterior = $0
        state = "state_tail"
      } else {
       linea_anterior = $0
       md5_anterior   = $1
      }
    break;
    case "state_tail":
      if ($1 == md5_anterior) {
        print_checked(linea_anterior, whitelist)
        linea_anterior = $0
      } else {
        print_checked(linea_anterior, whitelist)
        print "======================================"
       linea_anterior = $0
        md5_anterior   = $1
        state = "state_head"
      }
    break;
  }
}

Finalmente, qué sorpresa, está el bloque END, para procesar la última línea:

END {
  if (state == "state_tail" ) {
    print_checked(linea_anterior, whitelist)
 }
}

Aplicándolo al ejemplo que vengo arrastrando:


    7a8ac  /SORT/Secur...aining April 16th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac  /SORT/Secur...aining May 28th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac  /SORT/Secur...g/OWASP Default Training/OWASP ESAPI/Esapi-datasheet.pdf
======================================
b04c2  /INBOX/pasa...dspecs/atmel-2586-avr-8-bit-microco...iny85_datasheet.pdf
b04c2 /REPO/githu...h_cooler/doc/Atmel-2586-AVR-8-bit-Microco...iny85_Datasheet.pdf
======================================
 bf45f  /REPO/githu...AA_K60/Datasheets/BK-913-datasheet.pdf
bf45f  /REPO/githu...EDU-NXP/Datasheets/BK-913-datasheet.pdf
======================================
c23db  /PlanDeEstu...uments/msp430fr569xx_datasheet.pdf
c23db  /REPO/githu...bricante/TI/msp430fr59x_69x_datasheet.pdf
c23db  /SORT/free/...atasheet/TI/msp430fr569xx_datasheet.pdf
======================================
f6e40 /INBOX/ANTE...ATABLE/robot/utc uln2003.pdf
f6e40 /SORT/free/.../components/utc uln2003 DARLINGTON SINK DRIVER.pdf

Y si en el archivo whitelist.txt ponemos alguna ruta, por ejemplo la de github:

    7a8ac  /SORT/Secur...aining April 16th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac  /SORT/Secur...aining May 28th 2010/OWASP ESAPI/Esapi-datasheet.pdf
7a8ac  /SORT/Secur...g/OWASP Default Training/OWASP ESAPI/Esapi-datasheet.pdf
======================================
b04c2  /INBOX/pasa...dspecs/atmel-2586-avr-8-bit-microco...iny85_datasheet.pdf
XXX b04c2 /REPO/githu...h_cooler/doc/Atmel-2586-AVR-8-bit-Microco...iny85_Datasheet.pdf
======================================
XXX bf45f  /REPO/githu...AA_K60/Datasheets/BK-913-datasheet.pdf
XXX bf45f  /REPO/githu...EDU-NXP/Datasheets/BK-913-datasheet.pdf
======================================
c23db  /PlanDeEstu...uments/msp430fr569xx_datasheet.pdf
XXX c23db  /REPO/githu...bricante/TI/msp430fr59x_69x_datasheet.pdf
c23db  /SORT/free/...atasheet/TI/msp430fr569xx_datasheet.pdf
======================================
f6e40 /INBOX/ANTE...ATABLE/robot/utc uln2003.pdf
f6e40 /SORT/free/.../components/utc uln2003 DARLINGTON SINK DRIVER.pdf

con XXX marca cuales he decidido ignorar pero me sirven para saber que hacer, por ejemplo puedo borrar msp430fr569xx_datasheet.pdf si lo deseo, probablemente no, pues me gusta tener una carpeta con datasheets aunque queden duplicadas.


Por último, después de mirar muchos duplicados veremos que hay un patrón, puede ser muy útil aparte de identificar duplicación de archivos la duplicación aunque sea parcial de carpetas.

Cuando encontras varios archivos duplicados dentro de una misma carpeta, podés comparar las carpetas con el comando dirdiff, si no lo teneś:

sudo apt install dirdiff

Este programa te muestra canditatos a ser diferentes por fecha de modificación, pero no contenido, ni siquiera por longitud, no le confíes mucho, pero es indudablemente útil para ordenarte.

El código en github

2020/06/08

Primer programa en un ATtiny85 bare y luego ArduinoIDE con SoftUART

Bare pues es el chip sólito que voy a poner en mi propio circuito, no sé si hay manera de hacerlo utilizando ArduinoIDE como he hecho con un ATMega328p en otro ejercicio.

Como siempre, podría buscar todo en Internet y como siempre lo evitaré.

Compilación


Me voy a apoyar en un Makefile que tenía para ATMega328p, para compilar:

$(GCCPATH)/avr-gcc -mmcu=attiny85 -Wall -std=gnu99 -Os -o blink.elf blink.c && \
$(GCCPATH)/avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex

Para la elección de mcu, es attiny85, sale de la documentación de gcc.

Para el blinky tendría que elegir el pin, ok, por default son GPIO:


ATtiny85 pinout

Este sería un blinky en PB0, el pin 5:

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>

int main (void) {
    DDRB |= 0x00111111;
    while(1) {
        PORTB ^= 0x00000001;
        _delay_ms(500);
    }
}

Nos falta ver si funciona, para ello falta la...

Programación


Este es el comando para programar el chip:

BURNER=usbasp
AVRDEVICE=???
FUSES=???
avrdude -p $(AVRDEVICE) -c $(BURNER) -e -F -U flash:w:blink.hex -U $(FUSES) -C /etc/avrdude.conf

Falta definir AVRDEVICE y FUSES, por ahora voy a probar sin los FUSES.


Nuevamente, la documentación nos dice que es t85 y parece funcionar ok:


~ $ make burn
avrdude -p t85 -c usbasp -e -F -U flash:w:blink.hex  -C /etc/avrdude.conf
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e930b (probably t85)
avrdude: erasing chip
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: reading input file "blink.hex"
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: writing flash (86 bytes):

Writing | ################################################## | 100% 0.09s

avrdude: 86 bytes of flash written
avrdude: verifying flash memory against blink.hex:
avrdude: load data flash data from input file blink.hex:
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: input file blink.hex contains 86 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.06s

avrdude: verifying ...
avrdude: 86 bytes of flash verified
avrdude: safemode: Fuses OK (E:FF, H:DF, L:62)

avrdude done.  Thank you.

Lo ponemos en el protoboard y...

Funciona, pero es muy básico, tendría que pasar al siguiente nivel, que es por ejemplo leer el sensor interno de temperatura y enviarlo por el puerto serial... salvo que ATtiny85 no tiene puerto serial, hay que implementarlo por software.

Al llegar a este punto se abren varias posibilidades:

Continuando con bare metal, implementar yo la SoftUART


Mmh, me mata, esto es un desvío dentro de otro proyecto.

Buscar una librería apta para bare metal


Parece que todo el mundo desarrolla para el entorno de ArduinoIDE, lo mejorcito que hallé sólo transmite.


Incorporar a mi bare metal librerías de arduino.


Lo primero es pasar de c a c++, no hay problema, que use avr-c++ en lugar de avr-gcc y que quitar -std=gnu99:


$(GCCPATH)/avr-c++ -mmcu=attiny85 -Wall -Os -o blink.elf blink.c && \
$(GCCPATH)/avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex

El problema es cuando ponés el primer #include <>, no es un buen camino. Además, no entiende al ATtiny85.

Usar ATtiny85 desde ArduinoIDE


Para esto tuve que recurrir a Internet, reproduzco:

Primero agregás de dónde bajar las descripciones de los boards:

Arduino -> Preferences -> Additional Board Managers URLs

Agregar con coma adelante si ya tenés algo:

https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json


Luego agregás una nueva descripción:

Tools-> Board-->Boards Manager -> filtrar con attiny

Seleccionar e instalar Attiny de David. A Mellis

Finalmente, en tu proyecto elegís ATiny85, NO olvides elegir procesador ATtiny85 pues viene como ATtiny25 que no le entra nada. No toqué el clock por ahora.

El programa del ejemplo del tutorial y lo modifiqué pensando en lo que voy a necesitar, el serial y tres pines (dos termómetros y un PWM, tema aparte.

#include <SoftwareSerial.h>

const byte rx = 0;
const byte tx = 1;
char data;

SoftwareSerial swSerial(rx, tx);
void setup() {  
  pinMode(rx,INPUT);
  pinMode(tx,OUTPUT);
  DDRB |= B00011100;
  delay(5000);
  swSerial.begin(9600);
  swSerial.println("BEGIN");
  PORTB &= B11100011;
 delay(1000);
  PORTB |= B00000100;
  swSerial.println("led 0");
  delay(1000); 
  PORTB |= B00001000;
  swSerial.println("led 1");
  delay(1000); 
  PORTB |= B00010000;
  swSerial.println("led 2");
  delay(1000);

  swSerial.println("limpiando");
  PORTB &= B11100011;
  delay(1000);
}

void loop() {
  if(swSerial.available() > 0){
    data = swSerial.read();

    switch (data) {
      case '5':
         PORTB &= B11000011;
         swSerial.println("limpiando");
      break;

      case '0':
         PORTB |= B00000100;
         swSerial.println("led 0");
      break;
      case '1':
         PORTB |= B00001000;
         swSerial.println("led 1");
      break;
      case '2': 
         PORTB |= B00010000;
         swSerial.println("led 2");
      break;

      default:
        swSerial.println("mi no entender");
      break;
    }
  }
}
El reset va a 5v, lo puse con una resistencia para poder activarlo cortando a GND. Entiendo que si quisiera usar el reset como GPIO, se me dificultaría volver a programarlo, veremos...

2020/06/06

Compartiendo el zócalo para programar ATMega328p y ATtiny85


En el marco de necesitar programar un ATtiny85 con usbasp, como ya tengo armado el circuito para ATMega328p, quiero aprovecharlo y programar ambos con el mismo. Como siempre, puedo buscar en Internet como se hace, pero para aprender no me sirve, así que a arremangarse...



Por si no sabés, los arduinos normalmente se suelen programar con el chip en la placa, aprovechando la conexión serial existente y utilizando un pequeñísimo programa que se encarga.

Cuando tenés el chip pelado y/o lo podés sacar de la placa, prescindís del programa y utilizás una interfaz llamada Serial Programming Interface. Para comunicarte con ésta, necesitas algo que entienda SPI por un lado y encima de eso que "sepa" como programar lo que le enviás. Eso lo hace usbasp.

Desde la línea de comandos usás avrdude, desde ArduinoIDE, le decís que

Sketch -> Upload Using Programmer

que usa avrdude.



Este es el conector del programador usbasp:


        +------+------+------+------+------+
        | MISO |  SCK | RESET|  N/C | MOSI |
        +------+------+------+------+------+
        | GND  |                    |  5V  |
        +------+                    +------+

Este es pinout del ATMega328p:


      +-----------------+
RESET ->  1          28 -
      -        A        -
      -        T        -
      -        m        -
      -        e        -
      -        g        -
           - Vcc    a   GND  -  GND
 GND  - GND    3        -
          -        2  AVcc  -  5V
           -        8   SCK <-  SCK
            -        p  MISO <-> MISO
            -           MOSI  -> MOSI
       -                 - 
       - 14           15 - 
      +-----------------+



Este el del ATtiny85:


          +---------------+       
 RESET -> 1       Vcc  -  5v
        -          SCK <-  SCK
         -         MISO <-> MISO
     GND - GND     MOSI  -> MOSI
   +---------------+


Y este es el programador como está ahora:



Los pines del atmega328p


Lo natural es aprovechar el espacio libre y cablear ahí:


ATtiny85 en sus propios pines


Si te fijás bien, hay una alta superposición que no debe ser accidental:



        +-----------------+
 RESET  ->  1          28 -
        -        A        -
        -        T        -
        -        m        -
        -        e        -
        -        g        -
   A         - Vcc    a   GND  -  GND
T     GND - GND    3        -  
  t  RESET  - PB6    2  AVcc  -  5V
   i         -        8   SCK <-  SCK
    n         -        p  MISO <-> MISO
    n     GND - PD6       MOSI  -> MOSI

8         -                 -  
5         - 14           15 -  
        +-----------------+


Mmmh, qué interesante, puedo ponerlo superpuesto y con dos jumpers determinar si habilitar los RESET y GND en PB6 y PD6 al programar ATtiny85.


Attiny85 compartiendo pines



Apuesto a que los pines coincidentes con ATMega328p arranca en alta impedancia y ni hacen falta los jumpers.


El incentivo que tengo para no usar los jumpers es que es menos trabajo y que si no hay jumpers no me voy a olvidar de ponerlos. Esto me debería obligar a consultar y entender la documentación.

La documentación dice:

"The Port X pins are tri-stated when a reset condition becomes active,
even if the clock is not running."

y con respecto a RESET:

"A low level on this pin for longer than the minimum pulse length
will generate a Reset,
even if the clock is not running."


¿Qué signica esto? Que si el programador tiene el RESET en bajo está todo ok, ¿pero quien llega primero? ¿Cómo está cuando arranca?

Me imagino que usbasp ni sabe ni le interesa nuestras superposiciones y que incluso debe preveer que se pueda utilizar en un chip que esté colocado en su circuito, así que debe activar y desactivar RESET en lugar dejarlo fijo, si no, ¿para qué tiene control sobre este pin si no lo va a ejercer?


Ahora tengo el estímulo de fijarme y el experimento será observar el comportamiento de RESET por un lado y ver si PB6 y PD6 arrancan en modo input o triestado.

Como siempre, aclaro que mis conocimientos de electrónica en general son escuálidos y en particular los de analógica.


Experimento 1


Programar un ATMega328p y observar el comportamiento de RESET.

Deseo que siempre esté bajo, pero por lo expresado más arriba, espero que cambie.

Resultados


El programador baja RESET


Arranca en alto, no lo puedo ignorar.




Experimento 2


Conectar un ATMega328p y observar las características eléctricas de PB6 y PD6.

Momento de replanteo, si el usbasp arranca con RESET en alto, lo que haya en PB6 y PD6 dependerá del programa almacenado previamente.

Pero si lo estoy alimentando por AVcc y no por Vcc, ¿se activa ese programa?


Subexperimento 2.1


Programar un ATMega328p con un programa que haga blinky en  PB6 y PD6 y ver si estando en el zócalo de programación se manifiesta.

void setup() {
DDRD |= B01000000;
  DDRB |= B01000000;
}

void loop() {
  PORTB |= B01000000;
  PORTD |= B01000000;
  delay(1000);
  PORTB &= B10111111;
  PORTD &= B10111111;
  delay(1000);
}


Resultado


El chip conectado en un circuito completo:


Con alimentación correcta corre blinky


El chip conectado al circuito programador:



Con AVcc no hay actividad



El programa no se activa, eso es bueno.

Subexperimento 2.2


Programar un ATMega328p con un programa que haga blinky en  PB6 y PD6, sin configurar los pines como salida y ver si se manifiesta. De no hacerlo, podemos deducir que el estado inicial no es output.

void setup() {
DDRD &= B10111111;
  DDRB &= B10111111;
}

void loop() {
  PORTB |= B01000000;
  PORTD |= B01000000;
  delay(1000);
  PORTB &= B10111111;
  PORTD &= B10111111;
  delay(1000);
}


Resultado


Se manifiesta, pero tengo dudas


Subexperimento 2.3


Programar un ATMega328p con un programa que haga blinky en  PB6 y PD6, configurando los pines como entradas y ver si se manifiesta.

void setup() {

}

void loop() {
  PORTB |= B01000000;
  PORTD |= B01000000;
  delay(1000);
  PORTB &= B10111111;
  PORTD &= B10111111;
  delay(1000);
}


Resultado


Se manifiesta, entonces sigo sin saber como arranca.



Subexperimento 2.3



Confeccionar un programa que ponga los pines en todos los estados posibles, luego tomar mediciones y usarlas para comparar con

Aunque no lo documenté en la otra experiencia con los modos de los pines, hay que tener presente que las transiciones de input a output tienen un cierto orden, no es que podés pasar directamente.

Resultado


No lo voy a hacer, se me está complicando mucho, yo sólo quería ahorrarme unos jumpers para poder programar el chip para ver si lo podía usar para controlar la velocidad de unos coolers de un switch, voy a volver a mirar la documentación. Y dice:


"The I/O ports of the AVR are immediately reset to their initial state
when a reset source goes active"

Pero no encuentro cuál es el estado inicial...


Finalmente me rendí y busqué en internet, no cómo resolver mi cableado sino como detectar si algo está en triestado y Crutshow el 2009-08-28 lo dijo:

Place two large (say 100K ohm) resistors in series between the +5V and ground. Connect the junction of the resistors to the tri-state output. If the output is in the tri-state mode, then the output will be about +2.5V. Otherwise the output will be high or low depending upon its output logic level.



Voy a considerar que está triestado y si rompo algo, eso me enseñará a aprender electrónica analógica.

Agregué los cables, programé un ATMega328p con el código del subexperimento 2.1 y, redoble de tambores...

Funciona, recién ahora, puedo programar el ATtiny85.

Tengo dos caminos, tomar el bare metal o como venía con ArduinoIDE.

El problema con el primer camino es que no sé como incluir las librerías para el serial, el DHT11, el PWM que ya tiene resuelto arduino.

El problema con el ArduinoIDE es que para ATMega328p uso Arduino Nano como referencia, pero ninguno existe que use ATtiny85.


Es todo un problema. En realidad es el problema de cómo agregar un board propio a ArduinoIDE, que vengo postergando desde la otra experiencia, para mi problema actual de la velocidad de cooler, optaré por baremetal y lo del "bare chip" resolveré en otro momento.