sábado, 6 de fevereiro de 2021

UBLOX NINA B302 LENDO DADOS DO GPS UBLOX NEO 6M e MANDANDO VIA BLE BROADCASTING

 UBLOX NINA B302 LENDO DADOS DO GPS UBLOX NEO 6M e MANDANDO VIA BLE BROADCASTING


O objetivo deste BLOG é demonstrar como é possível interpretar programas codificados em JAVASCRIPT (ESPRUINO) no módulo U-BLOX NINA B302 (BREAKOUT). Neste exemplo faremos a leitura das coordenadas do GPS da U-BLOX, NEO 6M (PROTOCOLO NMEA) e então o Broadcast (BLE) dos mesmos: LATITUDE e LONGITUDE.


Adquirimos então os seguintes componentes



Montado ficou assim



O esquema elétrico é este



Algumas características do Kit

-Botão de RESET;
-Botão de Modo BOOTLOADER (W102);
-Plugável no PROTOBOARD;
-Acesso às várias GPIOS;

Pequena 

UBLOX NEO 6M


A série de módulos NEO-6 é uma família de receptores GPS autônomos apresentando o u-blox 6 de alto desempenho. Esses receptores flexíveis e econômicos oferecem inúmeras opções de conectividade em uma miniatura Embalagem de 16 x 12,2 x 2,4 mm. Sua arquitetura compacta e opções de alimentação e memória tornam os módulos NEO-6 ideal para dispositivos móveis operados por bateria com custos e restrições de espaço muito restritos. O motor de posicionamento u-blox 6 de 50 canais possui um Time-To-First-Fix (TTFF) de menos de 1 segundo. O dedicado motor de aquisição, com 2 milhões de correlacionadores, é capaz de pesquisas espaciais de tempo / frequência paralelas massivas, permitindo que ele encontre satélites instantaneamente. Design e tecnologia inovadores suprimem fontes de interferência e atenua os efeitos de multipercurso, dando aos receptores NEO-6 GPS excelente desempenho de navegação mesmo na maioria dos ambientes desafiadores.

IMPORTANTE: o NEO-6M é item de família u-blox 6 a qual é bem antiga. NÃO recomendados a utilização dela em novos projetos. Recomendamos utilizar itens de famílias mais novas como da família u-blox 8 (MAX-M8Q, SAM-M8Q, CAM-M8Q entre outros) ou superior.



Espruino é um intérprete de JavaScript para microcontroladores que torna o desenvolvimento de software embarcado rápido e fácil. O intérpretador Espruino é um firmware de código aberto que roda em uma variedade de microcontroladores diferentes.

O Espruino em si não é apenas o firmware ou hardware do interpretador - há também o IDE da Web, ferramentas de linha de comando, documentação, tutoriais e módulos que formam uma solução completa para desenvolvimento de software embarcado.
 
