Quantcast
Channel: Seguridad Agile
Viewing all 264 articles
Browse latest View live

Qué podés hacer cuando tenés dos ISPs

$
0
0
Debido a que en casa estamos cambiando de ISP, hemos tenido unas semanas de doble servicio, ¿qué experimentos podemos hacer que habitualmente no con una sola conexión?

Si no estuviera un poco aburrido del asunto de la ciberseguridad, me pondría a tirar nmaps y esas cosas... bueno, lo hice igual, pero la verdad es que más es interesante...


Multitier torrent


Normalmente cuando usas bittorrent, si estás bajando algo popular alcanzás una muy alta velocidad, limitada en última instancia por los componentes cercanos a vos, o sea, tu ISP.

El experimento que voy a realizar es comparar bajar el mismo contenido de distintas maneras teniendo múltiples (dos) ISPs.

Limitaciones


No me interesa explorar si hay algún cliente que sabe cómo lidiar con la situación, pues es algo que no puedo generalizar luego para otras aplicaciones.

No puedo usar dos placas de red, pues me consta que la máquina donde puedo poner varias placas por tener bus PCI tiene contención de ese mismo bus, en otra oportunidad me afectó.

No puedo usar un dongle USB-Ethernet pues baja considerablemente la velocidad.

Tampoco pienso poner una placa en mi máquina pues en los últimos cinco años he andado con mala suerte y se me ha roto una proporción desproporcionada de las máquinas que he abierto.


Tres escenarios


En realidad son dos pero necesito uno de referencia para poder comparar.

Referencia


Hay que medir primero la performance de cada ISP por separado. Para ello agrego un router que tenía tirado por ahí y le conecto otra máquina. En ambas bajo lo mismo.

Considerá que todos estos números son un tanto imprecisos, sobre todo los del ISP 1, pues la misma conexión está siendo usada a la vez por otras personas.




Medición ISP 1

Bajé el archivo completo:

  • 3.86 GB
  • 21 minutos 1260 segundos
  • 3860398080 / 1260 = 3063808 B/s = 3.06 MB/s
  • por momentos 3.65 MB/s


Medición ISP 2


Cuando llegó a 15 minutos me aburrí, tomé estos datos parciales

  • 1.18 GB
  • 15 minutos  = 900 segundos
  • 1180000000  / 900 = 1311112 B/s = 1.31 MB/s
  • por momentos 1.54 MB/s


Vía ISP 2




Dos máquinas




Dos máquinas, cada una conectada a un ISP y aprovechar que mi cliente entiende buscar en la red local si hay alguien bajando lo mismo, de este modo quizás cada uno baje un mitad y la comparta con el otro.


Local Peer Discovery en ambas máquinas


Para esto hay que:
  • desactivar DHCP en el router del ISP2
  • poner al router en una IP de la red del ISP1, por ejemplo 192.168.1.10
  • poner a la máquina 2 con IP 192.168.1.11 y gateway 192.168.1.10
  • tirar un cable del router al switch
  • activar LPD en ambas máquinas

Pre prueba


Que una máquina vea a la otra en la red local y baje todo de ahí, ok, dejé que la segunda máquina terminara y anduvo.


Habiendo activado Local Peer Discovery


Medición dos máquinas


  • 3.86 GB
  • 16 minutos, son 960 segundos
  • 3860398080 / 960 = 4021248 B/s = 4MB/s
  • Por momentos 7MB/s


Bajada combinando un ISP y la otra instancia





Se ve la dirección local de la otra máquina


Es conveniente ejecutar en ambas máquinas como root o sudo:

$> mii-tool enp3s0
enp3s0: negotiated 100baseTx-FD flow-control, link ok


y las velocidades deberían coincidir.


Una máquina, dos rutas





En lo anterior no he cumplido con ser neutral con respecto al cliente de bittorrent, no sé si otros programas soportan LPD. Tampoco puedo contar con tener dos computadoras y espacio libre en ambas, notá que aunque bajé una sola instancia de la imagen, la tengo duplicada.

Lo que hay que hacer ahora es:
  • mantener el router del ISP2
    • DHCP desactivado
    • una IP estática conocida
    • cable al switch de la red principal
  • quitar la segunda máquina
  • LPD ya no es necesario
  • manipular sus rutas

Para manipular las rutas hace falta tener una vaga idea de cuál será la partición.

Tirando un

watch -n 10 netstat -tn >> ips.txt

toda la noche, me hice un mapa de las IPs típicas, el problema es que la salida me quedó con caracteres de escape, más o menos lo limpié con esto, seguro se puede hacer mejor:


 strings ips.txt | grep "[01234567890.]*:443" -o \
   | grep "\..*\..*\..*"  | cut -d "." -f 1-2 \
   | sort -n | uniq -c

Quitando los errores del comando anterior me deja:


      6 1.13
      5 2.16
      2 2.18
      2 2.43
      7 3.77
      2 52.1
      7 6.58
     62 8.43
      1 8.67
      3 13.33
      1 15.96
      6 16.58
      1 16.73
      1 16.74
     30 2.217
      8 23.12
      1 23.32
      1 23.55
    104 23.77
     52 3.107
    194 31.13
      3 3.223
      3 3.232
      4 34.98
      2 4.233
     12 4.244
      1 45.54
     10 5.201
    131 52.43
     54 68.67
      1 86.18
      1 88.99
     70 92.16
     31 104.87
      1 115.96
    148 13.107
      7 13.227
      1 144.76
      1 185.63
      7 186.18
    113 192.16
      1 192.73
     15 200.42
    260 216.58
      5 23.197
     10 23.222
      2 34.194
    199 35.201
      1 35.241
      2 52.195
      1 54.187
      1 54.219
    170 64.233
    297 72.217
      1 74.119
      2 74.125
      3 95.216
     99 104.244
      4 104.254
      1 108.174
      1 151.101
     16 152.195
      1 152.199
    953 172.217
     22 192.168

y agrupando a ojo:

  • redes entre 1.0.0.0 y 63.0.0.0 = 700
  • redes entre 64.0.0.0 y 127.0.0.0 = 1500
  • redes entre 128.0.0.0 y 255.0.0.0 = 1000

Ojo otra vez, esas IPs son las conexiones que hubieron durante un tiempo, no es un buen análisis pues no tengo idea del tráfico que hubo que es lo que realmente me interesa para particionar.

Veamos primero que hay:

$> route -n
Kernel IP routing table
Destination Gateway     Genmask       Flags Metric Iface
0.0.0.0     192.168.1.1 0.0.0.0       UG    100    enp3s0
169.254.0.0 0.0.0.0     255.255.0.0   U     1000   enp3s0
192.168.1.0 0.0.0.0     255.255.255.0 U     100    0     0 enp3s0



Lo que tengo que agregar es una ruta tal que el Gateway sea el router que conduce al ISP 2, esto es, 192.168.1.10. Luego usando dos servicios de identificación de cuál es mi IP, ver que uno me dice una y otro la otra.

Tengo dos, con ping -c 1 obtengo sus IP

https://whatismyipaddress.com  104.16.155.36
https://www.whatismyip.com     104.27.199.91

ufa, están muy juntas.

https://www.myip.com           172.67.208.45


Mejor, de paso ya hago el particionado en 128.0.0.0, todos los route add son como root.

route add -net 128.0.0.0 netmask 128.0.0.0 gw 192.168.1.10 metric 100

Lo que nos da:

$> route -n
Kernel IP routing table
Destination Gateway      Genmask       Flags Metric Ref Use Iface
0.0.0.0     192.168.1.1  0.0.0.0       UG    100    0   0   enp3s0
128.0.0.0   192.168.1.10 128.0.0.0     UG    100    0   0   enp3s0
169.254.0.0 0.0.0.0      255.255.0.0   U     1000   0   0   enp3s0
192.168.1.0 0.0.0.0      255.255.255.0 U     100    0   0   enp3s0



Observá las distintas IPs según a quien le preguntes


Listo para torrentear.


En uno de los momentos de máxima velocidad



  • 3.86 GB
  • 17 minutos 1020 segundos
  • 3860398080 / 1260 = 3063808 B/s = 3.78 MB/s
  • por momentos 4.77 MB/s


Resultados y reflexiones

Aun con un particionado muy bestia como el que he realizado, se pueden combinar exitosamente las velocidades de dos o más ISP.


 Modo tiempo
[s]
 velocidad
[MB/s]
 pico
[MB/s]
 ISP 1
 1260 3.06 3.65
 ISP 2
  1.31 1.54
 Dos máquinas
 960 4 7
 Dos rutas
 1020 3.78 4.77


El pico no es muy representativo, en "Dos Máquinas" indica lo que ocurrió en la LAN. Lo interesante es que la red local de 100 Mb está prácticamente saturada, si agregara un tercer proveedor como el primero no lo podría aprovechar completamente, tendría que usar una red interna de 1Gb.

Siguientes pasos


Me interesa mucho este tema, pero dentro de dos días me quedo sin el segundo ISP y la verdad es que no me paso el día bajando cosas y tengo otras muchas tan o más interesantes que hacer, lo que sigue te puede servir de inspiración para que lo hagas vos. ¿No tenés dos ISP? No hay problema, le pedís a un vecino que tenga WiFi con un proveedor distinto al tuyo mejor que te preste sus credenciales y ya tenés dos ISPs, o tres o más.


Distribución mediante DHCP


Todo lo que hice antes fué en una sola máquina, si querés que todas tus máquinas tomen esa configuración, parece que con DHCP se puede.

Balanceo dinámico con ruteo


Si tenés varios canales como es este caso y además tenés el control en ambos extremos, el balanceo debe ser sencillo, en particular en una red local lo he hecho usando trunking/bonding.

Para el caso actual, donde están de un sólo lado del caño, no es tan sencillo, habría que estar midiendo cual es el mejor camino, una combinación de ancho de banda, latencia, saltos hasta el destino. Debe existir una manera común y normal pero para mejor aprender e investigar voy a seguir sin buscarla y pensando.

Para ver el tráfico discriminado se me ocurre agregar una interfaz virtual, de este modo se puede ver la saturación y si a la vez mirás netstat, podrías ir reparticionando. Cuando le pescaste la mano, reemplazás con un script. Pero no debe ser ten fácil, ¿qué pasa con una conexión que tenés abierta si cambia el enrutamiento? ¿El kernel se dá cuenta y no te la corta? Ahí recordé que man route ofrece:

-C     operate on the kernel's routing cache.


Parece que el kernel tiene un cache y que a menos que uno le pida explícitamente, add no lo toca. Esto no sólo salvaría a una conexión existente si no que muchas otras conexiones nuevas no tomarían la nueva ruta, debe haber un TTL por ahí.

Es todo un tema, listo, ya me cansé de pensarlo.


Si ponés en google algo así como

"dynamically changing routes to balance traffic between two providers"

tenés para divertirte.





Rescatando un 8051

$
0
0

O de como pasar la cuarentena.

En los primeros días de Octubre de 2019, anticipando #quedateencasa en general y #QuedateEnCasaYReverseateAlgo en particular, mientras elaboraba los contenidos de "Método de entrenamiento de (de)soldado" y "Para estudiar Hardware Security" y sentando las bases para "EDU-CIAA-NXP-SEG", necesitaba soldar para ésta última un lpc43s37 de reemplazo, pero mis torpes manos no estaban a la altura de la tarea, así que me propuse fabricarme algún tipo de herramienta.

Para construir esa herramienta necesitaba elementos, repartidos en decenas de cajones, cajitas, bolsas, o sea, el quilombo habitual.

Me puse a ordenar y tras varias semanas de trabajo lo logré, pasé de tener una pocilga a un quirófano y de paso (re)encontré esto, que hace años había perdido de vista:





Es la controladora de un disco rígido muy viejo, probablemente ESDI. Lo que me interesa es la CPU, que en realidad es un microcontrolador, esto es una CPU con varios periféricos en el mismo chip. Entiendo que fué y quizás sigue siendo un chip muy estimado en los cursos introductorios de programación de microcontroladores en varias universidades.







Leyendo en varias sitios llegué a este conocimiento:

  • Tiene una PROM, esto es Programmable ROM.
  • Es WORM (Write Once, Read Many), sólo se puede programar una vez.
  • Pero alguien dijo que una vez programado se puede reusar arrancando de una ROM externa.

Probablemente mi proyecto sea viable:

  • Aplicaré el enunciado del capítulo 4 de Hardware Security que consiste en identificar los componentes. Esto no es del todo necesario pero quiero cruzar la hoja de datos con lo que tenga conectado como para practicar.
  • Desoldaré todo lo que pueda, para practicar tambien (en realidad este fué el primer paso, pero debió haber sido el segundo...)
  • Asumiré que no está rota.
  • Haré la conexión eléctrica mínima tal que funcione.
  • Pondré un blinky en una EEPROM o similar.
  • Andará y eso es todo, me daré por satisfecho.
Puede ser que no llegue a hacer todo, ya sea por:
  • Falta de habilidad
  • Destrucción prematura del 8051
  • Imposibilidad real de ejecutar código externo

 

 Las preguntas


¿Me atreveré a intentar hacerla andar a partir de las especificaciones o buscaré, estoy seguro que tengo, algún apunte que heredé de algún estudiante de electrónica donde explica cómo hacerlo? Especificaciones y google, en alguna limpieza me deshice de los apuntes o los dejé muy bien escondidos.

¿Programaré una eeprom o intentaré algún hack como el del increiblemente inspirante artículo Emulación de ROM de Quinn BlondieHacks?

¿Seré capaz de darme cuenta si he llegado a un punto muerto? ¿Seré capaz de rendirme?

Lo que pensé que sería un proyecto relativamente corto resultó ser una pesadilla de ramificaciones directas que me llevó a escribir:

  • https://seguridad-agile.blogspot.com/2020/04/generador-precario-de-senales-cuadradas.html
  • https://seguridad-agile.blogspot.com/2020/04/diagnosticando-avrdude-usbasp-arduino.html
  • https://seguridad-agile.blogspot.com/2020/05/programando-eprom-con-atmega328p.html
E indirectas por oportunidad, estuve adquiriendo o completando conocimientos para terminar cosas a medio hacer:

  • https://seguridad-agile.blogspot.com/2020/04/twister-del-azar.html
  • https://seguridad-agile.blogspot.com/2020/04/adaptacion-de-los-microcontroladores.html
  • https://seguridad-agile.blogspot.com/2020/04/metodos-para-identificar-el-pinout-de.html

Manos a la obra, al final hay un resumen por si te resulta muy tedioso leer todo esto.

Desoldado


Nada especial, aire caliente a 390 °C del otro lado y la cosita que aspira.

Reconocimiento

No sé donde dejé la placa de donde saqué el chip, así que no voy a poder ver a qué estaba conectado y no voy a disponer del cristal original por que lo saqué hace años.

Mientras, viendo http://www.cpu-world.com/CPUs/8051/Intel-P8051AH.html y la datasheet entiendo que:



  • RAM
    • 128 B internal, me interesa
    • va de 0x00H a 0x7F
    • de 0x00 a 0x1F están mapeados los registros R0–R7
    • de 0x80 de 0xFF Registros especiales
    • 64 KB external, no me interesa
  • ROM
    • 4 KB internal, inútil
    • 60 KB external, me interesa 0000H a FFFFH

Pinout


VCC y VSS: para la alimentación.

RST: High para reset.

ALE/~PROG: emite a 1/6 de la frecuencia del oscilador, me servirá como control.

EA (External Access): debe estar a tierra para que use la memoria de programa externa. Si el security bit está activo, estoy afuera, no va a accederla.

~PSEN para el enable de la lectura de memoria externa, me interesa.

XTAL1 y XTAL2: acá va el cristal y unos capacitores que bastante me hicieron sufrir.

PORT0 se usa para acceder al programa externo, tiene multiplexado la parte baja de la dirección y el bus de datos. Esto me va a complicar horriblemente la vida.

PORT1 parece ok para los leds.

PORT2 se usa para acceder al programa externo, la parte alta de las direcciones.

PORT3 se usa para la memoria externa que no me interesa, podría usarlo.

Acción


Primer paso, el clock.


Conecté en un protoboard la alimentación, el cristal y los capacitores que canibalicé, es difícil un lunes feriado de cuarentena conseguir nada.




Medí en XTAL1 y ALE y aunque las formas son horribles, las frecuencias están bien, fijate que 1.6 (cyan) x 6 = 9.6 (amarillo), entiendo que puedo seguir.




 


Primer paso, segundo intento.


Basándome en https://www.electroschematics.com/at89s52-minimum-development-board-8051-tutorial-2/, puse algunas conexiones más a ver si se manifiesta en mejores curvitas y voy arrimando a lo que hay que llegar de todos modos. No hubo diferencia, así que me mudé a un PCB preperforado o como se llame, perdiendo en el camino el cristal de 9.6, lo reemplacé por uno de 8.


Los zócalos de la izquierda no están en uso, pero observá que uno está poblado


Fijate que las cuentas se mantienen ok, pero como invertí las puntas los colores están al revés.




Lo que no me gusta es que arrancó consumiendo 1.84A y luego bajó a .8A, lo cual está muy mal pues dice consumir 250 mA, espero que no esté frito. Igual tengo esperanzas, al ponerle RST a tierra bajó, veremos.

Me imagino que el comportamiento que estoy viendo no indica que el microcontrolador esté funcionando, sólo el clock.

Segundo paso, las direcciones externas.

Para ver si hay vida, ahora le voy a pedir que use la ROM externa y espero encontrar alguna actividad digital en las pistas, vamos por EA.



Recordemos, hay que poner EA a tierra.



Tras mucho sufrir:
  • ¿Viste que había algo en uno de los zócalos supuestamente vacíos? Era un 74LS374 del próximo paso que por los cambios del trazado del PCB estaba con la polaridad invertida, de ahí los 0.8 A, ahora estamos con 70 mA.
  • El 8051 tiende a soltarse del zócalo.
  • Tuve que poner las resistencia a positivo del PORT0
  • No recordaba en absoluto como usar el analizador de protocolos.
Hay señales de vida:




A esas transiciones no les veo un patrón claro, pero sin duda son demasiado regulares, puede ser que esté en coma, pero no muerto.


sigrok-cli  -d fx2lafw:conn=5.6 --time 3000 -o dump.vcd -O vcd

# prender y apagar el microcontrolador

gtkwave dump.vcd



Luego ví en el man sigrok-cli que existe pulseviewque tiene decoders y puede usar al analizador lógico directamente, pero es menos usable, no tiene para avanzar y retroceder buscando la próxima transición ni para medir intervalos.




Con el decoder de paralelo podemos ver los valores hexadecimales del PORT0


Lo tengo instalado vía los repositorios de la distro, con versión 0.2, en su repo va por la 0.4, es muy tentador pero antes voy a intentar usar el formato nativo de sigrok y sus opciones de docoder a ver si me quedo con gtkwave.

Nop, no incluye el decoding.

Ahora bien, si lo que se está ejecutando es un programa, cada vez que arranca debería producir la misma traza.

Tras bastante probar y reflexionar y hacer cosas como ejecutar dos veces esto con distintos archivos de salida:

sigrok-cli  -d fx2lafw --time 3000 --config "samplerate=24 MHz" \
    --triggers 0=1,1=1,2=1,3=1,4=1,5=1,6=1,7=1 --wait-trigger\
    -O vcd -o dumpDec24.1.vcd



Aunque podemos ver patrones repetitivos, los comienzos son distintos así que me imagino que estoy encarando mal.

Por un lado, estoy mirando PORT0 con programa externo que implica que va a multiplexar escritura de dirección con lectura de código y eso no debe ser bueno para un principiante como yo.

Voy a mirar PORT2 que dice sólo emitir la direcciones altas y yo apostaría que debe estar todo en cero, veamos.



Perfecto, acá claramente se vé un patrón que parece corresponder a estar barriendo todo el espacio de memoria en 100 ms, si miramos las capturas anteriores el ciclo completo debería durar 100 / 256 = 0.4 us,


Al comienzo en el pin 7 (cero en el chip) hay un poco de basura, distinta en ambos pero el resto es idéntico.




Segundo paso emprolijado

