LMIC for MOTE_L152RC
Currently version 1.5
LoRaWAN network configuration for end-device
The following three pieces of information uniquely identifies end-device to network to allow over-the-air activation. These are stored in the end-device prior to join procedure.
AppEUI
Uniquely identifies application provider of end-device.
Least-significant byte first, 8 bytes. Use LMIC_reverse_memcpy() for AppEUI to keep same byte order as that on lora server.
example C code
static const u1_t APPEUI[8] = { 0x01, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x25, 0x00 };
This is copied into LMIC by os_getArtEui()
callback function in application.
DevEUI
End-device ID, unique to each end-node.
Least-significant byte first, 8 bytes. Use LMIC_reverse_memcpy() for DevEUI to keep same byte order as that on lora server.
example C code
static const u1_t DEVEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x0C, 0x25, 0x00 };
This is copied into LMIC by os_getDevEui()
callback function in application.
AppKey (aka DevKey)
128-bit (16byte) AES key.
example C code
static const u1_t DEVKEY[16] = { 0xe4, 0x72, 0x71, 0xc5, 0xf5, 0x30, 0xa9, 0x9f, 0xcf, 0xc4, 0x0e, 0xab, 0xea, 0xd7, 0x19, 0x42 };
This is copied into LMIC by os_getDevKey()
callback function in application.
Using over-the air activation, the end-device (LMIC) performs a join procedure every time it starts for first time, or has lost session context information. When join procedure has successfully completed, the end-device will have a network session key (NwkSKey) and an application session key (AppSKey), which are used for encryption and message integrity check.
configuration with http://us01-iot.semtech.com/
- log in to server
- click on Applications
- find your application and click it
- go to configure motes
- to create a mote, you may enter a new DevEUI
- you may copy-paste the 16byte application key from an already existing mote, if you desire.
Information
DevEUI is entered in reverse order into C-code from that shown on server (unique device ID).
AppEUI is entered in reverse order into C-code from that shown on server.
AppEUI is equivalent to "Application"
transmit power limits
FCC Part 15 rules permit one watt of transmit power when more than 50 channels are used. When received by a 64-channel gateway, the maximum power may be used.
However, if end-device is sending to a 8-channel gateway (single SX1301), the maximum transmit power permitted is +20dBm.
To configure LMIC for use with 8-channel gateway, CHNL_HYBRID
should be defined in in config.h, and should be undefined for use with 64-channel gateway.
CHNL_HYBRID | 125KHz | 500KHz |
---|---|---|
defined value | channels | channel |
0 | 0 to 7 | 64 |
1 | 8 to 15 | 65 |
2 | 16 to 23 | 66 |
3 | 24 to 31 | 67 |
4 | 32 to 39 | 68 |
5 | 40 to 47 | 69 |
6 | 48 to 55 | 70 |
7 | 56 to 63 | 71 |
undef | 0 to 63 | 64 to 71 |
TARGET_MOTE_L152RC/hal.cpp
- Committer:
- dudmuck
- Date:
- 2015-06-02
- Revision:
- 0:f2716e543d97
- Child:
- 1:04fd63382b03
File content as of revision 0:f2716e543d97:
/* HAL for MOTE_L152RC */ #include "mbed.h" #include "oslmic.h" #include "debug.h" #define RADIO_MOSI PB_15 #define RADIO_MISO PB_14 #define RADIO_SCLK PB_13 #define RADIO_NSS PB_12 #define RESET_PIN PC_2 #define RFSW1 PC_4 //NorAm_Mote RFSwitch_CNTR_1 #define RFSW2 PC_13 //NorAm_Mote RFSwitch_CNTR_2 static DigitalOut nss(RADIO_NSS); static SPI spi(RADIO_MOSI, RADIO_MISO, RADIO_SCLK); // (mosi, miso, sclk) static DigitalInOut rst(RESET_PIN); //DigitalOut RFSwitch_CNTR_2(PC_13); //static DigitalOut rxtx(PC_4); // RFSwitch_CNTR_1 DigitalOut rfsw1(RFSW1); DigitalOut rfsw2(RFSW2); static DigitalOut hdr_fem_ctx(PC_7); static InterruptIn dio0(PC_6); static InterruptIn dio1(PC_10); static InterruptIn dio2(PC_11); extern RTC_HandleTypeDef RtcHandle; // HAL state static struct { int irqlevel; } HAL; void radio_irq_handler (u1_t dio); static void dio0Irq( void ){ radio_irq_handler( 0 ); } static void dio1Irq( void ){ radio_irq_handler( 1 ); } static void dio2Irq( void ){ radio_irq_handler( 2 ); } void hal_disableIRQs() { __disable_irq(); HAL.irqlevel++; } void hal_enableIRQs() { if (--HAL.irqlevel == 0) { __enable_irq(); } } void hal_failed () { while (1) asm("nop"); } static void rtc_wkup_irq(void) { HAL_RTCEx_WakeUpTimerIRQHandler(&RtcHandle); } void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) { /* Clear Wake Up Flag */ __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); } /*void HAL_RCC_CCSCallback() { for (;;) asm("nop"); }*/ volatile uint32_t /*rcc_cr_a, rcc_cr_b,*/ rcc_cr_c; void hal_init (void) { memset(&HAL, 0x00, sizeof(HAL)); hal_disableIRQs(); #if USE_SMTC_RADIO_DRIVER #else // configure input lines dio0.mode(PullDown); dio0.rise(dio0Irq); dio0.enable_irq(); dio1.mode(PullDown); dio1.rise(dio1Irq); dio1.enable_irq(); dio2.mode(PullDown); dio2.rise(dio2Irq); dio2.enable_irq(); // configure reset line rst.input(); // configure spi spi.frequency(8000000); spi.format(8, 0); nss = 1; //RFSwitch_CNTR_2 = 1; #endif set_time(0); // initialize RTC /* Enable Ultra low power mode */ HAL_PWREx_EnableUltraLowPower(); /* Enable the fast wake up from Ultra low power mode */ HAL_PWREx_EnableFastWakeUp(); __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&RtcHandle, RTC_FLAG_WUTF); NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)rtc_wkup_irq); NVIC_EnableIRQ(RTC_WKUP_IRQn); hdr_fem_ctx = 0; hal_enableIRQs(); GPIOA->MODER |= 0x01415500; // unused pins as outputs: PA4, PA5, PA6, PA7, PA8, (PA11,PA12 USB) GPIOB->MODER |= 0x00000401; // unused pins as outputs: PB0(HDR_DIO1), PB5 (PB10 pulled hi by LED), PB3-T_SWO GPIOC->MODER |= 0x00000041; // unused pins as outputs: PC0(HDR_FEM_CSD), PC3(SPI3_enable) } u4_t hal_ticks () { RTC_DateTypeDef dateStruct; RTC_TimeTypeDef timeStruct; struct tm timeinfo; uint16_t sub_seconds; RtcHandle.Instance = RTC; // Read actual date and time // Warning: the time must be read first! HAL_RTC_GetTime(&RtcHandle, &timeStruct, FORMAT_BIN); HAL_RTC_GetDate(&RtcHandle, &dateStruct, FORMAT_BIN); sub_seconds = 16384 - timeStruct.SubSeconds; // RTC_SSR counts down // Setup a tm structure based on the RTC timeinfo.tm_wday = dateStruct.WeekDay; timeinfo.tm_mon = dateStruct.Month - 1; timeinfo.tm_mday = dateStruct.Date; timeinfo.tm_year = dateStruct.Year + 100; timeinfo.tm_hour = timeStruct.Hours; timeinfo.tm_min = timeStruct.Minutes; timeinfo.tm_sec = timeStruct.Seconds; // Convert to timestamp time_t t = mktime(&timeinfo); t &= 0xffff; // 14: SSR is driven at 16384Hz return (t << 14) | sub_seconds; } void hal_waitUntil (u4_t time) { while (hal_ticks() < time) asm("nop"); } volatile char deep_sleep; /* return 1 if target time is soon, return 0 if timer was programmed */ u1_t hal_checkTimer (u4_t time) { int d = time - hal_ticks(); HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle); __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&RtcHandle, RTC_FLAG_WUTF); if (d < 0x10000) { // less than 4s deep_sleep = 0; if (d < 4) return 1; // very soon if (d > ms2osticks(100)) { d -= 13; // HSE_PLL startup time deep_sleep = 1; } // 61.035us steps HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, d, RTC_WAKEUPCLOCK_RTCCLK_DIV2); } else if (d < 0x20000) { // less than 8s d -= 6; // HSE_PLL startup time deep_sleep = 1; // 122us steps HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, d >> 1, RTC_WAKEUPCLOCK_RTCCLK_DIV4); } else if (d < 0x40000) { // less than 16s deep_sleep = 1; // 244us steps HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, d >> 2, RTC_WAKEUPCLOCK_RTCCLK_DIV8); } else if (d < 0x80000) { // less than 32s deep_sleep = 1; // 488us steps HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, d >> 3, RTC_WAKEUPCLOCK_RTCCLK_DIV16); } else { deep_sleep = 1; // 1s steps to 18hours HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, d >> 14, RTC_WAKEUPCLOCK_CK_SPRE_16BITS); /* RTC_WAKEUPCLOCK_CK_SPRE_17BITS: 18h to 36h */ /*for (;;) asm("nop");*/ } return 0; } //#define SLEEP_DEBUG 1 void hal_sleep () { #ifdef SLEEP_DEBUG u4_t start_tick, end_tick; volatile uint32_t time_asleep; #endif /* SLEEP_DEBUG */ #ifdef USE_DEBUGGER HAL_EnableDBGStopMode(); if (!DBGMCU->CR & DBGMCU_CR_DBG_STOP) for (;;) asm("nop"); #endif /* USE_DEBUGGER */ if (deep_sleep) debug_done(); // wait here if debug still printing if (__HAL_RTC_WAKEUPTIMER_GET_FLAG(&RtcHandle, RTC_FLAG_WUTF) == 0) { // set gpio for sleep #ifdef SLEEP_DEBUG start_tick = hal_ticks(); #endif /* SLEEP_DEBUG */ hdr_fem_ctx = 1; if (deep_sleep) { #ifndef USE_DEBUGGER /* PA13 to undriven JTMS/SWDIO pin (from AF0 to GPIO), and PA2 */ GPIOA->MODER &= 0xf7ffffdf; GPIOB->MODER &= 0xffffdfff; // PB6 UART_TX to input #endif deepsleep(); // blocks until waking #ifndef USE_DEBUGGER /* PA13 back to JTMS/SWDIO pin (from GPIO to AF0), and PA2 */ GPIOA->MODER |= 0x08000020; GPIOB->MODER |= 0x00002000; // PB6 input to UART_TX #endif } else sleep(); // blocks until waking hdr_fem_ctx = 0; #ifdef SLEEP_DEBUG end_tick = hal_ticks(); time_asleep = end_tick - start_tick; printf("%d\r\n", time_asleep); #endif /* SLEEP_DEBUG */ // restore gpio from sleep } } void hal_pin_nss (u1_t val) { nss = val; } u1_t hal_spi (u1_t out) { return spi.write(out); } // 0=RX 1=TX /*void hal_pin_rxtx (u1_t val) { rxtx = !val; }*/ #define OPMODE_LORA 0x80 #define OPMODE_MASK 0x07 #define OPMODE_SLEEP 0x00 #define OPMODE_STANDBY 0x01 #define OPMODE_FSTX 0x02 #define OPMODE_TX 0x03 #define OPMODE_FSRX 0x04 #define OPMODE_RX 0x05 #define OPMODE_RX_SINGLE 0x06 #define OPMODE_CAD 0x07 void hal_opmode(u1_t mode, u1_t pa_boost) { if (mode == OPMODE_TX) { // start of transmission // assuming always using PA_BOOST if (pa_boost) { rfsw2 = 0; rfsw1 = 1; } else { rfsw2 = 1; rfsw1 = 0; } } else if (mode == OPMODE_RX || mode == OPMODE_RX_SINGLE || mode == OPMODE_CAD) { // start of reception rfsw2 = 1; rfsw1 = 1; } else { // RF switch shutdown rfsw2 = 0; rfsw1 = 0; } } void hal_pin_rst (u1_t val) { if (val == 0 || val == 1) { // drive pin rst.output(); rst = val; } else { // keep pin floating rst.input(); } }