Compilando 
osboxes@osboxes:~$ mkdir javascript
osboxes@osboxes:~$ cd javascript/
osboxes@osboxes:~/javascript$ git clone https://github.com/espruino/Espruino.git
Cloning into 'Espruino'...
remote: Enumerating objects: 156, done.
remote: Counting objects: 100% (156/156), done.
remote: Compressing objects: 100% (117/117), done.
remote: Total 59581 (delta 76), reused 73 (delta 39), pack-reused 59425
Receiving objects: 100% (59581/59581), 208.91 MiB | 3.43 MiB/s, done.
Resolving deltas: 100% (41614/41614), done.
Updating files: 100% (3087/3087), done.
osboxes@osboxes:~/javascript$ cd Espruino/
osboxes@osboxes:~/javascript/Espruino$ ./scripts/provision.sh NRF52840DK
NRF_SDK15=1
Provision BOARDNAME = NRF52840DK
Provision FAMILY = NRF52
===== NRF52
Installing NRF SDK 15.0 to targetlibs/nrf5x_15/components
mv: cannot move 'nRF5_SDK_15.0.0_a53641a/external' to 'targetlibs/nrf5x_15/external': Directory not empty
mv: cannot move 'nRF5_SDK_15.0.0_a53641a/external/micro-ecc' to 'targetlibs/nrf5x_15/external/micro-ecc': Directory not empty
======================================================
FIXME - SDK15 NFC patches don't apply cleanly
======================================================
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #2 succeeded at 163 (offset 9 lines).
Hunk #3 succeeded at 367 (offset 65 lines).
Hunk #4 succeeded at 401 (offset 65 lines).
Hunk #5 succeeded at 700 (offset 126 lines).
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.h
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #1 succeeded at 738 (offset 126 lines).
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.h
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #1 succeeded at 119 (offset 1 line).
Hunk #2 FAILED at 712.
1 out of 2 hunks FAILED -- saving rejects to file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c.rej
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #1 FAILED at 712.
Hunk #2 FAILED at 728.
2 out of 2 hunks FAILED -- saving rejects to file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c.rej
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #1 FAILED at 709.
1 out of 1 hunk FAILED -- saving rejects to file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c.rej
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #1 succeeded at 729 (offset 126 lines).
Hunk #2 succeeded at 758 (offset 126 lines).
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c
Hunk #1 succeeded at 119 (offset 1 line).
Hunk #2 succeeded at 165 (offset 9 lines).
Hunk #3 succeeded at 733 (offset 126 lines).
Hunk #4 succeeded at 750 (offset 126 lines).
Hunk #5 FAILED at 732.
Hunk #6 FAILED at 753.
Hunk #7 succeeded at 910 (offset 142 lines).
Hunk #8 succeeded at 930 (offset 142 lines).
2 out of 8 hunks FAILED -- saving rejects to file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.c.rej
patching file targetlibs/nrf5x_15/components/nfc/t2t_lib/hal_t2t/hal_nfc_t2t.h
patching file targetlibs/nrf5x_15/modules/nrfx/mdk/nrf.h
patching file targetlibs/nrf5x_15/components/libraries/bootloader/nrf_bootloader.c
patching file targetlibs/nrf5x_15/components/ble/ble_services/ble_nus/ble_nus.c
patching file targetlibs/nrf5x_15/components/ble/ble_services/ble_nus/ble_nus.h
patching file targetlibs/nrf5x_15/components/drivers_nrf/usbd/nrf_drv_usbd_errata.h
===== ARM
arm-none-eabi-gcc installed
osboxes@osboxes:~/javascript/Espruino$ make clean && BOARD=NRF52840DK RELEASE=1 make
Makefile:796: warning: ignoring prerequisites on suffix rule definition
Makefile:800: warning: ignoring prerequisites on suffix rule definition
Cleaning targets
Makefile:796: warning: ignoring prerequisites on suffix rule definition
Makefile:800: warning: ignoring prerequisites on suffix rule definition
Generating platform configs
Generating pin info
Generating JS wrappers
WRAPPERSOURCES = src/jswrap_array.c src/jswrap_arraybuffer.c src/jswrap_dataview.c src/jswrap_date.c src/jswrap_error.c src/jswrap_espruino.c src/jswrap_flash.c src/jswrap_functions.c src/jswrap_interactive.c src/jswrap_io.c src/jswrap_json.c src/jswrap_modules.c src/jswrap_pin.c src/jswrap_number.c src/jswrap_object.c src/jswrap_onewire.c src/jswrap_pipe.c src/jswrap_process.c src/jswrap_promise.c src/jswrap_regexp.c src/jswrap_serial.c src/jswrap_storage.c src/jswrap_spi_i2c.c src/jswrap_stream.c src/jswrap_string.c src/jswrap_waveform.c libs/compression/jswrap_heatshrink.c libs/math/jswrap_math.c libs/graphics/jswrap_graphics.c libs/network/jswrap_net.c libs/network/http/jswrap_http.c libs/network/js/jswrap_jsnetwork.c libs/bluetooth/jswrap_bluetooth.c libs/neopixel/jswrap_neopixel.c
DEFINES = -DGIT_COMMIT=e0a76293 -DNO_ASSERT -DRELEASE -DBUILDNUMBER="119" -DNRF52840DK -DCONFIG_GPIO_AS_PINRESET -DBOARD_PCA10056 -DNRF_USB=1 -DUSB -DNEOPIXEL_SCK_PIN=22 -DNEOPIXEL_LRCK_PIN=23 -DUSE_DEBUGGER -DUSE_TAB_COMPLETE -DUSE_HEATSHRINK -DUSE_MATH -DUSE_GRAPHICS -DUSE_NET -DUSE_NETWORK_JS -DBLUETOOTH -DUSE_NEOPIXEL -DS140 -DNRF_SD_BLE_API_VERSION=6 -D__HEAP_SIZE=0 -DBLE_STACK_SUPPORT_REQD -DSWI_DISABLE0 -DSOFTDEVICE_PRESENT -DFLOAT_ABI_HARD -DNRF52_SERIES -DNRF52840_XXAA -DNRF52840 -DNRF5X -DNRF5X_SDK_15 -DARM -DLINK_TIME_OPTIMISATION -DEMBEDDED
CC libs/compression/heatshrink/heatshrink_encoder.o
CC libs/compression/heatshrink/heatshrink_decoder.o
libs/compression/heatshrink/heatshrink_encoder.c: In function 'heatshrink_encoder_poll':
libs/compression/heatshrink/heatshrink_encoder.c:237:24: warning: this statement may fall through [-Wimplicit-fallthrough=]
  237 |             hse->state = st_flush_bit_buffer(hse, &oi);
      |             ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libs/compression/heatshrink/heatshrink_encoder.c:238:9: note: here
  238 |         case HSES_DONE:
      |         ^~~~
