Desta vez, pensei em esconder um rastreador GPS na minha bicicleta como precaução. Existem toneladas de dispositivos autônomos no mercado para rastrear carros, cargas, bicicletas, malas, crianças e animais. A grande maioria deles interage com o usuário via SMS. Opções mais caras fornecem a funcionalidade Localizar meu telefone, mas estão vinculadas a um serviço online específico.
Idealmente, eu gostaria de ter controle total sobre o rastreador: use-o em um modo conveniente, sem SMS e registro. O google superficial me trouxe alguns módulos da China, um dos quais eu pedi (placa de pudim A9G) (~ $ 15).

Este artigo é sobre como eu fiz o python funcionar neste módulo.
Se o A9G for um análogo do ESP (a propósito, o fabricante é o mesmo), a placa de pudim em si é uma analogia da placa NodeMCU, exceto que a placa de pudim não possui um conversor USB-UART embutido. Mas há muitas outras coisas interessantes. Especificações do Fabricante :
- Núcleo de 32 bits (RISC), até 312 MHz
- GPIO 29x (todos são soldados, todas as interfaces estão incluídas neste número)
- relógios e cão de guarda
- 1x interface USB 1.1 (não a encontrei lá, mas copie do local) e microUSB para alimentação
- 2x UART (serviço +1)
- 2x SPI (não tentado)
- 3x I2C (não tentei)
- 1x SDMMC (com slot físico)
- 2x entradas analógicas (10 bits, possivelmente uma delas é usada pelos controladores de bateria de lítio)
- Flash de 4 Mb
- PSRAM de 4Mb
- ADC (microfone, existe fisicamente no quadro) e DAC (alto-falante, ausente)
- controlador de carga da bateria (não há bateria propriamente dita)
- de fato, GSM (800, 900, 1800, 1900 MHz) com SMS, voz e GPRS
- GPS conectado via UART2 (existe um módulo "A9" sem ele)
- Slot SIM (nanoSIM)
- dois botões (um reset, outro - inclusão e função programável)
- dois LEDs
A tensão operacional é de 3,3V, a tensão de entrada é de 5-3,8V (dependendo da conexão). Em geral, o módulo possui todo o hardware necessário para montar um simples dispositivo móvel com botão de pressão. Mas a partir dos exemplos, parece que os chineses estão comprando-o para venda em máquinas caça-níqueis ou caça-níqueis ou algo assim. Alternativas ao módulo são os bastante populares módulos SIM800, que, infelizmente, não têm um SDK no domínio público (ou seja, os módulos são vendidos como modems AT).
SDK
O módulo vem com um SDK em inglês satisfatório. Instala no Ubuntu, mas Windows e containers são os preferidos. Tudo funciona através da cutucada na GUI: ESPtool para este módulo ainda não foi revertida. O firmware em si é construído pelo Makefile. O depurador está presente: antes do congelamento, o módulo lança o rastreamento de pilha na porta de serviço. Mas, pessoalmente, não consegui traduzir os endereços em linhas de código (o gdb relata que os endereços não correspondem a nada). É possível que isso se deva ao pouco suporte ao Linux como tal. Portanto, se você quiser mexer no módulo - tente fazê-lo no Windows (e cancele a inscrição no github). Caso contrário, aqui está a instrução para Linux. Após a instalação, é necessário verificar a correção dos caminhos no arquivo .bashrc e excluir (renomear) todos os CSDTK/lib/libQt*
: caso contrário, o pisca-pisca (também conhecido como depurador) simplesmente não será iniciado devido a um conflito com o libQt instalado, provavelmente.

