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 Mar 18 13:42:03 2016 +0000
Revision:
0:46990814dc89
Child:
1:fbf2fb2c2718
Initial commit of Senet NAMote network coverage tool

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