CC libs/compression/compress_heatshrink.o
CC libs/graphics/bitmap_font_4x6.o
CC libs/graphics/bitmap_font_6x8.o
CC libs/graphics/vector_font.o
.
.
Testing espruino_2v08.119_nrf52840.elf for NRF52840DK STORAGE: 966656 -> 1007616 FS DATA: 456604 -> 456624 (20 bytes) CODE: 155648 -> 456624 (300096 bytes) Code area Fits before Storage Area arm-none-eabi-objcopy -O ihex espruino_2v08.119_nrf52840.elf espruino_2v08.119_nrf52840.hex Merging SoftDevice python scripts/hexmerge.py /home/osboxes/javascript/Espruino/targetlibs/nrf5x_15/components/softdevice/s140/hex/s140_nrf52_6.0.0_softdevice.hex espruino_2v08.119_nrf52840.app_hex -o espruino_2v08.119_nrf52840.hex osboxes@osboxes:~/javascript/Espruino$
COMPATIBILIZANDO COM NINA B302
 Altere NRF52840DK.py para
#!/bin/false # This file is part of Espruino, a JavaScript interpreter for Microcontrollers # # Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk> # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # # ---------------------------------------------------------------------------------------- # This file contains information for a specific board - the available pins, and where LEDs, # Buttons, and other in-built peripherals are. It is used to build documentation as well # as various source and header files for Espruino. # ---------------------------------------------------------------------------------------- import pinutils; info = { 'name' : "nRF52840 U-BLOX NINA B302", 'link' : [ "https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle" ], 'espruino_page_link' : 'nRF52840_B302', # This is the PCA10059 'default_console' : "EV_SERIAL1", 'default_console_tx' : "D45", 'default_console_rx' : "D29", 'default_console_baudrate' : "9600", 'variables' : 12500, # How many variables are allocated for Espruino to use. RAM will be overflowed if this number is too high and code won't compile. # 'bootloader' : 1, 'binary_name' : 'espruino_%v_nrf52840_B302.hex', 'build' : { 'optimizeflags' : '-Os', 'libraries' : [ 'BLUETOOTH', 'NET', 'GRAPHICS', # 'NFC', 'NEOPIXEL' ], 'makefile' : [ 'DEFINES += -DCONFIG_GPIO_AS_PINRESET', # Allow the reset pin to work 'DEFINES += -DBOARD_PCA10059', 'DEFINES += -DNRF_USB=1 -DUSB', 'NRF_SDK15=1' ] } }; chip = { 'part' : "NRF52840", 'family' : "NRF52", 'package' : "QFN48", 'ram' : 256, 'flash' : 1024, 'speed' : 64, 'usart' : 2, 'spi' : 3, 'i2c' : 2, 'adc' : 1, 'dac' : 0, 'saved_code' : { 'address' : ((246 - 10) * 4096), # Bootloader takes pages 248-255, FS takes 246-247 'page_size' : 4096, 'pages' : 10, 'flash_available' : 1024 - ((31 + 8 + 2 + 10)*4) # Softdevice uses 31 pages of flash, bootloader 8, FS 2, code 10. Each page is 4 kb. }, }; devices = { 'GPIO_1' : { 'pin' : 'D13' }, 'GPIO_2' : { 'pin' : 'D14' }, 'GPIO_3' : { 'pin' : 'D15' }, 'GPIO_4' : { 'pin' : 'D16' }, 'GPIO_5' : { 'pin' : 'D24' }, 'GPIO_7' : { 'pin' : 'D25' }, 'GPIO_8' : { 'pin' : 'D32' }, 'GPIO_16' : { 'pin' : 'D3' }, 'GPIO_17' : { 'pin' : 'D28' }, 'GPIO_18' : { 'pin' : 'D2' }, 'GPIO_20' : { 'pin' : 'D31' }, 'GPIO_21' : { 'pin' : 'D44' }, 'GPIO_22' : { 'pin' : 'D45' }, 'GPIO_23' : { 'pin' : 'D29' }, 'GPIO_24' : { 'pin' : 'D30' }, 'GPIO_25' : { 'pin' : 'D4' }, 'GPIO_27' : { 'pin' : 'D5' }, 'GPIO_28' : { 'pin' : 'D9' }, 'GPIO_29' : { 'pin' : 'D10' }, 'GPIO_32' : { 'pin' : 'D11' }, 'GPIO_33' : { 'pin' : 'D41' }, 'GPIO_34' : { 'pin' : 'D40' }, 'GPIO_35' : { 'pin' : 'D33' }, 'GPIO_36' : { 'pin' : 'D34' }, 'GPIO_37' : { 'pin' : 'D35' }, 'GPIO_38' : { 'pin' : 'D42' }, 'GPIO_39' : { 'pin' : 'D43' }, 'GPIO_40' : { 'pin' : 'D47' }, 'GPIO_41' : { 'pin' : 'D46' }, 'GPIO_42' : { 'pin' : 'D26' }, 'GPIO_43' : { 'pin' : 'D6' }, 'GPIO_44' : { 'pin' : 'D27' }, 'GPIO_45' : { 'pin' : 'D7' }, 'GPIO_46' : { 'pin' : 'D12' }, 'GPIO_47' : { 'pin' : 'D23' }, 'GPIO_48' : { 'pin' : 'D21' }, 'GPIO_49' : { 'pin' : 'D22' }, 'GPIO_50' : { 'pin' : 'D20' }, 'GPIO_51' : { 'pin' : 'D17' }, 'GPIO_52' : { 'pin' : 'D19' } }; # left-right, or top-bottom order board = { 'left' : [ 'VDD', 'VDD', 'RESET', 'VDD','5V','GND','GND','','','D3','D4','D28','D29','D30','D31'], 'right' : [ 'D27', 'D26', 'D2', 'GND', 'D25','D24','D23', 'D22','D20','D19','', 'D18','D17','D16','D15','D14','D13','D12','D11','', 'D10','D9','D8','D7','D6','D5','D21','D1','D0'], '_notes' : { 'D13' : "Serial console RX", 'D15' : "Serial console TX" } }; board["_css"] = """ [#board](http://forum.espruino.com/search/?q=%23board) { width: 528px; height: 800px; top: 0px; left : 200px; background-image: url(img/NRF528DK.jpg); } [#boardcontainer](http://forum.espruino.com/search/?q=%23boardcontainer) { height: 900px; } [#left](http://forum.espruino.com/search/?q=%23left) { top: 219px; right: 466px; } [#right](http://forum.espruino.com/search/?q=%23right) { top: 150px; left: 466px; } .leftpin { height: 17px; } .rightpin { height: 17px; } """; def get_pins(): pins = pinutils.generate_pins(0,47) # 48 General Purpose I/O Pins. pinutils.findpin(pins, "PD0", True)["functions"]["XL1"]=0; pinutils.findpin(pins, "PD1", True)["functions"]["XL2"]=0; # pinutils.findpin(pins, "PD5", True)["functions"]["RTS"]=0; # pinutils.findpin(pins, "PD6", True)["functions"]["TXD"]=0; # pinutils.findpin(pins, "PD7", True)["functions"]["CTS"]=0; # pinutils.findpin(pins, "PD8", True)["functions"]["RXD"]=0; # pinutils.findpin(pins, "PD9", True)["functions"]["NFC1"]=0; # pinutils.findpin(pins, "PD10", True)["functions"]["NFC2"]=0; pinutils.findpin(pins, "PD2", True)["functions"]["ADC1_IN0"]=0; pinutils.findpin(pins, "PD3", True)["functions"]["ADC1_IN1"]=0; pinutils.findpin(pins, "PD4", True)["functions"]["ADC1_IN2"]=0; pinutils.findpin(pins, "PD5", True)["functions"]["ADC1_IN3"]=0; pinutils.findpin(pins, "PD28", True)["functions"]["ADC1_IN4"]=0; pinutils.findpin(pins, "PD29", True)["functions"]["ADC1_IN5"]=0; pinutils.findpin(pins, "PD30", True)["functions"]["ADC1_IN6"]=0; pinutils.findpin(pins, "PD31", True)["functions"]["ADC1_IN7"]=0; # Make buttons and LEDs negated pinutils.findpin(pins, "PD13", True)["functions"]["RXD"]=0; pinutils.findpin(pins, "PD14", True)["functions"]["NEGATED"]=0; pinutils.findpin(pins, "PD15", True)["functions"]["TXD"]=0; pinutils.findpin(pins, "PD16", True)["functions"]["NEGATED"]=0; pinutils.findpin(pins, "PD11", True)["functions"]["NEGATED"]=0; pinutils.findpin(pins, "PD12", True)["functions"]["NEGATED"]=0; pinutils.findpin(pins, "PD24", True)["functions"]["NEGATED"]=0; pinutils.findpin(pins, "PD25", True)["functions"]["NEGATED"]=0; # TODO: SW2 is also connected to P0.19, P0.21, P0.23, and P0.25. This is done to simplify PCB routing. These # GPIOs should not be used and should be left as input with no pull or be disconnected by firmware. # everything is non-5v tolerant for pin in pins: pin["functions"]["3.3"]=0; #[#The](http://forum.espruino.com/search/?q=%23The) boot/reset button will function as a reset button in normal operation. Pin reset on PD21 needs to be enabled on the nRF52832 device for this to work. return pins

