Senet-ized LMIC for MOTE_L152RC

Fork of lmic_MOTE_L152RC by Semtech

TARGET_MOTE_L152RC/hal.cpp

Committer:
dudmuck
Date:
2015-06-03
Revision:
1:04fd63382b03
Parent:
0:f2716e543d97
Child:
2:edb5d1f3deeb

File content as of revision 1:04fd63382b03:

/* 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);

    // 14: SSR is driven at 16384Hz
    t <<= 14;
    return t | 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 */

    //printf("%x cr:%06x isr:%04x %d\r\n", RtcHandle.Instance->WUTR, RtcHandle.Instance->CR, RtcHandle.Instance->ISR, deep_sleep);
    //debug_done();

    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("%u = %u - %u\r\n", time_asleep, end_tick, start_tick);
#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();
    }
}