Senet network coverage survey tool

Dependencies:   GeoPosition Senet_Packet lib_gps lib_mma8451q lib_mpl3115a2 lib_sx9500 lmic_MOTE_L152RC mbed-src

Senet Network Coverage Program

Test Senet Network coverage with various data rates and transmit powers

/media/uploads/shaunkrnelson/norammote.jpg

Configure Device ID and App Key

For your device to connect to the Senet Network, set Device ID and App Key in Commissioning.h

Commissioning.h

/* CHANGE: Device ID  registered to your Developer Portal account */
 u1_t reverse_DEVEUI[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 

/* CHANGE: Device App Key. To get this select the device, click on Gear button at top left then select Device Edit */  
u1_t DEVKEY[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
                                                                        
/*NOCHANGE: Senet Developer Portal Application ID */ 
 u1_t reverse_APPEUI[8]={0x00,0x25,0x0C,0x00,0x00,0x01,0x00,0x01};
 

Connecting to the Senet Network

When the device is turned on the USR LED will blink while it is joining the Senet Network. When LED state changes to solid green it has joined the network. Failure to join network will be the result of:

  1. No network coverage in that area
  2. App Key configuration is incorrect

Siting Mode

The device is in Siting test mode when positioned vertically with LEDs facing up. The Siting test consists of transmitting Senet GPS packets with acknowledgment requested at transmit power levels 14, 20, 30 in that order. For each power level the device will attempt 3 transmits at DR0, stopping if ack is received and moving on to next tx power. After first run through all powers at DR0 the test will stop if acknowledgements received at all power levels; otherwise, the test will proceed to alternate between 3 transmits at DR4 and 3 at DR0 for remaining unacknowledged tx powers until ack received.

Siting LED Profile

  1. USR
    1. Blink fast while joining
    2. Solid when joined and GPS lock
    3. Blink slow when not GPS lock
  1. RED
    1. 30 dBm status indicator
    2. Blink on transmit
    3. Solid after downlink received
  1. YELLOW
    1. 20 dBm status indicator
    2. Blink on transmit
    3. Solid after ack received
  1. GREEN
    1. 14 dBm status indicator
    2. Blink on transmit
    3. Solid after downlink received

Range Mode

The device is in this mode when not in the siting orientation.
This test consists of transmitting 8 packets at:

  1. DR3 Tx Power 14
  2. DR0 Tx Power 14
  3. DR4 Tx Power 20
  4. DR3 Tx Power 20
  5. DR0 Tx Power 20
  6. DR4 Tx Power 26
  7. DR3 Tx Power 30
  8. DR0 Tx Power 30

After transmit cycle completes the next test will start in 560 seconds unless following:

  1. After 140 seconds if no ack received
  2. After 80 seconds if 30 meters travelled from last transmit location

Range LED Profile

  • USR
    • Blink fast while joining
    • Solid when joined and GPS lock
    • Blink slow when not GPS locked
  • RED
    • Transmit indicator
    • Blink on transmit
  • YELLOW
    • Ack indicator
    • Set at beginning of transmit cycle and cleared when ack received
  • GREEN
    • V3 Mote
      • Test indicator
      • Solid while test transmit cycle in progress
    • V2 Mote
      • Not controllable by firmware

Switching Mode

Set mote orientation to desired mode. After a few seconds the new orientation will be detected and the device will indicate it is switching mode by blinking the red, yellow and green LEDs simultaneously for a couple seconds before switching to the new mode.

Committer:
shaunkrnelson
Date:
Fri Jan 20 20:14:42 2017 +0000
Revision:
19:e37b3bd60d5a
Parent:
16:2e5438977b6c
Commit LMIC disabled confirmed uplinks

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shaunkrnelson 0:46990814dc89 1 #include "mbed.h"
shaunkrnelson 0:46990814dc89 2 #include "lmic.h"
shaunkrnelson 0:46990814dc89 3 #include "debug.h"
shaunkrnelson 0:46990814dc89 4 #include "gps.h"
shaunkrnelson 0:46990814dc89 5 #include "mpl3115a2.h"
shaunkrnelson 0:46990814dc89 6 #include "mma8451q.h"
shaunkrnelson 0:46990814dc89 7 #include "sx9500.h"
shaunkrnelson 0:46990814dc89 8 #include "GeoPosition.h"
shaunkrnelson 0:46990814dc89 9 #include "senet_packet.h"
shaunkrnelson 0:46990814dc89 10
shaunkrnelson 1:fbf2fb2c2718 11 // Automatically generated by the program_device script
shaunkrnelson 1:fbf2fb2c2718 12 #include "Commissioning.h"
shaunkrnelson 3:35e8af53c6cf 13 #define NORAM_MOTE_DEVICE_TYPE 0x001001
shaunkrnelson 1:fbf2fb2c2718 14 #define MAJOR 1
shaunkrnelson 1:fbf2fb2c2718 15 #define MINOR 1
shaunkrnelson 19:e37b3bd60d5a 16 #define POINT 4
shaunkrnelson 1:fbf2fb2c2718 17 #define BUILD_NUMBER 0
shaunkrnelson 1:fbf2fb2c2718 18 #define DEVELOPER_ID 0
shaunkrnelson 0:46990814dc89 19
shaunkrnelson 16:2e5438977b6c 20
shaunkrnelson 0:46990814dc89 21
shaunkrnelson 0:46990814dc89 22 // provide application router ID (8 bytes, LSBF)
shaunkrnelson 0:46990814dc89 23 void os_getArtEui (u1_t* buf) {
shaunkrnelson 0:46990814dc89 24 //memcpy(buf, APPEUI, 8);
shaunkrnelson 0:46990814dc89 25 LMIC_reverse_memcpy(buf, reverse_APPEUI, 8);
shaunkrnelson 0:46990814dc89 26 }
shaunkrnelson 0:46990814dc89 27
shaunkrnelson 0:46990814dc89 28 // provide device ID (8 bytes, LSBF)
shaunkrnelson 0:46990814dc89 29 void os_getDevEui (u1_t* buf) {
shaunkrnelson 0:46990814dc89 30 //memcpy(buf, DEVEUI, 8);
shaunkrnelson 0:46990814dc89 31 LMIC_reverse_memcpy(buf, reverse_DEVEUI, 8);
shaunkrnelson 0:46990814dc89 32 }
shaunkrnelson 0:46990814dc89 33
shaunkrnelson 0:46990814dc89 34 // provide device key (16 bytes)
shaunkrnelson 0:46990814dc89 35 void os_getDevKey (u1_t* buf) {
shaunkrnelson 0:46990814dc89 36 memcpy(buf, DEVKEY, 16);
shaunkrnelson 0:46990814dc89 37 }
shaunkrnelson 0:46990814dc89 38
shaunkrnelson 0:46990814dc89 39 typedef enum {
shaunkrnelson 0:46990814dc89 40 MOTE_NONE = 0,
shaunkrnelson 0:46990814dc89 41 MOTE_V2,
shaunkrnelson 0:46990814dc89 42 MOTE_V3
shaunkrnelson 0:46990814dc89 43 } mote_version_e;
shaunkrnelson 0:46990814dc89 44
shaunkrnelson 0:46990814dc89 45 /***********************************************************************
shaunkrnelson 0:46990814dc89 46 * END LORA Device configuration
shaunkrnelson 0:46990814dc89 47 ***********************************************************************/
shaunkrnelson 0:46990814dc89 48
shaunkrnelson 0:46990814dc89 49 // Following is peripheral configuration
shaunkrnelson 0:46990814dc89 50 GPS gps(PB_6, PB_7, PB_11);
shaunkrnelson 0:46990814dc89 51 GeoPosition lastTxPos;
shaunkrnelson 0:46990814dc89 52
shaunkrnelson 0:46990814dc89 53 // I2C Bus connecting sensors
shaunkrnelson 0:46990814dc89 54 I2C i2c(I2C_SDA, I2C_SCL);
shaunkrnelson 0:46990814dc89 55 DigitalIn i2c_int_pin(PB_4);
shaunkrnelson 0:46990814dc89 56
shaunkrnelson 0:46990814dc89 57 // Accelerometer
shaunkrnelson 0:46990814dc89 58 MMA8451Q mma8451q(i2c, i2c_int_pin);
shaunkrnelson 0:46990814dc89 59 // Altimeter
shaunkrnelson 0:46990814dc89 60 MPL3115A2 mpl3115a2(i2c, i2c_int_pin);
shaunkrnelson 0:46990814dc89 61 // Proximity sensor
shaunkrnelson 0:46990814dc89 62 SX9500 sx9500(i2c, PA_9, PA_10);
shaunkrnelson 0:46990814dc89 63
shaunkrnelson 0:46990814dc89 64 // Applicative transmit datarate
shaunkrnelson 0:46990814dc89 65 u1_t dr = 0;
shaunkrnelson 0:46990814dc89 66 // Applicative transmit power
shaunkrnelson 0:46990814dc89 67 u1_t pw = 0;
shaunkrnelson 0:46990814dc89 68
shaunkrnelson 0:46990814dc89 69 // LEDs
shaunkrnelson 0:46990814dc89 70 #define LED_RED PB_1
shaunkrnelson 0:46990814dc89 71 #define LED_YEL PB_10
shaunkrnelson 0:46990814dc89 72 #define LED_GREEN PC_3
shaunkrnelson 0:46990814dc89 73 #define LED_USR PA_5
shaunkrnelson 0:46990814dc89 74
shaunkrnelson 0:46990814dc89 75 DigitalOut ledRed(LED_RED);
shaunkrnelson 0:46990814dc89 76 DigitalOut ledYellow(LED_YEL);
shaunkrnelson 0:46990814dc89 77 DigitalOut ledGreen(LED_GREEN);
shaunkrnelson 0:46990814dc89 78 DigitalOut ledUsr(LED_USR);
shaunkrnelson 0:46990814dc89 79
shaunkrnelson 0:46990814dc89 80 DigitalOut pc_7(PC_7);
shaunkrnelson 0:46990814dc89 81 DigitalIn pc_1(PC_1);
shaunkrnelson 0:46990814dc89 82 AnalogIn *bat;
shaunkrnelson 0:46990814dc89 83
shaunkrnelson 0:46990814dc89 84 uint8_t ReadBatteryLevel()
shaunkrnelson 0:46990814dc89 85 {
shaunkrnelson 0:46990814dc89 86 uint8_t level = 0;
shaunkrnelson 0:46990814dc89 87
shaunkrnelson 0:46990814dc89 88 if(bat != NULL)
shaunkrnelson 1:fbf2fb2c2718 89 level = ((bat->read_u16() >> 8) + (bat->read_u16() >> 9))>>5;
shaunkrnelson 0:46990814dc89 90
shaunkrnelson 0:46990814dc89 91 debug("Battery level: %d\r\n", level);
shaunkrnelson 0:46990814dc89 92 return level;
shaunkrnelson 0:46990814dc89 93 }
shaunkrnelson 0:46990814dc89 94
shaunkrnelson 0:46990814dc89 95 // Get Mote version
shaunkrnelson 0:46990814dc89 96 mote_version_e get_mote_version()
shaunkrnelson 0:46990814dc89 97 {
shaunkrnelson 0:46990814dc89 98 static mote_version_e mote_version = MOTE_NONE;
shaunkrnelson 0:46990814dc89 99
shaunkrnelson 0:46990814dc89 100 if (mote_version == MOTE_NONE)
shaunkrnelson 0:46990814dc89 101 {
shaunkrnelson 0:46990814dc89 102 pc_7 = 1;
shaunkrnelson 0:46990814dc89 103 char first = pc_1;
shaunkrnelson 0:46990814dc89 104 pc_7 = 0;
shaunkrnelson 0:46990814dc89 105
shaunkrnelson 0:46990814dc89 106 if (first && !pc_1) {
shaunkrnelson 0:46990814dc89 107 printf("v2\r\n");
shaunkrnelson 0:46990814dc89 108 mote_version = MOTE_V2;
shaunkrnelson 0:46990814dc89 109 bat = new AnalogIn(PA_0);
shaunkrnelson 0:46990814dc89 110 } else {
shaunkrnelson 0:46990814dc89 111 printf("v3\r\n");
shaunkrnelson 0:46990814dc89 112 mote_version = MOTE_V3;
shaunkrnelson 0:46990814dc89 113 bat = new AnalogIn(PA_1);
shaunkrnelson 0:46990814dc89 114 }
shaunkrnelson 0:46990814dc89 115 }
shaunkrnelson 0:46990814dc89 116 return mote_version;
shaunkrnelson 0:46990814dc89 117 }
shaunkrnelson 0:46990814dc89 118
shaunkrnelson 0:46990814dc89 119 void board_peripherals_init()
shaunkrnelson 0:46990814dc89 120 {
shaunkrnelson 0:46990814dc89 121 ledRed = 1;
shaunkrnelson 0:46990814dc89 122 ledYellow = 1;
shaunkrnelson 0:46990814dc89 123 ledGreen = 1;
shaunkrnelson 0:46990814dc89 124 ledUsr = 0;
shaunkrnelson 0:46990814dc89 125
shaunkrnelson 0:46990814dc89 126 // Start GPS
shaunkrnelson 0:46990814dc89 127 gps.init();
shaunkrnelson 0:46990814dc89 128 if(get_mote_version() == MOTE_V3)
shaunkrnelson 0:46990814dc89 129 gps.en_invert = false;
shaunkrnelson 0:46990814dc89 130 else
shaunkrnelson 0:46990814dc89 131 gps.en_invert = true;
shaunkrnelson 0:46990814dc89 132
shaunkrnelson 0:46990814dc89 133 gps.enable(false);
shaunkrnelson 0:46990814dc89 134
shaunkrnelson 0:46990814dc89 135 GPIOA->MODER |= 0x01415500; // unused pins as outputs: PA4, PA5, PA6, PA7, PA8, (PA11,PA12 USB)
shaunkrnelson 0:46990814dc89 136 //printf("GPIOA->MODER:%08x\r\n", GPIOA->MODER);
shaunkrnelson 0:46990814dc89 137
shaunkrnelson 0:46990814dc89 138 GPIOB->MODER |= 0x00000401; // unused pins as outputs: PB0(HDR_DIO1), PB5 (PB10 pulled hi by LED), PB3-T_SWO
shaunkrnelson 0:46990814dc89 139 //printf("GPIOB->MODER:%08x\r\n", GPIOB->MODER);
shaunkrnelson 0:46990814dc89 140
shaunkrnelson 0:46990814dc89 141 GPIOC->MODER |= 0x00000045; // unused pins as outputs: PC0(hdr_fem_csd) PC1(hdr_fem_ctx) PC3(SPI3_enable)
shaunkrnelson 0:46990814dc89 142 //printf("GPIOC->MODER:%08x\r\n", GPIOC->MODER);
shaunkrnelson 0:46990814dc89 143
shaunkrnelson 0:46990814dc89 144 sx9500.RegProxCtrl0.bits.sensor_en = 3; // only CS0 and CS1 connected
shaunkrnelson 0:46990814dc89 145 sx9500.write(SX9500_REG_PROXCTRL0, sx9500.RegProxCtrl0.octet);
shaunkrnelson 0:46990814dc89 146
shaunkrnelson 0:46990814dc89 147 // set PROXTHRESH to 80 because CS1 has 48 showing always on PROXDIFF
shaunkrnelson 0:46990814dc89 148 sx9500.write(SX9500_REG_PROXCTRL6, 0x04);
shaunkrnelson 0:46990814dc89 149
shaunkrnelson 0:46990814dc89 150 // Enable accelerometer orientation detection
shaunkrnelson 0:46990814dc89 151 #define DEBUG
shaunkrnelson 0:46990814dc89 152 #ifdef DEBUG
shaunkrnelson 0:46990814dc89 153 mma8451q.verbose = true;
shaunkrnelson 0:46990814dc89 154 #endif
shaunkrnelson 0:46990814dc89 155 mma8451q.orient_detect();
shaunkrnelson 0:46990814dc89 156 mma8451q.set_active(true);
shaunkrnelson 0:46990814dc89 157
shaunkrnelson 0:46990814dc89 158 mpl3115a2.init();
shaunkrnelson 0:46990814dc89 159 mpl3115a2.SetModeStandby();
shaunkrnelson 0:46990814dc89 160
shaunkrnelson 0:46990814dc89 161 gps.enable(true);
shaunkrnelson 0:46990814dc89 162 }
shaunkrnelson 0:46990814dc89 163
shaunkrnelson 0:46990814dc89 164 // application commmon
shaunkrnelson 0:46990814dc89 165 bool gps_service()
shaunkrnelson 0:46990814dc89 166 {
shaunkrnelson 0:46990814dc89 167 gps.have_fix = false;
shaunkrnelson 0:46990814dc89 168 if (gps.enabled()) {
shaunkrnelson 0:46990814dc89 169 for(int32_t i = 0; i < 10; i++)
shaunkrnelson 0:46990814dc89 170 {
shaunkrnelson 0:46990814dc89 171 gps.service();
shaunkrnelson 0:46990814dc89 172 if (gps.have_fix == true) {
shaunkrnelson 0:46990814dc89 173 return true;
shaunkrnelson 0:46990814dc89 174 }
shaunkrnelson 0:46990814dc89 175 else
shaunkrnelson 1:fbf2fb2c2718 176 wait(.1);
shaunkrnelson 0:46990814dc89 177 }
shaunkrnelson 0:46990814dc89 178 }
shaunkrnelson 0:46990814dc89 179 return false;
shaunkrnelson 0:46990814dc89 180 }
shaunkrnelson 0:46990814dc89 181
shaunkrnelson 0:46990814dc89 182
shaunkrnelson 0:46990814dc89 183
shaunkrnelson 0:46990814dc89 184 static void restore_hsi()
shaunkrnelson 0:46990814dc89 185 {
shaunkrnelson 0:46990814dc89 186 RCC_OscInitTypeDef osc_init;
shaunkrnelson 0:46990814dc89 187 /* if HSI was shut off in deep sleep (needed for AnalogIn) */
shaunkrnelson 0:46990814dc89 188 HAL_RCC_GetOscConfig(&osc_init);
shaunkrnelson 0:46990814dc89 189 if (osc_init.HSIState != RCC_HSI_ON) {
shaunkrnelson 0:46990814dc89 190 // Enable the HSI (to clock the ADC)
shaunkrnelson 0:46990814dc89 191 osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSI;
shaunkrnelson 0:46990814dc89 192 osc_init.HSIState = RCC_HSI_ON;
shaunkrnelson 0:46990814dc89 193 osc_init.PLL.PLLState = RCC_PLL_NONE;
shaunkrnelson 0:46990814dc89 194 HAL_RCC_OscConfig(&osc_init);
shaunkrnelson 0:46990814dc89 195 }
shaunkrnelson 0:46990814dc89 196 }
shaunkrnelson 0:46990814dc89 197
shaunkrnelson 0:46990814dc89 198
shaunkrnelson 0:46990814dc89 199 u1_t PrepareDataFrame( SenetPacketT type )
shaunkrnelson 0:46990814dc89 200 {
shaunkrnelson 0:46990814dc89 201 u1_t pktLen = 0;
shaunkrnelson 0:46990814dc89 202
shaunkrnelson 0:46990814dc89 203 restore_hsi();
shaunkrnelson 0:46990814dc89 204
shaunkrnelson 0:46990814dc89 205 switch (type)
shaunkrnelson 0:46990814dc89 206 {
shaunkrnelson 0:46990814dc89 207 case SELF_ID_PACKET:
shaunkrnelson 0:46990814dc89 208 {
shaunkrnelson 0:46990814dc89 209 // Self Id packet type serialized to the LMIC frame buffer
shaunkrnelson 0:46990814dc89 210 SelfIdPacket packet(LMIC.frame, MAX_LEN_FRAME);
shaunkrnelson 1:fbf2fb2c2718 211
shaunkrnelson 0:46990814dc89 212 // Device Type
shaunkrnelson 0:46990814dc89 213 packet.setDeviceType(NORAM_MOTE_DEVICE_TYPE, get_mote_version());
shaunkrnelson 0:46990814dc89 214
shaunkrnelson 0:46990814dc89 215 // Software version
shaunkrnelson 0:46990814dc89 216 packet.setSwVersion(MAJOR, MINOR, POINT, BUILD_NUMBER, DEVELOPER_ID);
shaunkrnelson 0:46990814dc89 217
shaunkrnelson 0:46990814dc89 218 // Battery level
shaunkrnelson 0:46990814dc89 219 packet.setBatteryLevel(ReadBatteryLevel());
shaunkrnelson 0:46990814dc89 220
shaunkrnelson 0:46990814dc89 221 // Serialize packet to LMIC transmit buffer
shaunkrnelson 0:46990814dc89 222 pktLen = packet.serialize();
shaunkrnelson 0:46990814dc89 223
shaunkrnelson 0:46990814dc89 224 break;
shaunkrnelson 0:46990814dc89 225 }
shaunkrnelson 0:46990814dc89 226 case GPS_PACKET:
shaunkrnelson 0:46990814dc89 227 default:
shaunkrnelson 0:46990814dc89 228 {
shaunkrnelson 0:46990814dc89 229 // Gps packet type serialized to the LMIC frame buffer
shaunkrnelson 0:46990814dc89 230 GpsPacket packet(LMIC.frame, MAX_LEN_FRAME);
shaunkrnelson 1:fbf2fb2c2718 231
shaunkrnelson 0:46990814dc89 232 // set packet transmit power
shaunkrnelson 0:46990814dc89 233 packet.setTxPower(pw);
shaunkrnelson 0:46990814dc89 234
shaunkrnelson 1:fbf2fb2c2718 235 // Set packet coordinates
shaunkrnelson 1:fbf2fb2c2718 236 uint16_t altitudeGps = atoi(gps.NmeaGpsData.NmeaAltitude);
shaunkrnelson 1:fbf2fb2c2718 237 packet.setCoordinates(gps.LatitudeBinary, gps.LongitudeBinary, altitudeGps);
shaunkrnelson 1:fbf2fb2c2718 238 lastTxPos.set(gps.Latitude,gps.Longitude);
shaunkrnelson 1:fbf2fb2c2718 239
shaunkrnelson 0:46990814dc89 240 // Serialize packet
shaunkrnelson 0:46990814dc89 241 pktLen = packet.serialize();
shaunkrnelson 0:46990814dc89 242 break;
shaunkrnelson 0:46990814dc89 243 }
shaunkrnelson 0:46990814dc89 244 }
shaunkrnelson 0:46990814dc89 245
shaunkrnelson 0:46990814dc89 246 return pktLen;
shaunkrnelson 0:46990814dc89 247 }
shaunkrnelson 0:46990814dc89 248
shaunkrnelson 0:46990814dc89 249 void displayBuildInfo()
shaunkrnelson 0:46990814dc89 250 {
shaunkrnelson 0:46990814dc89 251 debug("Range & Site Tester\r\n");
shaunkrnelson 0:46990814dc89 252 debug("Version %02d.%02d.%02d.%04d.%02d\r\n",MAJOR,MINOR,POINT,BUILD_NUMBER,DEVELOPER_ID);
shaunkrnelson 0:46990814dc89 253 debug("\r\nDevEUI: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\r\n",
shaunkrnelson 0:46990814dc89 254 reverse_DEVEUI[0],
shaunkrnelson 0:46990814dc89 255 reverse_DEVEUI[1],
shaunkrnelson 0:46990814dc89 256 reverse_DEVEUI[2],
shaunkrnelson 0:46990814dc89 257 reverse_DEVEUI[3],
shaunkrnelson 0:46990814dc89 258 reverse_DEVEUI[4],
shaunkrnelson 0:46990814dc89 259 reverse_DEVEUI[5],
shaunkrnelson 0:46990814dc89 260 reverse_DEVEUI[6],
shaunkrnelson 0:46990814dc89 261 reverse_DEVEUI[7]);
shaunkrnelson 0:46990814dc89 262 debug("AppEUI: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\r\n",
shaunkrnelson 0:46990814dc89 263 reverse_APPEUI[0],
shaunkrnelson 0:46990814dc89 264 reverse_APPEUI[1],
shaunkrnelson 0:46990814dc89 265 reverse_APPEUI[2],
shaunkrnelson 0:46990814dc89 266 reverse_APPEUI[3],
shaunkrnelson 0:46990814dc89 267 reverse_APPEUI[4],
shaunkrnelson 0:46990814dc89 268 reverse_APPEUI[5],
shaunkrnelson 0:46990814dc89 269 reverse_APPEUI[6],
shaunkrnelson 0:46990814dc89 270 reverse_APPEUI[7]);
shaunkrnelson 0:46990814dc89 271 }
shaunkrnelson 0:46990814dc89 272
shaunkrnelson 0:46990814dc89 273
shaunkrnelson 0:46990814dc89 274 void startLMIC()
shaunkrnelson 0:46990814dc89 275 {
shaunkrnelson 0:46990814dc89 276 // reset MAC state
shaunkrnelson 0:46990814dc89 277 LMIC_reset();
shaunkrnelson 0:46990814dc89 278 // start joining
shaunkrnelson 0:46990814dc89 279 LMIC_startJoining();
shaunkrnelson 0:46990814dc89 280 }
shaunkrnelson 0:46990814dc89 281
shaunkrnelson 0:46990814dc89 282
shaunkrnelson 0:46990814dc89 283
shaunkrnelson 0:46990814dc89 284 // Operational mode
shaunkrnelson 0:46990814dc89 285 enum OperMode
shaunkrnelson 0:46990814dc89 286 {
shaunkrnelson 0:46990814dc89 287 // Range testing
shaunkrnelson 0:46990814dc89 288 RANGE_TEST,
shaunkrnelson 0:46990814dc89 289 // Site testing
shaunkrnelson 0:46990814dc89 290 SITE_TEST,
shaunkrnelson 0:46990814dc89 291 // Sending self-id packet
shaunkrnelson 0:46990814dc89 292 SELF_ID,
shaunkrnelson 0:46990814dc89 293 // No mode set
shaunkrnelson 0:46990814dc89 294 IDLE
shaunkrnelson 0:46990814dc89 295 };
shaunkrnelson 0:46990814dc89 296
shaunkrnelson 0:46990814dc89 297 // OS job management objects
shaunkrnelson 0:46990814dc89 298 static osjob_t statusLedJob;
shaunkrnelson 0:46990814dc89 299 static osjob_t txLedJob;
shaunkrnelson 0:46990814dc89 300 static osjob_t orientationJob;
shaunkrnelson 0:46990814dc89 301 static osjob_t sendFrameJob;
shaunkrnelson 0:46990814dc89 302
shaunkrnelson 0:46990814dc89 303 // Mote orientation is checked periodically. The mote test mode
shaunkrnelson 0:46990814dc89 304 // is selected by orientation. When mote is vertical it is in
shaunkrnelson 0:46990814dc89 305 // site test mode and range test mode when horizontal.
shaunkrnelson 0:46990814dc89 306 // Note that changing mote mode will abort previous mode testing
shaunkrnelson 0:46990814dc89 307 #define ORIENTATION_CHECK_PERIOD 5
shaunkrnelson 0:46990814dc89 308
shaunkrnelson 0:46990814dc89 309 // Debounce orientation change
shaunkrnelson 0:46990814dc89 310 #define ORIENTATION_DEBOUNCE_TIME 5
shaunkrnelson 0:46990814dc89 311
shaunkrnelson 0:46990814dc89 312 #define STATUS_FAST_BLINK 1
shaunkrnelson 0:46990814dc89 313 #define STATUS_SLOW_BLINK 4
shaunkrnelson 0:46990814dc89 314 #define STATUS_OK_PERIOD 5
shaunkrnelson 0:46990814dc89 315
shaunkrnelson 0:46990814dc89 316 static u4_t txCount = 0;
shaunkrnelson 0:46990814dc89 317 static ostime_t lastTestDoneT = 0;
shaunkrnelson 0:46990814dc89 318 static bool ackRequested = false;
shaunkrnelson 0:46990814dc89 319 static OperMode operMode = IDLE;
shaunkrnelson 0:46990814dc89 320 static OperMode txMode = IDLE;
shaunkrnelson 0:46990814dc89 321
shaunkrnelson 0:46990814dc89 322 //////////////////////////////////////////////////
shaunkrnelson 0:46990814dc89 323 // Range test configuration
shaunkrnelson 0:46990814dc89 324 //////////////////////////////////////////////////
shaunkrnelson 0:46990814dc89 325 #define RANGE_TXCYCLE_TRANSMITS 8
shaunkrnelson 0:46990814dc89 326 #define RANGE_NEXT_TEST_LONG 560
shaunkrnelson 0:46990814dc89 327 #define RANGE_NEXT_TEST_NOACK 140
shaunkrnelson 0:46990814dc89 328 #define RANGE_NEXT_TEST_DISTANCE 80
shaunkrnelson 0:46990814dc89 329 #define RANGE_NEXT_TEST_MIN_TIME 80
shaunkrnelson 0:46990814dc89 330 #define RANGE_NEXT_TX 5
shaunkrnelson 0:46990814dc89 331 #define RANGE_START_TEST_DISTANCE 30 // meters
shaunkrnelson 0:46990814dc89 332 #define RANGE_NEXT_TEST_DISTANCE_T 15
shaunkrnelson 0:46990814dc89 333
shaunkrnelson 0:46990814dc89 334
shaunkrnelson 0:46990814dc89 335 //////////////////////////////////////////////////
shaunkrnelson 0:46990814dc89 336 // Site test configuration
shaunkrnelson 0:46990814dc89 337 //////////////////////////////////////////////////
shaunkrnelson 0:46990814dc89 338 #define SITE_TX_PW1 14
shaunkrnelson 0:46990814dc89 339 #define SITE_TX_PW2 20
shaunkrnelson 0:46990814dc89 340 #define SITE_TX_PW3 30
shaunkrnelson 0:46990814dc89 341 #define SITE_GREEN_LED_PW SITE_TX_PW1
shaunkrnelson 0:46990814dc89 342 #define SITE_YELLOW_LED_PW SITE_TX_PW2
shaunkrnelson 0:46990814dc89 343 #define SITE_RED_LED_PW SITE_TX_PW3
shaunkrnelson 0:46990814dc89 344
shaunkrnelson 0:46990814dc89 345 static u1_t siteDrs[2] = {0,4};
shaunkrnelson 0:46990814dc89 346 static u1_t sitePws[3] = {SITE_TX_PW1, SITE_TX_PW2, SITE_TX_PW3};
shaunkrnelson 0:46990814dc89 347 static u1_t siteAck[3] = {0,0,0};
shaunkrnelson 0:46990814dc89 348 static u1_t siteDr = 0;
shaunkrnelson 0:46990814dc89 349 static u1_t sitePw = 0;
shaunkrnelson 0:46990814dc89 350 static u1_t siteDrPwAttempts = 0;
shaunkrnelson 0:46990814dc89 351 #define SITE_DR_MAX sizeof(siteDrs)
shaunkrnelson 0:46990814dc89 352 #define SITE_PW_MAX sizeof(sitePws)
shaunkrnelson 0:46990814dc89 353 #define SITE_PW_DR_ATTEMPTS 3
shaunkrnelson 0:46990814dc89 354
shaunkrnelson 0:46990814dc89 355
shaunkrnelson 0:46990814dc89 356 static void txLedCb(osjob_t *job)
shaunkrnelson 0:46990814dc89 357 {
shaunkrnelson 0:46990814dc89 358 if(operMode == RANGE_TEST)
shaunkrnelson 0:46990814dc89 359 {
shaunkrnelson 0:46990814dc89 360 ledRed = 1;
shaunkrnelson 0:46990814dc89 361 }
shaunkrnelson 0:46990814dc89 362 else if(operMode == SITE_TEST)
shaunkrnelson 0:46990814dc89 363 {
shaunkrnelson 0:46990814dc89 364 switch(pw)
shaunkrnelson 0:46990814dc89 365 {
shaunkrnelson 0:46990814dc89 366 case SITE_GREEN_LED_PW:
shaunkrnelson 0:46990814dc89 367 ledGreen = 1;
shaunkrnelson 0:46990814dc89 368 break;
shaunkrnelson 0:46990814dc89 369 case SITE_YELLOW_LED_PW:
shaunkrnelson 0:46990814dc89 370 ledYellow = 1;
shaunkrnelson 0:46990814dc89 371 break;
shaunkrnelson 0:46990814dc89 372 case SITE_RED_LED_PW:
shaunkrnelson 0:46990814dc89 373 ledRed = 1;
shaunkrnelson 0:46990814dc89 374 break;
shaunkrnelson 0:46990814dc89 375 }
shaunkrnelson 0:46990814dc89 376 }
shaunkrnelson 0:46990814dc89 377 }
shaunkrnelson 0:46990814dc89 378
shaunkrnelson 0:46990814dc89 379
shaunkrnelson 0:46990814dc89 380 static void onSendFrame(osjob_t* j)
shaunkrnelson 0:46990814dc89 381 {
shaunkrnelson 1:fbf2fb2c2718 382 u1_t pktSize = 0;
shaunkrnelson 0:46990814dc89 383
shaunkrnelson 0:46990814dc89 384 // Return if still transmitting. Next transmit will be scheduled by onEvent() when tx finishes
shaunkrnelson 0:46990814dc89 385 if (LMIC.opmode & OP_TXRXPEND)
shaunkrnelson 0:46990814dc89 386 return;
shaunkrnelson 0:46990814dc89 387
shaunkrnelson 0:46990814dc89 388 if(operMode == RANGE_TEST)
shaunkrnelson 0:46990814dc89 389 {
shaunkrnelson 0:46990814dc89 390 // Select dr and tx power
shaunkrnelson 0:46990814dc89 391 switch(txCount&0x07)
shaunkrnelson 0:46990814dc89 392 {
shaunkrnelson 0:46990814dc89 393 case 0:
shaunkrnelson 0:46990814dc89 394 dr = 3;
shaunkrnelson 0:46990814dc89 395 pw = 14;
shaunkrnelson 0:46990814dc89 396 ackRequested = true; // set this on the first tx of the group
shaunkrnelson 0:46990814dc89 397 ledYellow = 0;
shaunkrnelson 0:46990814dc89 398 ledGreen = 0;
shaunkrnelson 0:46990814dc89 399 break;
shaunkrnelson 0:46990814dc89 400 case 1:
shaunkrnelson 0:46990814dc89 401 dr = 0;
shaunkrnelson 0:46990814dc89 402 pw = 14;
shaunkrnelson 0:46990814dc89 403 break;
shaunkrnelson 0:46990814dc89 404 case 2:
shaunkrnelson 0:46990814dc89 405 dr = 4;
shaunkrnelson 0:46990814dc89 406 pw = 20;
shaunkrnelson 0:46990814dc89 407 break;
shaunkrnelson 0:46990814dc89 408 case 3:
shaunkrnelson 0:46990814dc89 409 dr = 3;
shaunkrnelson 0:46990814dc89 410 pw = 20;
shaunkrnelson 0:46990814dc89 411 break;
shaunkrnelson 0:46990814dc89 412 case 4:
shaunkrnelson 0:46990814dc89 413 dr = 0;
shaunkrnelson 0:46990814dc89 414 pw = 20;
shaunkrnelson 0:46990814dc89 415 break;
shaunkrnelson 0:46990814dc89 416 case 5:
shaunkrnelson 0:46990814dc89 417 dr = 4;
shaunkrnelson 0:46990814dc89 418 pw = 26;
shaunkrnelson 0:46990814dc89 419 break;
shaunkrnelson 0:46990814dc89 420 case 6:
shaunkrnelson 0:46990814dc89 421 dr = 3;
shaunkrnelson 0:46990814dc89 422 pw = 30;
shaunkrnelson 0:46990814dc89 423 break;
shaunkrnelson 0:46990814dc89 424 case 7:
shaunkrnelson 0:46990814dc89 425 dr = 0;
shaunkrnelson 0:46990814dc89 426 pw = 30;
shaunkrnelson 0:46990814dc89 427 break;
shaunkrnelson 0:46990814dc89 428 }
shaunkrnelson 0:46990814dc89 429 // Blink transmit LED
shaunkrnelson 0:46990814dc89 430 ledRed = 0;
shaunkrnelson 0:46990814dc89 431 os_setTimedCallback( &txLedJob, os_getTime() + 1, txLedCb);
shaunkrnelson 0:46990814dc89 432 }
shaunkrnelson 0:46990814dc89 433 else if (operMode == SITE_TEST)
shaunkrnelson 0:46990814dc89 434 {
shaunkrnelson 0:46990814dc89 435 ackRequested = true;
shaunkrnelson 0:46990814dc89 436
shaunkrnelson 0:46990814dc89 437 if((siteDr < SITE_DR_MAX) && (sitePw < SITE_PW_MAX))
shaunkrnelson 0:46990814dc89 438 {
shaunkrnelson 0:46990814dc89 439 dr = siteDrs[siteDr];
shaunkrnelson 0:46990814dc89 440 pw = sitePws[sitePw];
shaunkrnelson 0:46990814dc89 441 }
shaunkrnelson 0:46990814dc89 442 // Restarting test
shaunkrnelson 0:46990814dc89 443 else
shaunkrnelson 0:46990814dc89 444 {
shaunkrnelson 0:46990814dc89 445 debug("Bad dr=%d or pw=%d index\r\n", siteDr, sitePw);
shaunkrnelson 0:46990814dc89 446 siteDr = 0;
shaunkrnelson 0:46990814dc89 447 sitePw = 0;
shaunkrnelson 0:46990814dc89 448 }
shaunkrnelson 0:46990814dc89 449 // Blink tx LED
shaunkrnelson 0:46990814dc89 450 switch(pw)
shaunkrnelson 0:46990814dc89 451 {
shaunkrnelson 0:46990814dc89 452 case SITE_GREEN_LED_PW:
shaunkrnelson 0:46990814dc89 453 ledGreen = 0;
shaunkrnelson 0:46990814dc89 454 break;
shaunkrnelson 0:46990814dc89 455 case SITE_YELLOW_LED_PW:
shaunkrnelson 0:46990814dc89 456 ledYellow = 0;
shaunkrnelson 0:46990814dc89 457 break;
shaunkrnelson 0:46990814dc89 458 case SITE_RED_LED_PW:
shaunkrnelson 0:46990814dc89 459 ledRed = 0;
shaunkrnelson 0:46990814dc89 460 break;
shaunkrnelson 0:46990814dc89 461 }
shaunkrnelson 0:46990814dc89 462 os_setTimedCallback( &txLedJob, os_getTime() + 1, txLedCb);
shaunkrnelson 0:46990814dc89 463 }
shaunkrnelson 16:2e5438977b6c 464
shaunkrnelson 1:fbf2fb2c2718 465 // Send GPS data
shaunkrnelson 1:fbf2fb2c2718 466 for(int32_t i=0; i<3; i++)
shaunkrnelson 1:fbf2fb2c2718 467 {
shaunkrnelson 1:fbf2fb2c2718 468 if(gps_service() == true)
shaunkrnelson 1:fbf2fb2c2718 469 {
shaunkrnelson 16:2e5438977b6c 470 pktSize = PrepareDataFrame(GPS_PACKET);
shaunkrnelson 1:fbf2fb2c2718 471 break;
shaunkrnelson 1:fbf2fb2c2718 472 }
shaunkrnelson 1:fbf2fb2c2718 473 }
shaunkrnelson 1:fbf2fb2c2718 474
shaunkrnelson 16:2e5438977b6c 475 // if unable to get GPS, send self-id
shaunkrnelson 1:fbf2fb2c2718 476 if(0 == pktSize)
shaunkrnelson 16:2e5438977b6c 477 pktSize = PrepareDataFrame(SELF_ID_PACKET);
shaunkrnelson 0:46990814dc89 478
shaunkrnelson 0:46990814dc89 479
shaunkrnelson 16:2e5438977b6c 480 // Set next dr and tx power
shaunkrnelson 16:2e5438977b6c 481 LMIC_setDrTxpow(dr,pw);
shaunkrnelson 16:2e5438977b6c 482
shaunkrnelson 0:46990814dc89 483 txCount++;
shaunkrnelson 0:46990814dc89 484 txMode = operMode;
shaunkrnelson 0:46990814dc89 485
shaunkrnelson 0:46990814dc89 486 debug("onSendFrame mode=%d: dr=%d, pw=%d, ack=%d\r\n",operMode, dr, pw, ackRequested);
shaunkrnelson 0:46990814dc89 487 LMIC_setTxData2(1, LMIC.frame, pktSize, ackRequested);
shaunkrnelson 0:46990814dc89 488 }
shaunkrnelson 0:46990814dc89 489
shaunkrnelson 0:46990814dc89 490 static void checkIfRangeTestStart(osjob_t *job)
shaunkrnelson 0:46990814dc89 491 {
shaunkrnelson 0:46990814dc89 492 const ostime_t waitT = ackRequested ? RANGE_NEXT_TEST_NOACK : RANGE_NEXT_TEST_LONG;
shaunkrnelson 0:46990814dc89 493 const ostime_t startT = lastTestDoneT + sec2osticks(waitT);
shaunkrnelson 0:46990814dc89 494
shaunkrnelson 0:46990814dc89 495 debug("%u seconds elapsed since last test\r\n",osticks2ms(os_getTime()-lastTestDoneT)/1000);
shaunkrnelson 0:46990814dc89 496
shaunkrnelson 16:2e5438977b6c 497 if(os_getTime() >= startT)
shaunkrnelson 16:2e5438977b6c 498 {
shaunkrnelson 16:2e5438977b6c 499 os_setCallback( &sendFrameJob, onSendFrame );
shaunkrnelson 16:2e5438977b6c 500 }
shaunkrnelson 16:2e5438977b6c 501 else if(gps_service())
shaunkrnelson 0:46990814dc89 502 {
shaunkrnelson 0:46990814dc89 503 // Do we have last tx coordinates
shaunkrnelson 0:46990814dc89 504 if((lastTxPos.latitude() == 0) && (lastTxPos.longitude() == 0))
shaunkrnelson 0:46990814dc89 505 {
shaunkrnelson 0:46990814dc89 506 // Set last tx position to current location
shaunkrnelson 0:46990814dc89 507 lastTxPos.set(gps.Latitude,gps.Longitude);
shaunkrnelson 0:46990814dc89 508 }
shaunkrnelson 0:46990814dc89 509 else
shaunkrnelson 0:46990814dc89 510 {
shaunkrnelson 0:46990814dc89 511 GeoPosition location(gps.Latitude, gps.Longitude);
shaunkrnelson 0:46990814dc89 512 double distance = location.distance(lastTxPos);
shaunkrnelson 0:46990814dc89 513
shaunkrnelson 0:46990814dc89 514 if(distance >= RANGE_START_TEST_DISTANCE)
shaunkrnelson 0:46990814dc89 515 {
shaunkrnelson 0:46990814dc89 516 debug("position change %f >= %u\r\n",distance, RANGE_START_TEST_DISTANCE);
shaunkrnelson 0:46990814dc89 517 os_setCallback( &sendFrameJob, onSendFrame );
shaunkrnelson 0:46990814dc89 518 return;
shaunkrnelson 0:46990814dc89 519 }
shaunkrnelson 0:46990814dc89 520 }
shaunkrnelson 0:46990814dc89 521 }
shaunkrnelson 0:46990814dc89 522
shaunkrnelson 0:46990814dc89 523 // Schedule next check
shaunkrnelson 0:46990814dc89 524 ostime_t nextChkT = os_getTime() + sec2osticks(RANGE_NEXT_TEST_DISTANCE_T);
shaunkrnelson 0:46990814dc89 525
shaunkrnelson 0:46990814dc89 526 // If distance check time less than test start, schedule distance check
shaunkrnelson 0:46990814dc89 527 if(nextChkT <= startT)
shaunkrnelson 0:46990814dc89 528 {
shaunkrnelson 0:46990814dc89 529 os_setTimedCallback( &sendFrameJob, nextChkT, checkIfRangeTestStart);
shaunkrnelson 0:46990814dc89 530 }
shaunkrnelson 0:46990814dc89 531 // Else test start less than distance check time
shaunkrnelson 0:46990814dc89 532 else
shaunkrnelson 0:46990814dc89 533 {
shaunkrnelson 0:46990814dc89 534 os_setTimedCallback( &sendFrameJob, startT, onSendFrame);
shaunkrnelson 0:46990814dc89 535 }
shaunkrnelson 0:46990814dc89 536 }
shaunkrnelson 0:46990814dc89 537
shaunkrnelson 0:46990814dc89 538 static void preTestStart(osjob_t *job)
shaunkrnelson 0:46990814dc89 539 {
shaunkrnelson 0:46990814dc89 540 static u1_t wait = 0;
shaunkrnelson 0:46990814dc89 541
shaunkrnelson 0:46990814dc89 542 // onEvent will initiate test on join or tx complete
shaunkrnelson 0:46990814dc89 543 if(((LMIC.opmode & OP_JOINING) != 0) || ((LMIC.opmode & OP_TXRXPEND) != 0))
shaunkrnelson 0:46990814dc89 544 return;
shaunkrnelson 0:46990814dc89 545
shaunkrnelson 0:46990814dc89 546 if(wait < 6)
shaunkrnelson 0:46990814dc89 547 {
shaunkrnelson 0:46990814dc89 548 if((wait & 1) == 0)
shaunkrnelson 0:46990814dc89 549 {
shaunkrnelson 0:46990814dc89 550 ledRed = 0;
shaunkrnelson 0:46990814dc89 551 ledGreen = 0;
shaunkrnelson 0:46990814dc89 552 ledYellow = 0;
shaunkrnelson 0:46990814dc89 553 }
shaunkrnelson 0:46990814dc89 554 else
shaunkrnelson 0:46990814dc89 555 {
shaunkrnelson 0:46990814dc89 556 ledRed = 1;
shaunkrnelson 0:46990814dc89 557 ledGreen = 1;
shaunkrnelson 0:46990814dc89 558 ledYellow = 1;
shaunkrnelson 0:46990814dc89 559 }
shaunkrnelson 0:46990814dc89 560 wait++;
shaunkrnelson 0:46990814dc89 561 os_setTimedCallback( &sendFrameJob, os_getTime() + sec2osticks(1), preTestStart);
shaunkrnelson 0:46990814dc89 562 }
shaunkrnelson 0:46990814dc89 563 else
shaunkrnelson 0:46990814dc89 564 {
shaunkrnelson 0:46990814dc89 565 wait = 0;
shaunkrnelson 0:46990814dc89 566 os_setCallback( &sendFrameJob, onSendFrame);
shaunkrnelson 0:46990814dc89 567 }
shaunkrnelson 0:46990814dc89 568 }
shaunkrnelson 0:46990814dc89 569
shaunkrnelson 0:46990814dc89 570
shaunkrnelson 0:46990814dc89 571 // Protocol event handler
shaunkrnelson 0:46990814dc89 572 void onEvent (ev_t ev)
shaunkrnelson 0:46990814dc89 573 {
shaunkrnelson 0:46990814dc89 574 debug_event(ev);
shaunkrnelson 0:46990814dc89 575 switch(ev)
shaunkrnelson 0:46990814dc89 576 {
shaunkrnelson 0:46990814dc89 577 // network joined, session established
shaunkrnelson 0:46990814dc89 578 case EV_JOINED:
shaunkrnelson 1:fbf2fb2c2718 579 {
shaunkrnelson 1:fbf2fb2c2718 580 displayBuildInfo();
shaunkrnelson 1:fbf2fb2c2718 581 //
shaunkrnelson 0:46990814dc89 582 // Disable link check validation
shaunkrnelson 0:46990814dc89 583 LMIC_setLinkCheckMode(false);
shaunkrnelson 0:46990814dc89 584
shaunkrnelson 1:fbf2fb2c2718 585 // Start transmitting
shaunkrnelson 1:fbf2fb2c2718 586 os_setCallback( &sendFrameJob, onSendFrame);
shaunkrnelson 0:46990814dc89 587
shaunkrnelson 0:46990814dc89 588 break;
shaunkrnelson 0:46990814dc89 589 }
shaunkrnelson 0:46990814dc89 590 // scheduled data sent (optionally data received)
shaunkrnelson 0:46990814dc89 591 case EV_TXCOMPLETE:
shaunkrnelson 0:46990814dc89 592 // Check transmitted frame mode matches running mode. If not, skip results
shaunkrnelson 0:46990814dc89 593 // and start sending frames for current mode
shaunkrnelson 0:46990814dc89 594 if(txMode != operMode)
shaunkrnelson 0:46990814dc89 595 {
shaunkrnelson 0:46990814dc89 596 // Prepare to start test
shaunkrnelson 0:46990814dc89 597 os_setCallback( &sendFrameJob, preTestStart);
shaunkrnelson 0:46990814dc89 598 }
shaunkrnelson 0:46990814dc89 599 else if(operMode == RANGE_TEST)
shaunkrnelson 0:46990814dc89 600 {
shaunkrnelson 0:46990814dc89 601 // Check ack received
shaunkrnelson 0:46990814dc89 602 if((LMIC.txrxFlags & (TXRX_DNW1|TXRX_DNW2) )!= 0 )
shaunkrnelson 0:46990814dc89 603 {
shaunkrnelson 0:46990814dc89 604 ackRequested = false;
shaunkrnelson 0:46990814dc89 605 ledYellow = 1;
shaunkrnelson 0:46990814dc89 606 }
shaunkrnelson 0:46990814dc89 607
shaunkrnelson 0:46990814dc89 608 if(0 == (txCount & 0x07))
shaunkrnelson 0:46990814dc89 609 {
shaunkrnelson 0:46990814dc89 610 // Schedule job to check for range test restart
shaunkrnelson 0:46990814dc89 611 lastTestDoneT = os_getTime();
shaunkrnelson 0:46990814dc89 612 os_setTimedCallback( &sendFrameJob, lastTestDoneT + sec2osticks(RANGE_NEXT_TEST_MIN_TIME), checkIfRangeTestStart);
shaunkrnelson 0:46990814dc89 613 debug("Check for test restart in %u seconds\r\n",RANGE_NEXT_TEST_MIN_TIME);
shaunkrnelson 0:46990814dc89 614
shaunkrnelson 0:46990814dc89 615 // Turn off transmit cycle indicator led
shaunkrnelson 0:46990814dc89 616 ledGreen = 1;
shaunkrnelson 0:46990814dc89 617 }
shaunkrnelson 0:46990814dc89 618 else
shaunkrnelson 0:46990814dc89 619 {
shaunkrnelson 0:46990814dc89 620 os_setTimedCallback( &sendFrameJob, os_getTime() + sec2osticks(RANGE_NEXT_TX), onSendFrame);
shaunkrnelson 0:46990814dc89 621 }
shaunkrnelson 0:46990814dc89 622 }
shaunkrnelson 0:46990814dc89 623 else if(operMode == SITE_TEST)
shaunkrnelson 0:46990814dc89 624 {
shaunkrnelson 0:46990814dc89 625 // Ack received
shaunkrnelson 0:46990814dc89 626 if(((LMIC.txrxFlags & (TXRX_DNW1|TXRX_DNW2) ) != 0 ))
shaunkrnelson 0:46990814dc89 627 {
shaunkrnelson 0:46990814dc89 628 siteAck[sitePw] = 1;
shaunkrnelson 0:46990814dc89 629
shaunkrnelson 0:46990814dc89 630 // Turn on LED
shaunkrnelson 0:46990814dc89 631 switch(pw)
shaunkrnelson 0:46990814dc89 632 {
shaunkrnelson 0:46990814dc89 633 case SITE_GREEN_LED_PW:
shaunkrnelson 0:46990814dc89 634 ledGreen = 0;
shaunkrnelson 0:46990814dc89 635 break;
shaunkrnelson 0:46990814dc89 636 case SITE_YELLOW_LED_PW:
shaunkrnelson 0:46990814dc89 637 ledYellow = 0;
shaunkrnelson 0:46990814dc89 638 break;
shaunkrnelson 0:46990814dc89 639 case SITE_RED_LED_PW:
shaunkrnelson 0:46990814dc89 640 ledRed = 0;
shaunkrnelson 0:46990814dc89 641 break;
shaunkrnelson 0:46990814dc89 642 }
shaunkrnelson 0:46990814dc89 643
shaunkrnelson 0:46990814dc89 644 // Set next tx power first transmit rate
shaunkrnelson 0:46990814dc89 645 sitePw++;
shaunkrnelson 0:46990814dc89 646 siteDrPwAttempts = 0;
shaunkrnelson 0:46990814dc89 647 }
shaunkrnelson 0:46990814dc89 648 // No ACK
shaunkrnelson 0:46990814dc89 649 else if(++siteDrPwAttempts >= SITE_PW_DR_ATTEMPTS)
shaunkrnelson 0:46990814dc89 650 {
shaunkrnelson 0:46990814dc89 651 sitePw++;
shaunkrnelson 0:46990814dc89 652 siteDrPwAttempts = 0;
shaunkrnelson 0:46990814dc89 653 }
shaunkrnelson 0:46990814dc89 654
shaunkrnelson 0:46990814dc89 655 if(sitePw >= SITE_PW_MAX)
shaunkrnelson 0:46990814dc89 656 {
shaunkrnelson 0:46990814dc89 657 sitePw=0;
shaunkrnelson 0:46990814dc89 658 siteDr++;
shaunkrnelson 0:46990814dc89 659 if(siteDr >= SITE_DR_MAX)
shaunkrnelson 0:46990814dc89 660 siteDr=0;
shaunkrnelson 0:46990814dc89 661 }
shaunkrnelson 0:46990814dc89 662
shaunkrnelson 0:46990814dc89 663 if(siteAck[sitePw] == 0)
shaunkrnelson 0:46990814dc89 664 {
shaunkrnelson 0:46990814dc89 665 os_setTimedCallback( &sendFrameJob, os_getTime() + sec2osticks(1), onSendFrame );
shaunkrnelson 0:46990814dc89 666 }
shaunkrnelson 0:46990814dc89 667 else
shaunkrnelson 0:46990814dc89 668 {
shaunkrnelson 0:46990814dc89 669 bool foundNACK = false;
shaunkrnelson 0:46990814dc89 670
shaunkrnelson 0:46990814dc89 671 for(uint32_t i=sitePw; i < SITE_PW_MAX;i++)
shaunkrnelson 0:46990814dc89 672 {
shaunkrnelson 0:46990814dc89 673 if(siteAck[i] == 0)
shaunkrnelson 0:46990814dc89 674 {
shaunkrnelson 0:46990814dc89 675 sitePw = i;
shaunkrnelson 0:46990814dc89 676 os_setTimedCallback( &sendFrameJob, os_getTime() + sec2osticks(1), onSendFrame );
shaunkrnelson 0:46990814dc89 677 foundNACK = true;
shaunkrnelson 0:46990814dc89 678 break;
shaunkrnelson 0:46990814dc89 679 }
shaunkrnelson 0:46990814dc89 680 }
shaunkrnelson 0:46990814dc89 681
shaunkrnelson 0:46990814dc89 682 if(foundNACK == false)
shaunkrnelson 0:46990814dc89 683 {
shaunkrnelson 0:46990814dc89 684 siteDr++;
shaunkrnelson 0:46990814dc89 685 if(siteDr >= SITE_DR_MAX)
shaunkrnelson 0:46990814dc89 686 siteDr=0;
shaunkrnelson 0:46990814dc89 687
shaunkrnelson 0:46990814dc89 688 for(uint32_t i=0; i < sitePw;i++)
shaunkrnelson 0:46990814dc89 689 {
shaunkrnelson 0:46990814dc89 690 if(siteAck[i] == 0)
shaunkrnelson 0:46990814dc89 691 {
shaunkrnelson 0:46990814dc89 692 sitePw = i;
shaunkrnelson 0:46990814dc89 693 os_setTimedCallback( &sendFrameJob, os_getTime() + sec2osticks(1), onSendFrame );
shaunkrnelson 0:46990814dc89 694 break;
shaunkrnelson 0:46990814dc89 695 }
shaunkrnelson 0:46990814dc89 696 }
shaunkrnelson 0:46990814dc89 697 }
shaunkrnelson 0:46990814dc89 698 }
shaunkrnelson 0:46990814dc89 699 }
shaunkrnelson 0:46990814dc89 700 break;
shaunkrnelson 0:46990814dc89 701 default:
shaunkrnelson 0:46990814dc89 702 break;
shaunkrnelson 0:46990814dc89 703 }
shaunkrnelson 0:46990814dc89 704 }
shaunkrnelson 0:46990814dc89 705
shaunkrnelson 0:46990814dc89 706
shaunkrnelson 0:46990814dc89 707 static void statusLedCb(osjob_t *job)
shaunkrnelson 0:46990814dc89 708 {
shaunkrnelson 0:46990814dc89 709 ostime_t sleep;
shaunkrnelson 0:46990814dc89 710
shaunkrnelson 0:46990814dc89 711 if(ledUsr == 1)
shaunkrnelson 0:46990814dc89 712 {
shaunkrnelson 0:46990814dc89 713 if((LMIC.opmode & OP_JOINING) != 0)
shaunkrnelson 0:46990814dc89 714 {
shaunkrnelson 0:46990814dc89 715 ledUsr = 0;
shaunkrnelson 0:46990814dc89 716 sleep = STATUS_FAST_BLINK;
shaunkrnelson 0:46990814dc89 717 }
shaunkrnelson 0:46990814dc89 718 else if(gps.have_fix == false)
shaunkrnelson 0:46990814dc89 719 {
shaunkrnelson 0:46990814dc89 720 ledUsr = 0;
shaunkrnelson 0:46990814dc89 721 sleep = STATUS_SLOW_BLINK;
shaunkrnelson 0:46990814dc89 722 }
shaunkrnelson 0:46990814dc89 723 else
shaunkrnelson 0:46990814dc89 724 {
shaunkrnelson 0:46990814dc89 725 sleep = STATUS_OK_PERIOD;
shaunkrnelson 0:46990814dc89 726 }
shaunkrnelson 0:46990814dc89 727 }
shaunkrnelson 0:46990814dc89 728 else
shaunkrnelson 0:46990814dc89 729 {
shaunkrnelson 0:46990814dc89 730 ledUsr = 1;
shaunkrnelson 0:46990814dc89 731 sleep = 1;
shaunkrnelson 0:46990814dc89 732 }
shaunkrnelson 0:46990814dc89 733
shaunkrnelson 0:46990814dc89 734 os_setTimedCallback( &statusLedJob, os_getTime() + sec2osticks(sleep), statusLedCb );
shaunkrnelson 0:46990814dc89 735 }
shaunkrnelson 0:46990814dc89 736
shaunkrnelson 0:46990814dc89 737
shaunkrnelson 0:46990814dc89 738 static void orientationJobCb(osjob_t *job)
shaunkrnelson 0:46990814dc89 739 {
shaunkrnelson 0:46990814dc89 740 static MMA_orientation last;
shaunkrnelson 16:2e5438977b6c 741 MMA_orientation current;
shaunkrnelson 0:46990814dc89 742 int sleepTime = ORIENTATION_CHECK_PERIOD;
shaunkrnelson 0:46990814dc89 743
shaunkrnelson 0:46990814dc89 744 mma8451q.service();
shaunkrnelson 16:2e5438977b6c 745 current = mma8451q.getOrientation();
shaunkrnelson 0:46990814dc89 746
shaunkrnelson 16:2e5438977b6c 747 if(current != last)
shaunkrnelson 0:46990814dc89 748 {
shaunkrnelson 16:2e5438977b6c 749 last = current;
shaunkrnelson 0:46990814dc89 750 sleepTime = ORIENTATION_DEBOUNCE_TIME;
shaunkrnelson 0:46990814dc89 751 }
shaunkrnelson 0:46990814dc89 752 else
shaunkrnelson 16:2e5438977b6c 753 {
shaunkrnelson 16:2e5438977b6c 754 const bool currIsVertical = !current.low && current.right;
shaunkrnelson 16:2e5438977b6c 755 const OperMode mode = currIsVertical ? SITE_TEST : RANGE_TEST;
shaunkrnelson 7:6a23db89f2a6 756
shaunkrnelson 0:46990814dc89 757 if(mode != operMode)
shaunkrnelson 0:46990814dc89 758 {
shaunkrnelson 0:46990814dc89 759 debug("Change to %s mode\r\n", mode==SITE_TEST?"Site":"Range");
shaunkrnelson 0:46990814dc89 760
shaunkrnelson 0:46990814dc89 761 // onEvent will start test if currently joining or transmitting
shaunkrnelson 0:46990814dc89 762 if(((LMIC.opmode & OP_JOINING) == 0) && ((LMIC.opmode & OP_TXRXPEND) == 0))
shaunkrnelson 0:46990814dc89 763 {
shaunkrnelson 0:46990814dc89 764 if(operMode != IDLE)
shaunkrnelson 0:46990814dc89 765 {
shaunkrnelson 0:46990814dc89 766 os_setCallback( &sendFrameJob, preTestStart);
shaunkrnelson 0:46990814dc89 767 }
shaunkrnelson 0:46990814dc89 768 else
shaunkrnelson 0:46990814dc89 769 {
shaunkrnelson 0:46990814dc89 770 os_setCallback( &sendFrameJob, onSendFrame);
shaunkrnelson 0:46990814dc89 771 }
shaunkrnelson 0:46990814dc89 772 }
shaunkrnelson 0:46990814dc89 773
shaunkrnelson 0:46990814dc89 774 // Set mode
shaunkrnelson 0:46990814dc89 775 operMode = mode;
shaunkrnelson 0:46990814dc89 776
shaunkrnelson 0:46990814dc89 777 // Reset test indicator LEDs
shaunkrnelson 0:46990814dc89 778 ledRed = 1;
shaunkrnelson 0:46990814dc89 779 ledGreen = 1;
shaunkrnelson 0:46990814dc89 780 ledYellow = 1;
shaunkrnelson 0:46990814dc89 781
shaunkrnelson 0:46990814dc89 782 // Reset test state
shaunkrnelson 0:46990814dc89 783 txCount = 0;
shaunkrnelson 0:46990814dc89 784 siteDr = 0;
shaunkrnelson 0:46990814dc89 785 sitePw = 0;
shaunkrnelson 0:46990814dc89 786 memset(siteAck, 0, sizeof(siteAck));
shaunkrnelson 0:46990814dc89 787 }
shaunkrnelson 0:46990814dc89 788 }
shaunkrnelson 0:46990814dc89 789
shaunkrnelson 0:46990814dc89 790 os_setTimedCallback( &orientationJob, os_getTime() + sec2osticks(sleepTime), orientationJobCb );
shaunkrnelson 0:46990814dc89 791 }
shaunkrnelson 0:46990814dc89 792
shaunkrnelson 0:46990814dc89 793 // Kick off initial jobs
shaunkrnelson 0:46990814dc89 794 void application_init()
shaunkrnelson 0:46990814dc89 795 {
shaunkrnelson 0:46990814dc89 796 // Start status led job
shaunkrnelson 0:46990814dc89 797 os_setCallback(&statusLedJob, statusLedCb);
shaunkrnelson 0:46990814dc89 798
shaunkrnelson 0:46990814dc89 799 // Start orientation job - Test will start once orientation is determined
shaunkrnelson 0:46990814dc89 800 os_setCallback(&orientationJob, orientationJobCb);
shaunkrnelson 0:46990814dc89 801
shaunkrnelson 0:46990814dc89 802 // Get current gps coordinates
shaunkrnelson 0:46990814dc89 803 if(gps_service() == true)
shaunkrnelson 0:46990814dc89 804 lastTxPos.set(gps.Latitude,gps.Longitude);
shaunkrnelson 0:46990814dc89 805 else
shaunkrnelson 0:46990814dc89 806 lastTxPos.set(0,0);
shaunkrnelson 0:46990814dc89 807 }
shaunkrnelson 0:46990814dc89 808
shaunkrnelson 0:46990814dc89 809
shaunkrnelson 0:46990814dc89 810 int main(void)
shaunkrnelson 0:46990814dc89 811 {
shaunkrnelson 0:46990814dc89 812 // initialize runtime env
shaunkrnelson 0:46990814dc89 813 os_init();
shaunkrnelson 0:46990814dc89 814
shaunkrnelson 0:46990814dc89 815 // initialize debug system
shaunkrnelson 0:46990814dc89 816 debug_init();
shaunkrnelson 0:46990814dc89 817
shaunkrnelson 0:46990814dc89 818 // Display build info
shaunkrnelson 0:46990814dc89 819 displayBuildInfo();
shaunkrnelson 0:46990814dc89 820
shaunkrnelson 0:46990814dc89 821 // initialize peripherals
shaunkrnelson 0:46990814dc89 822 board_peripherals_init();
shaunkrnelson 0:46990814dc89 823
shaunkrnelson 0:46990814dc89 824 // Application initialization
shaunkrnelson 0:46990814dc89 825 application_init();
shaunkrnelson 0:46990814dc89 826
shaunkrnelson 0:46990814dc89 827 // Start protocol
shaunkrnelson 0:46990814dc89 828 startLMIC();
shaunkrnelson 0:46990814dc89 829
shaunkrnelson 0:46990814dc89 830 // execute scheduled jobs and events
shaunkrnelson 0:46990814dc89 831 os_runloop();
shaunkrnelson 0:46990814dc89 832 // (not reached)
shaunkrnelson 0:46990814dc89 833 }
shaunkrnelson 0:46990814dc89 834