Lab exercise code for FAE Summit 09/2019.

main.cpp

Committer:
lru
Date:
2019-09-18
Revision:
59:4628ef4b0d52
Parent:
58:cf54c181a632

File content as of revision 59:4628ef4b0d52:

/**
 * Copyright (c) 2017, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>

#include "lorawan/LoRaWANInterface.h"
#include "lorawan/system/lorawan_data_structures.h"
#include "events/EventQueue.h"
#include "psoc6_utils.h"
#include "mbed.h"

// Application helpers
#include "trace_helper.h"
#include "lora_radio_helper.h"
#include "neo_iso_drv.h"


using namespace events;
using namespace mbed;


// Max payload size can be LORAMAC_PHY_MAXPAYLOAD.
// This example only communicates with much shorter messages (<30 bytes).
// If longer messages are used, these buffers must be changed accordingly.
uint8_t tx_buffer[30];
uint8_t rx_buffer[30];

/*
 * Sets up an application dependent transmission timer in ms. Used only when Duty Cycling is off for testing
 */
#define TX_TIMER                        10000

/**
 * Maximum number of events for the event queue.
 * 10 is the safe number for the stack events, however, if application
 * also uses the queue for whatever purposes, this number should be increased.
 */
#define MAX_NUMBER_OF_EVENTS            10

/**
 * Maximum number of retries for CONFIRMED messages before giving up
 */
#define CONFIRMED_MSG_RETRY_COUNTER     3

/**
 * Dummy pin for dummy sensor
 */
#define PC_9                            0

/**
* This event queue is the global event queue for both the
* application and stack. To conserve memory, the stack is designed to run
* in the same thread as the application and the application is responsible for
* providing an event queue to the stack that will be used for ISR deferment as
* well as application information event queuing.
*/
static EventQueue ev_queue(MAX_NUMBER_OF_EVENTS *EVENTS_EVENT_SIZE);

/**
 * Event handler.
 *
 * This will be passed to the LoRaWAN stack to queue events for the
 * application which in turn drive the application.
 */
static void lora_event_handler(lorawan_event_t event);

/**
 * Constructing Mbed LoRaWANInterface and passing it the radio object from lora_radio_helper.
 */
static LoRaWANInterface lorawan(radio);

/**
 * Application specific callbacks
 */
static lorawan_app_callbacks_t callbacks;


/**
 * Button switch processing handler.
 */
 static void button_handler(void);


Timer g_timer;
DigitalOut led(LED1);
DigitalIn  button1(BUTTON1);

bool frame_send = false;
bool is_connected = false;

neoiso::NeoIso ssr(I2C_SCL, I2C_SDA, 0);

static const uint8_t target_device_eui[] = MBED_CONF_APP_TARGET_DEVICE_EUI;
//static const uint8_t target_device_eui[] = { 0x00, 0xa0, 0x50, 0xff, 0xfe, 0x81, 0x27, 0x95 };

/**
 * Entry point for application
 */
int main(void)
{
    static uint8_t mac_address[6];
    static uint8_t device_eui[8] = {0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00};
    static const uint8_t application_eui[] = MBED_CONF_LORA_APPLICATION_EUI;
    static const uint8_t application_key[] = MBED_CONF_LORA_APPLICATION_KEY;
    static lorawan_connect_t connect_params = {
        .connect_type = LORAWAN_CONNECTION_OTAA,
    };

    // setup tracing
    setup_trace();

    // stores the status of a call to LoRaWAN protocol
    lorawan_status_t retcode;

    // Create unique, hardware-dependent EUI.
    cy_get_bd_mac_address(mac_address);
    // MAC address is in reverse sequence.
    for (int i = 0; i < 3; ++i) {
        device_eui[i] = mac_address[5 - i];
        device_eui[i + 5] = mac_address[2 - i];
    }
    printf("\r\nDevice EUI is %02X", device_eui[0]);
    for (int i = 1; i < 8; ++i) {
        printf(":%02X", device_eui[i]);
    }
    printf("\r\n");

    // Initialize LoRaWAN stack
    if (lorawan.initialize(&ev_queue) != LORAWAN_STATUS_OK) {
        printf("\r\n LoRa initialization failed! \r\n");
        return -1;
    }

    printf("\r\n Mbed LoRaWANStack initialized \r\n");

    // prepare application callbacks
    callbacks.events = mbed::callback(lora_event_handler);
    lorawan.add_app_callbacks(&callbacks);

    // Set number of retries in case of CONFIRMED messages
    if (lorawan.set_confirmed_msg_retries(CONFIRMED_MSG_RETRY_COUNTER)
            != LORAWAN_STATUS_OK) {
        printf("\r\n set_confirmed_msg_retries failed! \r\n\r\n");
        return -1;
    }

    printf("\r\n CONFIRMED message retries : %d \r\n",
           CONFIRMED_MSG_RETRY_COUNTER);

    // Enable adaptive data rate
    if (lorawan.enable_adaptive_datarate() != LORAWAN_STATUS_OK) {
        printf("\r\n enable_adaptive_datarate failed! \r\n");
        return -1;
    }

    printf("\r\n Adaptive data  rate (ADR) - Enabled \r\n");

    // Specify class C
    if (lorawan.set_device_class(CLASS_C) != LORAWAN_STATUS_OK) {
        printf("\r\n setting class C failed! \r\n");
        return -1;
    }

    printf("\r\n Class C - Enabled \r\n");

    connect_params.connection_u.otaa.dev_eui = device_eui;
    connect_params.connection_u.otaa.app_eui = const_cast<uint8_t *>(application_eui);
    connect_params.connection_u.otaa.app_key = const_cast<uint8_t *>(application_key);
    connect_params.connection_u.otaa.nb_trials = MBED_CONF_LORA_NB_TRIALS;

    g_timer.start();

    retcode = lorawan.connect(connect_params);

    if (retcode == LORAWAN_STATUS_OK ||
            retcode == LORAWAN_STATUS_CONNECT_IN_PROGRESS) {
    } else {
        printf("\r\n Connection error, code = %d \r\n", retcode);
        return -1;
    }

    printf("\r\n Connection - In Progress ...\r\n");

    // Start button handler; will check button switch every 100ms.
    ev_queue.call_every(100, button_handler);

    // make your event queue dispatching events forever
    ev_queue.dispatch_forever();

    return 0;
}


