Esta vez pensé en esconder un rastreador GPS en mi bicicleta como medida de precaución. Hay toneladas de dispositivos autónomos en el mercado para rastrear automóviles, carga, bicicletas, equipaje, niños y animales. La gran mayoría de ellos interactúa con el usuario a través de SMS. Las opciones más caras proporcionan la funcionalidad Buscar mi teléfono, pero están vinculadas a un servicio en línea específico.
Idealmente, me gustaría tener control total sobre el rastreador: utilícelo en un modo conveniente sin SMS ni registro. Google superficial me trajo un par de módulos de China, uno de los cuales pedí (tablero de pudín A9G) (~ $ 15).

Este artículo trata sobre cómo hice que Python funcionara en este módulo.
Si el A9G es un análogo de ESP (el fabricante, por cierto, es el mismo), entonces el tablero de pudín en sí es un análogo de la placa NodeMCU, excepto que el tablero de pudín no tiene un convertidor USB-UART incorporado. Pero hay muchas otras cosas interesantes. Especificaciones del fabricante :
- Núcleo de 32 bits (RISC), hasta 312MHz
- GPIO 29x (todos están soldados, todas las interfaces están incluidas en este número)
- relojes y perro guardián
- 1x interfaz USB 1.1 (no la encontré allí, pero copie desde fuera del sitio) y microUSB para poder
- 2x UART (+1 servicio)
- 2x SPI (no probado)
- 3x I2C (no probado)
- 1x SDMMC (con ranura física)
- 2 entradas analógicas (10 bits, posiblemente uno de ellos sea utilizado por controladores de batería de litio)
- Flash de 4Mb
- PSRAM de 4Mb
- ADC (micrófono, existe físicamente en el tablero) y DAC (altavoz, ausente)
- controlador de carga de la batería (no hay batería en sí)
- de hecho, GSM (800, 900, 1800, 1900 MHz) con SMS, voz y GPRS
- GPS conectado a través de UART2 (hay un módulo "A9" sin él)
- Ranura SIM (nanoSIM)
- dos botones (uno restablecer, el otro - inclusión y función programable)
- dos LEDs
El voltaje de operación es 3.3V, el voltaje de entrada es 5-3.8V (dependiendo de la conexión). En general, el módulo tiene todo el hardware necesario para ensamblar un simple dispositivo móvil con un solo botón. Pero a partir de los ejemplos, parece que los chinos lo están comprando para la venta en máquinas tragamonedas o máquinas tragamonedas o algo así. Las alternativas al módulo son los módulos SIM800 bastante populares, que, desafortunadamente, no tienen un SDK en el dominio público (es decir, los módulos se venden como módems AT).
SDK
El módulo viene con un SDK en inglés satisfactorio. Se instala en Ubuntu, pero se prefieren Windows y contenedores. Todo funciona a través de la interfaz gráfica de usuario: ESPtool para este módulo aún no se ha revertido. El firmware en sí está construido por el Makefile. El depurador está presente: antes de congelar, el módulo arroja el seguimiento de la pila en el puerto de servicio. Pero personalmente, no pude traducir las direcciones en líneas de código (gdb informa que las direcciones no corresponden a nada). Es posible que esto se deba a un mal soporte para Linux como tal. En consecuencia, si desea jugar con el módulo, intente hacerlo en Windows (y anule la suscripción en github). De lo contrario, aquí están las instrucciones para Linux. Después de la instalación, debe verificar la corrección de las rutas en .bashrc y eliminar (renombrar) todos los CSDTK/lib/libQt*
: de lo contrario, el flasher (también conocido como depurador) simplemente no se iniciará debido a un conflicto con, probablemente, libQt instalado.

Para la luz intermitente hay una instrucción .
Conexión
Todo es más complicado que en NodeMCU. Los módulos tienen un aspecto similar, pero no hay un chip USB-TTY en la placa de pudín y el microUSB se usa solo para alimentación. En consecuencia, necesitará USB-TTY a 3.3V. Dos son mejores: uno para el puerto de depuración y otro para UART1: el primero se usa para cargar firmware y el segundo se puede usar como terminal normal. Para no arrastrar todos estos mocos a la computadora, compré adicionalmente un divisor USB de 4 puertos con un cable de dos metros y una fuente de alimentación externa (requerida). El costo total de este kit con el módulo en sí será de $ 25-30 (sin fuente de alimentación: uso desde el teléfono).
Firmware
El módulo viene con firmware AT: puede conectarse a un arduino de 3.3V y usarlo como módem a través de UART1. Su firmware está escrito en C. make
crea dos archivos de firmware: uno está cosido durante aproximadamente un minuto, el otro es lo suficientemente rápido. Solo se puede coser uno de estos archivos: la primera vez es grande, las siguientes son pequeñas. En total, durante el proceso de desarrollo, tengo el SDK chino ( coolwatcher
) abierto en el escritorio para administrar el módulo, miniterm como stdio y el editor de código.
API
El contenido de la API refleja la lista anterior y se parece al ESP8266 en sus primeros días: me llevó aproximadamente 3 horas lanzar HelloWorld. Desafortunadamente, el conjunto de funciones disponibles para el usuario es muy limitado: por ejemplo, no hay acceso a la guía telefónica en la tarjeta SIM, información de bajo nivel sobre cómo conectarse a la red celular, etc. La documentación de la API es aún menos completa, por lo que debe confiar en ejemplos (de los cuales hay dos docenas) e incluir archivos. Sin embargo, el módulo puede hacer muchas cosas hasta conexiones SSL: obviamente, el fabricante se centró en las funciones más prioritarias.
Sin embargo, la programación de los microcontroladores chinos a través de la API china debe ser amada. Para todos los demás, el fabricante comenzó a portar micropython a este módulo. Decidí probarme en un proyecto de código abierto y continuar este buen trabajo (enlace al final del artículo).
micropython