RECOMPILE! 

Grave o código HEX usando o utility J-FLASH LITE ou NRFGO STUDIO no NINA B302

espruino_2v08.119_nrf52840_B302.hex



Resete o NINA B302

Instale o ESPRUINO IDE (Native)

Instale o USB DONGLE CSR 4.0 (drivers)


Mas atenção!

Para o Windows 8.1 e posterior
O IDE é capaz de usar os drivers BLE do próprio Windows. A única configuração necessária é que você vá para as configurações de Bluetooth do seu sistema e clique em Conectar (Parear no Windows 10) no seu dispositivo NINA B302. Isso expõe ao sistema e garante que ele apareça no IDE da Web. Para o Windows anterior ao 8.1
Como as versões do Windows anteriores à 8.1 não suportam Web Bluetooth no sistema operacional, o noble (que o Espruino IDE usa) precisa acessar diretamente o adaptador BLE - portanto, é necessário garantir que o driver WinUSB seja carregado para ele (como oposição a um driver específico do fabricante). Baixe o Zadig e execute-o - é apenas um executável Vá para Opções -> Listar todos os dispositivos Escolha o seu adaptador BLE (o meu é CSR8510 A10) Certifique-se de que o WinUSB esteja definido como o driver Agora, quando você executar o IDE da Web nativo e clicar em "conectar" no canto superior esquerdo, deverá ver uma lista de dispositivos BLE conectáveis.




