Преглед на файлове

thinknode_m3: initial commit

Florent преди 8 месеца
родител
ревизия
bde4fc3a23

+ 72 - 0
boards/thinknode_m3.json

@@ -0,0 +1,72 @@
+{
+  "build": {
+    "arduino": {
+      "ldscript": "nrf52840_s140_v6.ld"
+    },
+    "core": "nRF5",
+    "cpu": "cortex-m4",
+    "extra_flags": "-DNRF52840_XXAA",
+    "f_cpu": "64000000L",
+    "hwids": [
+      [
+        "0x239A",
+        "0x4405"
+      ],
+      [
+        "0x239A",
+        "0x0029"
+      ],
+      [
+        "0x239A",
+        "0x002A"
+      ]
+    ],
+    "usb_product": "elecrow_eink",
+    "mcu": "nrf52840",
+    "variant": "ELECROW-ThinkNode-M3",
+    "bsp": {
+      "name": "adafruit"
+    },
+    "softdevice": {
+      "sd_flags": "-DS140",
+      "sd_name": "s140",
+      "sd_version": "6.1.1",
+      "sd_fwid": "0x00B6"
+    },
+    "bootloader": {
+      "settings_addr": "0xFF000"
+    }
+  },
+  "connectivity": [
+    "bluetooth"
+  ],
+  "debug": {
+    "jlink_device": "nRF52840_xxAA",
+    "onboard_tools": [
+      "jlink"
+    ],
+    "svd_path": "nrf52840.svd",
+    "openocd_target": "nrf52.cfg"
+  },
+  "frameworks": [
+    "arduino"
+  ],
+  "name": "elecrow nrf",
+  "upload": {
+    "maximum_ram_size": 248832,
+    "maximum_size": 815104,
+    "speed": 115200,
+    "use_1200bps_touch": true,
+    "require_upload_port": true,
+    "wait_for_upload_port": true,
+    "protocol": "nrfutil",
+    "protocols": [
+      "jlink",
+      "nrfjprog",
+      "nrfutil",
+      "stlink"
+    ]
+  },
+  "url": "https://github.com/Elecrow-RD",
+  "vendor": "ELECROW"
+}

+ 80 - 0
variants/thinknode_m3/ThinknodeM3Board.cpp

@@ -0,0 +1,80 @@
+#include <Arduino.h>
+#include "ThinknodeM3Board.h"
+#include <Wire.h>
+
+#include <bluefruit.h>
+
+void ThinknodeM3Board::begin() {
+  // for future use, sub-classes SHOULD call this from their begin()
+  startup_reason = BD_STARTUP_NORMAL;
+  btn_prev_state = HIGH;
+
+  sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
+
+  // Enable DC/DC converter for improved power efficiency
+  NRF_POWER->DCDCEN = 1;
+
+  Wire.begin();
+
+  delay(10);   // give sx1262 some time to power up
+}
+
+#if 0
+static BLEDfu bledfu;
+
+static void connect_callback(uint16_t conn_handle) {
+  (void)conn_handle;
+  MESH_DEBUG_PRINTLN("BLE client connected");
+}
+
+static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
+  (void)conn_handle;
+  (void)reason;
+
+  MESH_DEBUG_PRINTLN("BLE client disconnected");
+}
+
+
+bool TrackerThinknodeM3Board::startOTAUpdate(const char* id, char reply[]) {
+  // Config the peripheral connection with maximum bandwidth
+  // more SRAM required by SoftDevice
+  // Note: All config***() function must be called before begin()
+  Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
+  Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
+
+  Bluefruit.begin(1, 0);
+  // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
+  Bluefruit.setTxPower(4);
+  // Set the BLE device name
+  Bluefruit.setName("T1000E_OTA");
+
+  Bluefruit.Periph.setConnectCallback(connect_callback);
+  Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
+
+  // To be consistent OTA DFU should be added first if it exists
+  bledfu.begin();
+
+  // Set up and start advertising
+  // Advertising packet
+  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+  Bluefruit.Advertising.addTxPower();
+  Bluefruit.Advertising.addName();
+
+  /* Start Advertising
+    - Enable auto advertising if disconnected
+    - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
+    - Timeout for fast mode is 30 seconds
+    - Start(timeout) with timeout = 0 will advertise forever (until connected)
+
+    For recommended advertising interval
+    https://developer.apple.com/library/content/qa/qa1931/_index.html
+  */
+  Bluefruit.Advertising.restartOnDisconnect(true);
+  Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
+  Bluefruit.Advertising.setFastTimeout(30);   // number of seconds in fast mode
+  Bluefruit.Advertising.start(0);             // 0 = Don't stop advertising after n seconds
+
+  strcpy(reply, "OK - started");
+  return true;
+}
+#endif