Para o pisca-pisca há uma instrução .
Ligação
Tudo é mais complicado do que no NodeMCU. Os módulos parecem semelhantes, mas não há chip USB-TTY na placa de pudim e o microUSB é usado apenas para energia. Assim, você precisará de USB-TTY em 3.3V. Dois são melhores: um para porta de depuração e outro para UART1: o primeiro é usado para fazer upload de firmware e o segundo que você pode usar como um terminal comum. Para não arrastar todos esses obstáculos para o computador, comprei adicionalmente um divisor USB de 4 portas com um cabo de dois metros e uma fonte de alimentação externa (necessária). O custo total deste kit com o próprio módulo será de US $ 25 a 30 (sem fonte de alimentação: use pelo telefone).
Firmware
O módulo vem com firmware AT: você pode conectar-se a um arduino de 3.3V e usá-lo como modem via UART1. Seu firmware está escrito em C. make
cria dois arquivos de firmware: um é costurado por cerca de um minuto, o outro é rápido o suficiente. Somente um desses arquivos pode ser costurado: a primeira vez é grande, os tempos subsequentes são pequenos. No total, durante o processo de desenvolvimento, tenho o SDK chinês ( coolwatcher
) aberto na área de trabalho para gerenciar o módulo, o miniterm como stdio e o editor de código.
API
O conteúdo da API reflete a lista acima e se assemelha ao ESP8266 nos primeiros dias: levei cerca de 3 horas para lançar o HelloWorld. Infelizmente, o conjunto de funções disponíveis para o usuário é muito limitado: por exemplo, não há acesso à lista telefônica no cartão SIM, informações de baixo nível sobre a conexão à rede celular e assim por diante. A documentação da API é ainda menos completa, portanto, você deve confiar em exemplos (dos quais existem duas dúzias) e incluir arquivos. No entanto, o módulo pode fazer muitas coisas até conexões SSL: obviamente, o fabricante focou nas funções mais prioritárias.
No entanto, a programação de microcontroladores chineses por meio da API chinesa deve ser amada. Para todos os outros, o fabricante começou a portar micropython para este módulo. Decidi me testar em um projeto de código aberto e continuar esse bom trabalho (link no final do artigo).
micropython

