From 11ac166f3476116b08eeaffc25d80b163573089b Mon Sep 17 00:00:00 2001 From: Mike Fiore Date: Tue, 17 Nov 2015 13:04:00 -0600 Subject: join works, but only once - added object for running LoRa operations in a thread, lots of misc updates --- ButtonHandler/ButtonHandler.cpp | 12 ++- ButtonHandler/ButtonHandler.h | 2 +- Layout/Layout.cpp | 29 ++++++ Layout/Layout.h | 2 + Layout/LayoutJoin.cpp | 93 +++++++++++++++++++ Layout/LayoutJoin.h | 43 +++++++++ LoRaHandler/LoRaHandler.cpp | 166 ++++++++++++++++++++++++++++++++++ LoRaHandler/LoRaHandler.h | 50 ++++++++++ main.cpp | 196 ++++++++++++++++++++++++++++++++++++---- 9 files changed, 572 insertions(+), 21 deletions(-) create mode 100644 Layout/LayoutJoin.cpp create mode 100644 Layout/LayoutJoin.h create mode 100644 LoRaHandler/LoRaHandler.cpp create mode 100644 LoRaHandler/LoRaHandler.h diff --git a/ButtonHandler/ButtonHandler.cpp b/ButtonHandler/ButtonHandler.cpp index e32cb42..25cf08e 100644 --- a/ButtonHandler/ButtonHandler.cpp +++ b/ButtonHandler/ButtonHandler.cpp @@ -1,6 +1,7 @@ #include "ButtonHandler.h" +#include "MTSLog.h" -#define signal (uint32_t)0xFF +#define signal (int32_t)0xA0 typedef enum { b_none = 0, @@ -13,13 +14,14 @@ typedef enum { InternalButtonEvent event = b_none; bool check_sw1 = false; -void worker(void const* argument) { +void b_worker(void const* argument) { ButtonHandler* b = (ButtonHandler*)argument; osEvent e; while (true) { e = Thread::signal_wait(signal, 250); if (e.status == osEventSignal) { + logInfo("button worker received signal"); switch (event) { case b_sw1_fall: if (! b->_sw1_running) { @@ -84,7 +86,7 @@ void worker(void const* argument) { ButtonHandler::ButtonHandler(osThreadId main) : _main(main), - _thread(worker, (void*)this), + _thread(b_worker, (void*)this), _sw1(PA_12), _sw2(PA_11), _sw1_time(0), @@ -113,20 +115,24 @@ ButtonHandler::ButtonEvent ButtonHandler::getButtonEvent() { void ButtonHandler::sw1_fall() { event = b_sw1_fall; _thread.signal_set(signal); + _thread.signal_clr(signal); } void ButtonHandler::sw1_rise() { event = b_sw1_rise; _thread.signal_set(signal); + _thread.signal_clr(signal); } void ButtonHandler::sw2_fall() { event = b_sw2_fall; _thread.signal_set(signal); + _thread.signal_clr(signal); } void ButtonHandler::sw2_rise() { event = b_sw2_rise; _thread.signal_set(signal); + _thread.signal_clr(signal); } diff --git a/ButtonHandler/ButtonHandler.h b/ButtonHandler/ButtonHandler.h index 00898c6..e99c767 100644 --- a/ButtonHandler/ButtonHandler.h +++ b/ButtonHandler/ButtonHandler.h @@ -4,7 +4,7 @@ #include "mbed.h" #include "rtos.h" -#define buttonSignal (uint32_t)0x01 +#define buttonSignal (int32_t)0x01 class ButtonHandler { public: diff --git a/Layout/Layout.cpp b/Layout/Layout.cpp index a38cc4f..7b0c375 100644 --- a/Layout/Layout.cpp +++ b/Layout/Layout.cpp @@ -46,6 +46,7 @@ bool Layout::writeField(const Field& field, const std::string& value, bool apply if (apply) startUpdate(); + // fill the whole length with blank space in case the previous value was longer than this one while (v.size() < field._maxSize) v += " "; @@ -57,6 +58,27 @@ bool Layout::writeField(const Field& field, const std::string& value, bool apply return true; } +bool Layout::writeField(const Field& field, const char* value, size_t size, bool apply) { + bool ret; + char buf[32]; + size_t s = (field._maxSize > size) ? size : field._maxSize; + + // fill the whole length with blank space in case the previous value was longer than this one + memset(buf, 0x20, sizeof(buf)); + + if (apply) + startUpdate(); + + snprintf(buf, s, "%s", value); + + ret = writeText(field._col, field._row, value, field._maxSize); + + if (apply) + endUpdate(); + + return true; +} + bool Layout::writeImage(const Image& image, bool apply) { bool ret; @@ -71,6 +93,13 @@ bool Layout::writeImage(const Image& image, bool apply) { return ret; } +void Layout::removeField(const Field& field) { + startUpdate(); + std::string s(' ', field._maxSize); + writeText(field._row, field._col, s.c_str(), s.size()); + endUpdate(); +} + bool Layout::writeText(uint8_t col, uint8_t row, const char* value, size_t size) { _lcd->writeText(col*6, row, font_6x8, value, size); diff --git a/Layout/Layout.h b/Layout/Layout.h index 5e7ece2..29d59ff 100644 --- a/Layout/Layout.h +++ b/Layout/Layout.h @@ -44,7 +44,9 @@ class Layout { void endUpdate(); bool writeLabel(const Label& label); bool writeField(const Field& field, const std::string& value, bool apply = false); + bool writeField(const Field& field, const char* value, size_t size, bool apply = false); bool writeImage(const Image& image, bool apply = false); + void removeField(const Field& field); private: bool writeText(uint8_t col, uint8_t row, const char* value, size_t size); diff --git a/Layout/LayoutJoin.cpp b/Layout/LayoutJoin.cpp new file mode 100644 index 0000000..1b0fb20 --- /dev/null +++ b/Layout/LayoutJoin.cpp @@ -0,0 +1,93 @@ +#include "LayoutJoin.h" + +LayoutJoin::LayoutJoin(DOGS102* lcd, uint8_t band) + : Layout(lcd), + _lId(0, 1, "NI="), + _lKey(0, 2, "NK="), + _lFsb(0, 3, "FSB="), + _lRate(0, 5, "DR="), + _lPower(6, 5, "P="), + _fStatus(0, 0, 17), + _fId(3, 1, 14), + _fKey(3, 2, 14), + _fFsb(4, 3, 2), + _fRate(3, 5, 2), + _fPower(8, 5, 2), + _fCountdown(0, 7, 9), + _fCountdownLabel(0, 6, 17), + _fCancel(11, 7, 6), + _band(band) +{} + +LayoutJoin::~LayoutJoin() {} + +void LayoutJoin::display() { + clear(); + startUpdate(); + + writeLabel(_lId); + writeLabel(_lKey); + if (_band == mDot::FB_915) { + writeLabel(_lFsb); + } + writeLabel(_lRate); + writeLabel(_lPower); + + displayCancel(); + + endUpdate(); +} + +void LayoutJoin::updateId(std::string id) { + writeField(_fId, id, true); +} + +void LayoutJoin::updateKey(std::string key) { + writeField(_fKey, key, true); +} + +void LayoutJoin::updateFsb(uint8_t band) { + char buf[8]; + size_t size; + + size = snprintf(buf, sizeof(buf), "%u", band); + writeField(_fFsb, buf, size, true); +} + +void LayoutJoin::updateRate(std::string rate) { + writeField(_fRate, rate); +} + +void LayoutJoin::updatePower(uint32_t power) { + char buf[16]; + size_t size; + + size = snprintf(buf, sizeof(buf), "%lu", power); + writeField(_fPower, buf, size, true); +} + +void LayoutJoin::updateStatus(std::string status) { + writeField(_fStatus, status, true); +} + +void LayoutJoin::updateCountdown(uint32_t seconds) { + char buf[16]; + size_t size; + + writeField(_fCountdownLabel, "No Free Channel"); + size = snprintf(buf, sizeof(buf), "%lu", seconds); + writeField(_fPower, buf, size, true); +} + +void LayoutJoin::removeCountdown() { + removeField(_fCountdownLabel); + removeField(_fCountdown); +} + +void LayoutJoin::displayCancel(bool display) { + if (display) + writeField(_fCancel, "Cancel", true); + else + removeField(_fCancel); +} + diff --git a/Layout/LayoutJoin.h b/Layout/LayoutJoin.h new file mode 100644 index 0000000..f2b7e41 --- /dev/null +++ b/Layout/LayoutJoin.h @@ -0,0 +1,43 @@ +#ifndef __LAYOUTJOIN_H__ +#define __LAYOUTJOIN_H__ + +#include "Layout.h" +#include "mDot.h" + +class LayoutJoin : public Layout { + public: + LayoutJoin(DOGS102* lcd, uint8_t band); + ~LayoutJoin(); + + void display(); + + void updateId(std::string id); + void updateKey(std::string key); + void updateFsb(uint8_t band); + void updateRate(std::string rate); + void updatePower(uint32_t power); + void updateStatus(std::string status); + void updateCountdown(uint32_t seconds); + void removeCountdown(); + void displayCancel(bool display = true); + + private: + Label _lId; + Label _lKey; + Label _lFsb; + Label _lRate; + Label _lPower; + + Field _fStatus; + Field _fId; + Field _fKey; + Field _fFsb; + Field _fRate; + Field _fPower; + Field _fCountdown; + Field _fCountdownLabel; + Field _fCancel; + uint8_t _band; +}; + +#endif diff --git a/LoRaHandler/LoRaHandler.cpp b/LoRaHandler/LoRaHandler.cpp new file mode 100644 index 0000000..3e28782 --- /dev/null +++ b/LoRaHandler/LoRaHandler.cpp @@ -0,0 +1,166 @@ +#include "LoRaHandler.h" +#include "MTSLog.h" + +#define signal (int32_t)0xA0 + +typedef enum { + l_none = 0, + l_ping, + l_send, + l_join +} InternalLoRa; + +uint8_t cmd = l_none; +std::vector send_data; + +void l_worker(void const* argument) { + LoRaHandler* l = (LoRaHandler*)argument; + osEvent e; + + l->_dot = mDot::getInstance(); + int32_t ret; + mDot::ping_response pr; + mDot::rssi_stats rs; + mDot::snr_stats ss; + + while (true) { + e = Thread::signal_wait(signal); + if (e.status == osEventSignal) { + logInfo("LoRa worker received signal"); + switch (cmd) { + case l_ping: + l->_mutex.lock(); + pr = l->_dot->ping(); + l->_mutex.unlock(); + if (pr.status == mDot::MDOT_OK) { + l->_ping.up = pr; + l->_mutex.lock(); + rs = l->_dot->getRssiStats(); + ss = l->_dot->getSnrStats(); + l->_mutex.unlock(); + l->_ping.down.rssi = rs.last; + l->_ping.down.snr = ss.last; + l->_status = LoRaHandler::ping_success; + } else { + l->_status = LoRaHandler::ping_failure; + } + logInfo("LoRa worker signaling main"); + osSignalSet(l->_main, loraSignal); + break; + + case l_send: + l->_mutex.lock(); + ret = l->_dot->send(send_data); + l->_mutex.unlock(); + if (ret == mDot::MDOT_OK) + l->_status = LoRaHandler::send_success; + else + l->_status = LoRaHandler::send_failure; + logInfo("LoRa worker signaling main"); + osSignalSet(l->_main, loraSignal); + break; + + case l_join: + logInfo("LoRa worker joining"); + l->_mutex.lock(); + ret = l->_dot->joinNetworkOnce(); + l->_mutex.unlock(); + if (ret == mDot::MDOT_OK) { + logInfo("LoRa worker signaling main - success"); + l->_status = LoRaHandler::join_success; + } else { + logInfo("LoRa worker signaling main - failure"); + l->_status = LoRaHandler::join_failure; + } + osSignalSet(l->_main, loraSignal); + break; + + default: + break; + } + } + } +} + +LoRaHandler::LoRaHandler(osThreadId main) + : _main(main), + _thread(l_worker, (void*)this), + _status(none) +{ + logInfo("starting"); + _ping.status = false; +} + +bool LoRaHandler::setDataRate(uint8_t rate) { + int32_t res; + _mutex.lock(); + res = _dot->setTxDataRate(rate); + _mutex.unlock(); + if (res == mDot::MDOT_OK) + return true; + + return false; +} + +bool LoRaHandler::setPower(uint32_t power) { + int32_t res; + _mutex.lock(); + res = _dot->setTxPower(power); + _mutex.unlock(); + if (res == mDot::MDOT_OK) + return true; + + return false; +} + +bool LoRaHandler::ping() { + return action(l_ping); +} + +bool LoRaHandler::send(std::vector data) { + send_data = data; + return action(l_send); +} + +bool LoRaHandler::join() { + return action(l_join); +} + +bool LoRaHandler::action(uint8_t c) { + if (_status != busy) { + cmd = c; + _thread.signal_set(signal); + _thread.signal_clr(signal); + return true; + } + + return false; +} + +LoRaHandler::LoRaStatus LoRaHandler::getStatus() { + LoRaStatus status; + _mutex.lock(); + status = _status; + _mutex.unlock(); + + return status; +} + +LoRaHandler::LoRaPing LoRaHandler::getPingResults() { + LoRaPing ping; + _mutex.lock(); + ping = _ping; + _mutex.unlock(); + + return ping; +} + +uint32_t LoRaHandler::getNextTx() { + uint32_t ms; + _mutex.lock(); + ms = _dot->getNextTxMs(); + _mutex.unlock(); + + return ms; +} + diff --git a/LoRaHandler/LoRaHandler.h b/LoRaHandler/LoRaHandler.h new file mode 100644 index 0000000..20f9d6f --- /dev/null +++ b/LoRaHandler/LoRaHandler.h @@ -0,0 +1,50 @@ +#ifndef __LORAHANDLER_H__ +#define __LORAHANDLER_H__ + +#include "mDot.h" + +#define loraSignal (int32_t)0x02 + +class LoRaHandler { + public: + typedef enum { + none = 0, + busy, + ping_success, + send_success, + join_success, + ping_failure, + send_failure, + join_failure + } LoRaStatus; + + typedef struct { + bool status; + mDot::ping_response up; + mDot::ping_response down; + } LoRaPing; + + LoRaHandler(osThreadId main); + ~LoRaHandler(); + + bool setDataRate(uint8_t rate); + bool setPower(uint32_t power); + bool ping(); + bool send(std::vector data); + bool join(); + bool action(uint8_t cmd); + LoRaStatus getStatus(); + LoRaPing getPingResults(); + uint32_t getNextTx(); + + + osThreadId _main; + Thread _thread; + LoRaStatus _status; + LoRaPing _ping; + mDot* _dot; + Mutex _mutex; +}; + +#endif + diff --git a/main.cpp b/main.cpp index cd89699..864c86b 100644 --- a/main.cpp +++ b/main.cpp @@ -4,6 +4,7 @@ // MTS headers #include "mDot.h" #include "MTSLog.h" +#include "MTSText.h" // sensor headers #include "ISL29011.h" #include "MMA845x.h" @@ -14,8 +15,11 @@ #include "NCP5623B.h" #include "LayoutStartup.h" #include "LayoutScrollSelect.h" +#include "LayoutJoin.h" // button header #include "ButtonHandler.h" +// LoRa header +#include "LoRaHandler.h" // misc heders #include @@ -27,31 +31,41 @@ DigitalOut lcd_cd(XBEE_ON_SLEEP, 1); DOGS102* lcd; NCP5623B* lcd_backlight; +// Thread informaiton +osThreadId main_id; + // Button controller ButtonHandler* buttons; +// LoRa controller +LoRaHandler* lora; +mDot* dot; + // Serial debug port Serial debug(USBTX, USBRX); // Prototypes void mainMenu(); +void join(); +void configuration(); int main() { debug.baud(115200); - MTSLog::setLogLevel(MTSLog::TRACE_LEVEL); - logInfo("starting..."); lcd = new DOGS102(lcd_spi, lcd_spi_cs, lcd_cd); lcd_backlight = new NCP5623B(backlight_i2c); + main_id = Thread::gettid(); + buttons = new ButtonHandler(main_id); + dot = mDot::getInstance(); + // display startup screen for 3 seconds LayoutStartup ls(lcd); ls.display(); osDelay(3000); - osThreadId main_id = Thread::gettid(); - buttons = new ButtonHandler(main_id); - + //MTSLog::setLogLevel(MTSLog::TRACE_LEVEL); + MTSLog::setLogLevel(MTSLog::INFO_LEVEL); logInfo("displaying main menu"); mainMenu(); @@ -59,6 +73,16 @@ int main() { } void mainMenu() { + bool mode_selected = false; + std::string selected; + + typedef enum { + demo = 2, + config, + single, + sweep + } menu_items; + std::string menu_strings[] = { "MultiTech EVB", "Select Mode", @@ -69,32 +93,170 @@ void mainMenu() { }; std::vector items; - items.push_back(menu_strings[2]); // demo - items.push_back(menu_strings[3]); // config - items.push_back(menu_strings[4]); // single - items.push_back(menu_strings[5]); // sweep + items.push_back(menu_strings[demo]); + items.push_back(menu_strings[config]); + items.push_back(menu_strings[single]); + items.push_back(menu_strings[sweep]); + + while (true) { + LayoutScrollSelect menu(lcd, items, menu_strings[0], menu_strings[1]); + menu.display(); + + while (! mode_selected) { + osEvent e = Thread::signal_wait(buttonSignal); + logInfo("main - received signal %#X", e.value.signals); + if (e.status == osEventSignal) { + ButtonHandler::ButtonEvent ev = buttons->getButtonEvent(); + switch (ev) { + case ButtonHandler::sw1_press: + logInfo("sw1 press"); + selected = menu.select(); + logInfo("selected %s", selected.c_str()); + mode_selected = true; + break; + case ButtonHandler::sw2_press: + logInfo("sw2 press"); + menu.scroll(); + break; + case ButtonHandler::sw1_hold: + logInfo("sw1 hold - already in main menu"); + break; + default: + break; + } + } + } + + if (selected == menu_strings[demo]) { + join(); + } else if (selected == menu_strings[config]) { + configuration(); + } else if (selected == menu_strings[single]) { + join(); + } else if (selected == menu_strings[sweep]) { + join(); + } + + mode_selected = false; + } +} - LayoutScrollSelect menu(lcd, items, menu_strings[0], menu_strings[1]); - menu.display(); +void join() { + uint32_t next_tx; + uint8_t rate; + uint8_t power; + uint8_t band; + bool joined = false; + ButtonHandler::ButtonEvent ev; + LoRaHandler::LoRaStatus status; + + // start of temporary stuff! + if (dot->getFrequencyBand() == mDot::FB_915) + dot->setFrequencySubBand(mDot::FSB_7); + dot->setJoinMode(mDot::OTA); + dot->setNetworkName("mikes_lora_network"); + dot->setNetworkPassphrase("password_123"); + dot->setAck(1); + // end of temporary stuff! + + power = 20; + band = dot->getFrequencyBand(); + if (band == mDot::FB_915) + rate = mDot::SF_10; + else + rate = mDot::SF_12; + + logInfo("joining"); + LayoutJoin lj(lcd, band); + lj.display(); + lj.updateStatus("Joining..."); + + if (dot->getJoinMode() == mDot::MANUAL) { + lj.updateId(mts::Text::bin2hexString(dot->getNetworkId())); + lj.updateKey(mts::Text::bin2hexString(dot->getNetworkKey())); + } else { + lj.updateId(dot->getNetworkName()); + lj.updateKey(dot->getNetworkPassphrase()); + } + if (band == mDot::FB_915) + lj.updateFsb(dot->getFrequencySubBand()); + lj.updateRate(dot->DataRateStr(rate)); + lj.updatePower(power); + + lora = new LoRaHandler(main_id); + lora->setDataRate(rate); + lora->setPower(power); + + while (! joined) { + next_tx = lora->getNextTx(); + if (next_tx) { + lj.updateCountdown(next_tx * 1000); + } else { + logInfo("main joining"); + lj.updateStatus("Joining..."); + if (! lora->join()) + logError("cannot join - LoRa layer busy"); + } + + osEvent e = Thread::signal_wait(0, 250); + logInfo("main - received signal %#X", e.value.signals); + if (e.status == osEventSignal) { + if (e.value.signals & buttonSignal) { + logInfo("main - button signal"); + ev = buttons->getButtonEvent(); + switch (ev) { + case ButtonHandler::sw1_press: + logInfo("sw1 press"); + return; + case ButtonHandler::sw2_press: + logInfo("sw2 press"); + break; + case ButtonHandler::sw1_hold: + logInfo("sw1 hold"); + return; + } + } + if (e.value.signals & loraSignal) { + logInfo("main - LoRa signal"); + status = lora->getStatus(); + switch (status) { + case LoRaHandler::join_success: + logInfo("main - join success"); + lj.updateStatus("Join Success!"); + lj.displayCancel(false); + joined = true; + osDelay(2000); + break; + + case LoRaHandler::join_failure: + logInfo("main - join failure"); + lj.updateStatus("Join Failure!"); + osDelay(2000); + break; + } + } + } + } +} + +void configuration() { + logInfo("config mode"); while (true) { osEvent e = Thread::signal_wait(buttonSignal); + logInfo("main - received signal %#X", e.value.signals); if (e.status == osEventSignal) { ButtonHandler::ButtonEvent ev = buttons->getButtonEvent(); - std::string selected; switch (ev) { case ButtonHandler::sw1_press: logInfo("sw1 press"); - selected = menu.select(); - logInfo("selected %s", selected.c_str()); break; case ButtonHandler::sw2_press: logInfo("sw2 press"); - menu.scroll(); break; case ButtonHandler::sw1_hold: - logInfo("sw1 hold - already in main menu"); - break; + logInfo("sw1 hold"); + return; default: break; } -- cgit v1.2.3