No he prestado mucha atención a que los pines del chip correspondan a los canales y llegó el momento de correlacionar, así que tomaré los cuatro más altos de los bajos (PORT0 4 a 7) y los cuatro más bajos de los altos (PORT2 0 a 3).




Perfecto, ahora, tras examinar las lineas de control ALE y PSEN en relación a varios, llegué a esta captura:




Los dos primeros canales son ALE y PSEN, el tercero es A8 en PORT2, los restantes AD7, AD3, AD2, AD1 y AD0 (Siendo A Address y D Data) de  PORT0

Se nota claramente como influye ALE sobre los canales de PORT0, le hace meter esos niveles positivos por los pullups cuando esta low, cosa que no ocurre con A8 de PORT2, recordemos que siguiendo la danza de ALE y PSEN esas mismas líneas se utilizan para leer de la ROM tras haber puesto la dirección.

Para comprender los tiempos, me hice una planillita que calcula los valores variables, en este caso para 8 Mhz




Las fórmulas por si te sirven

Combinando la tabla con el siguiente gráfico, hay que comprender como funciona.



No es muy intuitivo, pero gtkwave te deja medir un intervalo haciendo click y arrastrando.



Midiendo TAVLL


Luego registro todos los valores, notando que algunos están dados por el hardware actual y los otros son los que habrán que respetar.





Lo que queda es calcular algo tal que se respete todo lo amarillo...


...o mucho mejor aun, meter sin más reflexión directamente el 74LS373  con el opcode de NOP, total acá no dice que haya que tomar ningun precaución extra.


Tercer paso, nop

Siguiendo la idea de Quinn ya citada, con estas instrucciones lo que pensaba intentar hacer es que ante cualquier pedido de instrucción aparezca un NOP en el bus de datos, para eso hace falta un 74LS373 y tengo un 74LS374, cuya única diferencia es esta:

que parece ser que lo que tengo sólo tomará el cambio en el flanco positivo del reloj provisto por ALE. Esto puede ser un problema pues según lo visto previamente, o quizás algo de lo anterior está mal analizado.


Pero el NOP no se va a manifestar más que lo que está haciendo ahora, está leyendo FF:





Está simplemente pasando a la instrucción siguiente, me conviene ya pasar al siguiente paso para despejarme.

Instalé mcu8051ide que es muy bonito y tiene un simulador al cual incluso se le pueden pegar unos leds.

Éste es el código que necesito, inicializa PORT1 (0x90, 144) en vano (malinterpreté en ese momento, el yo del futuro que revisa lo escrito sabe que debí haberlo inicializado en cero pero luego me hubiera complicado la escritura del al PROM), luego pone un 1 en el registro A, el cual copia a PORT1, le hace un shift con carry, un nop y salta al loop.


A la izquierda el código assembly, a la derecha el de máquina.






Me voy a quedar con una versión más corta,

     mov A,#254
loop:
     mov 144, A
     rlc A
     sjmp loop


(74 FE F5 90 33 80 FB)

pues con tres bits de direccionamiento alcanza para servirlo en lugar de cuatro bits.

Ahora tengo que ver como usando los tres bits más bajos sirvo esa secuencia, tengo que implementar un emulador de memoria de 8 direcciones.

La verdad es que ya estoy bastante conforme con lo que he logrado y aprendido hasta ahora, todo parece indicar que el chip está vivo, el bit de protección no está activado y si le pusiera una ROM la ejecutaría. Me frustraría mucho quemar todo al tratar de hacer la conexión que falta. Lo que hizo Quinn me sirve de inspiración, pero es demasiado, no quiero cargar programas arbitrarios y cuando dice "ROM emulator" no es lo que las palabras me sugieren, es una RAM a la cual su CPU no puede escribir pero ella sí con gran ingenio.

Alguna noche mientras transitaba esta experiencia tuve una epifanía, en realidad mi "ROM emulator" ni siquiera necesita decodificar las direcciones, alcanza con que entregue la siguiente secuencia:

74 FE F5 90 33 80FB F5 90 33 80FB F5 90 33 80 FB ....


Así que voy a meditar dos implementaciones de ROM emulator, una que decodifique la dirección pedida y en función de esta entregue un código y otra que sólo detecte que es momento de mandar la próxima instrucción.

Mi dificultad en este momento pasa por la electrónica, no quemar nada.







Habiendo descansado, noto que me estoy salteando un paso: poner el 74LS374 y ver si obtengo la señal de PORT0 limpia. No la obtengo y me ha costado entender.

Tal como había anticipado, la diferencia entre 74LS374 y 74LS374 me está afectando. Tengo varios 74LS374, y podría canibalizar varios maś, pero ningún 74LS373, debe ser por que todo lo que tengo proviene de sistemas con clock.

La situación es que le pulso ascendente de ALE no me sirve.

Para arreglarlo se me ocurre esto usan una señal de alta frecuencia y hacer AND con ALE para que vaya actualizandose el buffer.


Pero no tengo como generar señales, ¿o si?

Un 555


Esto es puro robo, tengo que buscar un diagrama en Internet y si tengo las resistencia y capacitores apropiados, tendré mi señal. Y si los 555 que tengo generan esa frecuencia, lo dudo, ni me voy a fijar.

Un timer de otro microcontrolador


Mirándo rápido, para el LPC4337 de la edu-ciaa-nxp quizás tendría, pero nuevamente me estaría copiando, es un tema interesante... para otra ocasión.

Una FPGA


¿Para qué llevo meses/años practicando Verilog? Y como puede ser que me equivoque y queme algo, ¿qué mejor que usar el iCEstick? , así de paso aprendo a usar el entorno de Lattice.

Me voy a hacer un rústico generador de ondas cuadradas lo que sin duda me desvía del tema 8051, pero bueno, la idea era aprender todo lo posible en el camino, no?

<desvío>

Para programar necesito usar Lattice iCEcube2 que tengo instalado en una máquina virtual con una licencia que venció en el 2018, luego, hacer el programa, hacer la adaptación eléctrica de 3.3v de la FPGA a los 5 del 8051 y finalmente probar a ver si anda todo ok.

Como es muy largo y como dije más arriba es un desvío, que además tiene subdesvíos, lo vas a tener que leer en otra entrada y luego volver.


https://es.wikipedia.org/wiki/Archivo:Turnout_components.jpg


</desvío>


Recapitulando, he puesto la señal ALE con un AND a 12Mhz, de modo tal que se generen pulsos para el clock del 74ls374 y tome el valor de la dirección en el momento apropiado en lugar de en el flanco ascendente de ALE.






Que con el analizar lógico se ve mejor:




Observá que a veces hay uno y uno, tres y dos pulsos en la tercera linea que es 12Mhz AND ALE debe tener que ver con la baja calidad de lo que he hecho, la falta de conocimiento mía de electrónica analógica.

Poniéndo un inversor 74ls14 entre 12Mhz y el AND mejora mucho.




Ahora siempre hay tres pulsos

El siguiente paso es ver si se fué el multiplexado del PORT0 a la salida del 74ls374... no, tras tomar el siguiente desvío y sufrir la estructura fractal de este proyecto, me compré un 74ls373 para no tener que lidiar con esto, buen intento, olvidemos la FPGA, la adaptación de niveles y todo eso y...

<desvío>

... concentrémonos en grabar el programa en la EPROM.

</desvío>

Dos meses despues de iniciada esta aventura, tengo grabada en una EPROM un programa que de ejecutarse se manifestaría en GPIO.


Address? (xxxx): 0010
Size? (xxxx): 0040
Reading address from: 0010 to : 0050
0010  40  31  EA  40  D3  01  DB  05 
0018  24  22  52  05  3E  40  D3  01 
0020  1E  00  18  17  FF  FF  FF  FF 
0028  10  10  11  10  11  00  FB  11 
0030  74  FE  F5  90  33  80  FB  FF 
0038  C3  4E  01  D3  1E  D3  1A  10 
0040  63  D3  10  3E  49  D3  11  10 
0048  45  D3  12  3E  97  D3  13  3E

esto siginifica que tengo mi programa en la dirección 0030 cuando debería estar en 0000, voy a tener que manipular físicamente las direcciones.


Esto deseo, en negrita lo direccionable por la eprom:

0000 0000 0000 0000

Esto tengo:

0000 0000 0011 0000



Este es el circuito




Mi programa sólo necesita las tres últimas líneas, resto irá puenteado directamente a 0 o 1.


            +---------------------------+
           <- P1.0                 Vcc  - 5v
           <- P1.1             A0 P0.0 <-> 1D
           <- P1.2        I    A1 P0.1 <-> 2D
           <- P1.3        N    A2P0.2 <-> 3D
           <- P1.4       T    A3 P0.3 <-> 4D
           <- P1.5       E    A4 P0.4 <-> 5D
           <- P1.6        L    A5 P0.5 <-> 6D
           <- P1.7             A6P0.6 <-> 7D
            - RST         8    A7 P0.7 <-> 8D
            - P3.0  RXD  0         EA  - GND
            - P3.1  TXD   5       ALE  ->
            - P3.2  INT0  1      PSEN  -> OE/CE
            - P3.3  INT1     A15 P2.7  -> N/C
            - P3.4  T0       A14 P2.6  -> N/C
            - P3.5  T1       A13 P2.5  -> N/C
            - P3.6  WR       A12 P2.4  -> N/C
            - P3.7  RD        A12 P2.3  -> N/C
       xtal - XTAL2          A10 P2.2  -> N/C
       xtal - XTAL1            A9 P2.1  -> N/C
        GND - Vss              A8 P2.0  -> N/C
            +---------------------------+



                +------------------+
            GND -> OC         Vcc  - 5v
               <- 1Q     7     8Q  ->
          P0.0  -> 1D    4     8D <- P0.7
          P0.1  -> 2D    L     7D <- P0.6
               <-  2Q    S     7Q  ->
               <-  3Q    3     6Q  ->
          P0.2  -> 3D    7     6D <- P0.5
          P0.3  -> 4D    3     5D <- P0.4
               <- 4Q           5Q  ->
                -  GND         C  <- ALE
                +-----------------+


                 +------------------+
            GND  -> A7         Vcc  - 5v
            GND  -> A6    2     A8 <- GND
            GND  -> A5    K     A9 <- GND
             5v  -> A4    B    Vpp  - Vcc
             5v  -> A3          OE <- PSEN
             3Q  -> A2    E    A10 <- GND
             2Q  -> A1    P     CE <- PSEN
             1Q  -> A0    R     D7  -> P0.7
           P0.0<-  D0    O     D6  -> P0.6
           P0.1<-  D1    M     D5  -> P0.5
           P0.2<-  D2          D4  -> P0.4
            GND  -  GND         D3  -> P0.3
                 +------------------+



Así sería si quisiera acceder a toda la EPROM:

                 +------------------+
             8Q  -> A7         Vcc  - 5v
             7Q  -> A6    2     A8 <- P2.0
             6Q  -> A5    K     A9 <- P2.1
             5Q  -> A4    B    Vpp  - Vcc
             4Q  -> A3          OE <- PSEN
             3Q  -> A2    E    A10 <- P2.2
             2Q  -> A1    P     CE <- PSEN
             1Q  -> A0    R     D7  -> P0.7
           P0.0<-  D0    O     D6  -> P0.6
           P0.1<-  D1    M     D5  -> P0.5
           P0.2<-  D2          D4  -> P0.4
            GND  -  GND         D3  -> P0.3
                 +------------------+





La últimas  desventuras





Habiendo soldado todo, comprobado visualmente y cortos y continuidad con el tester, se me desoldado uno de los capacitores y no lo encuentro.

Rescato los SMD de la placa original y cuando estoy por soldar... se me sale volando uno y no lo encuentro.

Cuando estoy desoldando los de la placa de la central telefónica, se deprende una patita.... lo arreglo.

Conecto mirando PORT1, ruido...



A diagnosticar...


El comportamiento en el bus de direcciones no ha cambiado, apuesto a que mi programa no se activó.

Me parece que no configuré correctamente PORT1 como output, pero aún así, al menos en un bit debería tener actividad y no la hay.

Esto está respaldado por lo que se vé en PORT1, se parece a modo input.

Si mi programa estuviera funcionando el patrón de PORT0 debería ser algo así como

0
1
2
3
4
5
6
2
3
....

con los valores de las instrucciones intercaladas y no lo es.



Por un lado, si en realidad es posible, estoy muy cerca de finalizarlo, por el otro, ya aprendí un montón de cosas, estoy cansado y me estoy atrasando en otras mil cosas que quiero hacer. De un modo u otro, debo asumir mi derrota...

Quizás dentro de unas semanas o meses me inspire e investigue otra vez, por ahora, ya está.

Resumen


Pasos


Cambiando levemente el orden:

  • Extraje el chip
  • Identifiqué los pines y sus funciones
  • Le puse un cristal para ver si funcionaba el clock con el osciloscopio
  • Configuré para que use ROM externa
  • Miré si había actividad en el bus de direcciones con un analizador lógico
  • Estudié el timing del multiplexado de datos y direcciones en PORT0
  • Puse un 74ls374 para demultiplexar
  • Recuperé el uso de iCEcube2 y VHDL
  • Escribí un VHDL para generar una señal por la falta de 74ls373
  • Puse un 74ls373
  • Asumí que el demultiplexado está ocurriendo correctamente
  • Aprendí a leer y grabar EPROM con un microcontrolador
  • Escribí un programa de 8051
  • Lo grabé
  • Armé la placa
  • Fallé


Recursos utilizados


Algunos no son de esta entrada si no de las derivadas, enumero para mostrar todo lo que implica una investigación sencilla como esta.


Herramientas

  • Soldador
  • Multímetro
  • Fuente
  • Osciloscopio
  • Analizador lógico
  • USBasp


Hardware

  • Protoboard
  • PCB de desarrollo
  • 74ls374
  • 74ls373
  • 74hc164
  • 14008
  • iCEstick
  • cristal quarzo 8Mhz (tras perder el de 9.6Mhz)
  • cablecitos, resistencias, pines, zócalo, capacitores, transistores, rele


Software

  • dia
  • Lattice iCEcube2
  • MCU 8051 IDE
  • recordmydesktop --x=400 --y=1800 --width=900 --height=700 --no-sound
  • pulseview
  • gtkwave
  • sigrok-cli
  • avrdude
  • arduino-ide
  • virtualbox
  • gimp
  • libreoffice calc

Documentación