Micropython é um projeto de código aberto que transporta o cPython para microcontroladores. O desenvolvimento é realizado em duas direções. O primeiro é o suporte e o desenvolvimento de bibliotecas principais comuns a todos os microcontroladores que descrevem o trabalho com os principais tipos de dados em python: objetos, funções, classes, strings, tipos atômicos e muito mais. A segunda é, de fato, as portas: para cada microcontrolador é necessário "ensinar" a biblioteca a trabalhar com o UART para entrada e saída, selecionar uma pilha para uma máquina virtual, especificar um conjunto de otimizações. Opcionalmente, o trabalho com hardware é descrito: GPIO, energia, sem fio, sistema de arquivos.
Tudo isso é escrito em C puro com macros: o micropython possui um conjunto de receitas recomendadas, desde a declaração de strings na ROM até a gravação de módulos. Além disso, os módulos auto-escritos python são totalmente suportados (o principal é não esquecer o tamanho da memória). Os curadores do projeto estabeleceram como objetivo a oportunidade de lançar uma dzhanga (figura com um pedaço de pão). Como anúncio publicitário: o projeto vende sua própria placa para estudantes de pyboard , mas as portas para os módulos ESP8266 e ESP32 também são populares.
Quando o firmware estiver pronto e carregado - basta conectar-se ao microcontrolador via UART e entrar no 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
Depois disso, você pode começar a escrever em python3 quase normal, sem esquecer as limitações de memória.
O módulo A9G não é oficialmente suportado (uma lista de módulos oficialmente suportados está disponível em micropython/ports
, existem cerca de uma dúzia deles). No entanto, o fabricante de ferro bifurcou o micropython e criou o ambiente para a porta micropython/ports/gprs_a9
: micropython/ports/gprs_a9
, pela qual muitos agradecimentos a ele. No momento em que me interessei por esse problema, a porta foi compilada com êxito e o microcontrolador me recebeu com REPL. Infelizmente, a partir de módulos de terceiros, havia apenas trabalho com o sistema de arquivos e o GPIO: nada relacionado à rede sem fio e ao GPS estava disponível. Decidi consertar esse defeito e estabeleci o objetivo de portar todas as funções necessárias para um rastreador GPS. A documentação oficial para este caso é desnecessariamente concisa: portanto, tive que vasculhar o código.
Por onde começar
Primeiro, vá para micropython/ports
e copie micropython/ports/minimal
para a nova pasta em que a porta estará localizada. Em seguida, edite main.c
para sua plataforma. Lembre-se de que todo o gostoso está na função main
, onde você precisa chamar o inicializador mp_init()
, tendo preparado previamente o microcontrolador e as configurações de pilha para ele. Em seguida, para a API orientada a eventos, você precisa chamar pyexec_event_repl_init()
e alimentar os caracteres digitados via UART para a função pyexec_event_repl_process_char(char)
. Isso fornecerá interoperabilidade através do REPL. O segundo arquivo, micropython/ports/minimal/uart_core.c
descreve o bloqueio de entrada e saída no UART. Eu trago o código original do STM32 para aqueles que estão com preguiça de procurar.
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
Depois disso, você precisa reescrever o Makefile usando as recomendações / compilador do fabricante: tudo aqui é individual. Tudo, idealmente, deve ser suficiente: coletamos, preenchemos o firmware e vemos REPL no UART.
Após reviver o micropython
você precisa cuidar do seu bem-estar: configurar o coletor de lixo, a reação correta ao Ctrl-D (reinicialização suave) e algumas outras coisas nas quais não vou me debruçar: consulte o arquivo mpconfigport.h
.
Crie um módulo
O mais interessante é escrever seus próprios módulos. Portanto, o módulo (não necessário, mas desejável) começa com seu próprio arquivo mod[].c
, que é adicionado pelo Makefile
(variável SRC_C
, se você seguir a convenção). Um módulo vazio é o seguinte:
Obviamente, a porta em si não reconhece a constante mp_module_mymodule
: ela deve ser adicionada à variável MICROPY_PORT_BUILTIN_MODULES
nas mpconfigport.h
porta mpconfigport.h
. By the way papéis de parede chatos o nome do chip e o nome da porta também mudam por lá. Após todas essas alterações, você pode tentar compilar o módulo e importá-lo do REPL. Somente um atributo __name__
com o nome do módulo estará disponível para o módulo (um ótimo caso para verificar a conclusão automática no REPL via guia).
>>> import mymodule >>> mymodule.__name__ 'mymodule'
Constantes
O próximo estágio da complexidade é adicionar constantes. As constantes geralmente são necessárias para configurações ( INPUT
, OUTPUT
, HIGH
, LOW
etc.) Tudo aqui é bem simples. Aqui, por exemplo, a 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) }, };
Teste:
>>> import mymodule >>> mymodule.magic_number 10
Funções
A adição de uma função a um módulo segue o princípio geral: declarar, quebrar, adicionar (eu dou um exemplo um pouco mais complexo do que na documentação).
Teste:
>>> import mymodule >>> mymodule.conditional_add_one(3) 4 >>> mymodule.conditional_add_one(9) >>>
Classes (Tipos)
Com as classes (tipos), tudo também é relativamente simples. Aqui está um exemplo da documentação (bem, quase):
Teste:
>>> mymodule.helloObj <type 'helloObj'>
O tipo resultante pode ser herdado, comparado, mas não possui um construtor ou dados associados. Os dados são adicionados "ao lado" do construtor: propõe-se criar uma estrutura separada na qual o tipo Python será armazenado separadamente e separadamente - um conjunto de dados arbitrário.
Como interagir com esses dados? Uma das maneiras mais difíceis é através do construtor.
Dos outros campos, há também .print
, e acho que o resto da magia do Python3
.
Mas make_new
não é necessário para obter uma instância de um objeto: a inicialização pode ser feita em uma função arbitrária. Aqui está um bom exemplo de micropython/ports/esp32/modsocket.c
:
Métodos vinculados
O próximo passo é adicionar os métodos vinculados. No entanto, isso não é muito diferente de todos os outros métodos. Retornamos ao exemplo da documentação:
Isso é tudo!
>>> x = mymodule.helloObj(12) >>> x.inc()
Todos os outros atributos: getattr , setattr
Que tal adicionar não funções, usando @property
e geralmente seu próprio __getattr__
? Por favor: isso é feito manualmente ignorando mymodule_hello_locals_dict_table
.
Algo dolorosamente conciso acabou, você diz. Onde estão todos esses mp_raise_AttributeError
( nota : essa função não existe)? De fato, um AttributeError
será chamado automaticamente. O segredo é que dest
é uma matriz de dois elementos. O primeiro elemento tem o significado de "saída", somente gravação: ele assume o valor MP_OBJ_SENTINEL
se o valor precisar ser gravado e MP_OBJ_NULL
se precisar ser lido. Assim, na saída da função, MP_OBJ_NULL
é esperado no primeiro caso e algo mp_obj_t
no segundo. O segundo elemento é entrada, somente leitura: pega o valor do objeto a ser gravado se o valor precisar ser gravado e MP_OBJ_NULL
se precisar ser lido. Você não precisa mudar isso.
Isso é tudo, você pode verificar:
>>> x = mymodule.helloObj(12) >>> x.val = 3 >>> x.val 3
O mais interessante é que a conclusão da guia no REPL ainda funciona e oferece .val
! Para ser sincero, não sou especialista em C, portanto, só posso adivinhar como isso acontece (redefinindo o operador '==').
Port
Voltando ao módulo A9G, descrevi o suporte de todas as funções básicas, como SMS, GPRS (usockets), GPS, gerenciamento de energia. Agora você pode enviar algo assim para o módulo e ele funcionará:
import cellular as c import usocket as sock import time import gps import machine
O projeto agradece qualquer ajuda possível. Se você gostou do projeto e / ou deste artigo, não se esqueça de deixar um like no github .