Execute o ESPRUINO IDE (Native)


Faça o SCAN para encontrar o NINA B302


Conecte ao NINA B302


Transfira o SCRIPT JAVASCRIPT abaixo 


var gps_lon; var gps_lat; var ieee0,ieee1,ieee2,ieee3,ieee4,ieee5,ieee6,ieee7; Serial1.setup(38400,{tx:D14,rx:D13}); function UpdateAdv() { NRF.setAdvertising({},{manufacturer: 0x0590, manufacturerData:[ieee0,ieee1,ieee2,ieee3,ieee4,ieee5,ieee6,ieee7]}); } function convertToArray(num){ var floatArr = new Float32Array(2); floatArr[1] = gps_lat; //-26.94478466666; floatArr[0] = gps_lon; //-49.06907866666; var byteArr = new Int8Array(floatArr.buffer); console.log(byteArr); //lat/lon little endian //new Int8Array([-81, 70, 68, -62, -38, -114, -41, -63]) ieee0 = byteArr[0]; ieee1 = byteArr[1]; ieee2 = byteArr[2]; ieee3 = byteArr[3]; ieee4 = byteArr[4]; ieee5 = byteArr[5]; ieee6 = byteArr[6]; ieee7 = byteArr[7]; } var gps = require("GPS").connect(Serial1, function(data) { gps_lat = parseFloat(data.lat); gps_lon = parseFloat(data.lon); console.log("LAT "+gps_lat); console.log("LOG "+gps_lon); convertToArray(); UpdateAdv(); });




P0.13 = D13 = IO1 (RX PARA RECEPÇÃO DOS DADOS DO GPS)

No exemplo, os dados  correspondentes à LATITUDE  e LONGITUDE representados em
IEEE Standard for Floating-Point Arithmetic (IEEE 754) são convertidos para ARRAY de BYTES  para serem mandados por BLE BROADCASTING.

No software de recepção do BROADCASTING, deve ser convertido novamente para Float.

floatArr[1] = gps_lat; //-26.94478466666; floatArr[0] = gps_lon; //-49.06907866666; var byteArr = new Int8Array(floatArr.buffer); console.log(byteArr); //lat/lon little endian //new Int8Array([-81, 70, 68, -62, -38, -114, -41, -63]) ieee0 = byteArr[0]; ieee1 = byteArr[1]; ieee2 = byteArr[2]; ieee3 = byteArr[3]; ieee4 = byteArr[4]; ieee5 = byteArr[5]; ieee6 = byteArr[6]; ieee7 = byteArr[7];

Aqui é a parte do código para Broadcasting

function UpdateAdv() { NRF.setAdvertising({},{manufacturer: 0x0590, manufacturerData:[ieee0,ieee1,ieee2,ieee3,ieee4,ieee5,ieee6,ieee7]}); }



Este são os dados capturados do GPS pelo U-BLOX NINA B302


{
  "time": "15:58:56",
  "lat": -26.94478466666, "lon": -49.06907866666, "fix": 1, "satellites": 7, "altitude": 39 }
{
 
Olhando no MAPA



Montagem



Questões: suporte@smartcore.com.br

FONTES: 

Sobre a SMARTCORE

A SmartCore fornece módulos para comunicação wireless, biometria, conectividade, rastreamento e automação.
Nosso portifólio inclui modem 2G/3G/4G/NB-IoT/Cat.M, satelital, módulos WiFi, Bluetooth, GNSS / GPS, Sigfox, LoRa, leitor de cartão, leitor QR code, mecanismo de impressão, mini-board PC, antena, pigtail, LCD, bateria, repetidor GPS e sensores.
Mais detalhes em www.smartcore.com.br