+ 68 - 0
variants/thinknode_m3/ThinknodeM3Board.h

@@ -0,0 +1,68 @@
+#pragma once
+
+#include <MeshCore.h>
+#include <Arduino.h>
+
+#define ADC_FACTOR ((1000.0*ADC_MULTIPLIER*AREF_VOLTAGE)/ADC_MAX)
+
+class ThinknodeM3Board : public mesh::MainBoard {
+protected:
+  uint8_t startup_reason;
+  uint8_t btn_prev_state;
+
+public:
+  void begin();
+
+  uint16_t getBattMilliVolts() override {
+    int adcvalue = 0;
+
+    analogReference(AR_INTERNAL_2_4);
+    analogReadResolution(ADC_RESOLUTION);
+    delay(10);
+
+    // ADC range is 0..2400mV and resolution is 12-bit (0..4095)
+    adcvalue = analogRead(PIN_VBAT_READ);
+    // Convert the raw value to compensated mv, taking the resistor-
+    // divider into account (providing the actual LIPO voltage)
+    return (uint16_t)((float)adcvalue * ADC_FACTOR);
+  }
+
+  uint8_t getStartupReason() const override { return startup_reason; }
+
+  #if defined(P_LORA_TX_LED)
+  #if !defined(P_LORA_TX_LED_ON)
+    #define P_LORA_TX_LED_ON HIGH
+  #endif
+  void onBeforeTransmit() override {
+    digitalWrite(P_LORA_TX_LED, P_LORA_TX_LED_ON);   // turn TX LED on
+  }
+  void onAfterTransmit() override {
+    digitalWrite(P_LORA_TX_LED, !P_LORA_TX_LED_ON);   // turn TX LED off
+  }
+  #endif
+
+  const char* getManufacturerName() const override {
+    return "Elecrow ThinkNode M3";
+  }
+
+  int buttonStateChanged() {
+  #ifdef BUTTON_PIN
+    uint8_t v = digitalRead(BUTTON_PIN);
+    if (v != btn_prev_state) {
+      btn_prev_state = v;
+      return (v == LOW) ? 1 : -1;
+    }
+  #endif
+    return 0;
+  }
+
+  void powerOff() override {
+    sd_power_system_off();
+  }
+
+  void reboot() override {
+    NVIC_SystemReset();
+  }
+
+//  bool startOTAUpdate(const char* id, char reply[]) override;
+};

+ 122 - 0
variants/thinknode_m3/platformio.ini

