#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <GNSS.h>
/************** Defines *****************************/
#define STRING_BUFFER_SIZE 128 /**< %Buffer size */
/************** Declarations *****************************/
/**
@enum ParamSat
@brief Satellite system
*/
enum ParamSat {
eSatGps, /**< GPS World wide coverage */
eSatGlonass, /**< GLONASS World wide coverage */
eSatGpsSbas, /**< GPS+SBAS North America */
eSatGpsGlonass, /**< GPS+Glonass World wide coverage */
eSatGpsQz1c, /**< GPS+QZSS_L1CA East Asia & Oceania */
eSatGpsGlonassQz1c, /**< GPS+Glonass+QZSS_L1CA East Asia & Oceania */
eSatGpsQz1cQz1S, /**< GPS+QZSS_L1CA+QZSS_L1S Japan */
};
/*********** global data *****************/
static SpGnss Gnss; /**< SpGnss object */
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8]={ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}
#define LORA_PKG_LENGTH 40
static uint8_t mydata[LORA_PKG_LENGTH] = "";
static osjob_t sendjob;
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;
static enum ParamSat satType = eSatGpsGlonass;
// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = 6,
.rxtx = LMIC_UNUSED_PIN,
.rst = 5,
.dio = {2, 3, 4},
};
void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch (ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
// Disable link check validation (automatically enabled
// during join, but not supported by TTN at this time).
LMIC_setLinkCheckMode(0);
break;
case EV_RFU1:
Serial.println(F("EV_RFU1"));
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
default:
Serial.println(F("Unknown event"));
break;
}
}
void do_send(osjob_t* j) {
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
/* Check update. */
if (Gnss.waitUpdate(-1))
{
/* Get NaviData. */
SpNavData NavData;
Gnss.getNavData(&NavData);
/* Set posfix LED. */
bool LedSet = (NavData.posDataExist && (NavData.posFixMode != FixInvalid));
/* Print position information. */
print_pos(&NavData);
snprintf((char *)mydata, LORA_PKG_LENGTH, "{\"lat\":%0.7f,\"lng\":%0.7f}", NavData.latitude, NavData.longitude);
Serial.println((char *)mydata);
}
else
{
/* Not update. */
Serial.println("data not update");
}
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
Serial.println(F("Packet queued"));
}
// Next TX is scheduled after TX_COMPLETE event.
}
/* GNSS related functions */
static void print_pos(SpNavData *pNavData)
{
char StringBuffer[STRING_BUFFER_SIZE];
/* print time */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day);
Serial.print(StringBuffer);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d.%06d, ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec, pNavData->time.usec);
Serial.print(StringBuffer);
/* print satellites count */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites);
Serial.print(StringBuffer);
/* print position data */
if (pNavData->posFixMode == FixInvalid)
{
Serial.print("No-Fix, ");
}
else
{
Serial.print("Fix, ");
}
if (pNavData->posDataExist == 0)
{
Serial.print("No Position");
}
else
{
Serial.print("Lat=");
Serial.print(pNavData->latitude, 6);
Serial.print(", Lon=");
Serial.print(pNavData->longitude, 6);
}
Serial.println("");
}
static void print_condition(SpNavData *pNavData)
{
char StringBuffer[STRING_BUFFER_SIZE];
unsigned long cnt;
/* Print satellite count. */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites);
Serial.print(StringBuffer);
for (cnt = 0; cnt < pNavData->numSatellites; cnt++)
{
const char *pType = "---";
SpSatelliteType sattype = pNavData->getSatelliteType(cnt);
/* Get satellite type. */
/* Keep it to three letters. */
switch (sattype)
{
case GPS:
pType = "GPS";
break;
case GLONASS:
pType = "GLN";
break;
case QZ_L1CA:
pType = "QCA";
break;
case SBAS:
pType = "SBA";
break;
case QZ_L1S:
pType = "Q1S";
break;
default:
pType = "UKN";
break;
}
/* Get print conditions. */
unsigned long Id = pNavData->getSatelliteId(cnt);
unsigned long Elv = pNavData->getSatelliteElevation(cnt);
unsigned long Azm = pNavData->getSatelliteAzimuth(cnt);
float sigLevel = pNavData->getSatelliteSignalLevel(cnt);
/* Print satellite condition. */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2d] Type:%s, Id:%2d, Elv:%2d, Azm:%3d, CN0:", cnt, pType, Id, Elv, Azm );
Serial.print(StringBuffer);
Serial.println(sigLevel, 6);
}
}
/* Setup and loop functions */
void setup() {
int error_flag = 0;
Serial.begin(115200);
Serial.println(F("Starting"));
Gnss.setDebugMode(PrintInfo);
int result;
/* Activate GNSS device */
result = Gnss.begin();
if (result != 0)
{
Serial.println("Gnss begin error!!");
error_flag = 1;
}
else
{
/* Setup GNSS
It is possible to setup up to two GNSS satellites systems.
Depending on your location you can improve your accuracy by selecting different GNSS system than the GPS system.
See: https://developer.sony.com/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_gnss
for detailed information.
*/
switch (satType)
{
case eSatGps:
Gnss.select(GPS);
break;
case eSatGpsSbas:
Gnss.select(GPS);
Gnss.select(SBAS);
break;
case eSatGlonass:
Gnss.select(GLONASS);
break;
case eSatGpsGlonass:
Gnss.select(GPS);
Gnss.select(GLONASS);
break;
case eSatGpsQz1c:
Gnss.select(GPS);
Gnss.select(QZ_L1CA);
break;
case eSatGpsQz1cQz1S:
Gnss.select(GPS);
Gnss.select(QZ_L1CA);
Gnss.select(QZ_L1S);
break;
case eSatGpsGlonassQz1c:
default:
Gnss.select(GPS);
Gnss.select(GLONASS);
Gnss.select(QZ_L1CA);
break;
}
/* Start positioning */
result = Gnss.start(COLD_START);
if (result != 0)
{
Serial.println("Gnss start error!!");
error_flag = 1;
}
else
{
Serial.println("Gnss setup OK");
}
}
/* Set error LED. */
if (error_flag == 1)
{
exit(0);
}
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
// Start job (sending automatically starts OTAA too)
do_send(&sendjob);
}
void loop() {
os_runloop_once();
}
Comments