Micropython es un proyecto de código abierto que transfiere cPython a microcontroladores. El desarrollo se lleva a cabo en dos direcciones. El primero es el soporte y desarrollo de bibliotecas centrales comunes a todos los microcontroladores que describen el trabajo con los principales tipos de datos en python: objetos, funciones, clases, cadenas, tipos atómicos y más. El segundo es, de hecho, los puertos: para cada microcontrolador es necesario "enseñar" a la biblioteca cómo trabajar con UART para entrada-salida, seleccionar una pila para una máquina virtual, especificar un conjunto de optimizaciones. Opcionalmente, se describe el trabajo con hardware: GPIO, alimentación, inalámbrico, sistema de archivos.
Todo esto está escrito en C puro con macros: micropython tiene un conjunto de recetas recomendadas desde declarar cadenas en ROM hasta escribir módulos. Además de esto, los módulos escritos por Python son totalmente compatibles (lo principal es no olvidarse del tamaño de la memoria). Los curadores del proyecto establecieron como objetivo la oportunidad de lanzar un dzhanga (imagen con una barra de pan). Como anuncio: el proyecto vende su propia placa para los estudiantes de pyboard , pero los puertos para los módulos ESP8266 y ESP32 también son populares.
Cuando el firmware esté listo y cargado, simplemente conéctese al microcontrolador a través de UART y entre en Python REPL.
$ miniterm.py /dev/ttyUSB1 115200 --raw MicroPython cd2f742 on 2017-11-29; unicorn with Cortex-M3 Type "help()" for more information. >>> print("hello") hello
Después de eso, puede comenzar a escribir en python3 casi normal sin olvidarse de las limitaciones de memoria.
El módulo A9G no es oficialmente compatible (una lista de módulos oficialmente compatibles está disponible en micropython/ports
, hay una docena de ellos). Sin embargo, el fabricante de hierro bifurcó micropython y creó el entorno para el puerto micropython/ports/gprs_a9
: micropython/ports/gprs_a9
, por lo que muchas gracias a él. En el momento en que me interesé en este problema, el puerto se compiló con éxito y el microcontrolador me recibió con REPL. Pero, desafortunadamente, en los módulos de terceros solo había trabajo con el sistema de archivos y GPIO: no había nada relacionado con la red inalámbrica y el GPS. Decidí solucionar este defecto y me propuse portar todas las funciones necesarias para un rastreador GPS. La documentación oficial para este caso es innecesariamente concisa: por lo tanto, tuve que hurgar en el código.
Por donde empezar
Primero, vaya a micropython/ports
y copie micropython/ports/minimal
a la nueva carpeta donde se ubicará el puerto. Luego, edite main.c
para su plataforma. Tenga en cuenta que todo lo delicioso está en la función main
, donde debe llamar al inicializador mp_init()
, ya que ha preparado previamente el microcontrolador y la configuración de la pila. Luego, para la API controlada por eventos, debe llamar a pyexec_event_repl_init()
y alimentar los caracteres ingresados a través de UART a la función pyexec_event_repl_process_char(char)
. Esto proporcionará interoperabilidad a través de REPL. El segundo archivo, micropython/ports/minimal/uart_core.c
describe el bloqueo de entrada y salida en UART. Traigo el código original para STM32 para aquellos que son demasiado vagos para buscar.
main.c
int main(int argc, char **argv) { int stack_dummy; stack_top = (char*)&stack_dummy; #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); #endif mp_init(); #if MICROPY_ENABLE_COMPILER #if MICROPY_REPL_EVENT_DRIVEN pyexec_event_repl_init(); for (;;) { int c = mp_hal_stdin_rx_chr(); if (pyexec_event_repl_process_char(c)) { break; } } #else pyexec_friendly_repl(); #endif
uart_core.c
Después de eso, debe volver a escribir el Makefile utilizando las recomendaciones / compilador del fabricante: aquí todo es individual. Todo, esto idealmente debería ser suficiente: recopilamos, completamos el firmware y vemos REPL en UART.
Después de revivir micropython
debe cuidar su bienestar: configure el recolector de basura, la reacción correcta a Ctrl-D (reinicio por software) y algunas otras cosas en las que no me mpconfigport.h
: consulte el archivo mpconfigport.h
.
Crear un módulo
Lo más interesante es escribir sus propios módulos. Entonces, el módulo (no necesario, pero deseable) comienza con su propio archivo mod[].c
, que se agrega mediante el Makefile
(variable SRC_C
si sigue la convención). Un módulo vacío es el siguiente:
Por supuesto, el puerto en sí no reconoce la constante mp_module_mymodule
: debe agregarse a la variable MICROPY_PORT_BUILTIN_MODULES
en la mpconfigport.h
puerto mpconfigport.h
. Por cierto fondos de pantalla aburridos el nombre del chip y el nombre del puerto también cambian allí. Después de todos estos cambios, puede intentar compilar el módulo e importarlo desde REPL. Solo un atributo __name__
con el nombre del módulo estará disponible para el módulo (un gran caso para verificar la finalización automática en REPL a través de Tab).
>>> import mymodule >>> mymodule.__name__ 'mymodule'
Constantes
La siguiente etapa en complejidad es agregar constantes. Las constantes son a menudo necesarias para la configuración ( INPUT
, OUTPUT
, HIGH
, LOW
, etc.) Aquí todo es bastante simple. Aquí, por ejemplo, la constante magic_number = 10
:
STATIC const mp_map_elem_t mymodule_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mymodule) }, { MP_OBJ_NEW_QSTR(MP_QSTR_magic_number), MP_OBJ_NEW_SMALL_INT(10) }, };
Prueba:
>>> import mymodule >>> mymodule.magic_number 10
Las funciones
Agregar una función a un módulo sigue el principio general: declarar, ajustar, agregar (doy un ejemplo un poco más complejo que en la documentación).
Prueba:
>>> import mymodule >>> mymodule.conditional_add_one(3) 4 >>> mymodule.conditional_add_one(9) >>>
Clases (tipos)
Con las clases (tipos), todo también es relativamente simple. Aquí hay un ejemplo de la documentación (bueno, casi):
Prueba:
>>> mymodule.helloObj <type 'helloObj'>
El tipo resultante se puede heredar, comparar, pero no tiene un constructor ni ningún dato asociado. Los datos se agregan "al lado" del constructor: se propone crear una estructura separada en la que el tipo Python se almacenará por separado y por separado, un conjunto de datos arbitrario.
¿Cómo interactuar con estos datos? Una de las formas más difíciles es a través del constructor.
De los otros campos, también hay .print
, y supongo que el resto de la magia de Python3
.
Pero make_new
no es necesario para obtener una instancia de un objeto: la inicialización se puede hacer en una función arbitraria. Aquí hay un buen ejemplo de micropython/ports/esp32/modsocket.c
:
Métodos vinculados
El siguiente paso es agregar los métodos enlazados. Sin embargo, esto no es muy diferente de todos los demás métodos. Volvemos al ejemplo de la documentación:
Eso es todo!
>>> x = mymodule.helloObj(12) >>> x.inc()
Todos los demás atributos: getattr , setattr
¿Qué hay de agregar no funciones, usando @property
y generalmente su propio __getattr__
? Por favor: esto se hace manualmente sin pasar por mymodule_hello_locals_dict_table
.
Algo dolorosamente conciso resultó, dices. ¿Dónde están todos estos mp_raise_AttributeError
( nota : tal función no existe)? De hecho, se llamará automáticamente a un AttributeError
. El secreto es que dest
es una matriz de dos elementos. El primer elemento tiene el significado de "salida", de solo escritura: toma el valor MP_OBJ_SENTINEL
si el valor debe escribirse y MP_OBJ_NULL
si necesita leerse. En consecuencia, a la salida de la función, se espera MP_OBJ_NULL
en el primer caso y algo mp_obj_t
en el segundo. El segundo elemento es input, solo lectura: toma el valor del objeto a escribir si el valor necesita ser escrito y MP_OBJ_NULL
si necesita ser leído. No necesitas cambiarlo.
Eso es todo, puedes verificar:
>>> x = mymodule.helloObj(12) >>> x.val = 3 >>> x.val 3
Lo más interesante es que la finalización de Tab en REPL todavía funciona y ofrece .val
! Para ser honesto, no soy un experto en C, por lo que solo puedo adivinar cómo sucede esto (redefiniendo el operador '==').
Puerto
Volviendo al módulo A9G, describí el soporte de todas las funciones básicas, a saber, SMS, GPRS (usockets), GPS, administración de energía. Ahora puede cargar algo como esto en el módulo y funcionará:
import cellular as c import usocket as sock import time import gps import machine
El proyecto agradece cualquier ayuda factible. Si le gustó el proyecto y / o este artículo, no olvide dejar un me gusta en el github .