@@ -0,0 +1,122 @@
+[ThinkNode_M3]
+extends = nrf52_base
+board = thinknode_m3
+board_build.ldscript = boards/nrf52840_s140_v6.ld
+build_flags = ${nrf52_base.build_flags}
+  -I src/helpers/nrf52
+  -I lib/nrf52/s140_nrf52_6.1.1_API/include
+  -I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
+  -I variants/thinknode_m3
+  -I src/helpers/ui
+  -D THINKNODE_M3
+  -D PIN_USER_BTN=12
+  -D USER_BTN_PRESSED=LOW
+  -D PIN_STATUS_LED=35
+  -D RADIO_CLASS=CustomLR1110
+  -D WRAPPER_CLASS=CustomLR1110Wrapper
+  -D LORA_TX_POWER=22
+  -D RF_SWITCH_TABLE
+  -D RX_BOOSTED_GAIN=true
+  -D P_LORA_BUSY=43
+  -D P_LORA_SCLK=45 
+  -D P_LORA_NSS=44
+  -D P_LORA_DIO_1=40
+  -D P_LORA_MISO=47
+  -D P_LORA_MOSI=46 
+  -D P_LORA_RESET=42
+  -D P_LORA_TX_LED=PIN_LED_BLUE
+  -D P_LORA_TX_LED_ON=LOW
+  -D LR11X0_DIO_AS_RF_SWITCH=true
+  -D LR11X0_DIO3_TCXO_VOLTAGE=3.3
+  -D MESH_DEBUG=1
+  -D ENV_INCLUDE_GPS=1
+build_src_filter = ${nrf52_base.build_src_filter}
+  +<helpers/*.cpp>
+  +<../variants/thinknode_m3>
+  +<helpers/sensors>
+debug_tool = stlink
+upload_protocol = nrfutil
+lib_deps= ${nrf52_base.lib_deps}
+
+[env:ThinkNode_M3_repeater]
+extends = ThinkNode_M3
+build_flags = ${ThinkNode_M3.build_flags}
+  -I examples/companion_radio/ui-orig
+  -D ADVERT_NAME='"ThinkNode_M3 Repeater"'
+  -D ADVERT_LAT=0.0
+  -D ADVERT_LON=0.0
+  -D ADMIN_PASSWORD='"password"'
+  -D MAX_NEIGHBOURS=50
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+build_src_filter = ${ThinkNode_M3.build_src_filter}
+  +<../examples/simple_repeater>
+lib_deps = ${ThinkNode_M3.lib_deps}
+  stevemarple/MicroNMEA @ ^2.0.6
+
+[env:ThinkNode_M3_room_server]
+extends = ThinkNode_M3
+build_flags = ${ThinkNode_M3.build_flags}
+  -I examples/companion_radio/ui-orig
+  -D ADVERT_NAME='"ThinkNode_M3 Room"'
+  -D ADVERT_LAT=0.0
+  -D ADVERT_LON=0.0
+  -D ADMIN_PASSWORD='"password"'
+  -D ROOM_PASSWORD='"hello"'
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+  -D RF_SWITCH_TABLE
+build_src_filter = ${ThinkNode_M3.build_src_filter}
+  +<../examples/simple_room_server>
+lib_deps = ${ThinkNode_M3.lib_deps}
+  stevemarple/MicroNMEA @ ^2.0.6
+
+[env:ThinkNode_M3_companion_radio_usb]
+extends = ThinkNode_M3
+board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
+board_upload.maximum_size = 708608
+build_flags = ${ThinkNode_M3.build_flags}
+  -I examples/companion_radio/ui-orig
+  -D MAX_CONTACTS=350
+  -D MAX_GROUP_CHANNELS=40
+;  -D MESH_PACKET_LOGGING=1
+;  -D MESH_DEBUG=1
+  -D OFFLINE_QUEUE_SIZE=256
+  -D DISPLAY_CLASS=NullDisplayDriver
+  -D PIN_BUZZER=23
+  -D PIN_BUZZER_EN=36
+build_src_filter = ${ThinkNode_M3.build_src_filter}
+  +<helpers/ui/buzzer.cpp>
+  +<../examples/companion_radio/*.cpp>
+  +<../examples/companion_radio/ui-orig/*.cpp>
+lib_deps = ${ThinkNode_M3.lib_deps}
+  densaugeo/base64 @ ~1.4.0
+  stevemarple/MicroNMEA @ ^2.0.6
+  end2endzone/NonBlockingRTTTL@^1.3.0
+
+[env:ThinkNode_M3_companion_radio_ble]
+extends = ThinkNode_M3
+board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
+board_upload.maximum_size = 708608
+build_flags = ${ThinkNode_M3.build_flags}
+  -I examples/companion_radio/ui-orig
+  -D MAX_CONTACTS=350
+  -D MAX_GROUP_CHANNELS=40
+  -D BLE_PIN_CODE=123456
+  -D BLE_TX_POWER=0
+;  -D BLE_DEBUG_LOGGING=1
+;  -D MESH_PACKET_LOGGING=1
+  -D GPS_NMEA_DEBUG
+  -D OFFLINE_QUEUE_SIZE=256
+  -D DISPLAY_CLASS=NullDisplayDriver
+  -D PIN_BUZZER=23
+  -D PIN_BUZZER_EN=36
+build_src_filter = ${ThinkNode_M3.build_src_filter}
+  +<helpers/nrf52/SerialBLEInterface.cpp>
+  +<helpers/ui/buzzer.cpp>
+  +<../examples/companion_radio/*.cpp>
+  +<../examples/companion_radio/ui-orig/*.cpp>
+lib_deps = ${ThinkNode_M3.lib_deps}
+  densaugeo/base64 @ ~1.4.0
+  stevemarple/MicroNMEA @ ^2.0.6
+  end2endzone/NonBlockingRTTTL@^1.3.0

+ 99 - 0
variants/thinknode_m3/target.cpp

@@ -0,0 +1,99 @@
+#include <Arduino.h>
+#include "target.h"
+#include <helpers/sensors/MicroNMEALocationProvider.h>
+
+ThinknodeM3Board board;
+
+RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
+
+WRAPPER_CLASS radio_driver(radio, board);
+
+VolatileRTCClock fallback_clock;
+AutoDiscoverRTCClock rtc_clock(fallback_clock);
+#ifdef ENV_INCLUDE_GPS
+MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
+EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
+#else
+EnvironmentSensorManager sensors = EnvironmentSensorManager();
+#endif
+
+#ifdef DISPLAY_CLASS
+  NullDisplayDriver display;
+#endif
+
+#ifndef LORA_CR
+  #define LORA_CR      5
+#endif
+
+#ifdef RF_SWITCH_TABLE
+static const uint32_t rfswitch_dios[Module::RFSWITCH_MAX_PINS] = {
+  RADIOLIB_LR11X0_DIO5,
+  RADIOLIB_LR11X0_DIO6,
+  RADIOLIB_NC,
+  RADIOLIB_NC, 
+  RADIOLIB_NC
+};
+
+static const Module::RfSwitchMode_t rfswitch_table[] = {
+  // mode                 DIO5  DIO6 
+  { LR11x0::MODE_STBY,   {LOW , LOW  }},  
+  { LR11x0::MODE_RX,     {HIGH, LOW  }},
+  { LR11x0::MODE_TX,     {HIGH, HIGH }},
+  { LR11x0::MODE_TX_HP,  {LOW , HIGH }},
+  { LR11x0::MODE_TX_HF,  {LOW , LOW  }}, 
+  { LR11x0::MODE_GNSS,   {LOW , LOW  }},
+  { LR11x0::MODE_WIFI,   {LOW , LOW  }},  
+  END_OF_MODE_TABLE,
+};
+#endif
+
+bool radio_init() {
+  rtc_clock.begin(Wire);
+  
+#ifdef LR11X0_DIO3_TCXO_VOLTAGE
+  float tcxo = LR11X0_DIO3_TCXO_VOLTAGE;
+#else
+  float tcxo = 1.6f;
+#endif
+
+  SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
+  SPI.begin();
+  int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
+  if (status != RADIOLIB_ERR_NONE) {
+    Serial.print("ERROR: radio init failed: ");
+    Serial.println(status);
+    return false;  // fail
+  }
+  
+  radio.setCRC(2);
+  radio.explicitHeader();
+
+#ifdef RF_SWITCH_TABLE
+  radio.setRfSwitchTable(rfswitch_dios, rfswitch_table);
+#endif
+#ifdef RX_BOOSTED_GAIN
+  radio.setRxBoostedGainMode(RX_BOOSTED_GAIN);
+#endif
+
+  return true;  // success
+}
+
+uint32_t radio_get_rng_seed() {
+  return radio.random(0x7FFFFFFF);
+}
+
+void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
+  radio.setFrequency(freq);
+  radio.setSpreadingFactor(sf);
+  radio.setBandwidth(bw);
+  radio.setCodingRate(cr);
+}
+
+void radio_set_tx_power(uint8_t dbm) {
+  radio.setOutputPower(dbm);
+}
+
+mesh::LocalIdentity radio_new_identity() {
+  RadioNoiseListener rng(radio);
+  return mesh::LocalIdentity(&rng);  // create new random identity
+}

+ 29 - 0
variants/thinknode_m3/target.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#define RADIOLIB_STATIC_ONLY 1
+#include <RadioLib.h>
+#include <helpers/radiolib/RadioLibWrappers.h>
+#include "ThinknodeM3Board.h"
+#include <helpers/radiolib/CustomLR1110Wrapper.h>
+#include <helpers/ArduinoHelpers.h>
+#include <helpers/sensors/EnvironmentSensorManager.h>
+#include <helpers/sensors/LocationProvider.h>
+#include <helpers/AutoDiscoverRTCClock.h>
+#ifdef DISPLAY_CLASS
+  #include "NullDisplayDriver.h"
+#endif
+
+#ifdef DISPLAY_CLASS
+  extern NullDisplayDriver display;
+#endif
+
+extern ThinknodeM3Board board;
+extern WRAPPER_CLASS radio_driver;
+extern AutoDiscoverRTCClock rtc_clock;
+extern EnvironmentSensorManager sensors;
+
+bool radio_init();
+uint32_t radio_get_rng_seed();
+void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
+void radio_set_tx_power(uint8_t dbm);
+mesh::LocalIdentity radio_new_identity();

+ 95 - 0
variants/thinknode_m3/variant.cpp

@@ -0,0 +1,95 @@
+/*
+ * variant.cpp
+ * Copyright (C) 2023 Seeed K.K.
+ * MIT License
+ */
+
+#include "variant.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] =
+{
+  0,  // P0.00
+  1,  // P0.01
+  2,  // P0.02
+  3,  // P0.03
+  4,  // P0.04
+  5,  // P0.05
+  6,  // P0.06
+  7,  // P0.07
+  8,  // P0.08
+  9,  // P0.09
+  10, // P0.10
+  11, // P0.11
+  12, // P0.12
+  13, // P0.13
+  14, // P0.14
+  15, // P0.15
+  16, // P0.16
+  17, // P0.17
+  18, // P0.18
+  19, // P0.19
+  20, // P0.20
+  21, // P0.21
+  22, // P0.22
+  23, // P0.23
+  24, // P0.24
+  25, // P0.25
+  26, // P0.26
+  27, // P0.27
+  28, // P0.28
+  29, // P0.29
+  30, // P0.30
+  31, // P0.31
+  32, // P1.00
+  33, // P1.01
+  34, // P1.02
+  35, // P1.03
+  36, // P1.04
+  37, // P1.05
+  38, // P1.06
+  39, // P1.07
+  40, // P1.08
+  41, // P1.09
+  42, // P1.10
+  43, // P1.11
+  44, // P1.12
+  45, // P1.13
+  46, // P1.14
+  47, // P1.15
+};
+
+void initVariant()
+{
+/* TODO */
+  pinMode(PIN_PWR_EN, OUTPUT);
+  digitalWrite(PIN_PWR_EN, HIGH);
+
+  pinMode(BAT_POWER, OUTPUT);
+  digitalWrite(BAT_POWER, HIGH);
+  pinMode(EEPROM_POWER, OUTPUT);
+  digitalWrite(EEPROM_POWER, HIGH);
+
+  pinMode(36, OUTPUT);
+  digitalWrite(36, HIGH);
+  pinMode(34, OUTPUT);
+  digitalWrite(34, HIGH);
+
+  pinMode(LED_POWER, OUTPUT);
+  digitalWrite(LED_POWER, HIGH);
+
+  pinMode(PIN_LED_BLUE, OUTPUT);
+  pinMode(PIN_LED_GREEN, OUTPUT);
+  pinMode(PIN_LED_RED, OUTPUT);
+
+  pinMode(BUTTON_PIN, INPUT_PULLUP);
+
+  pinMode(PIN_GPS_POWER, OUTPUT);
+  pinMode(PIN_GPS_EN, OUTPUT);
+  pinMode(PIN_GPS_RESET, OUTPUT);
+
+  // Power on gps but in standby
+  digitalWrite(PIN_GPS_EN, LOW);
+  digitalWrite(PIN_GPS_POWER, HIGH);
+}