/**
 * Sends a message to the Network Server
 */
static void send_message(int pwon)
{
    uint16_t packet_len;
    int16_t retcode;

    printf("\r\n[%8u] Sending message (%d) \r\n", g_timer.read_ms(), pwon);

    memcpy(tx_buffer, target_device_eui, 8);
    tx_buffer[8] = pwon? 0x09 : 0x00;

    packet_len = 9;

    led = 1;
    retcode = lorawan.send(MBED_CONF_LORA_APP_PORT, tx_buffer, packet_len,
                           MSG_CONFIRMED_FLAG);

    if (retcode < 0) {
        retcode == LORAWAN_STATUS_WOULD_BLOCK ? printf("send - WOULD BLOCK\r\n")
        : printf("\r\n send() - Error code %d \r\n", retcode);

        if (retcode == LORAWAN_STATUS_WOULD_BLOCK) {
            lorawan.cancel_sending();
            led = 0;
            //retry in 3 seconds
            if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
                ev_queue.call_in(3000, send_message, pwon);
            }
        }
        return;
    }

    frame_send = true;
    printf("\r\n[%8u] %d bytes scheduled for transmission \r\n", g_timer.read_ms(), retcode);
    memset(tx_buffer, 0, sizeof(tx_buffer));
}

/**
 * Receive a message from the Network Server
 */
static void receive_message()
{
    uint8_t port;
    int flags;
    int16_t retcode = lorawan.receive(rx_buffer, sizeof(rx_buffer), port, flags);

    if (retcode < 0) {
        printf("\r\n receive() - Error code %d \r\n", retcode);
        return;
    }

    printf("[%8u] RX Data on port %u (%d bytes): ", g_timer.read_ms(), port, retcode);
    for (uint8_t i = 0; i < retcode; i++) {
        printf("%02x ", rx_buffer[i]);
    }
    printf("\r\n");
    if (rx_buffer[0] == 0) {
        ssr = 0;
    } else {
        ssr = 1;
    }

    memset(rx_buffer, 0, sizeof(rx_buffer));
}

/**
 * Detects and processes button events.
 */
static void button_handler(void)
{
    static uint8_t prev_state = 1;
    static uint8_t stable_state = 1;
    static uint8_t power_on = 0;
    static uint8_t count = 2;

    uint8_t curr_state = button1;

    if (curr_state != prev_state) {
        count = 2;
    } else {
        if (count > 0) {
            --count;
        } else {
            if ((stable_state == 0) && (curr_state != 0)) {
                // we react on release of the button
                if (is_connected) {
                    power_on = power_on? 0 : 1;
                    send_message(power_on);
                }
            }
            stable_state = curr_state;
        }
    }
    prev_state = curr_state;
}


/**
 * Event handler
 */
static void lora_event_handler(lorawan_event_t event)
{
    switch (event) {
        case CONNECTED:
            printf("\r\n[%8u] Connection - Successful \r\n", g_timer.read_ms());
            is_connected = true;
            break;
        case DISCONNECTED:
            led = 0;
            frame_send = false;
            ev_queue.break_dispatch();
            printf("\r\n[%8u] Disconnected Successfully \r\n", g_timer.read_ms());
            break;
        case TX_DONE:
            led = 0;
            if (frame_send) {
                frame_send = false;
                printf("\r\n[%8u] Message Sent to Network Server \r\n", g_timer.read_ms());
            } else {
                printf("\r\n[%8u] Duplicate TX_DONE !!! \r\n", g_timer.read_ms());
            }
            break;
        case TX_TIMEOUT:
        case TX_ERROR:
        case TX_CRYPTO_ERROR:
        case TX_SCHEDULING_ERROR:
            led = 0;
            frame_send = false;
            printf("\r\n[%8u] Transmission Error - EventCode = %d \r\n", g_timer.read_ms(), event);
            break;
        case RX_DONE:
            printf("\r\n[%8u] Received message from Network Server \r\n", g_timer.read_ms());
            receive_message();
            break;
        case RX_TIMEOUT:
        case RX_ERROR:
            printf("\r\n[%8u] Error in reception - Code = %d \r\n", g_timer.read_ms(), event);
            break;
        case JOIN_FAILURE:
            printf("\r\n OTAA Failed - Check Keys \r\n");
            break;
        case UPLINK_REQUIRED:
            printf("\r\n[%8u] Uplink required by NS \r\n", g_timer.read_ms());
            break;
        default:
            MBED_ASSERT("Unknown Event");
    }
}

// EOF