Algunos artículos de Quinn los leí hace mucho y ahora apenas el pasé una mirada por encima, asi que los pasos quizás no sean los mismos. Pero sin duda es el origen de esta experiencia, lo que me inspiró a tomar este camino.


    Compartiendo el zócalo para programar ATMega328p y ATtiny85

    $
    0
    0

    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.

    Primer programa en un ATtiny85 bare y luego ArduinoIDE con SoftUART

    $
    0
    0
    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...

    Ayudas para gestionar archivos duplicados.

    $
    0
    0
    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

    revlo 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

    Primer contacto con ESP8266

    $
    0
    0
    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.eclipseorg) 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.





    Mi primer PMOD: unos leds y parte de un malware de hardware

    $
    0
    0

     




    fpga con pmod


     

    Para unas investigaciones y parte de una demo de una charlas de próxima exposición, siendo H4CK3D 2020 la pública y una interna en el trabajo, he necesitado expandir una placa FPGA, en particular una Nexys4DDR.

    Sin entrar mucho en detalles pues es otra entrada, lo que hice fué una CPU que ejecuta unas pocas instrucciones tal que me permiten mostrar un ataque de elevación de privilegios con la intervención de un troyano de hardware.

    Lo que necesito son cuatro leds separados de la placa para que tengan más protagonismo que los provistos por la placa pues los estoy usando para mostrar el estado, registros e instrucciones de la CPU y como las charlas son virtuales, se complica diferenciarlos.

    Estos cuatro leds vienen a representar un puerto de GPIO, que el programa prende y apaga y tambien evidencian la activación del malware.

    Tambien necesito la parte electrónica del malware que no puedo expresar en Verilog, que básicamente es un capacitor y un par de resistencias más un potenciómetro de calibración.


    Qué es PMOD

    Es una norma de conexión de expansiones para sensores y actuadores, tipo ponchos de EDU-CIAA-NXP, shields de Arduino o Raspberry Pi, pero más asociada a FPGAs, en particular del fabricante Digilent. Tiene unos puertos de alimentacion y unos de entrada y salida, tanto analógicos como digitales. 

    La asignación de ser entrada o salida, analógico o digital es completamente dependiente de cada modelo, a diferencia de los ponchos/shields, donde esta asignación depende de las capacidades disponibles del microcontrolador en cada pin.


    pmod 7 segmentos


     

    Qué es FPGA

    Muy corto, un circuito programable, se suelen programar en VHDL o Verilog. Se pueden instanciar circuitos tan sencillos como el que gobierna las lucesitas del auto fantástico hasta una CPU, mucho mucho más compleja que la que diseñé yo. 

    Una comparación muy libre sería la diferencia entre tener un programa almacenado en ROM que no lo podés cambiar sin cambiar el chip y uno en RAM, que lo cambiás cuando querés. Viene a ser lo mismo pero la lógica digital.

    Volviendo a mi PMOD, lo que hace la parte del malware es ir cargando un capacitor con la señal proveniente de la placa. En ausencia de señal, el capacitor se descarga vía una resistencia y como es un ajuste muy preciso tiene un potenciómetro.

    El método de construcción fué utilizar una placa preimpresa genérica, a la cual le corté el sobrante. El capacitor lo recuperé de la controladora de un aire acondicionado, me parece. El potenciómetro debe ser de una radio, lo debo tener desde hace unos veinticinco o treinta años, yo sabía que para algo me iba a servir, para la gente que me hace tirar "toda esa basura".

    La dificultad del uso del potenciómetro pasa por que es el único que tengo con resistencia baja y es muy sensible. Además se me dificulta medirlo para anotar el valor apropiado pues al hacerlo el capacitor se carga y modifica la medida, quizás debería poner un jumper para desconectar del capacitor y poder medir.

     

    fpga con pmod y detalles

     

    El haber utilizado una placa simple faz me complicó un poco el la fijación de los pines de conexión a la placa principal, pero era lo que tenía, mala suerte.

    Para no mandarme macanas hice una prueba muy sencilla, medir la línea que va hacia la FPGA mientras prendo y apago la que viene desde la misma, obviamente funcionó y tambien luego en la FPGA.



    La verás prendida y en funcionamiento en alguna entrada futura tras la charla H4CK3D, paciencia.




    Fuentes



    https://reference.digilentinc.com/reference/programmable-logic/nexys-4-ddr/reference-manual


    https://reference.digilentinc.com/_media/reference/pmod/pmod-interface-specification-1_1_0.pdf

    Mi segundo PMOD: Dual PMOD VGA

    $
    0
    0


    icestick con pmod vga

     

     

    Motivación

     

    Como parte de estudiar el libro  Designing Video Game Hardware in Verilog , del cual en algún momento terminaré un artículo y lo publicaré, estoy adaptando sus ejemplos a la placa Nexys4ddr y Vivado 2018 y necesito hacer pruebas de generación de señal VGA con una placa distinta, pues no me salen los ejemplos y al cambiar de placa y entorno (ICEstick +Lattice) algo voy a aprender.

    De paso me preparo para la inminente salida de la EDU-CIAA-FPGA, pero eso lo desarrollaré en otra entrada, no nos distraigamos.

    Tambien estoy probando de meter una señal "escondida" en algún color para fuga de información y si meto la pata, preferiero hacerlo con el ICEstick que es más barato, tema tambien de otra entrada y H4CK3D 2020.


    Podría hacer algo con un protoboard, pero esto es mucho más cool.


    Qué es un PMOD y FPGA

    No me voy a repetir, está en mi primer PMOD

     

    Qué es VGA


    Si te tengo que explicar que es VGA... bueno, quizás sos joven. VGA es una norma para transmitir video desde una computadora a una pantalla, es de lo más viejito que aún funciona, sin mirar en Internet, esto es lo que recuerdo de la evolución histórica, para nada precisa, sólo un mapa hecho a mano para mostrar lo viejo que soy:

    • monocromo: texto
    • hercules: con imagenes
    • CGA: colores, pocos, te sangran los ojos por la baja resolución
    • EGA: mejorcito
    • VGA: el tema de esta nota
    • xxxVGA: un montón de variaciones, de aquí en más se comienza a mezclar la resolución y los colores con el modo de transmisión.
    • DVI: analógico y digital
    • HDMI: es digital y suma audio
    • DisplayPort: y asi...


    Si te interesa mucho el tema, wikipedia.


    Lo que tengo que hacer es conectar a unos puertos del PMOD una adaptación con unas resistencias de modo tal que se respete lo que sigue, que es lo que existe en la placa Nexys4DDR:




    La idea es que esas resistencias funcionan como un DAC (Digital to Analog Converter), si prendés cada pin asociado a un color, cuanto mayor sea la resistencia conectada menos influirá.

     

    Además, hay dos señales de sincronización (HSync y VSync) y dos de I2C que se usan para comunicarse con el monitor.

     

     

    Evolución de la elección de las señales


    Necesito al menos 5 pines para RGB , VSync y HSync, me quedan sólo 3 pines libres, pues el PMOD tiene sólo 8. Si uso dos pines por color, tengo 64 colores.


    • VSync
    • HSync
    • Red 510
    • Red 1k
    • Green 510
    • Green 1k
    • Blue 510
    • Blue 1k


    I2C

    Habiendo I2C, es increiblemente tentador dejarlo preparado para algún futuro, pero me quedarían pocos colores. Se me ocurren varias maneras de combinar, pero terminan siendo 8 colores y/o gamas monocromáticas.

    • VSync
    • HSync
    • R
    • G
    • B
    • I2C clock
    • I2C data
    • uno libre, podría ser para el verde

     

     2 PMODs


    mmh, podríamos tener todo si usáramos dos PMODs como en este ejemplo:


    VGA con dos PMODs

    • PMOD 1
      • VSync
      • HSync
      • Red 510
      • Red 1k
      • Green 510
      • Green 1k
      • Blue 510
      • Blue 1k

     

    • PMOD2
      • I2C clock
      • I2C data
      • Red 2k
      • Red 4k
      • Green 2k
      • Green 4k
      • Blue 2k
      • Blue 4k

     

    ¿Con qué criterio los agrupé? Pues con hacer uno PMOD doble en el futuro y el de ahora hacerlo "expandible", por que la realidad es que lo que quiero ahora es para un PMOD, el ICEStick tiene uno solo.

     

    La idea sería hacer algo como, todo gimpeado usando pruebas fallidas, recurro a tu generosa imaginación, faltan resistencias y el conector entre módulos:


    Prototipo imaginario de doble pmod ensamblable

     

     

    Pasó un pajarito...

     

    Recuerdo haber catalogado un chip rescatado de un desguace, algo que decía VGA algo... a ver... si, SI!! sigue rindiendo el cajón de basura:

    IP4770/71/72CZ16 VGA/video interface with ESD protection de NXP Semiconductors

    está en el mother de una laptop que encontré tirada en la calle, de la cual recuperé exitosamente el touchpad, me falta hacer funcionar la pantalla y ahora esto, que va a quedar para otra ocasión pues no tengo capacidad de fabricar una placa con pistas tan juntas.



    Volviendo al tema


    Es muy complicado, mejor hago doble PMOD y ya me queda armado. Como es bastante difícil para mi hacer que los agujeritos del conector VGA me queden alieneados, tuve la tentación de usar este adaptador, que de paso disminuye el stress sobre los PMODs pero me resultó antideportivo.


    Adaptador conn_02x08 a db15 high density




    Los diagramas de kicad en https://github.com/cpantel/pmod_vga



    Dual PMOD a VGA, un sólo PMOD


    Como bien podrés apreciar, faltan algunas resistencias correspondientes al PMOD inferior, no importa pues no tengo ningún apuro en conectarle una placa de las caras. Quizás no puedas ver, pero las resistencias de 500 en realidad son dos de 1k en paralelo, es lo que hay...


    Aprendizajes

    El primer modelo lo hice con doble faz y puse vías por todos lados, luego me dí cuenta que al haber doble faz justamente se pueden evitar muchas, esto se refleja en la primera versión.

    Para perforar el DB15 High Density, hice cuatro intentos hasta que me quedó alineado bien y de ahí en más usé eso como plantilla para los intentos posteriores.

    Al comienzo consideré utilizar pines rectos para el conector PMOD y preguntando en embebidos me hiceron entrar en razón, muchas gracias, rescaté los pines en ángulo del conector de una diskettera que ya me había ayudado cediendo el conector de alimentación para el controlador de velocidad de los coolers de un switch que aún no he publicado por que el PWM amplificado mete ruido en el RS-232.

    Al hacerlo bien, no necesito doble faz, lo que me facilita todo.

    Como tengo poca experiencia en hacer circuitos con ácido y como hago pocos, esa experiencia se diluye, no me salió muy bien, lo cual fue una excelente oportunidad para estrenar la pintura reparadora que había adquirido para corregir las pistas de la EDU-CIAA-NXP a la que le arranqué (si, arranqué, en ese momento no sabía como sacar un chip) el microcontrolador para reemplazarlo por otro, uno de estos días/semanas/meses lo terminaré y compartiré.

    Con respecto a que de haberlo comprado hecho me hubiese salido u$s 9 más impuestos más gastos de envío, no hay ni la menor duda que debí haberlo comprado, pero no olvidemos que mi objetivo es aprender, todas estas horas no fueron mal invertidas.

     

    Promesas

    En pocos días, ya sea con ICECube o con la tool chain de la EDU-CIAA-FPGA, lo haré funcionar.

     


    Cronica de un ataque a un DVR hallado en la calle siguiendo la Cyber Kill Chain

    $
    0
    0

    En este artículo mostraré la planificación y recolección de información relacionada con reprogramar un dispositivo hallado en la calle:

     

    Grabadora de video de vigilancia

    Se trata de un sistema de vigilancia al que se le pueden conectar hasta ocho cámaras, usar de intercomunicador, grabar. Hasta donde ví entiendo que puede detectar movimientos y un montón de cosas más. Se lo puede acceder mediante una bontonera, mouse y monitor VGA o via red.

     

    Objetivos

    • Tomar el pleno control del dispositivo. Esto significa:
      • Tener una terminal ssh o serial.
      • Tener root
      • Poder usar libremente los GPIO actualmente asociados a los botones del frente.
      • Mejor si el sistema completo sigue funcionando.
    • Aplicar lo que sé y aprender más, tanto por descubrirlo en el momento como buscarlo en distintas fuentes.

     

    Deseos

    Deseo instalarle un firmware modificado por mí, pero debido a:

    • Mis limitaciones
    • Falta de tiempo
    • Quizás no sea posible

    debo armar una planificación realista. En mi mundo mágico sólo existe el Plan B, en el real, este es el orden:

     

    Plan A: hallar una terminal existente en el firmware actual

    Está limitado por la inexistencia de tal terminal y mi habilidad para hallarla

     

    Plan B: modificar el firmware

    Está limitado por la implimentación de firma de firmware y mi habilidad para modificarlo.


    Plan C: hallar una vulnerabilidad

    Me voy a aburrir y frustrar y no voy a llegar tan lejos.



    Metodología

     

    Como metodología intentaré usar Cyber Kill Chain. En criollo, le voy a poner etiquetas y orden a lo que hubiese hecho normalmente sin ton ni son. Este acercamiento disciplinado de paso me sirve para organizar y documentar.

    • Reconnaissance
    • Weaponization
    • Delivery
    • Exploitation
    • Installation
    • Command and control
    • Actions on objectives

     

    Primera iteración 


    Reconnaissance


    Pasivo

    Visualmente no parece haber nada roto, salvo que falta el disco, detalle menor. 

    Tiene un lindo conector VGA y cables SATA cortos de datos, si termino rompiéndolo, serán prolijamente canibalizados. La batería no la puedo medir sin desarmar o sacarla, luego veremos.



    Interior

     

    La tensión de alimentación dice ser 12v, pero no dice la polaridad. Midiendo continuidad entre alguna tierra y el conector determiné lo normal, pin positivo.


    Conectores

     

    OSINT


    El SOC es Hi 3520, tiene un pdf de casi mil páginas en chino. Digo chino de verdad, no que no entienda por que sea complicado. Por suerte también hay un brochure en inglés del cual se puede extraer que:

     

    Diagrama blocues Hi5320

    CPU: ARM1176 @600Mhz

    MMU: puede correr un sistema operativo complejo

    Security Engine: Implementing various encryption and decryption algorithms such as AES, DES, and 3DES through the hardware. Esto es malo, es más probable que los firmwares vengan firmados.

    Por suerte "Hi3520 secure boot" ni "Hi3520 signed firmware" trajeron nada.

    SDK: Providing the SDK based on Linux 2.6.24

    Esto nos da un indicio del qué kernel puede haber.



    Frente

    Una etiqueta interna, tvb9808bs-f2, me trajo más información, pero ningún frente coincide por completo.

    Existe un tvg9808b-f2 en  http://www.v-camip.com/product_show.asp?id=585, pero no cierran alguna características.


    Hay un chip de memoria:



    Memoria H5TQ2G63GFR-xxL



    que es RAM. Mientras buscaba la ROM/EEPROM, como no la encontraba terminé de desarmar y encontré del otro lado otros chips:

     

    PI101GR Transceptor Ethernet
    PI101GR Transceptor Ethernet
     
     
     
     
    24c02 eeprom
    24c02 eeprom
     
     

    25l12833f Serial NOR flash.png
    25l12833f Serial NOR flash.png


    y una etiqueta muy interesante:


    Etiqueta TVI9808GS1
    TVI9808GS1


    Sumando:

    • TVI9808GS1_v1.03 con fecha 2019.06.24

    • Memoria H5TQ2G63GFR-xxL que dice ser DDR3

    • El brochure dice que usa memoria DDR2

     

    La placa no es tan vieja como supuse, no coincide el tipo de memoria con la brochure. Entonces volví a buscar el SOC y con DRQCV300 tras varios saltos llegué a un brochure mucho mejor:

     


    SOC
    SOC


    Datos actualizados 


    CPU: Cortex A7 @ 800Mhz
     
    Security Engine: AES, DES and #DES algorithms implemented by hardware, sin cambios

    SDK: Linux 3.10-based SDK

    Llegó la hora de volver a buscar el soc, esta vez como Hi3520dv300 y encontré algo muy atractivo, un dev board, de la traducción automática que muestra se destila que cuando pasemos a examinar el tráfico de red puede ser que hallemos cosas muy interesantes, como intentos de boot por red.
     
     

    Dev board
    Dev board

     
    Además, dice venir con un SDK, si pudiera echarle mano... casi que pierde la gracia, no?


    Activo presencial


    Usando un monitor de descarte, la prendí:

     
    arranque
    arranque

    La pila parece estar cargada pues tiene la fecha y hora bastante bien.

    Le fuí agregando dispositivos, todo anda. Con respecto a la cámara, no me preguntes como identifiqué los cables pues esa cámara no sé de dónde la obtuve, sólo recuerdo que descifré el pin out para conectarla a una vieja macintosh que tenía capturadora de video y prolijamente guardé las notas que tomé en ese momento.


    Cámara ok
    Cámara ok


    Interactuando con la GUI, obtuve los siguientes datos:


    • System: 1.02.023c0228.79415076.t000.6
    • Extra info: 1.40.101223
    • Build date: 2019-11-28 17:50:22
    • En network->TCP Port: 34567 
    • En system->RS232 me da a entender que hay un puerto serial, veremos...
    • Ofrece un upgrade, supongo que es como cambiar el firmware, veremos...

     

    Red


    Primero hice exploración total de puertos:

    $nmap 192.168.1.127 -p 1-65535
     

    Luego le pedí reconocimiento de servicios y sistema operativo:

    $ nmap 192.168.1.127 -p 80,554,9527,9530,34567 -sV --version-all
    PORT      STATE SERVICE       VERSION
    80/tcp    open  http          uc-httpd/1.0.0
    554/tcp   open  rtsp
    9527/tcp  open  tcpwrapped
    9530/tcp  open  unknown
    34567/tcp open  dhanalakshmi?
    3 services unrecognized despite returning data.
     
     
    $ sudo nmap 192.168.1.129 -O

    No reconoció nada, es nmap 7.60, la actual 7.80, veremos...

    Probé con wget:


    wget  --server-response 192.168.1.129:554

      HTTP/1.1 200 OK
      Content-Type: application/x-rtsp-tunnelled
      Server: Topsvision Server v2.1
      Connection: close
      Cache-Control: private
      Length: unspecified [application/x-rtsp-tunnelled]


    Capturé con wireshark la actividad en red del arranque, nada.

    La mac address, c8:22:02 es desconocida, mmhhh.

    Mientras hacía estas pruebas ocurrió algo interesante, en un momento pasó a mostrar sólo la cámara activa y finalmente se reinició. Esto puede ser:

    • El escaneo le hizo mal
    • Es el motivo por el cual lo tiraron: tiene una falla de hardware


    Red vía navegador


    Exige un navegador que entienda activeX y te dice de bajar:

    http://www.topslink.net/WebClient_EN_SetUp.exe

    que tiene un hash que virustotal considera bastante e instlas almenos un ocx.

    Si vas a http://www.topslink.net/ te ofrece login y más instalación:

    http://www.topslink.net/CloudClientV2_EN_SetUp.exe

    virustotal sigue casi ok.

    Esos plugines no andan en edge, si andan en no sé que explorer de windows xp:


    Vía red
    Vía red




     

     

     

     

     

     

     

    USB

    Si le conecto un usb fat32, ofrece hacer upgrade con cualquier archivo que encuentre en la raiz sin ningún criterio


    RS-232

    El menú ofrece configurar el puerto RS-232, que no se manifiesta en el gabinete, pero quizás sea el conector interno libre.

    Debo identificar los pines. Supongamos que la datasheet de Hi3520 es parecida a Hi3520DV300, si tiene uart quizás esté cerca... nop, es otro encapsulado

    Le conecté osciloscopio y hay dos señales digitales, patrón repetitivo espejado, pero no sé que són, quedará para más adelante.


    UART
    UART


    OSINT otra ve


    He buscado sin éxito combinando "firmware""update" y "upgrade" con estas etiquetas:

    • H.264 network dvr
    • tv08ahd
    • TVB9808BS-F1
    • 264.001.0045
    • TVI9808GS1_V1.03

     



    Habiendo descansado y reflexionado, ha llegado el momento de revisar la estrategia y adaptar las tácticas. La situación actual es:

    He confirmado que el sistema funciona y si consiguiera cámaras (y más difícil, instalara el cablerío necesario) podría usarlo para lo cual fue concebido.

    El cliente de red apesta y es todo un desafío muy interesante hacer el análisis de los protocolos utilizados para hacer una implementación open source. De por sí es todo un proyecto y si en mi camino de reinstalar el firmware meto la pata, lo anulo.

    Sería bueno saber si hay algún modo de desbrickar, quizás arrancando apretando un botón al arranque.

    Se ha tornado vital obtener un firmware, mejor si es el actual. Debo hallar un firmware asociado a un modelo del cual haya una foto de la placa y parezca tener lo mismo o una descripción de funciones que coincida o sea menor.

    Y debo atenerme al Plan A, analizar varios firmwares y detectar:

    • el nivel de compatibilidad
    • la existencia de algún acceso

     En la próxima entrega, duro con el firmware.


    Curso Architecting AWS

    $
    0
    0

    Gracias a mi trabajo, he tenido el privilegio de tomar  los trainings Architecting on AWS y Exam Readiness: AWS Certified Solutions Architect - Associate, que corresponden a la certificación AWS Certified Solutions Architect – Associate


    Pensaba compartir las notas que tomé, pero al finalizar veo que son medio inútiles, así que me las guardo. Comparto aquí algunas reflexiones



    Organización

     

    Debido a que asistimos varias personas de varios paises, hubo una cierta confusión con los horarios, que no se tradujo en ningún inconveniente concreto, simplemente me conecté en el horario más temprano y le atiné.

    Son tres días, bastante heavy, coronados por medio día más de preparación para la certificación.

    La plataforma es gototraining que he utilizado bastante para asistir a webinars de Doulos. Funcionó ok varias horas y luego murió tanto mi micrófono como el alzar la mano. Me parecía que es por cambiar de desktop y le pedí a la ventana que este "always on top" y "always on visible desktop" epro no, despues de un cierto tiempo quedé mute y handless los tres días.


    Material


    El material se accede mediante una plataforma llamada eVantage, que por supuesto está para todas las plataformas menos linux, ok, igual se puede acceder vía web. No la aproveché más que para bajar el material pero ofrece marcarlo y todas esas cosas que facilitan el estudio, no el mío en particular pero supongo que el de alguien.


    Labs


    Se acceden vía qwiklabs. Están disponibles durante los primeros tres días.

    Hay seis labs de complejidad y dificultad creciente. Son del tipo mono copia pega con mínimas explicaciones intercaladas, ok, no me quejo, son muchísimos temas.

    El problema es el tiempo, se ven muy rápido, como que llegás a hacerlo copiando y pegando las instrucciones pero con poca asimilación.

    De hecho, gracias a un error que tuve en el cuarto lab se me fijó mejor un concepto, pero no pude terminarlo. La posibilidad era hacerlo despues, durante la noche, pero estar en un curso de casi 24 horas en tres días, seguir cumpliendo los requisitos mínimos de vida y además tener que resolver algunos problemas de trabajo, hace irreal esa opción, el cansancio es atroz.

    Sería viable si la cuenta siguiera viva una semana más.

     

    Visión general


    El curso comienza bien, el docente sabe y sabe explicar y es ameno. La velocidad fué apropiada para los conocimientos básicos iniciales. Luego, a medida que se ven conceptos más complicados, sube la velocidad con lo cual se torna muy difícil de seguir y más si le sumás que podés tener interrupciones (ajenas al curso, claro). El primer día logré una atención del 90%, el segundo 70%, el tercero recuperé a 80%. cayendo a 60% por la tarde. Cómo referencia, sólo me acerco al 100% de atención cuando yo expongo o si la clase es corta y el tema me resulta absolutamente interesante.


    No me ayudó una breve pero intensa interrupción laboral justo en el momento en que se veían los temas de seguridad. Igual no me quita el sueño pues en breve todo indica que tendré una capacitación igual de intensa pero orientada a seguridad exclusivamente.
     

    Algunos conocimiento previos útiles


    Networking pues se usa al armar las redes y conectarlas y el modelo OSI es frecuentemente referenciado.

    Bases de datos, la diferencia entre relacionales y no relacionales, escalabilidad.

    Aspectos de autorización de seguridad, por todo el rollo de los roles.

    Cómo funciona internet en general y en particular HTTP para la parte de caching.

    Arquitectura de la computadora y una cierta visión de asuntos logísticos para comprender el esquema de "enfriamiento" de los datos en S3 en analogía con la jerarquía de memoria.

    Cualquier cosa de informática pues AWS es como el mundo Simpson, donde todo ha ocurrido. O desde otra óptica, viene a ser como el mundo mágico de disney, donde está todo lo que sabés del mundo real pero con una distorsión homogeneizante.


     

    Datos de certificación


    Vale la pena dar la cloud practitioner? Quizás:


    • La ayuda a certificación  es gratuita por tandas
    • Pagar por el practtioner da boucher para el siguiente
    • Sirve para practicar





    El sesgo de las certificaciones

    $
    0
    0

    Daré contexto para mostrar que no es el resentimiento de no poder hacer una certificación lo que guía mis palabras sino unas ciertas condiciones que sí me provocan resentimiento. Estoy considerando rendir una pronto, publico esto antes por si las dudas me va mal, no quede ligado a ese fracaso.

     Tambien que se trata de pura especulación, no soy experto ni siquiera "associate" de los temas involucrados.

     

    Contexto


    He tomado una sola certificación, hace 20 años, si no fui el primero fui el segundo del pais, CCNA, lo tomé en ingles lo cual me dio tiempo extra y en menos de ese tiempo extra lo resolví.

    Dicho de otra manera, tenia 90 minutos para el examen y 45 adicionales por no tomarlo en mi lenguaje nativo y lo resolví en menos de 45, siendo estos números aproximados.

    Creo recordar que el acuerdo de confidencialidad decía que no podía decir que nota había sacado, me imagino que debía ser para no relevar que casi todos sacamos notas muy altas, si a todos nos va muy bien podemos sospechar que el examen es una truchada. Igual fijate que dije "casi".

    Contrastando, en la materia Algoritmos 2 con Mandrafina de FIUBA, el examen duraba cuatro horas, de las cuales media correspondía al docente explicar de qué se trataba el examen, que era prácticamente igual al trabajo práctico grupal.

    Cuando vas a dar una certificación dice que no podés llevar absolutamente nada, ni siquiera lápiz y papel en blanco. Esto es para la presencial, para la "proctored" ok, es una circunstancia especial, hay múltiples maneras de copiarse, pero si estás ahí y hay alguien mirándote, ¿cuál es el motivo de no poder escribir y dibujar para organizar tu pensamiento?

    ¿Qué no te lleves información del examen? ok, entregás todo lo que hayas escrito, no hay problema con eso.

    Según había leido hace mucho tiempo, hay distintas maneras de representar ideas en tu cabeza, siendo las más comunes mezcla visual y palabras, mayormente visual y sólo palabras.


    +-------------+-----------------+--------+
    |    muy      |      mezcla     | solo   |
    |   visual    |                 |palabras|
    +-------------+-----------------+--------+
    |     30%     |        45%      |  25 %  |
    +-------------+-----------------+--------+


    De hecho, se recomienda siempre al enseñar o explicar algo utilizar imágenes.

    Me ha contado una persona que a veces se habla a si misma para comprender un problema, lo cual no está permitido en este tipo de examen.

    Y si diéramos crédito a la teoría de las inteligencias múltiples, de las doce mencionadas, supongo que tres (Lingüístico-Verbal, Lógico-Matemática, Visual-espacial) estaríamos usando en un examen y una de ellas reprimida.

    De un modo u otro, todo me lleva a pensar que estas restricciones segregan a un tercio de la población directamente y quizás un quinto extra, favoreciendo desde un cuarto hasta poco más de la mitad de la población, pues supongo que la mezcla es gradual.

    ¿Se trata de un daño colateral producto de factores económicos?

    • Cuanto más restrictivo, más barato es el examen
    • Se impide la fuga de información de las preguntas para que no te puedas preparar mejor para la próxima vez

    Este segundo factor tambien favorece a quienes tienen buena memoria, independientemente de su capacidad analítica, pero esto ya viene de arrastre de antes al tratarse de un examen y no un trabajo práctico.

    Distingo una certificación, o sea, pura medición de modo quizás indirecto de que tenés experiencia en un tema de un examen, como el resultado de una prueba tras un curso, dónde quien lo dicta tiene oportunidad de ajustar el resultado pues ha visto tu desempeño y evolución.

    Tambien he aprendido mucho no sólo preparando exámenes sino en el momento mismo de darlos y una certificación es una muy buena excusa u oportunidad para estudiar e investigar.

    La verdad es que en cualquier situacion de la vida real, nadie me va impedir usar papel o hablar solo y para el caso tampoco consultar un libro u otra persona, pero ok, aceptemos las dos últimas restricciones como razonables para una situación de examen o certificación.

    Sin embargo, algo que he hecho en algún examen de física ha sido, partir de una formula (no recuerdo cuál), desarrollar todas las relacionadas en una hoja aparte, para así durante la resolución sacarme ese problema de la cabeza.

    En un examen de AWS probablemente me haría un grafo relacionando servicios, pues es una selva interminable y muchas respuestas dependen de recordar la existencia de esos servicios.

    Hasta acá no he dicho nada que no haya sido dicho y discutido antes. Incluso podría estar de acuerdo, que no lo estoy, que un examen de respuestas múltiples es una manera correcta de medir si es que se puede realmente medir.

    La verdad verdad es que no me importa mucho, incluso este tipo de exámenes me favorece, pues según he comprobado me va mejor que responder al azar incluso en temas que aún no conozco, como que veo la correlación entre las preguntas y puedo deducir por consistencia las correctas.


     

    Por fin al grano 


    Lo que si me intriga es si habrá además alguna correlación entre el modo de pensar no visual y otras características de las personas aprobadas que puedan ser útiles de modo directo o indirecto:

    • empatia
    • escrúpulos
    • solidaridad
    • obediencia
    • imaginación

    Y de haberla, si esta correlación ha sido descubierta y es usada.

    Lo único que se me ocurre es, supongamos que pensar de modo solo palabras está asociado a la falta de imaginación y muchísimas de las certificaciones son para herramientas que requieren sentarse y seguir procedimientos más que tener creatividad.

     

    Dejo este tema a quien tenga la formación, experiencia y certificación para tratarlo...

    DVR: completando el reconocimiento y explorando ataques ajenos

    $
    0
    0

    Repasemos y reformulemos tras lo aprendido en la primera ronda de reconocimiento:

    Tenemos una computadora de propósito específico (DVR) que no deja de ser atractiva para otros propósitos debido a que tiene:

    • CPU con FPU y SIMD (NEON)
    • SATA
    • USB
    • VGA
    • Ethernet
    • varios puertos GPIO
    • algo que parece ser RS-232 pero puede ser RS-485, según veremos luego
    • RTC con batería
    • aceleración criptográfica
    • todo un subsistema de procesamiento de audio y video 
    • y un lindo gabinete, aunque le falta la tapa

    En comparación con una Raspberry Pi, dependiendo del modelo puede tener más o menos poder computacional y si dejamos de lado el subsistema de video, la supera por tener SATA y RTC, convirtiéndola lo primero en apta para hacer un Network Storage.

     

    Lo de hoy


    En esta entrega, de la Cyber Kill Chain estaremos yendo y viniendo por:

    • Reconnaissance
    • Weaponization
    • Delivery
    • con esperanza de Exploitation

     

    UART 

     

    En una segunda inspeccion vi unos pines etiqueteados con GTR, apuesto a que este GTR no es, sino:
     
    G: Ground
    T: Transmit
    R: Receive
     

    Boot
    Boot


    Mirá el resultado del decoding, la linea verde y sus letritas.

    Me costó darme cuenta que la velocidad de la UART en boot no tiene nada que ver con la que se configura luego.

    Fuí probando con diversos dispositivos conectados.


    U-Boot 2010.06-svn (Oct 21 2019 - 14:58:50)

    Check Flash Memory Controller v100 ... Found
    SPI Nor(cs 0) ID: 0xc2 0x20 0x18
    Block:64KB Chip:16MB Name:"MX25L128XX"
    SPI Nor total size: 16MB
    In:    serial
    Out:   serial
    Err:   serial
    USB:   scanning bus for devices... 2 USB Device(s) found
    0 Storage Device(s) found
    PHY 0x01: OUI = 0x90C3, Model = 0x05, Rev = 0x04 .
    ETH0: PHY(phyaddr=1, mii) not link!
    higmac init fail!
    Press CTRL-C to abort autoboot in 2 seconds

     
    Con  el cable de red conectado:


    U-Boot 2010.06-svn (Oct 21 2019 - 14:58:50)

    Check Flash Memory Controller v100 ... Found
    SPI Nor(cs 0) ID: 0xc2 0x20 0x18
    Block:64KB Chip:16MB Name:"MX25L128XX"
    SPI Nor total size: 16MB
    In:    serial
    Out:   serial
    Err:   serial
    USB:   scanning bus for devices... 2 USB Device(s) found
    0 Storage Device(s) found
    PHY 0x01: OUI = 0x90C3, Model = 0x05, Rev = 0x04 .
    port_mode:0x3d
    ETH0: PHY(phyaddr=1, mii) link UP: DUPLEX=HALF : SPEED=10M
    MAC:   00-0C-1C-xx-xx-xx
    Press CTRL-C to abort autoboot in 2 seconds


     
    Si oprimo CTRL-C me da un shell sin comandos, con TAB me muestra pero están deshabilitados.


    hilinux #
      reset go bootd boot bootm tsload ddr decjpg ext2load
      ext2ls fatinfo fatls fatload getinfo ? help loady loadb
      ...


    Si lo dejo correr:
     

    Unknown command 'auto' - try 'help'
    16384 KiB hi_fmc at 0:0 is now current device

    pic load:0x8a000000
    pic save:0x8a300000
    0ff:0x8a000000
    can't find corresponding entry
     data LOAD ERROR<0> !
    OpenDev  vo:0 intf_type:36 out_sync:17
    OpenDev  vo:1 intf_type:1 out_sync:0

    ## Booting kernel from Legacy Image at 82000000 ...
       Image Name:   linux
       Image Type:   ARM Linux Kernel Image (uncompressed)
       Data Size:    2062808 Bytes = 2 MiB
       Load Address: 80008000
       Entry Point:  80008000
       Loading Kernel Image ... OK
    OK

    Starting kernel ...

    Uncompressing Linux... done, booting the kernel.



    Ese caracter loco me sugiere que cambió de baudrate...
     
     
    Glitch
    Glitch
     
     ...no, es nada.
     
     
    Para seguir interactuando con el linux ya corriendo o alguna aplicación, fuí probando los modos de RS-232:
    • General: nada
    • InteractCmd: nada
    • Ranging: nada
    • Transparent: nada

     

    USB

     

    Se me ha ocurrido que quizás si hay USB drive, diga algo:


    USB:   scanning bus for devices... 3 USB Device(s) found
    usb_stor_get_info->1431,blksz:512
    1 Storage Device(s) found
    Interface:  USB
      Device 0: Vendor: SMI      Rev: 1100 Prod: USB DISK       
                Type: Removable Hard Disk
                Capacity: 1901.0 MB = 1.8 GB (3893248 x 512)
    Partition 1: Filesystem: FAT32 "RIGOL      "
        36033   output.pdf
        63096   ds1z_quickprint1.png
        33421   ds1z_quickprint2.png
                .trash-1000/
                system volume information/

    3 file(s), 2 dir(s)

    do not need usb update



    Buen intento,  ahora necesito saber que busca.  El mensaje "do not need usab update" mi sugiere que hará update, no boot.
     
    En varias fuentes he visto archivos tipo auconfig.txt, ya veremos

     

    OSINT 

     

    Habiendo fallado por este lado e inspirado por un comentario a la primera parte apuntando a:

    https://www.exploit-db.com/docs/english/44003-hisilicon-dvr-hack.pdf

    y sumado a algunás búsquedas, volví a mirar los puertos, esta vez conectando con netcat, recordemos que eran 9527, 9530 y 34567:


    while [ true ] ; do
       echo retry
       nc IP PORT
    done

     
    Nada. Telnet contra los mismos, nada.

    Apliqué el ataque mencionado e implementado en https://github.com/Snawoot/hisilicon-dvr-telnet, nada, el de https://github.com/tothi/pwn-hisilicon-dvr, nada.

    Es evidente que el firmware que contiene está asegurado, como que el fabricante ha leido lo mismo que yo y lo ha corregido, estos son algunos de los links:

    • https://www.osm-s.com/en/2017/11/30/ip-camera-security-horror/
    • https://habr.com/en/post/486856/
    • https://ipvm.com/reports/backdoor-9530
    Sin embargo, fijate que más arriba decía:

    Unknown command 'auto' - try 'help'

    Esto me dice que lo arreglaron a hachazos, ¿para qué intentás ejecutar un comando que sabés que no va a estar?

     

    Punto de control

     

    Como habrás visto, he pasado por 
    • Weaponization
      • Elección y prepararación de cada exploit
    • Delivery
      • Interacciones con el dispositivo
    • Exploitation 
      • Sin éxito

     

    RS-485

     

    De paso, habiendo resuelto está RS-232, reviendo la señal que previa y erróneamente había asociado con RS-232 y viendo que en PTZ device configuration dice RS-485 y sabiendo que éste último usa par diferencial, apuesto a que ese conector mal identificado es en realidad RS-485, me faltaría saber por que tiene cuatro cables, qué está transmitiendo y si puedo manifestar algo por ahí.
     
     
    Evidencia de par diferencial
    Evidencia de par diferencial

     
     
     
    Es muy tentador pues nunca usé RS-485 y la EDU-CIAA-NXP lo tiene y también he hallado unos chips relacionados en otro dispositivo rescatado de la calle, pero me aleja mucho de mis propósitos.

     

    Próximos pasos

     

    Todo esto me deja en una encrucijada:
     
    • Lo uso como está
      • No aprendo nada
      • No lo voy a usar por que no tengo cámaras
        • No tengo ganas ni tiempo de instalarlas
        • No tengo motivos para mirarlas luego salvo ver a los perros que defecan en la vereda y si no lo he hecho aún no ha sido por no tener este dispositivo
    • Le plancho un firmware vulnerable
      • Puedo fallar y pierdo todo
      • Pierdo lo que hay ahora que parece ok
    • Obtengo físicamente el firmware
      • Más que puede, probablemente falle y pierda todo
      • Pero aprendo todo


     
    Le voy a dar un tiempo más a ver si encuentro algo hecho, en caso contrario, muy a mi pesar, le voy a arrancar el chip con el firmware y terminaré lo que empecé con el router al que lecayóelrayo.

    Prototipo de un regulador de ventilación de un switch

    $
    0
    0

    El problema


    "Entre toda la basura productiva que tengo está un switch 3300 mx cuyos coolers hacían un terrible ruido. Luego compré unos nuevos pero seguían siendo muy ruidosos. Así que modifiqué un poco las conexiones internas y los pasé de 12v a 5v.

    Pero aún así, sigue siendo muy molesto para mis delicados oidos.

    ¿Qué pasa si los apago completamente? Es lo que se llama "enfriamiento pasivo". El switch está diseñado para trabajar con hasta 24 bocas activas a full y un matrix connector. En casa con suerte hay cuatro bocas en uso a la vez, quizás de conjunto no se caliente mucho, pero algún chip en particular sí y eso lo rompa, no puedo prescindir de la ventilación.

    Es un excelente candidato para un arduino o similar con un sensor de temperatura y mediante PWM regular la velocidad de los coolers."

    Hasta acá había llegado hace meses sino años, lo había guardado en un cajón y reemplazado por un hub muy bonito, pero de 10, lo cual me ofende y no me facilita los backups por red pero bueno, es lo que hay.

    Ahora con #quedateencasa, la red hogareña se vé más exigida y me molesta tanta cosa en el backlog y me aburro asi que lo retomo, pero escribo desde el futuro, lo termino casi cuatro meses despues debido a lo infernalmente complicado que me ha resultado.


    Resumen


    Es un texto largo, pero puse bastantes dibujitos:

    • Elección de microcontrolador según sus recursos, me quedé con un ATMega328p, por fallas en la ArduinoIDE respecto a 1-wire en ATtiny85.
    • Elección de la comunicación al exterior buscando no romper el switch, un módulo RS-232.
    • Mi falta de conocimiento de electrónica analógica básica me frenó bastante e incluyó la destrucción de dos transistores y dos ATtiny85 pero aún no logré determinar el porqué, sí la destrucción de un ATMega328 por colocarlo desplazado un pin en el protoboard.
    • Desarrollo de un programa con parametría en EEPROM para no tener que estar abriendo y cerrando el gabinete, probablemente lo único con algún mérito.
    • Primer contacto con ATtiny85, EEPROM, SoftUART, PWM amplificado, sensor interno de temperatura.


    Temperatura


    Para comenzar, no sé cuál es la temperatura aceptable, el manual dice la temperatura de trabajo "exterior", no la que puede haber ahí dentro, dice ser 50 grados centígrados. Tampoco dice hasta que temperatura pueden llegar los chips, a ver la referencia, si, lo más parecido que encontré dice 70, así que procuraré mantener la temperatura dentro del switch por debajo de 60, 65, grados, veremos. La realidad es que este equipo estuvo mucho tiempo en un cuartito cerrado sin aire acondicionado con todas las bocas conectadas y los coolers trabados y sigue vivo.


    Para ir familiarizándome con el problema, lo medí de varias maneras con un termómetro IR (UNI-T UT306A) y con uno de contacto (UNI-T UT202) que en realidad debe ser un poco mayor, pues como estoy apretando el sensor con el dedo contra el chip, hago de disipador.

    Abierto, cerrado, sólo prendido, con gente mirando streaming, va de 50 a 60 grados en el chip que está más caliente.


    Disipación


    Considerá que yo no sé nada de este tema, usaré mi sentido común.

    Como disipador probé un perfíl L de aluminio que tiene poca superficie de intercambio, pero es lo que tengo. La pregunta es, si los chips están diseñados para trabajar sin disipador, el agregarle un disipador que no lo es tanto, ¿mejorará o empeorará la situación? ¿Serán refrigerantes o abrigantes?


    Estos disipadores sacan el calor de los chips y lo pondrán en el aire dentro del switch, en términos "totales" no hace diferencia. Lo que mejora es que los chips estarán menos calientes entonces podré tolerar temperaturas mayores en ese espacio, que es dónde mido.

    Esto me obliga a medir nuevamente, lamentablemente las herramientas que tengo no sirven así que no tiene mucho sentido que transcriba los valores. Sí puedo afirmar que midiendo un chip sin disipador me da una temperatura, le pongo el perfil un rato y se lo saco y me una inferior, asi que parece funcionar.

    Si pongo uno de los termómetros adherido al perfil, quizás tenga un mejor apreciación de lo que ocurre ahí dentro.

    Finalmente he decidido no poner disipadores por que me resulta muy difícil mantenerlos en posición a menos que use la cinta bifaz ridículamente cara.

    Ventilación



    Hasta donde yo sé, la velocidad de motores como los coolers se pueden regular de dos maneras, con el voltaje o con PWM. Lo primero es con un DAC, Digital to Analog Converter, que por lo general va afuera del microcontrolador. Mejor PWM, que es darle pulsos todo o nada.


    • Tengo que medir la corriente que circula en los coolers para ver que transistor usar.  (listo, 300 mA)

    Voltaje y consumo de un cooler
    Voltaje y consumo de un cooler


    En la foto podemos ver un cooler conectado con un transistor y su consumo.

    • Durante un tiempo debe ser externo por si falla no me rompa nada (ok, lo haré)
    • Tengo que ver la frecuencia del PWM por si genera ruido (faltan semanas de pruebas).

    Tendría que arrancar al máximo por que tiene onda, como los server raqueables que arrancan a full y despues bajan. Pero tras romper algunos transistores mejor que arranque a la mitad y luego suban y vuelvan a bajar, mantiene la onda y los transistores.


    Microcontrolador


    Tengo varias opciones, poner un ATMega328p, un ATtiny85 o un ATtiny85 Digispark.

    Lo bueno del ATtiny85 Digispark es que tiene un conector USB 1.1 Tipo A macho que en realidad es sólo serial no USB arbitrario como lo que tiene un Teensy. Lo malo es que provee alimentación y el microcontrolador ya va a recibir alimentación desde la fuente del switch y tengo entendido que no es buena idea conectar alimentaciones distintas así no más. Como carezco de los conocimientos, me tengo que quedar con comunicación serial, ya sea el ATMega328p o un ATtiny85 pelado.

    Grilla elección microcontrolador



     Aspecto ATMega328p ATtiny85
     Comunicación serial
    Hardware
    Software
     Memoria RAM 2KB 512B
     Memoria EPROM
     1024B 512B
     Memoria FLASH
     32KB 8KB
     PWM Si     Si
     Sensor temperatura Interno Interno
     GPIO libres para sensores
     montones 2
     Interesante No Si


    Lo bueno de haber confeccionado esta tabla es que me enteré que ambos chips contienen un sensor interno de temperatura.

    Voy a intentar usar el ATtiny85 por los siguientes motivos:
    • Nunca lo usé antes
    • Tener recursos más restringidos es un buen desafío


    Comunicación


    De un modo u otro, tengo que hacer la adaptación a la PC, puede ser un adaptador a RS-232 (el que maneja voltajes 12 y -12) o estaría re lindo ponerle un db9 y utilizar los transceptores no utilizados del max241c que tiene el switch, pues tiene un puerto serial y ese chip tiene cuatro, tendría que determininar si alguno no está en uso, desoldar las patitas, conectarlas al microcontrolador, poner el conector en el chasis. Tambien podría meterme en el medio si tuviera dos seriales en el microcontrolador e interceptar el diálogo de la terminal serial. Aunque muy interesante, hacker e instructivo, es más tiempo, así que voy por el algo más sencillo primero y además no corro el peligro de romper el chip y quedarme sin poder administrar al switch.



    El chip serial candidato
    El chip serial candidato


    Dado que está en un switch, podría usar ethernet, no? no:
    • Si no recuerdo que IP fija tiene o no coincide con la red actual...
    • Si levanta IP por DHCP tengo que buscarla...
    • Tengo que meter mucho más hardware y software...


    Grilla de elección de comunicaciones


     Aprovechar
    Max241c
    Interceptar
    Max241c
    Serial
    RS232
    Serial
    Pelado
    USBInfrarrojo
    RF Bluetooth
    InteresanteLo máximo
    Lo máximoMás o menosPara nadaPara nadaBastante
    RiesgosoCompletoCompletoPara nada
    Bajo pero podría conectar invertidoPara nadaPara nada
    HardwareSólo conector db9 que ya tengoNadaUsaría un módulo que ya tengo
    Para nadaUsaría un módulo que ya tengoEl que corresponda
    Costo SoftwareÍnfimoSoftUartÍnfimoÍnfimoÍnfimoComplicado
    Adaptador PCQuizásNoQuizásSiNoTengo que hacerlo
    Integración HardwarePerfectaPerfectaPerfectaHorribleMedio rara
    Depende, infrarrojo muy complicado, RF y BT supongo que antena afuera
    DificultadDifícilDifícilFácilFácilFácilNo tan fácil
    Puntos 13 14 16 12 15 8


    Los puntos son 3, 2, 1 y 0. Perdón que la grilla salga medio rota, esto no es muy WYSIWYG y no ando con energías de hacerla bien en otro lado y pegar la imagen.

    Tuve que agregar Dificultad pues me quedaban empatados los dos primeros pero a la vez no me cerraba.


    Venía ganando USB pese a que durante un momento había pensado que era con ATtiny85 Digispark lo que no es posible por la doble alimentación ya conversada y además me gustaría que tenga el conector Type-B.

    Memoria EEPROM



    Un detalle importante de este proyecto es que estoy usando el switch mientras lo diseño. No puedo estar abriéndolo y cerrándolo en cualquier momento. Entonces la calibración es un problema, no puedo ponerla en el programa pues puede cambiar ni ponerla en RAM por que de reiniciarse la pierdo. Tambien tendré que lidiar con el próximo verano. Salvando las distancias, es un escenario como el de las sondas interplanetarias, donde se manda el hardware con un mínimo software y durante el tiempo de viaje se desarrolla el software que se va a utilizar en el destino de la misión.


    Planificación


    De paso aprovecho para practicar parte de lo aprendido en la materia de gestión de proyectos del CEIoT. Podría hacer hacer un Gantt pero no lo voy a respetar.


    Tareas de armado


    • Colocar conector serial.
    • Colocar termómetros.
    • Colocar microcontrolador.


    Tareas de hardware


    • Conectar microcontrolador a 5v de la fuente del switch.
    • Conectar microcontrolador a termómetro.
    • Conectar adaptador de potencia de los coolers a 12v.
    • Conectar adaptador serial.


    Tareas de software


    • Programar blinky para ATtiny85 y transferirlo.
    • Implementar comunicación serial.
    • Leer sensor de temperatura incorporado y mostrar por serial.
    • Leer sensor de temperatura vía 1-wire.
    • Implementar PWM
      • Cambiar configuración del PWM según parametría en EEPROM.
      • Diseñar función velocidad.
        • Atender al REPL vía serial.
          • Mostrar temperatura.
          • Mostrar velocidad y PWM.
          • Cambiar velocidad y PWM.
          • Mostrar parametría en EEPROM.
          • Modificar parametría en EEPROM.

        De todo esto, tengo experiencia en todo salvo el acceso a EEPROM y la función de parametrización que no deja de ser un algoritmo más, así que digamos que si.


        Manos a la obra


        Como lo más difícil es la función de velocidad, por esta comenzaré.


        Función de velocidad, Brain para los amigos


        Necesito una velocidad que sea resultado de la temperatura actual de los sensores y la variación que hayan tenido.

        O sea si la temperatura actual es normal pero antes era alta, debo mantener la velocidad actual. Cuando vuelva a calcular la actuar será normal y la anterior normal, puedo bajar un poquito y así.


        Se me ocurren dos funciones:

        Velocidad = v( Tr0, Tr1, Tr2, Ts0, Ts1, Ts2,  Tendencia)

        Donde:


         Tr0 Temperatura referencia para el sensor interno
         Tr1 Temperatura referencia para el sensor externo 1
         Tr2 Temperatura referencia para el sensor externo 2
         Tr0 Temperatura sensor interno
         Ts1 Temperatura sensor externo 1
         Ts2 Temperatura sensor externo 2


        La variación de velocidad está dada por la siguiente tablita para cada tipo sensor interno/externo:


          Ts < Tr
         Ts == Tr
         Ts > Tr
        (+2) Subió mucho
         +++
         +++
        (+1) Subió = + ++
        (0) Igual - = +
        (-1) Bajó -- - =

        Para facilitarme la vida, entre paréntesis está el valor que es multiplicado por TA, Amplificador de Tendencia.

        Y esta es la Tendencia:


        Tendencia = t (TA, Promedio)


        y este el Promedio:

        Promedio = (W0,W1,W2,Ts0,Ts1,Ts2,Ts0-1,Ts1-1,Ts2-1,TsX-n,Ts2-n,..)

        que debe tener en cuenta el peso de los sensores, W0 a W2 y el Promedio

        Los variables que tengo para almacenar en la EEPROM son:


         Nombre Descripción Nombre variable
         Tr0 Temperatura referencia sensor interno 0
         param_temp_ref_0
         Tr1 Temperatura referencia sensor externo 1 param_temp_ref_1
         Tr2 Temperatura referencia sensor externo 2
         param_temp_ref_2
         W0 Peso sensor interno 0
         param_weight_0
         W1 Peso sensor externo 1
         param_weight_1
         W2 Peso sensor externo 2
         param_weight_2
         -- Cuánto decrementar mucho
         param_dec_1
         - Cuánto decrementar param_dec_2
         + Cuánto incrementar
         param_inc_1
         ++ Cuánto incrementar mucho param_inc_2
         +++ Cuánto incrementar muchísimo param_inc_3
         TA Amplificador de tendencia
         param_ta
         == Margen de igualdad
         param_delta_eq
         n Cantidad de historial de la tendencias
         param_history_length
         ST Tiempo de sampleo
         param_sample_interval


        Son todos valores enteros para facilitarme la carga con el REPL.

        Si en algún momento la velocidad fuera cero y la temperatura subiera, habría que arrancar con la velocidad inicial y luego ir a la mínima.

        Más adelante puedo reemplazar por AI, me han dicho en un webinar que hay algo llamado PID que podría andar en microcontroladores de 8 bits y hay algo para arduino, pero eso será en otra ocasión.

        Aca ya vemos que la fórmula de la tendencia va a tener que ser tambien parametrizable si quiero seguir en el modo "sonda espacial". Luego volveré sobre la implementación, ahora, que funcione en modo prototipo.


        Programación del microcontrolador


        Ya tengo un circuito armado para ATMega328p, pero no para ATtiny85, aparte cuento como me las arreglé.


        SoftUART


        Cuando me disponía a hacer el blinky para ver que pueda programarlo, me dí cuenta que ATtiny85 no cuenta con puerto serial, eso lo resolví usando una clase de Arduino llamada SerialSoftware acá.


        PWM


        Piece of Cake, al programa previo le agregué:

        const byte pwm = 4;
        char pwmSpeed = 128;

        y algunos

        analogWrite(pwm, pwmSpeed); 


        Sensor interno de temperatura


        En las páginas 123 y 253 de la datasheet explica como usarlo:


        "writing the MUX3...0 bits in ADMUX register to "1000"
        enablesthe temperature sensor"

        Luego hay que convertir el voltaje leido según esta tabla:


         Temperature -40°C +25°C +85°C
        ADC 230 LSB300 LSB
         370LSB

        Luego hay que ajustarse a la variación del proceso según esta fórmula:

        T = k * [(ADCH << 8) | ADCL] + Tos


        Donde Tos hay que guardarlo en EEPROM o en mi caso como tengo un solo ejemplar lo podría hardcodear, k es un coeficiente que no dice de donde sale y el resto no lo entiendo, lo que si entiendo es que

        "the accuracy of the temperature measurement is +/- 10°C"

        así que no me voy a molestar mucho con esto, o quizás si, en otro lado dice que se puede llegar a +/- 2°C.

        Y luego me basé en https://microchipdeveloper.com/8avr:avradc


        Para inicializar:

          ADMUX = B10001111;
          ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADEN);
          // Perform Dummy Conversion to complete ADC init
          ADCSRA |= (1<<ADSC);
          while ((ADCSRA & (1<<ADSC)) != 0);


        y luego en cada lectura:

          ADCSRA |= (1<<ADSC);
          while ((ADCSRA & (1<<ADSC)) != 0)
          Ctemp = (ADC - 247)/1.22;
          swSerial.println(Ctemp);

        Luego veré si lo calibro bien, todavía no sé si me va a alcanzar la memoria.


        EEPROM


        Tomé los ejemplos de ArduinoIDE, otra vez muy fácil:


          #include <EEPROM.h>

        y usar:

          char tmp;
        swSerial.print("stored pwn speed is: ");       
          EEPROM.get(0,tmp);
          swSerial.println(int(tmp));
         swSerial.print("stored: ");
          EEPROM.put(0, pwmSpeed);
          swSerial.println(int(pwmSpeed));


        DHT11


        Para estos sensores me quedan dos pines

        No me salió a la primera, el dht adafruit tenía unas dependencias que no me gustaron, dht algo le falló al intentar instalar las librerías y me quedé con dhtnew que copié en lib y debo haber sacado de...

        Otra vez, muy sencillo:


          #include <dhtnew.h>

          #define DHTPIN1 2
          #define DHTPIN2 3
          DHTNEW dht1(DHTPIN1);
          DHTNEW dht2(DHTPIN2);
          float humidity1;
          float temperature1;
          humidity1    = dht1.getHumidity();
          temperature1 = dht1.getTemperature();
          swSerial.print("Temperature 1: ");
          swSerial.println(temperature1);

        ...en teoría. Creéme, no funciona, hay algo mal con delayMicrosecond(), cuando me haga un rato lo diagnosticaré, ahora no aguanto más el ruido del switch.


        Conexiones finales que no fueron


        Así hubiese quedado:

                 +---------------+       
           5v -> RESET   Vcc  -  5v
          1-wire 2 <-> PB3     PB2 <-> 1-wire 1
              PWM <-  PB4     PB1  -> TX     
          GND -  GND     PB0 <-  RX
          +---------------+


        Fall back and regroup


        No estoy sobrellevando bien los fracasos desde lo de sacar el firmware del router al que le cayó el rayo y lo del 8051, voy a tener que descartar ATtiny85 y pasarme a ATMega328p.

        Como ahora tengo una cantidad infernal de pines de sobra podría regular la velocidad de cada cooler independientemente pero no descarto volver a usar un ATtiny85 y para ello debería hacer un circuito que sea pin compatible entre ambos chips, algo en el estilo de lo que hice para el programador, pero me supera y así no voy a terminar nunca. Olvidemos el ATtiny85.

        Además no quiero llenar todo de cables.

        Puedo (debo) prescindir de la soft UART.

        Recalculando...


        Grilla de elección de comunicaciones revisada


        Como me gustó la tabla, la voy a rehacer para divertirme, me gusta hacer tablas:

         Aprovechar
        Max241c
        Interceptar
        Max241c
        Serial
        RS232
        InteresanteLo máximo
        Lo máximoMás o menos
        RiesgosoCompletoCompletoPara nada
        HardwareSólo conector db9 que ya tengoNadaUsaría un módulo que ya tengo
        Costo Software ATtiny85
        SoftUart
        Imposible
        SoftUart
        Costo Software ATMega328p
        ÍnfimoSoftUart Ínfimo
        Adaptador PCQuizásNoQuizás
        Integración HardwarePerfectaPerfectaPerfecta
        DificultadDifícilDifícilFácil
        Puntos ATMega328/ATtiny85
         13/12 14/12 16/15



        Los puntos son 3, 2, 1 y 0. Sigue ganando usar el Serial, en particular con ATMega328p.

        Si mirás el código, para ATtiny85he ido probando cada funcionalidad por separado y luego juntado. Con ATMega328p tomé una camino más audaz, voy agregando funcionalidad en cada paso, apostando a que no hay interferencias.


        PWM


        Me quise saltar el paso del Serial pero el configurar ArduinoIDe para ATMega328p pelado era una deuda que tuve que pagar:

        File -> Preferences -> Settings -> Additional Boards Manager URLs:

        https://www.leonardomiliani.com/repository/package_leonardomiliani.com_index.json

        La URL la saqué de:


        Luego:

        Tools -> Board -> Boards Manager -> "atmega328p" ofrece boards de Leonardo Miliani

        Y por último elegí "Arduino ATMega328p @8Mhz with Arduino as ISP".

        Habiendo recuperado el Serial, al PWM sólo hubo que pescarlo, pues no sé cual es el mapeo. Lo que sí sé es que los pines de PWM son problablemente 11, 12, 15, 16, 17 y accidentalmente al primer intento con 11 en PB3 tengo PWM.


        Sensor interno de temperatura


        En las páginas 252 y 253 de la datasheet explica como usarlo:


        "Selecting the ADC8 channel by writing the MUX3...0 bits in
        ADMUX register to "1000" enables the temperature sensor"

        Luego hay que convertir el voltaje leido según esta tabla:


         Temperature -40°C +25°C +85°C
        Voltage/mV 242mV314mV
         380mV

        Luego hay que ajustarse a la variación del proceso según esta fórmula:

        T = { [(ADCH << 8) | ADCL] - T OS } / k


        que nuevamente ignoraré por ahora.

        El valor que me da es entre 84 y 87 grados, luego veré por qué.


        EEPROM


        Sin problemas, así que aproveché para averiguar por qué cada vez que grabo el programa, la EEPROM me queda borrada. El motivo es el bit EESAVE de HFUSE:


        Hfuses


        Ahora que entiendo lo que pasa, la verdad es que no me molesta, cambiaré los fuses cuando lo necesite.


        DHT11


        El primer problema es mapear los pines igual que con PWM, pero ya amerita intentar hallar las definiciones, tras un poco de escarbar, en

        $BASEPATH/arduino-1.8.10/hardware/arduino/avr/variants/standard/pins_arduino.h

        hay un mapeo que aunque no dice explícitamente ATMega328p parece corresponder:


        // ATMEL ATMEGA8 & 168 / ARDUINO
        //
        //                  +-\/-+
        //            PC6  1|    |28  PC5 (AI 5)
        //      (D 0) PD0  2|    |27  PC4 (AI 4)
        //      (D 1) PD1  3|    |26  PC3 (AI 3)
        //      (D 2) PD2  4|    |25  PC2 (AI 2)
        // PWM+ (D 3) PD3  5|    |24  PC1 (AI 1)
        //      (D 4) PD4  6|    |23  PC0 (AI 0)
        //            VCC  7|    |22  GND
        //            GND  8|    |21  AREF
        //            PB6  9|    |20  AVCC
        //            PB7 10|    |19  PB5 (D 13)
        // PWM+ (D 5) PD5 11|    |18  PB4 (D 12)
        // PWM+ (D 6) PD6 12|    |17  PB3 (D 11) PWM
        //      (D 7) PD7 13|    |16  PB2 (D 10) PWM
        //      (D 8) PB0 14|    |15  PB1 (D 9) PWM
        //                  +----+
        //
        // (PWM+ indicates the additional PWM pins on the ATmega168.)


        Me iba a quedar con:

                  +------------------+
           RESET  -> PC6             -
              RX  -> PD0    A        -
              TX <-  PD1    T        -
                  -  PD2    m        -
                  -  PD3    e        -
                  -  PD4    g        -
              5v  -  Vcc    a   GND  - GND
             GND  -  GND    3        -
                  -  PB6    2        -
                  -  PB7    8        -
                  -  PD5    p        -
                  -  PD6        PB3  -> PWM
             DHT2 -  PD7             -
             DHT1 -  PB0             -
                  +------------------+

        Pero luego cuando armé la placa puse los sensores junto a los pines de power para poder usar un conector sacado de un mother o placa de sonido.

                  +------------------+
           RESET  -> PC6             -
              RX  -> PD0    A        -
              TX <-  PD1    T        -
                  -  PD2    m        -
            
        DHT2 -  PD3    e        -
            
        DHT1 -  PD4    g        -
              5v  -  Vcc    a   GND  - GND
             GND  -  GND    3        -
                  -  PB6    2        -
                  -  PB7    8        -
                  -  PD5    p        -
                  -  PD6        PB3  -> PWM
                  -  PD7             -
                  -  PB0             -
                  +------------------+

        Anda todo ok, salvo el termómetro interno.


        Regulando velocidad del cooler


        Llegó la hora de tocar el mundo real, puse un transistor a la salida PWM según lo planeado, quemé dos, no quiero entrar en detalles pues no sé de electrónica digital, sería irresponsable de mi parte, pero si te sirve te cuento que no les daba la potencia, por eso es que arranco a media velocidad y uso tres transistores. Luego tuve que poner un par de capacitores por que se reseteaba el chip, no pongo detalles por que no puedo justificarlos con mi conocimiento.


        Implementación de las funciones

        Para facilitarme la vida he decidido ignorar al sensor interno.

        Hasta ahora, todo el código ha sido DLP (Debug Later Programming) en lugar de TDD (Test Driven Programming) y tiene que ver con que lo que he hecho es bastante sencillo. Pero las funciones de cálculo de velocidad, teniendo en cuenta un historial de longitud variable en tiempo de ejecución se me complica, así que a rescatar Test Driven Development for Embedded C (Pragmatic Programmers) 1st Edition de James W. Grenning y aplicarlo.


        La tentación de los que venimos de TDD en software "puro" es
        • hacer un test
        • que falle
        • hacerlo pasar
        • refactorizar.

        En este libro hay algo extra extremadamente importante debido a la dualidad de targets, el código que estoy haciendo no necesariamente va a correr donde lo estoy testeando, quizás ni use el mismo compilador y entorno.

        En TDD "normal", uno mockea lo que no tiene bajo control, o sea la DB, la API a la que va a consultar, el otro componente. En el caso de embebidos, suele ser el hardware mismo, lo que nos conduce a mockear el objeto mismo bajo test hasta tener todos o la mayoría de los tests antes de implementar ningún código. No estoy completamente seguro y no tengo ganas de volver a leer el libro, pero como que hay dos rondas:

        • tests puros
          • hacer un test sobre un mock
          • que falle
          • hacerlo pasar
        • implementación completando tests faltantes
          • reemplazar mock por código real
          • hacerlo pasar
          • refactorización
        Esto es conceptual, no hace falta usar un mock, se puede usar el CUT (Code Under Test) mismo.


        La integración de cpputest con ArduinoIDE es muy simple, armás la clase que querés testear en su ubicación, le agregás unos

        #ifdef UNIT_TEST 

        para incluir lo que no necesitás desde ArduinoIDE y desde el proyecto hacés unos links simbólicos a la clase, pero con nombres .ino en lugar de .cpp así ArduinoIDE hace su magia.

        Luego te dás cuena que parte de la magia de ArduinoIDE es que en lugar de abrir los archivos los vuelve a crear y te los reemplaza por lo que salve, así que tenés que invertir el sentido del link:



        /src/atmega328p/05_prototype/
                                     Brain.hpp
                                     Brain.ino
        /src/brain/
                   Brain.hpp  ->  ../atmega328p/07_alpha/Brain.hpp 
                   Brain.cpp  ->  ../atmega328p/07_alpha/Brain.ino



        La función respeta esta forma:

            velocidad
        actual
         
           0 <=min > min
         delta -20 0 min (-> powerOff)
         actual -20
          -10 0 min (-> powerOff)  actual -10
          cero
         0 min (-> powerOff) actual - cero
          + * arrancarmin + *
         actual + * (max 255)


        cero es 0 o un número negativo bajo

        Este tipo de funciones seguro tienen un nombre y se estudian quizás en alguna materia de secundaria y sin duda universidad, son las funciones que hacen que por ejemplo un autito siga una linea blanca en el piso. Pude haber buscado en internet, no digo en stackoverflow sino en foros especializados y libros pero la verdad es que he preferido sufrirlo para que el día que investigue lo existente estar en mejores condiciones de comprenderlo.


        Hardware


        Esto es lo que quería:


        Modelo 3d kicad
        Modelo 3D kicad


        En mi imaginación, arriba a la izquierda va un conector de floppy y en el centro el conector está en la otra cara.

        Esta es mi triste realidad, soy incapaz de hacer algo tan prolijo, gracias que con el tutorial de kicad y mi experiencia previa del curso CAPSE que en la primera cohorte se llamó Paquete tecnológico del proyecto CIAA, pero ahora parece haberse movido a otra materia, decía, pude hacer un bonito modelo pero no pude hacer el transfer con un papel viejo que tenía y no ando con ganas de $404 de envío por un sobre de $200. Entonces lo hice a mano y es como una herida en mi autoestima que me avergüenza mostrar:
         
         

        herida en la autoestima
        Herida en la autoestima



        Ni lo pasé por el ácido pues algunos agujeros me salieron tan desalineados que la verdad es que no entiendo por qué me molesté en dibujar el circuito.

        Todo este manoséo me retrasó tres fines de semana más.

        Ni a mi me gusta, pero no dejo de sentir un ínfimo orgullo:



        El circuito instalado
        El circuito instalado





        La fijación


        Hasta este momento no había caido en cuenta que no he pensado nada, medio que me imaginé que los sensores estarían pegados a... no sé. El microcontrolador está ok, pues va agarrado al conector serial, pero los sensores y los cables flotan perdidos.

        Entonces, pensé en los descartados disipadores, si hiciera una pieza que los sujete y a la vez sostuviera los cables y sensores, tendría bastante sentido y este es el momento en que muero por tener una impresora 3D. Tambien me pregunto por qué tiré toda la basura que tiré, ahí tenía superficies plásticas para rescatar.

        • No puedo usar madera por el riesgo de combustión. Lo mismo podría decir del plástico pues no sé como diferenciar un plástico apto de uno que no, pero de plástico será.
        • No debe interrumpir el flujo del aire.
        • No puedo usar mucho metal por que no sé como interacturá en términos electromagnéticos.




        Malla plástica soporta sensores
        Malla plástica soporta sensores

         

        Algunos percances



        Cuando ya estaba todo aparentemente funcionano, ocurrieron varios inconvenientes juntos:

        Por conectar RS-232 prendido, aparentemente rompí el chip del ponncho educativo y quizás el adaptador USB-RS-232. Terminé usando aglo como esto:



        Adaptadores varios
        Adaptadores varios

         

        Aparentemente rompi otro ATMega328p en la misma operación.

        No sé si me sobró un tornillo, pues había uno en la misma cajita donde venía juntando, la verdad es que no lo recuerdo.



        Resumen, conclusiones y aprendizajes



        • He instalado un microcontolador con algunos sensores de temperatura para regular la velocidad de los coolers según la temperatura interior del switch.
        • Decidí usar las soluciones menos riesgosas en términos de intervención del switch, lo cual es muy frustante, si encuentro otro switch, meteré las manos.
        • No agregué disipadores por la dificultad de mantenerlos en posición.
        • Hay que tener más chips cuando estás haciendo tantas pruebas.
        • Si me restrinjo al aspecto económico, por las horas que invertí me hubiera costado menos comprar un switch que no hiciera ruido.


         
        Como a la vez estaba en el trabajo a full con javascript, e ocurrió un error muy lindo, escribí esto, a ver si te das cuenta del error

            Serial.println("EEPROM valid");
            Serial.print("Stored speed: " + pwmSpeed);


        La salida fue:

         speed formula                        <REMOVE>

        ¿Nada? Es parte del mensaje del menú, ¿nada?

        Debí haber escrito:

            Serial.println("EEPROM valid");
            Serial.print("Stored speed: ");
            Serial.println(pwmSpeed);

        Próximos pasos...


        ...que quizás nunca haga:

        • Investigar si la frecuencias de PWM hace diferencia en el ruido.
          • Esto implica medir la velocidad de giro mientras aplico distintos voltajes y distintos duty-cycles de PWM midiendo el sonido.
        • Reportar como me fué con la parametrización de Brain
          • Tengo que esperar al verano pues no tengo estufa en el cuarto donde está el switch.
          • Tengo que medir la temperatura exterior
          • Tomar registro de ambas mediciones 
          • Excelentes candidatos para integrar a mi TP de CEIoT
        • Reemplazar la implementación actual de Brain por algo más inteligente:
          • Fuzzy Logic?
          • AI?
        • Reemplazar por otro mejor pensado que me permita reprogramarlo sin abrir el switch 


        Ejemplo de ejecución

         

        En estos 12 minutos acelerados a 5x (2:30) vemos el inicio y las mediciones periódicas junto a los ajustes:

        T1 y T2 son las temperaturas, CS la velocidad, siendo 127 el 50% y 255 el 100%.


        # T1:29.70, H1:38.00, T2:30.00, H2:39.00, CS:127


        Tras un ratito los coolers se apagan, muy pronto vuelven a prenderse, entonces le cambio la marca de temperatura y así...
         
         
         

         
        El código en github



        Adaptador USB RS-232 con display usando EDU-CIAA-NXP con un poncho

        $
        0
        0
        Cuando hice el regulador de velocidad de los coolers de mi ruidoso switch, elegí usar RS-232 para la comunicación una vez instalado en módulo en el switch y usé un adaptador USB-UART tambien llamado USB-TTL mientras desarrollaba.


        sin rs232

        En la fotico podemos ver de izquiera a derecha el cable USB proveniente de la computadora, el adaptador USB-UART y a la derecha medio escondido el controlador de velocidad de los coolers.


        +---------+   +-----------+   +----------+
        | compu | | +-------+ | | +------+ |
        | | | | UART ---------- UART | |
        | | | +---|---+ | | +------+ |
        | +-----+ | | +---|---+ | | |
        | | USB --------- USB | | | control |
        | +-----+ | | +-------+ | | cooler |
        +---------+ +-----------+ +----------+

        Por decisiones tomadas y justificadas en el otro proyecto, al conectar el adaptador RS-232 al módulo de control, ese cosito con el conector DB9 que apareció a la izquierda del controlador de velocidades, necesito un adaptador RS-232 - USB, que no tengo.


        con rs232


        +---------+   +-----------+        +----------+  +----------+
        | compu | | +-------+ | | +------+ | | control |
        | | | | RS-232 ------------ RS-232| | | cooler |
        | | | +---|---+ | | +---|--+ | | |
        | +-----+ | | +---|---+ | | +---|--+ | | +------+ |
        | | USB --------- USB | | | | UART -------- UART | |
        | +-----+ | | +-------+ | | +------+ | | +------+ |
        +---------+ +-----------+ +----------+ +----------+


        Mientras lo consigo, puedo usar una EDU-CIAA-NXP con el poncho educativo de UNSJ que tiene RS-232 y aprovechar que tiene un display para mostrar la información de temperatura, humedad y PWM aplicado a los coolers que envía el controlador de velocidades con el siguiente formato:

        # T1:18.10, H1:60.00, T2:18.90, H2:60.00, CS:84

        T1: temperatura sensor 1
        H1: humedad sensor 1
        T2: temperatura sensor 2
        H2: humedad sensor 2
        CS: duty cycle del PWM, cuanto mayor, mayor la velocidad de los coolers.


        Use sAPI del firmware_v3 en el tag r1.2.0 pues en r1.3.0 algo falla:

        git clone https://github.com/ciaa/firmware_v3.git
        git checkout r1.2.0

        creé una carpeta "projects"en la cual hice un symlink a mi proyecto:

        cd firmware_v3
        mkdir projects
        cd projects

        ln -s ../../../cpantel/SerialDisplayAdapter
        cd ..

        luego en program.mk

        PROGRAM_PATH = projects/SerialDisplayAdapter


        Canibalicé un poquito de dos proyectos, este y este y le sumé una FSM:

         estado actual  
         data[0] acción
         pasa a estado
         seek     '#' lcdClearAndHome(); seekT1
         seekT1 ':'  readT1
         readT1     ',' lcdSendStringRaw(space); seekH1
         readT1 *
         lcdSendStringRaw(data); 
         seekH1 ':'  readH1
         readH1 ',' lcdGoToXY( 0, 1 ); seekT2
         readH1 * lcdSendStringRaw(data); 
         seekT2 ':'  readT2
         readT2 ',' lcdSendStringRaw(space); seekH2
         readT2 * lcdSendStringRaw(data); 
         seekH2 ':'  readH2
         readH2 ',' lcdSendStringRaw(space); seekCS
         readH2 * lcdSendStringRaw(data); 
         seekCS ':'  readCS
         readCS eol  seek
         readCS * lcdSendStringRaw(data); 


        Lo que hace es descartar todo caracter hasta hallar '#' como identificador de linea de datos, es que yo puedo estar operando y no hay necesidad de que aparezca nada en el display, sólo debo tener cuidado de no ingreser ningún '#' por que si no se me va a trabar la FSM, mmmh, le pongo que si encuentra un '#' y no está en estado SEEK que se resetee a SEEK y listo, dame dos minutos... listo.

        Tuve la tentación de en lugar de usar switches e ifs anidados utilizar una estructura parametrizable, pero este proyecto es sólo un accesorio para otro más grande que ya quiero terminar y si me meto en tanto detalle no voy a terminar nunca.

        Lamentablemente,  mientras hacía pruebas quemé el max232n del poncho educativo y ahora estoy usando el poncho PLC con un adaptador TTL-RS-232

         
         

        Mostrando los mensajes del switch
        Mostrando los mensajes del switch


        Abajo a la izquierda el adaptador, en el display las temperaturas, humedades y velocidad del cooler.
         

        Lecturas por serial
        Lecturas por serial




        El código en https://github.com/cpantel/SerialDisplayAdapter, pronto progresará cuando le agregue un termómetro y registre la información para ajustar los parámetros.


        Modificaciones al display serial

        $
        0
        0

        Había hecho un display serial  para poder ver las temperaturas y la velocidad del controlador de ventilación de un switch y cuando me preparé para comenzar a registrar los valores para estudiarlos y poder parametrizar correctamente al algoritmo me encontré con algunos problemas.

         

        Hardware


        El primero, tal como había contado, había sido perder el max232n del poncho educativo debido a falta de pericia. Me pasé entonces al poncho PLC pero no me sirve pues me complica agregar el sensor de temperatura ambiental que necesito como referencia.


        Volví al poncho educativo y le saqué el chip, suponiendo que no había roto todo el chip si no la mitad, pero no resultó. Si supiera un poco más o tuviera más dedicación podría haber medido como corresponde, pero fuí directo a "recablear" para usar la mitad supuestamente sana, no funcionó, mala suerte, algún día conseguiré el repuesto, le conecté al poncho educativo el adaptador.


        Edu-ciaa-nxp en todo su esplendor
        Edu-ciaa-nxp en todo su esplendor

         

        En el display las dos temperaturas internas y la externa en la primera linea, en la segunda las temperaturas de referencia y la velocidad, tapada, dice 0. Y luego un "#" que alterna con "@" como heartbeat.


        A la izquierda el sensor externo, atras el switch.



        La fuente...

         
        ...calienta más que el resto, cambié uno de los sensores de lugar, lamentablemente no tomé nota de cuál, luego usaré el "peso" para darle mayor o menor participación en las decisiones.



        Temperatura ambiental


        El display serial tenía que mostrar en la pantallita los valores y dejar pasar los mensajes ida y vuelta y ahora se le agrega incorporar su propia medición. Esto lo resolví agregando un sensor de temperatura a la EDU-CIAA-NXP y actualizando el mensaje JSON recibido desde el controlador.

         

         

        La información y el formato de los mensajes


        Aquí cometí varios errores. Para comenzar debí haber generado JSON, pues tiene una fácil lectura para el humano y es inmediatamente integrable a cualquier aplicación, más que espero que el 99.99% de los mensajes sean leidos por un proceso, no por humanos.

        Otro, siguiendo en la linea de centrada en el usuario, no estoy publicando en cada mensaje la parametría y tengo que pedirla explícitamente. Esto me complica asociar los valores medidos con esta parametría.

        En términos de ancho de banda, más que tengo un solo sensor y es por UART que es como una red interna, no me hace diferencia. Esto no significa que de cada mensaje almacene todos los datos, pero esa decisión la hago al momento de almacenar, no de emitir.

        Dado que no quiero estar abriendo y cerrando el switch para reprogramar, debo ingeniármelas con lo que hay adentro. Recordemos: hice un sistema parametrizable justamente para evitar reprogramar, hasta que haya una nueva versión, debo lidiar externamente con todo.

        Una posibilidad es sumarle la tarea al display serial: como ya tiene que tomar el mensaje que viene y agregarle su propia medición, puede tambien cuando ve pasar la parametría tanto al comienzo como ante cualquier cambio, tomar nota y agregarla.

        Tambien puede hacer la conversión a JSON.

        La otra es del lado de la compu, que tiene la ventaja de ser mucho más fácil... recalculando... cuál es la gracia de hacerlo fácil...?

        Listo, va todo a la edu-ciaa y luego que la app decida qué y cómo almacenar.


        +----------+             +--------+
        | sensores |             | sensor |
        +-----+----+             +---+----+
              |                      |
        +-----v--+              +----v-----+          +-----+
        |        |  medición +  |          | +        |     |
        | Switch |  parametría  | edu-ciaa | medición | app |
        |        +-------------->          +---------->     |
        +--------+              +----+-----+          +-----+
                                     |
                                 +---v-----+
                                 | display |
                                 +---------+

         

        Lo que había implementado es una FSM que va buscando los mensajes de reporte y al hallarlos extrae la información y la va pasando caracter a caracter al display.

        Voy a tener que cambiar de enfoque, leer por lineas. El problema es que se me bloquea en la lectura, debe ser por ello que la sAPI no lo implementa.

        Una manera de lidiar con esto sería pasar a FreeRTOS, una experiencia interesante pero quiero hacerlo así.

        Lo que hice finalmente es una sencilla FSM que busca '{'. Si no la encuentra imprime en USB. Si la encuentra, comienza a copiar en un buffer hasta que encuentra '}'.


        En ese momento, corre este lindo:


        sscanf(buffer,"{ \"T1\" : \"%f\", \"H1\" : \"%f\", \"T2\" : \"%f\", \"H2\" : \"%f\", \"CS\" : \"%d\", \"R1\" : \"%d\", \"R2\" : \"%d\", \"W1\" : \"%d\", \"W2\" : \"%d\", \"D2\" : \"%d\", \"D1\" : \"%d\", \"D0\" : \"%d\", \"I1\" : \"%d\", \"I2\" : \"%d\", \"I3\" : \"%d\", \"MS\" : \"%d\", \"SC\" : \"%d\", \"DE\" : \"%d\", \"SI\" : \"%d\"}", &t1, &h1, &t2, &h2, &cs, &temp_ref_1, &temp_ref_2, &weight_1, &weight_2, &decrement_2, &decrement_1, &decrement_0, &increment_1, &increment_2, &increment_3, &min_speed, &scale, &delta_eq, &sample_interval);

         

        lee la temperatura ambiental:

         
        float tmp_t3;
        float tmp_h3;
        if( dht11Read(&tmp_h3, &tmp_t3) ) {
           t3 = tmp_t3;
           h3 = tmp_h3;
        } else {
           t3 = -1;
           h3 = -1;
        }

         

        y luego imprime en USB:


        sprintf(buffer,"{ \"CS\" : \"%d\", \"T1\" : \"%.2f\", \"H1\" : \"%.2f\", \"T2\" : \"%.2f\", \"H2\" : \"%.2f\", \"T3\" : \"%.2f\", \"H3\" : \"%.2f\", \"R1\" : \"%d\", \"R2\" : \"%d\", \"R3\" : \"%d\", \"W1\" : \"%d\", \"W2\" : \"%d\", \"W3\" : \"%d\", \"D2\" : \"%d\", \"D1\" : \"%d\", \"D0\" : \"%d\", \"I1\" : \"%d\", \"I2\" : \"%d\", \"I3\" : \"%d\", \"MS\" : \"%d\", \"SC\" : \"%d\", \"DE\" : \"%d\", \"SI\" : \"%d\"}", cs, t1, h1, t2, h2, t3, h3, temp_ref_1, temp_ref_2, temp_ref_3, weight_1, weight_2,weight_3, decrement_2, decrement_1, decrement_0, increment_1, increment_2, increment_3, min_speed, scale, delta_eq, sample_interval);

        uartWriteString( UART_USB, buffer);

         

         y display:

         

        sprintf(lcdOut0, "%.1f %.1f %.1f\0", t1,t2,t3);
        sprintf(lcdOut1, "%d   %d   %d   %c\0",  temp_ref_1, temp_ref_2, cs);
        lcdClearAndHome();
        lcdSendStringRaw(lcdOut0);
        lcdGoToXY( 0, 1 );
        lcdSendStringRaw(lcdOut1);

         

        El código actual esta en github: controlador y display



        Salida JSON
        Salida JSON












         

         





        Algunas mediciones del regulador de velocidad de ventilación del switch

        $
        0
        0

        Estas son las mediciones sobre el comportamiento del regulador de ventilación que he incorporado a un switch.

         

        Para comenzar, lo dejé prendido varios días y seguí a ojo el comportamiento apagándolo de noche, luego prendido permanente y finalmente le pasé las conexiones que tenía en el hub.

        Mientras, hice adaptaciones al Display Serial para fundamentalmente incorporar la medición de temperatura ambiental y poder realizar las mediciones finales.

         

        Ruido

         

        2AM, todo cerrado, con un programa medidor en el celular, es lo que hay...

        Puse al máximo y lo dejé bajar:

         



        Con paciencia tomé nota de los valores en la siguiente tabla:


        +-----+------+
        | 245 | 71.6 |
        +-----+------+
        | 234 | 71.0 |
        +-----+------+
        | 224 | 70.4 |
        +-----+------+
        | 214 | 70.0 |
        +-----+------+
        | 204 | 69.7 |
        +-----+------+
        | 194 | 69.3 |
        +-----+------+
        | 184 | 68.8 |
        +-----+------+
        | 174 | 67.8 |
        +-----+------+
        | 164 | 68.1 |
        +-----+------+
        | 154 | 67.3 |
        +-----+------+
        | 144 | 67.8 |
        +-----+------+
        | 134 | 68.2 |
        +-----+------+
        | 124 | 67.9 |
        +-----+------+
        | 114 | 66.0 |
        +-----+------+
        | 104 | 63.3 |
        +-----+------+
        |  94 | 63.8 |
        +-----+------+
        |  84 | 63.0 |
        +-----+------+
        |   0 | 44.0 |
        +-----+------+

         

        Subjetivamente no hay dudas de que va bajando el ruido con la velocidad, pero si mirás la tabla hay inconsistencias. Puede ser por la falta de coordinación mía, puede ser que esté muy cerca el celular de la fuente de ruido, se puede estar colando ruido del exterior al que no estoy prestando atención, puede haber algún componente del ruido muy agudo para mí pero que esté siendo medido.


        Vibración

         

        Entiendo que el ruido debe tener al menos tres componentes:

        La hélice contra el aire. Esto depende sin duda de la velocidad y la calidad, la última fuera de mi control.

        He leido por ahí una mala elección de frecuencia del PWM podría generar más ruido, algún día lo investigaré. De todos modos la librería de arduino no ofrece cambiarla, no sé por que perverso motivo.

        La vibración, resultado de la calidad. Intuyo que distintas velocidades deben producir distintas vibraciones, no necesariamente relacionadas, deben haber algunas velocidades óptimas, para eso hay que ser ingeniero y saber física.

        El programa medidor del celular o el sensor mismo no es lo suficientemente sensible, pero mis manos dicen que vibra y bastante, sin números.


         

        Temperatura y velocidad en el tiempo

         

        Para esto he usado una EDU-CIAA-NXP que recibe los mensajes y le agrega la temperatura exterior y la configuracion, según detallo en https://seguridad-agile.blogspot.com/2020/10/adaptador-usb-rs-232-con-display-usando.html y https://seguridad-agile.blogspot.com/2020/10/modificaciones-al-display-serial.html


        Pensé en usar cacti, pues hace dos trabajos, Javier A. lo usaba, pero cuando ví que además de aprender a usarlo y configurarlo había que instalar un mysql, miré fijo y noté que decía "The Complete RRDTool-based Graphing Solution" me pareció mejor ir directo a rrdtool.

        Esa noche no podía dormir, así que me machaqué el cerebro contra el teclado y pasé de no entender absolutamente nada a estar en condiciones de darte un introducción muy sencilla, espero que sea correcta, es como un hello world.

         

        Instalación


        sudo apt install rddtool

         

        Configuración


        La idea es que rddtool guarda los mensajes en su propia base, que es un buffer circular y pretende que le des datos con regularidad en el tiempo.


          rrdtool create "$DB" --step 60s \
          DS:temp1:GAUGE:120:0:60 \
          DS:temp2:GAUGE:120:0:60 \
          DS:temp3:GAUGE:120:0:60 \
          DS:speed:GAUGE:120:0:255 \
          DS:ref:GAUGE:120:0:60 \
          RRA:LAST:0.5:1:864000


        El step es la expectativa de llegada en el tiempo de los mensajes. Cada DS debe ser un DataSet, ponele, tiene un nombre, un tipo, para este caso DERIVE o GAUGE.

        Luego heartbeat, tiempo para meter un UNKNOWN. Luego valor mínimo y máximo. Ojo con esos dos valores, si te equivocás, no ves nada pues le pone UNKNOWN.

        Luego viene el RRA, que descripción del comportamiento con respecto a como almacenar los valores, por ejemplo LAST es el valor tal como viene pero podrían guardarse el promedio de los últimos N valores recibidos, como para eliminar ruido.

        El resto no lo he explorado aún. Entiendo que se pueden poner varios RRA.

         

        Insertar


        Luego le vas dando mensajes.

        Los lees de algún modo y los insertás así, las variables se llaman igual que los DS por disciplina, no hace falta que coincidan, son variables de bash:

        rrdtool update "$DB""N:$temp1:$temp2:$temp3:$speed:$ref"

         

        Graficando


        y periódicamente podés graficar la información que ya tengas, encontré un RRDTool Wizard muy bonito, ojo que no le pone bien el nombre de la rrd.

          rrdtool graph 'graph.png' \
          --width '800' \
          --height '300' \
          --start end-1h \
          'DEF:t1=temp.rrd:temp1:LAST' \
          'DEF:t2=temp.rrd:temp2:LAST' \
          'DEF:t3=temp.rrd:temp3:LAST' \
          'DEF:sp=temp.rrd:speed:LAST' \
          'DEF:ref=temp.rrd:ref:LAST' \
          'LINE3:ref#FF0000' \
          'LINE2:t2#00f7ff' \
          'LINE2:t3#00FF00' \
          'LINE3:sp#FF00FF' \
          'LINE2:t1#0000FF'


        El orden de los LINEx importa pues va pisando.


        Graficando temperaturas
        Graficando temperaturas

        Verde es temperatura ambiente

        Rojo temperatura límite

        Magenta es la velocidad del cooler

        Azul y cyan las temperaturas internas


        El programa completo de update


        stty -F "$DEV" ispeed "$BAUDRATE" ospeed "$BAUDRATE" \
              cread icanon time 10
        exec 99<>$DEV
        while true;  do
         read MSG <&99
         #echo $MSG
         MSG=$( echo $MSG | tr "{:,}\"""     " )
         read _label_cs speed \
              _label_t1 temp1 \
              _label_h1  _h1 \
              _label_t2 temp2 \
              _label_h2 _h2 \
              _label_t3 temp3 \
              _label_h3 _h3 \
              _label_r1 ref \
              _tail  < <(echo $MSG)
         #echo "t1: $temp1 t2: $temp2 t3: $temp3 speed: $speed ref: $ref"
         rrdtool update "$DB""N:$temp1:$temp2:$temp3:$speed:$ref"
        done


        Te recuerdo que mis mensajes son así:


        { "CS" : "0", "T1" : "40.10", "H1" : "13.00", "T2" : "40.50", "H2" : "13.00", "T3" : "20.70", "H3" : "51.00", "R1" : "48", "R2" : "48", "R3" : "0", "W1" : "5", "W2" : "5", "W3" : "0", "D2" : "20", "D1" : "10", "D0" : "0", "I1" : "10", "I2" : "20", "I3" : "50", "MS" : "84", "SC" : "1", "DE" : "2", "SI" : "15000"}

        y tr "{:,}\"""     " los convierten en 


        CS     0    T1     42.70    H1     14.00    T2     47.90    H2     17.00    T3     23.00    H3     48.00    R1     48    R2     48    R3     0    W1     5    W2     5    W3     0    D2     20    D1     10    D0     0    I1     10    I2     20    I3     50    MS     84    SC     1    DE     2    SI     15000


        y el read ... < <(echo $MSG) toma las variables.

         

        MQTT


        Tambien hice un scriptcito para que mande los mensajes con MQTT

        BAUDRATE="19200"
        DEV="/dev/ttyUSB2"
        TOPIC="/switch/data"
        BROKER_IP="127.0.0.1"
        BROKER_IP="192.168.1.134"

        stty -F "$DEV" ispeed "$BAUDRATE" ospeed "$BAUDRATE" cread icanon time 10
        exec 99<>$DEV
        while true;  do
          read MSG <&99
          echo "$MSG";
          mosquitto_pub -m "$MSG" -t "$TOPIC" -h "$BROKER_IP"
        done

        Todo el código en https://github.com/cpantel/CoolerControl



        PYNQ con dos seriales en FPGA

        $
        0
        0

        Introducción

         

        Mis requistos vienen a ser algo así como:

        Implementar el hardware necesario en la FPGA tal que un programa ejecutándose en el procesador pueda comunicarse via serial. Los caracteres recibidos serán enviados por un acelerador criptográfico y los por éste generados devueltos por la conexión serial.

        Debe haber además otro puerto serial donde el acelerado pueda escribir y una salida VGA con un patrón de ajuste.

        Para ello utilizaré como hardware un SOC ZYNQ-7020, en particular una placa PYNQ, que tiene dos procesadores y una FPGA y como SDK Xilinx Vivado 2018.2. Mi primer contacto con esta placa fue https://seguridad-agile.blogspot.com/2019/04/python-productivity-for-zynq.html y en realidad no la estoy usadon como PYNQ propiamente dicha sino como un ZYNQ 7020. Me hubiese gustado usar al Parallella pero ando con el tiempo muy justo y aunque despues al leer lo que sigue te parezca que la tengo re clara y una gran soltura con el tema, la verdad es que me cuesta horrores y no quiero la dificultad adicional de lidiar con una placa sin soporte.

        Esta experiencia la segmentaré en varias entregas:

        Primera entrega, son dos proyectos independientes, para ejercitar usar IPs existentes:

        • Serial, que el programa usara para hacer eco simple.
        • Doble serial, el programa pasará caracteres de uno a otro.


        Siguientes entregas, veremos cuántas y si se agrupan o no:

        • VGA, no hay IP,  tengo que portar lo que ya hice en otro lado.
        • Acelerador, recibe una clave, luego cifra cada caracter.
        • Integración, todo lo anterior funcionando pero con el segundo serial desconectado.

        Y finalmente la razón de todo esto:

        • Ataque, el acelerador publicará en el puerto serial la clave o el texto plano y eventualmente integraré esa señal dentro del VGA.



        La idea de fonto está en el estudio de un libro y me baso en los ejercicios del libro The Zynq Book, tal cual lo practicado. En aquella ocasión contaba con que quien leyera estuviera seguiendo los pasos del libro en su Vivado, así que fueron solo unas notas de acompañamiento. En esta oportundidad, detallaré mucho más, además mostrando donde hay fallas o limitaciones de la herramienta, ya sean reales o producidas por mi ignorancia.

         

        Estoy asumiendo que algo sabés. Sólo voy a poner las capturas de pantalla indispensables o significativas.

         

        Serial

         

        La idea es generar un BSP con las CPUs, el puerto serial y las conexiones y componentes de soporte.

         

        Cargar la placa a Vivado

        • En el primer ejercicio están las instrucciones para agregar la placa PYNQ a Vivado

        Crear el proyecto

        • Create Project
        • RTL Project
        • Target Language Verilog
        • Skip add files
        • Skip add constraints
        • Default Part
        • Boards
        • Seleccionar pynq-z2
        • Agregar el xdc, que es el mapeo de los pines a la FPGA
        • Y asignarle los nombres rx y tx a algún pin que quieras, yo a ar[0] y ar[1]

         

        xdc
        xdc

         

        Crear el hardware

         

        • IP INTEGRATOR
          • Create Block Design, poner un nombre apropiado
          • Agregar componentes con Add IP
            • ZYNQ7 Processing System
            • Run Block Automation

        Block Automation
        Block Automation

         

            • Uartlite 
            • Run Connection Automation
              • te va a agregar lo que haga falta para que funcione
              • pero sólo pedile S_AXI, basta de automation

         

        Connection Automation
        Connection Automation

         

         

              •  Te queda así, podés mover las cosas de lugar si querés

        Los componentes interconectados
        Los componentes interconectados

         

         

         

          •  Conectar al mundo exterior
            • Hacele click UART en axi_uartlite_0 para que se descomponga en rt y tx

         

        Detalle de puerto UART
        Detalle de puerto UART

            • Con botón derecho en rx y tx, haceles "make external"
            • Probablemente les ponga nombre rx_0 y tx_0
            • Corregí en el xdc
          • File -> Save Block Design
          • Tools -> Validate Design
          • Windows -> Sources -> botón derecho -> Create HDL Wrapper

         

        HDL Wrapper
        HDL Wrapper

         

         

          • Y finalmente vamos a sintetizar, implementar y generar el bitstream como siempre
            • IMPLEMENTATION -> Generate Bitstream 
              • Dispara todo el proceso
            • Mejor andate lejos de la máquina pues esto consume un montón de CPU y si le dás al Candy Crush te podés quedar sin vidas.
          • Podés "Open Implemented Design para ver los dibujitos"

         

        Implemented Design
        Implemented Design


        ¿Cuál es la situación actual?

         

        Tenemos un bitstream que define un puerto serial, lo conecta por un lado a dos pines del mundo exterior y por el otro, vía un AXI Interconnect al PS (Processing System).

         

        Ahora vamos a por el sofware


        • File -> Export -> Export Hardware -> include bitstream
        • File -> Launch SDK
          • Esto abre una nueva ventana, es otro programa
        • File-> new -> Application Project
          • Acá podrías elegir freertos, linux o standalone
            • standalone
          • template -> empty
          • Vas a tener system.mss
          • te ofrece un montón de "Import Examples"
            • para axi_uartlite_0
              • low level example
          • te recomiendo que veas todos los de uart
          • los que tienen interrupciones tienen fallas de inclusión que no quiero diagnosticar
          • En este punto podés hacer múltiples proyectos de software sobre el mismo hardware

         

        El primer programa, echo


        Voy a usar el ejemplo low level como base, poníendole en el main():

         

            u8 data;;
            xil_printf("start\r\n");
            for(data= 32; data < 60; ++data) {
               XUartLite_SendByte(UARTLITE_BASEADDR, data);
            }
            while (1) {
                data =  XUartLite_RecvByte(UARTLITE_BASEADDR);
                XUartLite_SendByte(UARTLITE_BASEADDR, data);
                xil_printf("Echoing %d\r\n", data);
            }

        Para ver los xil_printf hay que conectarse a la terminal:


        Abrir diálogo con el más verde
        Abrir diálogo con el más verde

        Elegir puerto
        Elegir puerto

        Listo
        Listo


        Pero antes, hay que mandar el bitstream, como siempre desde Vivado.


        • PROGRAM AND DEBUG
          • Open Hardware Manager
            • Open Target
              • Auto connect
            • Program Device


        Ahora tenemos el hardware listo, mientras no reiniciemos la placa, no hace falta reprogramar, volvamos al SDK.


        Elegir el proyecto -> botón derecho -> Run As -> Launch on HW (GDB)

         

        xil_printf ok
        xil_printf ok


        Si tenés un osciloscopio, conectá TX:

         

        Serial en osciloscopio
        Serial en osciloscopio

         

        Conectando a computadora vía un UART y con una leve modificación, confirmamos que está funcionando ok y a 9600

         

        Serial Ok
        Serial Ok

         

        Doble serial

         

        Es lo mismo que lo de antes pero con dos seriales, no? No sé, primero tengo que ver si uartlite soporta cambiar baudrate... no. Queda hardcodeada en el, valga la redundancia, hardware. Por eso debe ser "lite". La segunda la voy a poner a 115200 por las dudas y luego investigaré si sirve o tengo que cambiar por algo más veloz.


        Aunque sea tedioso, voy a rehacer todo desde cero, para practicar.

        • crear proyecto
        • agregar y ajustar xdc 
        • agregar zynq
        • block automation
        • agregar y configurar uarts
        • connection automation parcial
        • save block diagram
        • validate
        • agregar hdl wrapper
        • generar bitstream

        Teniendo alguna uartlite, doble click hace el truco:

         

        Seleccionar baudrate
        Seleccionar baudrate

         

        Cuando ya pusiste todo el hardware queda así:

         

        Doble UART
        Doble UART

        El software debería ser igual, sólo que ahora tengo dos dispositivos.

         

        Implemented Design
        Implemented Design 

         

        Hay un apenas perceptible aumento de uso de la FPGA, podríamos meter decenas de uartlites, quizás un centener si tuvieramos suficientes pines.
         

        Sigamos la carrera...

        • export hardware
        • launch SDK
        • create project
        • import example
        • modify
        • burn
        • run as


        ups, me pasé, tengo que volver a import example, me ofrece un ejemplo para cada uartlite, me imagino que cada uno tiene sus constantes que lo diferencian... no, son iguales.

        Veamos la memoria dónde están:


        Direcciones
        Direcciones

        Al comienzo de xuartlite_low_level_example.c hay una definición interesante, si te parás encima cuando es usada más abajo en main() te dice el valor:

         

        Dirección UART 0
        Dirección UART 0

         

        La segunda UART dice ser 0x42c10000, perfecto, sólo es cuestion de manosear un poco el código:

         

        #define UARTLITE_BASEADDR_0       XPAR_UARTLITE_0_BASEADDR
        #define UARTLITE_BASEADDR_1       XPAR_UARTLITE_1_BASEADDR


            u8 data ='0';
            xil_printf("start\r\n");
            XUartLite_SendByte(UARTLITE_BASEADDR_0, data);
            data = '1';
            XUartLite_SendByte(UARTLITE_BASEADDR_1, data);


            while (1) {
                data =  XUartLite_RecvByte(UARTLITE_BASEADDR_0);
                XUartLite_SendByte(UARTLITE_BASEADDR_0, data);
                XUartLite_SendByte(UARTLITE_BASEADDR_1, data);
                xil_printf("Echoing and bridging %c\r\n", data);
            }


        Para que se vea mejor en el osciloscopio, triple eco:


        Código y uart_0 a 9600
        Código y eco a uart_0 a 9600


        Se emite cero, cero más uno, cero más dos


        bridging triple a uart_1 a 115200
        bridging triple a uart_1 a 115200



        Proyecto funcionando
        Proyecto funcionando



        Anotados los componentes
        Anotados los componentes

        Amarillo: el adaptador usb-uart/ttl que se controla desde la terminal a 9600.

        Rojo: los pines de conexión de uart_1 a 115200 conectados al osciloscopio.

        Verde: los pines de conexión de uart_0 conectados a usb-uart/ttl.

        Naranja: la terminal de la SDK, alimentación, programación, debugger...

        Azul: tierra para el osciloscopio.


        Conclusiones

        Es muy sencillo agregar uarts, entre la herramienta y los ejemplos queda poco por hacer.


         

         



         


         





        PYNQ con acelerador

        $
        0
        0

        En pocas palabras para no repetir lo dicho antes:

         

        Necesito hacer un acelerador criptográfico en la PL (Programmable Logic) de un Zynq-7020 (PYNQ en particular) accesible desde un programa que se ejecute en el PS (Processing System) o como todos le conocemos, CPU.

        Ya había logrado usar IP (la forma en que llaman a los componentes en este mundo), en particular dos UARTs. Ahora quiero hacer mi propia IP y que haga un cirfrado sencillo.

        No voy a apoyarme en una experiencia anterior con Parallella sino en los ejercicios del libro comentado que he estudiado.

         

        Estos proyectos están a la par de los dos proyectos "serial" y "dual-serial"  y también lo construiré de cero sin ninguna dependencia cruzada para evitar complicaciones, apuntando a las siguientes hitos:


        • Acelerador echo: que me devuelva lo que escribo.
        • Acelerador xor: que calcule el xor de dos argumentos en un tercero.

         

         

        Acelerador con eco 


        Manos a la obra, esta parte es común a todos los proyectos anteriores:

        • Create Project
        • RTL Project
        • Target Language Verilog
        • Skip add files
        • Skip add constraints
        • Default Part
        • Boards
        • Seleccionar pynq-z2
        • Agregar el xdc, que es el mapeo de los pines a la FPGA

         

        Acá empieza la diferencia, crear el IP

        • Tools -> Create and Package New IP
        • Create a new AXI4 peripheral
        • Name, version, etc...
        • Next Steps -> Edit IP
        • Finish

         

        Ahora se pone delicado, hay que buscar el archivo que te creó y al final hay un comentario que dice "Add user logic here", nada por ahora.


        Edición del acelerador
        Edición del acelerador




        Más arriba, buscando "slv_reg0" encontras los nombres de los registros para comunicarte con la CPU. Son todos de 32 bits.

        Voy a usar

        • slv_reg0 como clave
        • slv_reg1 como input
        • slv_reg2 como output 
        • slv_reg3 como contador, ya que está...

         


        Lo primero que tengo que hacer es que me funcione como memoria, o sea, escribo algo y luego lo vuelvo a leer. Si está ok, estamos encaminados, sigamos entonces.

        Hay que ir al tab:

        • Package IP - accelerator
         Abajo de todo va a estar

        • Re-Package IP

         

        Listo, cerró, volvemos al proyecto original.

        • Create Block Design
        • Add IP
        • Zynq
        • run block automation 
        • Add IP
        • Buscar el nombre, en este caso accelerator
        • run connection automation
        • Save Block Design
        • Tools -> Validate
        • Sources -> Design Sources -> tu proyecto -> botón derecho -> Create HDL Wrapper
        • Generate bitstream
        • File -> Export Hardware
          • include bitstream
        • File -> Launch SDK

         

        Lo que queda es puro software

        • File -> New -> Application Project
        • Templates -> Empty

         

        Para encontrar la dirección del acelerador, hay que mirar system.hdf:


        Dirección del acelerador
        Dirección del acelerador

         

        Con este sencillo programa pruebo que funciona, lo que escribo lo puedo volver a leer:

         

        #include <stdio.h>
        #include "xil_printf.h"
        #include "xil_io.h"

        #define BaseAddress    0x43c00000
        #define REG_KEY        0
        #define REG_CLEARTEXT  4
        #define REG_CIPHERTEXT 8


        int main() {
          u32 key;
          u32 clearText;
          u32 cipherText;

          xil_printf("Accelerator\n\r");
          for (u32 i=0; i< 255; ++i) {
            key        = Xil_In32(BaseAddress + REG_KEY);
            clearText  = Xil_In32(BaseAddress + REG_CLEARTEXT);
            cipherText = Xil_In32(BaseAddress + REG_CIPHERTEXT);

            xil_printf("i          : %d\n", i );
            xil_printf("key        : %d\n", key );
            xil_printf("clear text : %d\n", clearText );
            xil_printf("cipher text: %d\n", cipherText );

            Xil_Out32(BaseAddress + REG_KEY, i);
            Xil_Out32(BaseAddress + REG_CLEARTEXT, i);
            Xil_Out32(BaseAddress + REG_CIPHERTEXT, i);
            sleep(5);
          }
          return 0;
        }


        La ejecución en la terminal:



        echo Ok
        echo Ok
         

        Acelerador XOR

         

        Recorrí un tortuoso camino, con muchas pruebas fallidas. Cuando finalmente me rendí y busqué en internet, lo primero que hallé fueron estos minutos de 4 a 8, que tampoco funcionó, hasta que me dí cuenta de mi error:

        #define BaseAddress    0x43c0000


        ¿Lo viste? Me quería matar, bueno, no importa, pensé bastante, el acelerador funciona y recorrí el camino de editar IP y reintegrarlo hasta el aburrimiento. Prometo que voy a hacer un machete de cómo hacer esto, pero despues, en diciembre que ahora estoy hasta las manos.

         

        Nota del futuro: el paso anterior de echo también tenía ese problema, pero no se manifestó pues la dirección errónea no coincidió con nada que se pudiera romper. Lo corregí y dió ok.


        El código Verilog, en verde mis agregados y modificaciones:


        Código Verilog xor
        Código Verilog xor

        Los dos bloques calculan tanto el xor como el incremento del contador, cuyos registros están conectados a los Out que permanentemente están conectados a los registros 2 y 3. No me gusta mucho pues claramente el contador está contando el clock, no la cantidad de pedidos de cifrado y el exor se hace en cada ciclo de clock, es demasiado veloz, qué pasa si quiero hacer un cifrado de verdad que no llegue a hacerse en tal breve intervalo o si quiero hacer el ataque pensado? Bueno, eso esa el próxima entrega o la siguiente...

         

        El programa tal como está ahora:


        #include <stdio.h>
        #include "xil_printf.h"
        #include "xil_io.h"

        #define BaseAddress    0x43c00000
        #define REG_KEY        0
        #define REG_CLEARTEXT  4
        #define REG_CIPHERTEXT 8
        #define REG_COUNT      12

        int main() {
          u32 key;
          u32 clearText;
          u32 cipherText;
          u32 count;

          xil_printf("Accelerator\n\r");

          Xil_Out32(BaseAddress + REG_KEY, 3);

          for (u32 i=0; i< 255; ++i) {
                Xil_Out32(BaseAddress + REG_CLEARTEXT, i);

            key        = Xil_In32(BaseAddress + REG_KEY);
            clearText  = Xil_In32(BaseAddress + REG_CLEARTEXT);
            cipherText = Xil_In32(BaseAddress + REG_CIPHERTEXT);
            count      = Xil_In32(BaseAddress + REG_COUNT);

            xil_printf("i          : 0x%08x\n", i );
            xil_printf("key        : 0x%08x\n", key );
            xil_printf("clear text : 0x%08x\n", clearText );
            xil_printf("cipher text: 0x%08x\n", cipherText );
            xil_printf("count      : 0x%08x\n", count );

            sleep(5);
          }
          return 0;
        }

         

        Y la salida, comparando con lo esperado en la calculadora:


        Ejecución Ok
        Ejecución Ok


         



        PYNQ con acelerador y serial

        $
        0
        0

        Si venís leyendo como generé el hardware y software para tener que la CPU del zynq-7020 de la PYNQ tuviera una terminal serial primero y luego un acelerador criptográfico de juguete luego y más si leiste la intro, no te sorprenderá que ahora quiera mezclar la cosas.

        En este paso lo que haré será dejar el sistema, llamemoslo "legítimo" funcionando. Esto es, desde la PC me comunico por serial con la PYNQ que hace el cifrado y me lo devuelve. Vendría a ser un acelerador criptográfico remoto.

         

        Para darle más sabor, en lugar de hacer todo a la vez, voy a agregar primero el puerto serial y luego el acelerador, pero en lugar de ir haciendo proyectos separados, los voy a ir modificando asi vemos como cambiar un proyecto. Es más, en la primera versión ya va hacer el cifrado, pero por software.


        Creo el proyecto y lo pongo una uartlite, eso está suficientemente explicado o al menos relatado en las entradas anteriores pero me gusta escribir, la repetición forma parte del aprendizaje.



        El serial


        • File -> Project -> New
        • IP INTEGRATOR -> Create Block Design
        • Add IP -> ZYNQ -> Run Block Automation
        • Add IP -> Uartlite -> Run Connection Automation -> S_AXI
        • axi_uartlite_0 -> UART -> expand
        • rx -> botón derecho -> make external (tomar nota del nombre del pin)
        • tx -> botón derecho -> make external (tomar nota del nombre del pin)
        • Sources -> + -> Add or create constraints -> pynq-z2_v1.0.xdc
        • Usar los nombres anotados en el xdc

         
        ##Arduino Digital I/O 
         
        set_property -dict { PACKAGE_PIN T14   IOSTANDARD LVCMOS33 } [get_ports { tx_0 }]; #IO_L5P_T0_34 Sch=ar[0]
        set_property -dict { PACKAGE_PIN U12   IOSTANDARD LVCMOS33 } [get_ports { rx_0 }]; #IO_L2N_T0_34 Sch=ar[1]


        • File -> Save Block Design
        • Tools -> Validate
        • Sources -> Design Sources -> remote accelerator -> botón derecho -> Create HDL Wrapper
        • PROGRAM AND DEBUG -> Generate Bitstream
        • File -> Export -> Export Hardware -> include bitstream
        • File -> Launch SDK
        • File -> New -> Application Project
        • Templates -> Empty Application
        • Project Explorer -> remote_accelerator -> src -> new -> file -> main.c

        A main.c le pegamos el código de lo hecho en una terminal serial y le agregamos la aceleración por software, o sea, data ^= 3;

         

        Aceleración por software
        Aceleración por software

         


        Si te preguntás de dónde sale XPAR_UARTLITE_0_BASEADDR, es de  

        /remote_accelerator_bsp/ps7_cortexa9_0/include/xparameters.h

        y debe coincidir con axi_uartlite_0 de system.hdf


        Volvés un momento a Vivado

        • PROGRAM AND DEBUG
          • Open Hardware Manager
            • Open Target
            • Auto Connect
          • Program Device

         

        Regresás a SDK 

        • Project Explorer -> botón derecho -> Run As -> Launch on Hardware (GDB)

         

        Abrís una terminal a un adaptador USB-UART/TTL que esté correctamente conectado a los puertos Arduino de la PYNQ, tipeas "abcd " y te va respondiendo:

         

        Aceleración por software
        Aceleración por software


        Lista una parte, es un buen momento para cerrar todo y versionar.

         

        El acelerador

         

        Ahora tendría que abrir el diseño del bloque (Open Block Design) para agregar el acelerador, pero es parte de otro proyecto, no se vé desde acá, antes hay que descubrir como traspasarlo.


        Settings -> IP -> Repository -> buscar la carpeta "IP Repo"

         

        Repositorio de usuario agregado
        Repositorio de usuario agregado

        Luego arrastrás accelerator_xor al Diagrama, "Run Connection Automation", es casi vergonzoso lo fácil que resulta.



        Diagrama completo
        Diagrama completo

        • File -> Save Block Design
        • Tools -> Validate Design
        • PROGRAM AND DEBUG -> Generate Bitstream
        • File -> Export Hardware -> include bitstream
        • File -> Launch SDK


        Si miramos el system.hdf, veremos ahora dos direcciones para nuestros dispositivos:

         

        Los dos dispositivos
        Los dos dispositivos


        El código final
        El código final


        La interacción con el acelerador:

         

        Interacción con acelerador
        Interacción con acelerador



         a  b  c  d     caracter entrada
        61 62 63 64     código ascii entrada

        05 05 05 05     exor

        64 67 66 61
             código ascii salida
         d  g  f  a
             caracter salida


         0  1  2  3
             caracter entrada
        30 31 32 33
             código ascii entrada

        05 05 05 05     exor

        35 34 37 36
             código ascii salida
         5  4  7  6    
        caracter salida

         

         Y las cuentas comprobadas:

         

        La cuentas
        La cuentas

         

         

        Notarás que aunque de alguna manera está haciendo cifrado por bloques, como puse 0x05050505 como key es como si hiciera cifrado por caracteres.

        PYNQ acelerador criptográfico con leak

        $
        0
        0

        Recapitulemos:


        Primero había visto como agregar un puerto serial y usarlo desde la CPU, luego un sencillo acelerador criptográfico por hardware y finalmente, que los mensajes enviados por el puerto serial fueran cifrados por el acelerador.


        Ha llegado el momento de hacer el ataque, que consiste en que el acelerador criptrográfico divulgue la clave o el mensaje no cifrado por algún canal alternativo.


        Para ello, primero tengo que aprender a usar un IP en mi IP, esto es un componte existente en mi componente. Esto lo voy a hacer en un proyecto aparte, luego regresaré al proyecto que ya está funcionando y aplicaré lo aprendido.

         

        IP en IP

         

        Otra vez...


        • File -> New Project ->...
        • Create and Package New IP 
        • Create a new AXI4 peripheral
        • Edit IP
        • IP INTEGRATOR
        • Create Block Design

        Mmm esto es un terrible problema, la uart no es simplemente una uart sino axi-uart, tendría que descifrar cómo usarla, quizás sea mucho más fácil y acorde al espíritu del ejercicio usar una uart verilog pelada.

        Además sólo necesito un transmisor UART y teniendo el código fuente puedo prescindir con sencillez del receptor.


        Fail

         

        UART Transmitter copy paste


        En la excelente página de nandland hay un ejemplo, veamos si puedo hacerlo funcionar, voy a editar el acelerador:


        • IP INTEGRATOR
        • Open Block Design
        • Window -> IP Catalog -> accelerator_xpr_v1.0 ->  Edit in IP Packager
        • Usar otro nombre, por ejemplo "accelerator_xor_bugger_v1_0_project"
        • Source -> + -> Add or Create constraints -> pynq-z2_v1.0.xdc

        ##Arduino Digital I/O 

        set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33}
        [get_ports { tx_1 }]; #IO_L21P_T3_DQS_34 Sch=ar[8]

        • Sources -> + -> Add or Create Design Sources -> Create -> UART_TX.v


        Esta es la interfaz de módulo

        module UART_tx
          #(parameter CLKS_PER_BIT = 870)
          (
           input       i_Clock,
           input       i_Tx_DV,
           input [7:0] i_Tx_Byte,
           output      o_Tx_Active,
           output reg  o_Tx_Serial,
           output      o_Tx_Done
           );

         

        Mirando fijo el código, apuesto que hace falta un high en i_Tx_DV para que inicie la transmisión, llamémoslo "uart_send":


        ¿Qué va en cada port al instanciar?


            UART_tx UART_tx(
              .i_Clock(S_AXI_ACLK),
              .i_Tx_DV(uart_send),
              .i_Tx_Byte(slv_reg1[7:0]),
              .o_Tx_Active(uart_active),
              .o_Tx_Serial(tx_1),
              .o_Tx_Done(uart_done)
            );


        S_AXI_ACLK: espero que sea de 100Mhz, sino hay que ajustar CLKS_PER_BIT.

        uart_send: tengo que detectar que hay un caracter a enviar.

        slv_reg1[7:0]: los caracteres vienen de a cuatro, por ahora sólo voy a transmitir el último.

        uart_active: puedo ignorarlo y no conectarlo.

        tx_1: va conectado al pin tx_1 declarado en xdc, es por donde fugará la información.

        uart_done: puedo ignorarlo y no conectarlo.

         

        Los que puedo ignorar se debe a que apuesto a que voy a transmitir más rápido que lo que me piden cifrar los caracteres y además como sólo voy a transmitir el menos significativo, con menor frecuencia. Para ser realistas, no puedo transmitir el texto plano a la velocidad que me lo puede llegar a pedir la CPU, tendría que transmitir sólo la clave. En realidad tendría que medir.

        Dejando de lado esas medidas y optimizaciones, me conviene no ignorarlos, pues para implementar la lógica me vienen bárbaro.

        Voy a tener que adaptar el programa para que tome cada caracter como un bloque de cifrado para no tener que implementar la lógica de ir transmitiendo de a cuatro caracteres, para lo cual sí necesitaría active y done.



        Otra vez los mismo...

        • Source -> + -> Add or create constraints -> pynq-z2_v1.0.xdc
        • Tools -> Create and Package New IP
        • Create a new AXI4 peripheral
        • Name, version, etc...
        • Next Steps -> Edit IP
        • Finish
        • Source -> + -> Add or create design sources
          • uart_tx.v
          • ip_repo/leaky_accelerator_1.0/src/
        • Agregué un puerto tx_1 tanto a accelerator_bugged_v1_0 como a accelerator_bugged_v1_0_S00_AXI_inst y en el primero lo conecté al segundo
        • Agregué uart_tx y lo instancié
        • Agregué la lógica y los puertos extra de diagnóstico


        • Package IP - accelerator 
        • Review and Package
          • merge * changes
        • Re-Package IP

        Volviendo al proyecto original

         Create Block Design

        • Add IP
        • Zynq
        • run block automation 
        • Add IP
          • accelerator_bugged
        • Add IP 
          • uartlite
        • run connection automation
          • axi 
        • axi_uart_lite
          • expandir UART
            • externalizar tx_0 y rx_0
        • accelerator_bugged
          • externalizar tx_1
        • Save Block Design
        • Tools -> Validate
        • Sources -> Design Sources -> leaky_accelerator -> botón derecho -> Create HDL Wrapper
        • Generate bitstream
        • File -> Export Hardware
          • include bitstream
        • File -> Launch SDK
        • File -> New -> Application Project
        • ajustar constantes
        • program device
        • run as...


        Falla...

        Cuando arranca tx_1_0 esta high como debe, al enviar el programa pasa a low


        • IP INTEGRATOR -> Open Block Design
        • IP Catalog -> leaky accelerator -> botón derecho -> Edit in IP Packager
        • Package IP
          • Review and Package -> merge changes
          • Re-Package IP
        • Detecta que hubo cambio de IP
        • Report IP Status
        • Re run report
        • Upgrade selected
        • Generate bitstream
        • File -> Export Hardware
          • include bitstream
        • File -> Launch SDK
        • System.mss -> Re-generate BSP Sources


        y así muchas veces hasta que te dás cuenta del error, que es en uart_tx, ¡¡¡no es sólo mío!!! No te puedo ofrecer mostrarte a ver si vos te dás cuenta... probemos:


        module uart_tx
          #(parameter CLKS_PER_BIT = 870)
          (
           input       i_Clock,
           input       i_Tx_DV,
           input [7:0] i_Tx_Byte,
           output      o_Tx_Active,
           output reg  o_Tx_Serial,
           output      o_Tx_Done
           );

        ...

          reg [2:0]    r_SM_Main     = 0;
          reg [7:0]    r_Clock_Count = 0;
          reg [2:0]    r_Bit_Index   = 0;
          reg [7:0]    r_Tx_Data     = 0;
          reg          r_Tx_Done     = 0;
          reg          r_Tx_Active   = 0;

        ....

        // Wait CLKS_PER_BIT-1 clock cycles for start bit to finish
          if (r_Clock_Count < CLKS_PER_BIT-1)
            begin
              r_Clock_Count <= r_Clock_Count + 1;
              r_SM_Main     <= s_TX_START_BIT;
              end
            else

         

        Medio que al seleccionar trozos de código te lo tiré en la cara, ¿no? No, ¿y ahora?


          #(parameter CLKS_PER_BIT = 870)
        ...
           input [7:0] i_Tx_Byte,
        ...
             if (r_Clock_Count < CLKS_PER_BIT-1)

         

         

        ¿Ya lo viste?


          #(parameter CLKS_PER_BIT = 870)
        ...
           input [7:0] i_Tx_Byte,
        ...
             if (r_Clock_Count < CLKS_PER_BIT-1)

         

        Se necesitan más de 8 bits (256 elementos) para contener 870. Supongo que la persona que hizo el código original de nandland, que había puesto 87 pues contaba con un clock de 10Mhz no previó que la gilada iba a tener 100Mhz o más.


        La solución es tan sencilla como


          reg [12:0]   r_Clock_Count = 0;


        No tengo ahora tiempo para documentarlo bien, pero para el diagnóstico de este problema hice un proyecto que usa uart_tx y lo activa al apretar un botón:


        module top(
          input sysclk,
          input btn_send,
          output led_trans_up,
          output led_state,
          output [2:0] ar
        );

        localparam char = 8'b10100011;
        wire trans_up;
        wire state;
        wire [2:0] bus;

        assign bus = ar;
        assign led_state = state;
        assign led_trans_up = trans_up;

        uart_tx uart_tx(
           .i_Clock(sysclk),
           .i_Tx_DV(trans_up),
           .i_Tx_Byte(char),
           .o_Tx_Active(bus[0]),
           .o_Tx_Serial(bus[1]),
           .o_Tx_Done(bus[2])
        );

        debouncer debouncer_enable(.CLK (sysclk),
          .switch_input(btn_send),
          .trans_up (trans_up),
          .state(state)
        );

        endmodule



        UART-Tx en acción en aislación
        UART-Tx en acción en aislación



        En realidad hice una simulación, cuando le bajé a 8 para no tener que esperar 870 ciclos para cada bit y ví que funcionaba, comprendí el error:



        `timescale 1ns/1ps

        module uart_testbench;
          reg simul_Clock;
          reg send;
          wire active;
          wire done;
          wire tx;

        localparam char = 8'b10100011;

          initial begin
            simul_Clock = 1'b0;
            forever simul_Clock = #2.5 ~simul_Clock;
          end

          initial begin
            send = 1'b0;
            #100 send = 1'b1;
            #10 send = 1'b0;
           
          end

          initial begin
            repeat(64) @(negedge simul_Clock);
            $finish;
          end

        uart_tx uart_tx(
           .i_Clock(simul_Clock),
           .i_Tx_DV(send),
           .i_Tx_Byte(char),
           .o_Tx_Active(active),
           .o_Tx_Serial(tx),
           .o_Tx_Done(done)
        );

        endmodule



        Simulación de UART_Tx
        Simulación de UART_Tx

        Se vé bien clarito como el send pone en active, manda el start bit y al finalizar el stop bit y pasa a done.

         

        Cuando comparta el código en github, va a estar en la carpeta uart_tx.


        Finalmente, a la 1:am, a sólo 16 horas de la demo, por que todo esto es para H4CK3D 2020, tras lidiar y renegar con unas señales, logré que:

         

        Entra "aaaa", sale "dddd"
        Entra "aaaa", sale "dddd"



        Tanto en un pin como en un led, la última letra del cleartext
        Tanto en un pin como en un led, la última letra del cleartext


         

        Para ahorrarme trabajo sólo estoy enviando la última letra de cada bloque, quizás en algún momento lo mejore. Tampoco se está mostrando las señales de done y send, igual no eran parte del objetivo, sólo diagnóstico, si el cyan que es active.

        Sólo me faltaría el circuito para tomar esa señal desde el led en lugar del pin.


        Este es el diseño final:


        Diseño final
        Diseño final



        Quedan mucho ajustes por hacer, como el rango de la memoria ocupada, comprobar que los tiempos y consumos estén ok, comprender y mejorar la organización de los proyectos,  y además muchos componentes y recursos por usar, tengo la sensación de haber llegado a un 1% o menos de comprensión/conocimiento/experiencia con este tema, me siento como hace mucho tiempo cuando hice

        10 print "hola"
        20 goto 10
        run

        Viewing all 264 articles
        Browse latest View live