+ 109 - 0
variants/thinknode_m3/variant.h

@@ -0,0 +1,109 @@
+/*
+ * variant.h
+ * Copyright (C) 2023 Seeed K.K.
+ * MIT License
+ */
+
+#pragma once
+
+#include "WVariant.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Low frequency clock source
+
+#define USE_LFXO    // 32.768 kHz crystal oscillator
+#define VARIANT_MCK (64000000ul)
+// #define USE_LFRC    // 32.768 kHz RC oscillator
+
+////////////////////////////////////////////////////////////////////////////////
+// Number of pins
+
+#define PINS_COUNT              (48)
+#define NUM_DIGITAL_PINS        (48)
+#define NUM_ANALOG_INPUTS       (1)
+#define NUM_ANALOG_OUTPUTS      (0)
+
+////////////////////////////////////////////////////////////////////////////////
+// Power
+
+#define NRF_APM                                 // detect usb power
+
+
+#define EXT_CHRG_DETECT         (32)            // P1.3
+#define EXT_PWR_DETECT          (31)             // P0.5
+
+#define PIN_VBAT_READ           (5) 
+#define AREF_VOLTAGE            (2.4f)
+#define ADC_MULTIPLIER          (2.0)           //(1.75f)
+// 2.0 gives more coherent value, 4.2V when charged, needs tweaking
+#define ADC_RESOLUTION          (12)
+#define ADC_MAX                 (4096)
+
+#define EEPROM_POWER            (7)
+#define BAT_POWER               (17)
+#define PIN_PWR_EN              (16)
+
+
+////////////////////////////////////////////////////////////////////////////////
+// UART pin definition
+
+#define PIN_SERIAL1_RX          PIN_GPS_TX
+#define PIN_SERIAL1_TX          PIN_GPS_RX
+
+////////////////////////////////////////////////////////////////////////////////
+// I2C pin definition
+
+#define HAS_WIRE                (1)
+#define WIRE_INTERFACES_COUNT   (1)
+
+#define PIN_WIRE_SDA            (26)             // P0.26
+#define PIN_WIRE_SCL            (27)             // P0.27
+#define I2C_NO_RESCAN
+
+////////////////////////////////////////////////////////////////////////////////
+// SPI pin definition
+
+#define SPI_INTERFACES_COUNT    (1)
+
+#define PIN_SPI_MISO            (47)            // P1.15
+#define PIN_SPI_MOSI            (46)            // P1.14
+#define PIN_SPI_SCK             (45)            // P1.13
+#define PIN_SPI_NSS             (44)            // P1.12
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtin LEDs
+
+#define LED_POWER               (29)
+#define LED_BLUE                (-1)            // No blue led
+#define PIN_LED_BLUE            (37)
+#define PIN_LED_GREEN           (35)            // P0.24
+#define PIN_LED_RED             (33)
+#define LED_PIN                 PIN_LED_GREEN
+#define LED_BUILTIN             PIN_LED_BLUE
+#define LED_STATE_ON            LOW
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtin buttons
+
+#define PIN_BUTTON1             (12)             // P0.12
+#define BUTTON_PIN              PIN_BUTTON1
+
+////////////////////////////////////////////////////////////////////////////////
+// GPS
+
+#define HAS_GPS                     1
+#define PIN_GPS_RX                  (22)    
+#define PIN_GPS_TX                  (20)
+
+#define PIN_GPS_POWER               (14)
+#define PIN_GPS_EN                  (21)            // STANDBY
+#define PIN_GPS_RESET               (25)            // REINIT
+#define GPS_RESET_ACTIVE            LOW
+#define GPS_EN_ACTIVE               HIGH
+#define GPS_BAUDRATE                9600
+
+////////////////////////////////////////////////////////////////////////////////
+// Buzzer
+
+#define BUZZER_EN               (37)            // P1.5
+#define BUZZER_PIN              (25)            // P0.25