2019-02-10 18:35:12 +00:00
/*
2019-07-12 12:43:39 +00:00
Main module
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
# Modified by Kyle T. Gabriel to fix issue with incorrect GPS data for TTNMapper
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
Copyright ( C ) 2018 by Xose Pérez < xose dot perez at gmail dot com >
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2019-02-10 18:35:12 +00:00
*/
# include "configuration.h"
2019-07-12 12:43:39 +00:00
# include "rom/rtc.h"
2019-08-26 00:44:56 +00:00
# include <TinyGPS++.h>
# include <Wire.h>
2019-02-10 18:35:12 +00:00
2019-08-25 17:46:03 +00:00
# ifdef T_BEAM_V10
# include "axp20x.h"
2019-08-25 17:56:43 +00:00
AXP20X_Class axp ;
bool pmu_irq = false ;
String baChStatus = " No charging " ;
2019-08-25 17:46:03 +00:00
# endif
2019-08-26 00:58:12 +00:00
bool ssd1306_found = false ;
bool axp192_found = false ;
2019-08-23 22:05:07 +00:00
# if defined(PAYLOAD_USE_FULL)
// includes number of satellites and accuracy
uint8_t txBuffer [ 10 ] ;
# elif defined(PAYLOAD_USE_CAYENNE)
2019-08-23 14:22:03 +00:00
// CAYENNE DF
static uint8_t txBuffer [ 11 ] = { 0x03 , 0x88 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
# endif
2019-02-10 18:35:12 +00:00
// -----------------------------------------------------------------------------
// Application
// -----------------------------------------------------------------------------
2020-01-17 23:15:00 +00:00
void buildPacket ( uint8_t txBuffer [ ] ) ; // needed for platformio
2019-02-10 18:35:12 +00:00
void send ( ) {
2019-07-12 12:43:39 +00:00
char buffer [ 40 ] ;
snprintf ( buffer , sizeof ( buffer ) , " Latitude: %10.6f \n " , gps_latitude ( ) ) ;
screen_print ( buffer ) ;
snprintf ( buffer , sizeof ( buffer ) , " Longitude: %10.6f \n " , gps_longitude ( ) ) ;
screen_print ( buffer ) ;
snprintf ( buffer , sizeof ( buffer ) , " Error: %4.2fm \n " , gps_hdop ( ) ) ;
screen_print ( buffer ) ;
buildPacket ( txBuffer ) ;
# if LORAWAN_CONFIRMED_EVERY > 0
bool confirmed = ( count % LORAWAN_CONFIRMED_EVERY = = 0 ) ;
# else
bool confirmed = false ;
# endif
ttn_send ( txBuffer , sizeof ( txBuffer ) , LORAWAN_PORT , confirmed ) ;
2019-02-10 18:35:12 +00:00
}
void sleep ( ) {
2019-07-12 12:43:39 +00:00
# if SLEEP_BETWEEN_MESSAGES
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
// Show the going to sleep message on the screen
char buffer [ 20 ] ;
snprintf ( buffer , sizeof ( buffer ) , " Sleeping in %3.1fs \n " , ( MESSAGE_TO_SLEEP_DELAY / 1000.0 ) ) ;
screen_print ( buffer ) ;
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
// Wait for MESSAGE_TO_SLEEP_DELAY millis to sleep
delay ( MESSAGE_TO_SLEEP_DELAY ) ;
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
// Turn off screen
screen_off ( ) ;
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
// Set the user button to wake the board
sleep_interrupt ( BUTTON_PIN , LOW ) ;
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
// We sleep for the interval between messages minus the current millis
// this way we distribute the messages evenly every SEND_INTERVAL millis
uint32_t sleep_for = ( millis ( ) < SEND_INTERVAL ) ? SEND_INTERVAL - millis ( ) : SEND_INTERVAL ;
sleep_millis ( sleep_for ) ;
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
# endif
2019-02-10 18:35:12 +00:00
}
2020-01-18 21:21:00 +00:00
2020-01-18 04:49:26 +00:00
2019-02-10 18:35:12 +00:00
void callback ( uint8_t message ) {
2019-07-12 12:43:39 +00:00
if ( EV_JOINING = = message ) screen_print ( " Joining TTN... \n " ) ;
2020-01-18 04:49:26 +00:00
if ( EV_JOINED = = message ) {
screen_print ( " TTN joined! \n " ) ;
}
2019-07-12 12:43:39 +00:00
if ( EV_JOIN_FAILED = = message ) screen_print ( " TTN join failed \n " ) ;
if ( EV_REJOIN_FAILED = = message ) screen_print ( " TTN rejoin failed \n " ) ;
if ( EV_RESET = = message ) screen_print ( " Reset TTN connection \n " ) ;
if ( EV_LINK_DEAD = = message ) screen_print ( " TTN link dead \n " ) ;
if ( EV_ACK = = message ) screen_print ( " ACK received \n " ) ;
if ( EV_PENDING = = message ) screen_print ( " Message discarded \n " ) ;
if ( EV_QUEUED = = message ) screen_print ( " Message queued \n " ) ;
if ( EV_TXCOMPLETE = = message ) {
screen_print ( " Message sent \n " ) ;
sleep ( ) ;
}
if ( EV_RESPONSE = = message ) {
screen_print ( " [TTN] Response: " ) ;
size_t len = ttn_response_len ( ) ;
uint8_t data [ len ] ;
ttn_response ( data , len ) ;
char buffer [ 6 ] ;
for ( uint8_t i = 0 ; i < len ; i + + ) {
snprintf ( buffer , sizeof ( buffer ) , " %02X " , data [ i ] ) ;
screen_print ( buffer ) ;
2019-02-10 18:35:12 +00:00
}
2019-07-12 12:43:39 +00:00
screen_print ( " \n " ) ;
}
2019-02-10 18:35:12 +00:00
}
2020-01-18 20:37:39 +00:00
2019-02-10 18:35:12 +00:00
2019-08-26 00:55:00 +00:00
void scanI2Cdevice ( void )
{
byte err , addr ;
int nDevices = 0 ;
for ( addr = 1 ; addr < 127 ; addr + + ) {
Wire . beginTransmission ( addr ) ;
err = Wire . endTransmission ( ) ;
if ( err = = 0 ) {
Serial . print ( " I2C device found at address 0x " ) ;
if ( addr < 16 )
Serial . print ( " 0 " ) ;
Serial . print ( addr , HEX ) ;
Serial . println ( " ! " ) ;
nDevices + + ;
if ( addr = = SSD1306_ADDRESS ) {
ssd1306_found = true ;
Serial . println ( " ssd1306 display found " ) ;
}
if ( addr = = AXP192_SLAVE_ADDRESS ) {
axp192_found = true ;
Serial . println ( " axp192 PMU found " ) ;
}
} else if ( err = = 4 ) {
Serial . print ( " Unknow error at address 0x " ) ;
if ( addr < 16 )
Serial . print ( " 0 " ) ;
Serial . println ( addr , HEX ) ;
}
}
if ( nDevices = = 0 )
Serial . println ( " No I2C devices found \n " ) ;
else
Serial . println ( " done \n " ) ;
}
2020-01-19 01:41:17 +00:00
/**
* Init the power manager chip
*
* axp192 power
DCDC1 0.7 - 3.5 V @ 1200 mA max - > OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192 share the same i2c bus, instead use ssd1306 sleep mode
DCDC2 - > unused
DCDC3 0.7 - 3.5 V @ 700 mA max - > ESP32 ( keep this on ! )
LDO1 30 mA - > charges GPS backup battery // turn this off during deep sleep to force the tiny J13 battery by the GPS to power the GPS ram (for a couple of days)
LDO2 200 mA - > LORA
LDO3 200 mA - > GPS
*/
void axp192Init ( ) {
if ( axp192_found ) {
if ( ! axp . begin ( Wire , AXP192_SLAVE_ADDRESS ) ) {
Serial . println ( " AXP192 Begin PASS " ) ;
} else {
Serial . println ( " AXP192 Begin FAIL " ) ;
}
// axp.setChgLEDMode(LED_BLINK_4HZ);
Serial . printf ( " DCDC1: %s \n " , axp . isDCDC1Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " DCDC2: %s \n " , axp . isDCDC2Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " LDO2: %s \n " , axp . isLDO2Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " LDO3: %s \n " , axp . isLDO3Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " DCDC3: %s \n " , axp . isDCDC3Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " Exten: %s \n " , axp . isExtenEnable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . println ( " ---------------------------------------- " ) ;
axp . setPowerOutPut ( AXP192_LDO2 , AXP202_ON ) ;
axp . setPowerOutPut ( AXP192_LDO3 , AXP202_ON ) ;
axp . setPowerOutPut ( AXP192_DCDC2 , AXP202_ON ) ;
axp . setPowerOutPut ( AXP192_EXTEN , AXP202_ON ) ;
axp . setPowerOutPut ( AXP192_DCDC1 , AXP202_ON ) ;
axp . setDCDC1Voltage ( 3300 ) ; // for the OLED power
Serial . printf ( " DCDC1: %s \n " , axp . isDCDC1Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " DCDC2: %s \n " , axp . isDCDC2Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " LDO2: %s \n " , axp . isLDO2Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " LDO3: %s \n " , axp . isLDO3Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " DCDC3: %s \n " , axp . isDCDC3Enable ( ) ? " ENABLE " : " DISABLE " ) ;
Serial . printf ( " Exten: %s \n " , axp . isExtenEnable ( ) ? " ENABLE " : " DISABLE " ) ;
pinMode ( PMU_IRQ , INPUT_PULLUP ) ;
attachInterrupt ( PMU_IRQ , [ ] {
pmu_irq = true ;
} , FALLING ) ;
axp . adc1Enable ( AXP202_BATT_CUR_ADC1 , 1 ) ;
axp . enableIRQ ( AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ , 1 ) ;
axp . clearIRQ ( ) ;
if ( axp . isChargeing ( ) ) {
baChStatus = " Charging " ;
}
} else {
Serial . println ( " AXP192 not found " ) ;
}
}
2019-02-10 18:35:12 +00:00
void setup ( ) {
2019-07-12 12:43:39 +00:00
// Debug
2019-08-25 16:57:37 +00:00
# ifdef DEBUG_PORT
2019-07-12 12:43:39 +00:00
DEBUG_PORT . begin ( SERIAL_BAUD ) ;
2019-08-25 16:57:37 +00:00
# endif
2019-08-26 00:55:00 +00:00
delay ( 1000 ) ;
2019-08-25 16:57:37 +00:00
# ifdef T_BEAM_V10
2019-08-26 00:44:56 +00:00
Wire . begin ( I2C_SDA , I2C_SCL ) ;
2019-08-26 00:55:00 +00:00
scanI2Cdevice ( ) ;
2019-08-26 00:44:56 +00:00
axp192_found = true ;
2020-01-19 01:41:17 +00:00
axp192Init ( ) ;
2019-08-25 16:57:37 +00:00
# endif
2019-02-10 18:35:12 +00:00
2019-07-12 12:43:39 +00:00
// Buttons & LED
pinMode ( BUTTON_PIN , INPUT_PULLUP ) ;
2020-01-19 01:41:17 +00:00
# ifdef LED_PIN
2019-07-12 12:43:39 +00:00
pinMode ( LED_PIN , OUTPUT ) ;
2020-01-19 01:41:17 +00:00
# endif
2019-07-12 12:43:39 +00:00
// Hello
DEBUG_MSG ( APP_NAME " " APP_VERSION " \n " ) ;
// Display
screen_setup ( ) ;
// Init GPS
gps_setup ( ) ;
2020-01-18 20:37:39 +00:00
// Show logo on first boot after removing battery
if ( ttn_get_count ( ) = = 0 ) {
2019-07-12 12:43:39 +00:00
screen_print ( APP_NAME " " APP_VERSION , 0 , 0 ) ;
screen_show_logo ( ) ;
screen_update ( ) ;
delay ( LOGO_DELAY ) ;
}
// TTN setup
if ( ! ttn_setup ( ) ) {
screen_print ( " [ERR] Radio module not found! \n " ) ;
delay ( MESSAGE_TO_SLEEP_DELAY ) ;
screen_off ( ) ;
sleep_forever ( ) ;
}
ttn_register ( callback ) ;
ttn_join ( ) ;
ttn_adr ( LORAWAN_ADR ) ;
2019-02-10 18:35:12 +00:00
}
void loop ( ) {
2019-07-12 12:43:39 +00:00
gps_loop ( ) ;
ttn_loop ( ) ;
screen_loop ( ) ;
// Send every SEND_INTERVAL millis
static uint32_t last = 0 ;
static bool first = true ;
if ( 0 = = last | | millis ( ) - last > SEND_INTERVAL ) {
if ( 0 < gps_hdop ( ) & & gps_hdop ( ) < 50 & & gps_latitude ( ) ! = 0 & & gps_longitude ( ) ! = 0 ) {
last = millis ( ) ;
first = false ;
Serial . println ( " TRANSMITTING " ) ;
send ( ) ;
} else {
if ( first ) {
screen_print ( " Waiting GPS lock \n " ) ;
first = false ;
}
if ( millis ( ) > GPS_WAIT_FOR_LOCK ) {
sleep ( ) ;
}
2019-02-10 18:35:12 +00:00
}
2019-07-12 12:43:39 +00:00
}
2019-02-10 18:35:12 +00:00
}