diff options
-rw-r--r-- | Layout/LayoutConfirm.cpp | 28 | ||||
-rw-r--r-- | Layout/LayoutConfirm.h | 22 | ||||
-rw-r--r-- | Layout/LayoutDemoHelp.cpp | 28 | ||||
-rw-r--r-- | Layout/LayoutDemoHelp.h | 22 | ||||
-rw-r--r-- | Layout/LayoutFile.cpp | 30 | ||||
-rw-r--r-- | Layout/LayoutFile.h | 23 | ||||
-rw-r--r-- | Layout/LayoutHelp.cpp | 49 | ||||
-rw-r--r-- | Layout/LayoutHelp.h | 31 | ||||
-rw-r--r-- | Layout/LayoutJoin.cpp | 19 | ||||
-rw-r--r-- | Layout/LayoutJoin.h | 1 | ||||
-rw-r--r-- | Layout/LayoutSurveyFailure.cpp | 58 | ||||
-rw-r--r-- | Layout/LayoutSurveyFailure.h | 33 | ||||
-rw-r--r-- | Layout/LayoutSurveyProgress.cpp | 36 | ||||
-rw-r--r-- | Layout/LayoutSurveyProgress.h | 24 | ||||
-rw-r--r-- | Layout/LayoutSurveySuccess.cpp | 116 | ||||
-rw-r--r-- | Layout/LayoutSurveySuccess.h | 48 | ||||
-rw-r--r-- | LoRaHandler/LoRaHandler.cpp | 20 | ||||
-rw-r--r-- | LoRaHandler/LoRaHandler.h | 3 | ||||
-rw-r--r-- | Mode/Mode.cpp | 116 | ||||
-rw-r--r-- | Mode/Mode.h | 27 | ||||
-rw-r--r-- | Mode/ModeJoin.cpp | 73 | ||||
-rw-r--r-- | Mode/ModeJoin.h | 17 | ||||
-rw-r--r-- | Mode/ModeSingle.cpp | 354 | ||||
-rw-r--r-- | Mode/ModeSingle.h | 44 | ||||
-rw-r--r-- | main.cpp | 69 |
25 files changed, 1133 insertions, 158 deletions
diff --git a/Layout/LayoutConfirm.cpp b/Layout/LayoutConfirm.cpp new file mode 100644 index 0000000..0c0e39a --- /dev/null +++ b/Layout/LayoutConfirm.cpp @@ -0,0 +1,28 @@ +#include "LayoutConfirm.h" + +LayoutConfirm::LayoutConfirm(DOGS102* lcd) + : Layout(lcd), + _lMsg1(0, 0, "Are You Sure You"), + _lMsg2(0, 1, "Want to Erase It?"), + _lIns1(0, 4, "Hold SW1 any time"), + _lIns2(0, 5, "for Main Menu"), + _lSw1(15, 7, "No"), + _lSw2(0, 7, "Yes") +{} + +LayoutConfirm::~LayoutConfirm() {} + +void LayoutConfirm::display() { + clear(); + startUpdate(); + + writeLabel(_lMsg1); + writeLabel(_lMsg2); + writeLabel(_lIns1); + writeLabel(_lIns2); + writeLabel(_lSw1); + writeLabel(_lSw2); + + endUpdate(); +} + diff --git a/Layout/LayoutConfirm.h b/Layout/LayoutConfirm.h new file mode 100644 index 0000000..891094e --- /dev/null +++ b/Layout/LayoutConfirm.h @@ -0,0 +1,22 @@ +#ifndef __LAYOUTCONFIRM_H__ +#define __LAYOUTCONFIRM_H__ + +#include "Layout.h" + +class LayoutConfirm : public Layout { + public: + LayoutConfirm(DOGS102* lcd); + ~LayoutConfirm(); + + void display(); + + private: + Label _lMsg1; + Label _lMsg2; + Label _lIns1; + Label _lIns2; + Label _lSw1; + Label _lSw2; +}; + +#endif diff --git a/Layout/LayoutDemoHelp.cpp b/Layout/LayoutDemoHelp.cpp deleted file mode 100644 index dab907e..0000000 --- a/Layout/LayoutDemoHelp.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "LayoutDemoHelp.h" - -LayoutDemoHelp::LayoutDemoHelp(DOGS102* lcd) - : Layout(lcd), - _lMode(0, 0, "LoRa Demo"), - _lDesc(0, 1, "Select TX Method"), - _lIns1(0, 4, "Hold SW1 any time"), - _lIns2(0, 5, "for Main Menu"), - _lSw1(10, 7, "Trigger"), - _lSw2(0, 7, "Interval") -{} - -LayoutDemoHelp::~LayoutDemoHelp() {} - -void LayoutDemoHelp::display() { - clear(); - startUpdate(); - - writeLabel(_lMode); - writeLabel(_lDesc); - writeLabel(_lIns1); - writeLabel(_lIns2); - writeLabel(_lSw1); - writeLabel(_lSw2); - - endUpdate(); -} - diff --git a/Layout/LayoutDemoHelp.h b/Layout/LayoutDemoHelp.h deleted file mode 100644 index 3e20df9..0000000 --- a/Layout/LayoutDemoHelp.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __LAYOUTDEMOHELP_H__ -#define __LAYOUTDEMOHELP_H__ - -#include "Layout.h" - -class LayoutDemoHelp : public Layout { - public: - LayoutDemoHelp(DOGS102* lcd); - ~LayoutDemoHelp(); - - void display(); - - private: - Label _lMode; - Label _lDesc; - Label _lIns1; - Label _lIns2; - Label _lSw1; - Label _lSw2; -}; - -#endif diff --git a/Layout/LayoutFile.cpp b/Layout/LayoutFile.cpp new file mode 100644 index 0000000..fd54ff1 --- /dev/null +++ b/Layout/LayoutFile.cpp @@ -0,0 +1,30 @@ +#include "LayoutFile.h" + +LayoutFile::LayoutFile(DOGS102* lcd) + : Layout(lcd), + _lMsg1(0, 0, "Erase or Append"), + _lMsg2(0, 1, "to Existing"), + _lMsg3(0, 2, "Survey Data File?"), + _lIns1(0, 4, "Hold SW1 any time"), + _lIns2(0, 5, "for Main Menu"), + _lSw1(11, 7, "Append"), + _lSw2(0, 7, "Erase") +{} + +LayoutFile::~LayoutFile() {} + +void LayoutFile::display() { + clear(); + startUpdate(); + + writeLabel(_lMsg1); + writeLabel(_lMsg2); + writeLabel(_lMsg3); + writeLabel(_lIns1); + writeLabel(_lIns2); + writeLabel(_lSw1); + writeLabel(_lSw2); + + endUpdate(); +} + diff --git a/Layout/LayoutFile.h b/Layout/LayoutFile.h new file mode 100644 index 0000000..640249f --- /dev/null +++ b/Layout/LayoutFile.h @@ -0,0 +1,23 @@ +#ifndef __LAYOUTFILE_H__ +#define __LAYOUTFILE_H__ + +#include "Layout.h" + +class LayoutFile : public Layout { + public: + LayoutFile(DOGS102* lcd); + ~LayoutFile(); + + void display(); + + private: + Label _lMsg1; + Label _lMsg2; + Label _lMsg3; + Label _lIns1; + Label _lIns2; + Label _lSw1; + Label _lSw2; +}; + +#endif diff --git a/Layout/LayoutHelp.cpp b/Layout/LayoutHelp.cpp new file mode 100644 index 0000000..7ed3e61 --- /dev/null +++ b/Layout/LayoutHelp.cpp @@ -0,0 +1,49 @@ +#include "LayoutHelp.h" + +LayoutHelp::LayoutHelp(DOGS102* lcd) + : Layout(lcd), + _lIns1(0, 4, "Hold SW1 any time"), + _lIns2(0, 5, "for Main Menu"), + _fMode(0, 0, 17), + _fDesc(0, 1, 17), + _fMsg(0, 6, 17), + _fSw1(9, 7, 8), + _fSw2(0, 7, 8) +{} + +LayoutHelp::~LayoutHelp() {} + +void LayoutHelp::display() { + clear(); + startUpdate(); + + writeLabel(_lIns1); + writeLabel(_lIns2); + + endUpdate(); +} + +void LayoutHelp::updateMode(std::string mode) { + writeField(_fMode, mode, true); +} + +void LayoutHelp::updateDescription(std::string description) { + writeField(_fDesc, description, true); +} + +void LayoutHelp::updateMsg(std::string msg) { + writeField(_fMsg, msg, true); +} + +void LayoutHelp::removeMsg() { + removeField(_fMsg); +} + +void LayoutHelp::updateSw1(std::string s) { + writeField(_fSw1, s, true); +} + +void LayoutHelp::updateSw2(std::string s) { + writeField(_fSw2, s, true); +} + diff --git a/Layout/LayoutHelp.h b/Layout/LayoutHelp.h new file mode 100644 index 0000000..44e70d5 --- /dev/null +++ b/Layout/LayoutHelp.h @@ -0,0 +1,31 @@ +#ifndef __LAYOUTHELP_H__ +#define __LAYOUTHELP_H__ + +#include "Layout.h" + +class LayoutHelp : public Layout { + public: + LayoutHelp(DOGS102* lcd); + ~LayoutHelp(); + + void display(); + void updateMode(std::string mode); + void updateDescription(std::string description); + void updateMsg(std::string msg); + void removeMsg(); + void updateSw1(std::string s); + void updateSw2(std::string s); + + private: + Label _lIns1; + Label _lIns2; + + Field _fMode; + Field _fDesc; + Field _fMsg; + Field _fSw1; + Field _fSw2; + +}; + +#endif diff --git a/Layout/LayoutJoin.cpp b/Layout/LayoutJoin.cpp index 3b67c28..fea558e 100644 --- a/Layout/LayoutJoin.cpp +++ b/Layout/LayoutJoin.cpp @@ -53,18 +53,20 @@ void LayoutJoin::updateFsb(uint8_t band) { char buf[8]; size_t size; + memset(buf, 0, sizeof(buf)); size = snprintf(buf, sizeof(buf), "%u", band); writeField(_fFsb, buf, size, true); } void LayoutJoin::updateRate(std::string rate) { - writeField(_fRate, rate); + writeField(_fRate, rate, true); } void LayoutJoin::updatePower(uint32_t power) { char buf[16]; size_t size; + memset(buf, 0, sizeof(buf)); size = snprintf(buf, sizeof(buf), "%lu", power); writeField(_fPower, buf, size, true); } @@ -73,6 +75,7 @@ void LayoutJoin::updateAttempt(uint32_t attempt) { char buf[16]; size_t size; + memset(buf, 0, sizeof(buf)); size = snprintf(buf, sizeof(buf), "%lu", attempt); writeField(_fAttempt, buf, size, true); } @@ -85,14 +88,12 @@ 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); + memset(buf, 0, sizeof(buf)); + // for some reason, there's a % character that gets displayed in the last column + // add the extra spaces to wipe it out + writeField(_fCountdownLabel, "No Free Channel ", true); + size = snprintf(buf, sizeof(buf), "%lu s", seconds); + writeField(_fCountdown, buf, size, true); } void LayoutJoin::displayCancel(bool display) { diff --git a/Layout/LayoutJoin.h b/Layout/LayoutJoin.h index 2f71aec..0f8e4f0 100644 --- a/Layout/LayoutJoin.h +++ b/Layout/LayoutJoin.h @@ -19,7 +19,6 @@ class LayoutJoin : public Layout { void updateAttempt(uint32_t attempt); void updateStatus(std::string status); void updateCountdown(uint32_t seconds); - void removeCountdown(); void displayCancel(bool display = true); private: diff --git a/Layout/LayoutSurveyFailure.cpp b/Layout/LayoutSurveyFailure.cpp new file mode 100644 index 0000000..d443098 --- /dev/null +++ b/Layout/LayoutSurveyFailure.cpp @@ -0,0 +1,58 @@ +#include "LayoutSurveyFailure.h" + +LayoutSurveyFailure::LayoutSurveyFailure(DOGS102* lcd) + : Layout(lcd), + _lTitle(0, 2, "Survey Failed"), + _lId(0, 0, "ID"), + _lDr(8, 0, "DR"), + _lPwr(13, 0, "P"), + _lSw1(12, 7, "Power"), + _lSw2(0, 7, "Survey"), + _fId(2, 0, 5), + _fDr(10, 0, 2), + _fPwr(14, 0, 2), + _fMsg1(0, 4, 17), + _fMsg2(0, 5, 17), + _fInfo(0, 6, 17) +{} + +LayoutSurveyFailure::~LayoutSurveyFailure() {} + +void LayoutSurveyFailure::display() { + clear(); + startUpdate(); + + writeLabel(_lTitle); + writeLabel(_lId); + writeLabel(_lDr); + writeLabel(_lPwr); + writeLabel(_lSw1); + writeLabel(_lSw2); + + endUpdate(); +} + +void LayoutSurveyFailure::updateId(uint32_t id) { + char buf[16]; + size_t size; + + size = snprintf(buf, sizeof(buf), "%lu", id); + writeField(_fId, buf, size, true); +} + +void LayoutSurveyFailure::updateRate(std::string rate) { + writeField(_fDr, rate, true); +} + +void LayoutSurveyFailure::updatePower(uint32_t power) { + char buf[16]; + size_t size; + + size = snprintf(buf, sizeof(buf), "%lu", power); + writeField(_fPwr, buf, size, true); +} + +void LayoutSurveyFailure::updateInfo(std::string info) { + writeField(_fInfo, info, true); +} + diff --git a/Layout/LayoutSurveyFailure.h b/Layout/LayoutSurveyFailure.h new file mode 100644 index 0000000..473fd9f --- /dev/null +++ b/Layout/LayoutSurveyFailure.h @@ -0,0 +1,33 @@ +#ifndef __LAYOUTSURVEYFAILURE_H__ +#define __LAYOUTSURVEYFAILURE_H__ + +#include "Layout.h" + +class LayoutSurveyFailure : public Layout { + public: + LayoutSurveyFailure(DOGS102* lcd); + ~LayoutSurveyFailure(); + + void display(); + void updateId(uint32_t id); + void updateRate(std::string rate); + void updatePower(uint32_t power); + void updateInfo(std::string msg); + + private: + Label _lTitle; + Label _lId; + Label _lDr; + Label _lPwr; + Label _lSw1; + Label _lSw2; + + Field _fId; + Field _fDr; + Field _fPwr; + Field _fMsg1; + Field _fMsg2; + Field _fInfo; +}; + +#endif diff --git a/Layout/LayoutSurveyProgress.cpp b/Layout/LayoutSurveyProgress.cpp new file mode 100644 index 0000000..4a50fbb --- /dev/null +++ b/Layout/LayoutSurveyProgress.cpp @@ -0,0 +1,36 @@ +#include "LayoutSurveyProgress.h" + +LayoutSurveyProgress::LayoutSurveyProgress(DOGS102* lcd) + : Layout(lcd), + _lMsg1(5, 2, "Survey"), + _lMsg2(7, 3, "in"), + _lMsg3(4, 4, "Progress"), + _fCountdownLabel(0, 6, 17), + _fCountdown(0, 7, 9) +{} + +LayoutSurveyProgress::~LayoutSurveyProgress() {} + +void LayoutSurveyProgress::display() { + clear(); + startUpdate(); + + writeLabel(_lMsg1); + writeLabel(_lMsg2); + writeLabel(_lMsg3); + + endUpdate(); +} + +void LayoutSurveyProgress::updateCountdown(uint32_t seconds) { + char buf[16]; + size_t size; + + memset(buf, 0, sizeof(buf)); + // for some reason, there's a % character that gets displayed in the last column + // add the extra spaces to wipe it out + writeField(_fCountdownLabel, "No Free Channel ", true); + size = snprintf(buf, sizeof(buf), "%lu s", seconds); + writeField(_fCountdown, buf, size, true); +} + diff --git a/Layout/LayoutSurveyProgress.h b/Layout/LayoutSurveyProgress.h new file mode 100644 index 0000000..85a029b --- /dev/null +++ b/Layout/LayoutSurveyProgress.h @@ -0,0 +1,24 @@ +#ifndef __LAYOUTSURVEYPROGRESS_H__ +#define __LAYOUTSURVEYPROGRESS_H__ + +#include "Layout.h" + +class LayoutSurveyProgress : public Layout { + public: + LayoutSurveyProgress(DOGS102* lcd); + ~LayoutSurveyProgress(); + + void display(); + + void updateCountdown(uint32_t seconds); + + private: + Label _lMsg1; + Label _lMsg2; + Label _lMsg3; + + Field _fCountdownLabel; + Field _fCountdown; +}; + +#endif diff --git a/Layout/LayoutSurveySuccess.cpp b/Layout/LayoutSurveySuccess.cpp new file mode 100644 index 0000000..02dd197 --- /dev/null +++ b/Layout/LayoutSurveySuccess.cpp @@ -0,0 +1,116 @@ +#include "LayoutSurveySuccess.h" + +LayoutSurveySuccess::LayoutSurveySuccess(DOGS102* lcd) + : Layout(lcd), + _lId(0, 0, "ID"), + _lDr(8, 0, "DR"), + _lPwr(13, 0, "P"), + _lUp(0, 1, "UP"), + _lDown(0, 2, "DWN"), + _fId(2, 0, 5), + _fDr(10, 0, 2), + _fPwr(14, 0, 2), + _fUpRssi(3, 1, 7), + _fUpSnr(11, 1, 5), + _fDownRssi(4, 2, 7), + _fDownSnr(12, 2, 5), + _fGpsLat(0, 4, 17), + _fGpsLon(0, 3, 17), + _fGpsTime(0, 5, 17), + _fInfo(0, 6, 17), + _fSw1(9, 7, 8), + _fSw2(0, 7, 8) +{} + +LayoutSurveySuccess::~LayoutSurveySuccess() {} + +void LayoutSurveySuccess::display() { + clear(); + startUpdate(); + + writeLabel(_lId); + writeLabel(_lDr); + writeLabel(_lPwr); + writeLabel(_lUp); + writeLabel(_lDown); + + endUpdate(); +} + +void LayoutSurveySuccess::updateId(uint32_t id) { + char buf[16]; + size_t size; + + size = snprintf(buf, sizeof(buf), "%lu", id); + writeField(_fId, buf, size, true); +} + +void LayoutSurveySuccess::updateRate(std::string rate) { + writeField(_fDr, rate, true); +} + +void LayoutSurveySuccess::updatePower(uint32_t power) { + char buf[16]; + size_t size; + + size = snprintf(buf, sizeof(buf), "%lu", power); + writeField(_fPwr, buf, size, true); +} + +void LayoutSurveySuccess::updateStats(LoRaHandler::LoRaPing ping) { + char buf[16]; + size_t size; + + startUpdate(); + + size = snprintf(buf, sizeof(buf), "%3d dbm", ping.up.rssi); + writeField(_fUpRssi, buf, size); + + memset(buf, 0, sizeof(buf)); + size = snprintf(buf, sizeof(buf), "%2d.%1d", ping.up.snr / 10, abs(ping.up.snr) % 10); + writeField(_fUpSnr, buf, size); + + memset(buf, 0, sizeof(buf)); + size = snprintf(buf, sizeof(buf), "%3d dbm", ping.down.rssi); + writeField(_fDownRssi, buf, size); + + memset(buf, 0, sizeof(buf)); + size = snprintf(buf, sizeof(buf), "%2d.%1d", ping.down.snr / 4, abs(ping.down.snr) % 10 * 25); + writeField(_fDownSnr, buf, size); + + endUpdate(); +} + +void LayoutSurveySuccess::updateGpsLatitude(GPSPARSER::latitude lat) { +} + +void LayoutSurveySuccess::updateGpsLongitude(GPSPARSER::longitude lon) { +} + +void LayoutSurveySuccess::updateGpsTime(struct tm time) { +} + +void LayoutSurveySuccess::updateInfo(std::string info) { + writeField(_fInfo, info, true); +} + +void LayoutSurveySuccess::updateSw1(std::string sw1) { + writeField(_fSw1, sw1, true); +} + +void LayoutSurveySuccess::updateSw2(std::string sw2) { + writeField(_fSw2, sw2, true); +} + +void LayoutSurveySuccess::updateCountdown(uint32_t seconds) { + char buf[16]; + size_t size; + + memset(buf, 0, sizeof(buf)); + // for some reason, there's a % character that gets displayed in the last column + // add the extra spaces to wipe it out + writeField(_fInfo, "No Free Channel ", true); + size = snprintf(buf, sizeof(buf), "%lu s", seconds); + writeField(_fSw2, buf, size, true); +} + diff --git a/Layout/LayoutSurveySuccess.h b/Layout/LayoutSurveySuccess.h new file mode 100644 index 0000000..dd7e740 --- /dev/null +++ b/Layout/LayoutSurveySuccess.h @@ -0,0 +1,48 @@ +#ifndef __LAYOUTSURVEYSUCCESS_H__ +#define __LAYOUTSURVEYSUCCESS_H__ + +#include "Layout.h" +#include "LoRaHandler.h" +#include "GPSPARSER.h" + +class LayoutSurveySuccess : public Layout { + public: + LayoutSurveySuccess(DOGS102* lcd); + ~LayoutSurveySuccess(); + + void display(); + void updateId(uint32_t id); + void updateRate(std::string rate); + void updatePower(uint32_t power); + void updateStats(LoRaHandler::LoRaPing ping); + void updateGpsLatitude(GPSPARSER::latitude lat); + void updateGpsLongitude(GPSPARSER::longitude lon); + void updateGpsTime(struct tm time); + void updateInfo(std::string info); + void updateSw1(std::string sw1); + void updateSw2(std::string sw2); + void updateCountdown(uint32_t seconds); + + private: + Label _lId; + Label _lDr; + Label _lPwr; + Label _lUp; + Label _lDown; + + Field _fId; + Field _fDr; + Field _fPwr; + Field _fUpRssi; + Field _fUpSnr; + Field _fDownRssi; + Field _fDownSnr; + Field _fGpsLat; + Field _fGpsLon; + Field _fGpsTime; + Field _fInfo; + Field _fSw1; + Field _fSw2; +}; + +#endif diff --git a/LoRaHandler/LoRaHandler.cpp b/LoRaHandler/LoRaHandler.cpp index 27eb266..7ba05f5 100644 --- a/LoRaHandler/LoRaHandler.cpp +++ b/LoRaHandler/LoRaHandler.cpp @@ -60,6 +60,7 @@ void l_worker(void const* argument) { case l_join: l->_mutex.lock(); ret = l->_dot->joinNetworkOnce(); + l->_join_attempts++; l->_mutex.unlock(); if (ret == mDot::MDOT_OK) { l->_status = LoRaHandler::join_success; @@ -80,7 +81,8 @@ void l_worker(void const* argument) { LoRaHandler::LoRaHandler(osThreadId main) : _main(main), _thread(l_worker, (void*)this), - _status(none) + _status(none), + _join_attempts(1) { _ping.status = false; } @@ -158,3 +160,19 @@ uint32_t LoRaHandler::getNextTx() { return ms; } +uint32_t LoRaHandler::getJoinAttempts() { + uint32_t val; + + _mutex.lock(); + val = _join_attempts; + _mutex.unlock(); + + return val; +} + +void LoRaHandler::resetJoinAttempts() { + _mutex.lock(); + _join_attempts = 1; + _mutex.unlock(); +} + diff --git a/LoRaHandler/LoRaHandler.h b/LoRaHandler/LoRaHandler.h index 20f9d6f..1a68668 100644 --- a/LoRaHandler/LoRaHandler.h +++ b/LoRaHandler/LoRaHandler.h @@ -36,6 +36,8 @@ class LoRaHandler { LoRaStatus getStatus(); LoRaPing getPingResults(); uint32_t getNextTx(); + uint32_t getJoinAttempts(); + void resetJoinAttempts(); osThreadId _main; @@ -44,6 +46,7 @@ class LoRaHandler { LoRaPing _ping; mDot* _dot; Mutex _mutex; + uint32_t _join_attempts; }; #endif diff --git a/Mode/Mode.cpp b/Mode/Mode.cpp index eea6d3c..ba60c01 100644 --- a/Mode/Mode.cpp +++ b/Mode/Mode.cpp @@ -1,19 +1,129 @@ #include "Mode.h" +#include "MTSLog.h" -Mode::Mode(DOGS102* lcd, ButtonHandler* buttons) +const char* Mode::_file_name = "SurveyData.txt"; + +Mode::Mode(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora) : _lcd(lcd), _buttons(buttons), + _dot(dot), + _lora(lora), + _main_id(Thread::gettid()), _index(0), - _main_id(Thread::gettid()) + _band(_dot->getFrequencyBand()), + _sub_band(_dot->getFrequencySubBand()), + _data_rate(mDot::SF_7), + _power(2), + _next_tx(0), + _send_data(false) {} Mode::~Mode() {} bool Mode::deleteDataFile() { - return true; + bool ret = true; + + // if survey data file exists, attempt to delete it + std::vector<mDot::mdot_file> files = _dot->listUserFiles(); + for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) + if (it->name == _file_name) { + if (! _dot->deleteUserFile(_file_name)) + ret = false; + break; + } + + return ret; } +// ID, Status, Lock, Lat, Long, Alt, Time, RSSIup, SNRup, RSSIdown, SNRdown, DataRate, Power bool Mode::appendDataFile(const DataItem& data) { + char main_buf[256]; + char id_buf[16]; + char lat_buf[32]; + char lon_buf[32]; + char alt_buf[16]; + char time_buf[32]; + char stats_buf[32]; + size_t size; + + memset(main_buf, 0, sizeof(main_buf)); + memset(id_buf, 0, sizeof(id_buf)); + memset(lat_buf, 0, sizeof(lat_buf)); + memset(lon_buf, 0, sizeof(lon_buf)); + memset(alt_buf, 0, sizeof(alt_buf)); + memset(time_buf, 0, sizeof(time_buf)); + memset(stats_buf, 0, sizeof(stats_buf)); + + snprintf(id_buf, sizeof(id_buf), "%c%ld", (data.type == single) ? 'P' : 'S', data.index); + + // if we had GPS lock, format GPS data + if (data.lock > 0) { + snprintf(lat_buf, sizeof(lat_buf), "%d %d %d.%03d %c", + abs(data.gps_latitude.degrees), + data.gps_latitude.minutes, + (data.gps_latitude.seconds * 6) / 1000, + (data.gps_latitude.seconds % 6) / 1000, + (data.gps_latitude.degrees > 0) ? 'N' : 'S'); + snprintf(lon_buf, sizeof(lon_buf), "%d %d %d.%03d %c", + abs(data.gps_longitude.degrees), + data.gps_longitude.minutes, + (data.gps_longitude.seconds * 6) / 1000, + (data.gps_longitude.seconds % 6) / 1000, + (data.gps_longitude.degrees > 0) ? 'E' : 'W'); + snprintf(alt_buf, sizeof(alt_buf), "%d", + data.gps_altitude); + snprintf(time_buf, sizeof(time_buf), "%02d:%02d:%02d %02d/%02d/%04d", + data.gps_time.tm_hour, + data.gps_time.tm_min, + data.gps_time.tm_sec, + data.gps_time.tm_mon + 1, + data.gps_time.tm_mday, + data.gps_time.tm_year + 1900); + } + + if (data.status) { + snprintf(stats_buf, sizeof(stats_buf), "%d,%d.%ld,%d,%d.%ld", + data.ping.up.rssi, + data.ping.up.snr / 10, abs(data.ping.up.snr) % 10, + data.ping.down.rssi, + data.ping.down.snr / 4, (abs(data.ping.down.snr) % 10) * 25); + } + + size = snprintf(main_buf, sizeof(main_buf), "%s,%c,%ld,%s,%s,%s,%s,%s,%s,%lu\n", + id_buf, + data.status ? 'S' : 'F', + data.lock, + (data.lock > 0) ? lat_buf : "", + (data.lock > 0) ? lon_buf : "", + (data.lock > 0) ? alt_buf : "", + (data.lock > 0) ? time_buf : "", + data.status ? stats_buf : ",,,", + _dot->DataRateStr(data.data_rate).substr(3).c_str(), + data.power); + + if (size < 0) { + logError("failed to format survey data"); + return false; + } + + if (! _dot->appendUserFile(_file_name, (void*)main_buf, size)) { + logError("failed to write survey data to file"); + return false; + } else { + logInfo("successfully wrote survey data to file"); + } + return true; } +void Mode::updateData(DataItem& data, DataType type, bool status) { + data.type = type; + data.index = _index; + data.status = status; + data.lock = 0; + // TODO add GPS info + data.ping = _ping_result; + data.data_rate = _data_rate; + data.power = _power; +} + diff --git a/Mode/Mode.h b/Mode/Mode.h index 1254a9e..8a4f030 100644 --- a/Mode/Mode.h +++ b/Mode/Mode.h @@ -3,6 +3,8 @@ #include "DOGS102.h" #include "ButtonHandler.h" +#include "mDot.h" +#include "LoRaHandler.h" #include "GPSPARSER.h" class Mode { @@ -21,15 +23,12 @@ class Mode { GPSPARSER::latitude gps_latitude; int16_t gps_altitude; struct tm gps_time; - int16_t rssi_up; - int16_t snr_up; - int16_t rssi_down; - int16_t snr_down; + LoRaHandler::LoRaPing ping; uint8_t data_rate; - uint8_t power; + uint32_t power; } DataItem; - Mode(DOGS102* lcd, ButtonHandler* buttons); + Mode(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora); ~Mode(); virtual bool start() = 0; @@ -37,11 +36,25 @@ class Mode { protected: bool deleteDataFile(); bool appendDataFile(const DataItem& data); + void updateData(DataItem& data, DataType type, bool status); DOGS102* _lcd; ButtonHandler* _buttons; - uint32_t _index; + mDot* _dot; + LoRaHandler* _lora; osThreadId _main_id; + static const char* _file_name; + uint32_t _index; + uint8_t _band; + uint8_t _sub_band; + uint8_t _data_rate; + uint8_t _power; + uint32_t _next_tx; + ButtonHandler::ButtonEvent _be; + LoRaHandler::LoRaStatus _ls; + LoRaHandler::LoRaPing _ping_result; + uint8_t _state; + bool _send_data; }; #endif diff --git a/Mode/ModeJoin.cpp b/Mode/ModeJoin.cpp index acdd407..d1e69ea 100644 --- a/Mode/ModeJoin.cpp +++ b/Mode/ModeJoin.cpp @@ -2,57 +2,44 @@ #include "MTSLog.h" #include "MTSText.h" -ModeJoin::ModeJoin(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, uint8_t band) - : Mode(lcd, buttons), - _lj(lcd, band), - _dot(dot), - _lora(lora), - _band(band), - _data_rate(band == mDot::FB_915 ? mDot::SF_10 : mDot::SF_12), - _power(20), - _next_tx(0), +ModeJoin::ModeJoin(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora) + : Mode(lcd, buttons, dot, lora), + _join(lcd, _band), _joined(false) {} ModeJoin::~ModeJoin() {} bool ModeJoin::start() { + bool joining = false; + // clear any stale signals osSignalClear(_main_id, buttonSignal | loraSignal); + + _data_rate = (_band == mDot::FB_915) ? mDot::SF_10 : mDot::SF_12; + _power = 20; _joined = false; - _index = 1; - _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) { - _sub_band = _dot->getFrequencySubBand(); - _lj.updateFsb(_sub_band); - } - // mDot::DataRateStr returns format SF_XX - we only want to display the XX part - _lj.updateRate(_dot->DataRateStr(_data_rate).substr(3)); - _lj.updatePower(_power); + display(); _lora->setDataRate(_data_rate); _lora->setPower(_power); + _lora->resetJoinAttempts(); while (! _joined) { _next_tx = _lora->getNextTx(); if (_next_tx) { - _lj.updateCountdown(_next_tx * 1000); - } else { - _lj.updateAttempt(_index++); - _lj.updateStatus("Joining..."); + logInfo("next tx %lu ms", _next_tx); + _join.updateStatus("Waiting..."); + _join.updateCountdown(_next_tx / 1000); + } else if (! joining) { + logInfo("attempting to join"); + joining = true; + display(); _lora->join(); } - osEvent e = Thread::signal_wait(0); + osEvent e = Thread::signal_wait(0, 250); if (e.status == osEventSignal) { if (e.value.signals & buttonSignal) { _be = _buttons->getButtonEvent(); @@ -69,8 +56,8 @@ bool ModeJoin::start() { _ls = _lora->getStatus(); switch (_ls) { case LoRaHandler::join_success: - _lj.updateStatus("Join Success!"); - _lj.displayCancel(false); + _join.updateStatus("Join Success!"); + _join.displayCancel(false); logInfo("joined"); _joined = true; osDelay(2000); @@ -78,6 +65,7 @@ bool ModeJoin::start() { case LoRaHandler::join_failure: logInfo("failed to join"); + joining = false; break; } } @@ -86,3 +74,22 @@ bool ModeJoin::start() { return false; } + +void ModeJoin::display() { + _join.display(); + _join.updateStatus("Joining..."); + if (_dot->getJoinMode() == mDot::MANUAL) { + _join.updateId(mts::Text::bin2hexString(_dot->getNetworkId())); + _join.updateKey(mts::Text::bin2hexString(_dot->getNetworkKey())); + } else { + _join.updateId(_dot->getNetworkName()); + _join.updateKey(_dot->getNetworkPassphrase()); + } + if (_band == mDot::FB_915) + _join.updateFsb(_sub_band); + // mDot::DataRateStr returns format SF_XX - we only want to display the XX part + _join.updateRate(_dot->DataRateStr(_data_rate).substr(3)); + _join.updatePower(_power); + _join.updateAttempt(_lora->getJoinAttempts()); +} + diff --git a/Mode/ModeJoin.h b/Mode/ModeJoin.h index 5b88e25..af48d94 100644 --- a/Mode/ModeJoin.h +++ b/Mode/ModeJoin.h @@ -3,28 +3,19 @@ #include "Mode.h" #include "LayoutJoin.h" -#include "mDot.h" -#include "LoRaHandler.h" class ModeJoin : public Mode { public: - ModeJoin(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, uint8_t band); + ModeJoin(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora); ~ModeJoin(); bool start(); private: - LayoutJoin _lj; - mDot* _dot; - LoRaHandler* _lora; - uint8_t _band; - uint8_t _sub_band; - uint8_t _data_rate; - uint8_t _power; - uint32_t _next_tx; + void display(); + + LayoutJoin _join; bool _joined; - ButtonHandler::ButtonEvent _be; - LoRaHandler::LoRaStatus _ls; }; #endif diff --git a/Mode/ModeSingle.cpp b/Mode/ModeSingle.cpp new file mode 100644 index 0000000..5609bab --- /dev/null +++ b/Mode/ModeSingle.cpp @@ -0,0 +1,354 @@ +#include "ModeSingle.h" +#include "MTSLog.h" + +ModeSingle::ModeSingle(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora) + : Mode(lcd, buttons, dot, lora), + _help(lcd), + _file(lcd), + _confirm(lcd), + _progress(lcd), + _success(lcd), + _failure(lcd) +{} + +ModeSingle::~ModeSingle() {} + +bool ModeSingle::start() { + bool data_file = false; + bool send_ping = false; + bool send_data = false; + bool no_channel_ping = false; + bool no_channel_data = false; + + // clear any stale signals + osSignalClear(_main_id, buttonSignal | loraSignal); + + // see if we're supposed to send the data packet after success + // that item is stored in the mDot::StartUpMode config field + _send_data = _dot->getStartUpMode(); + + // see if survey data file exists + std::vector<mDot::mdot_file> files = _dot->listUserFiles(); + for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) { + if (strcmp(it->name, _file_name) == 0) { + logInfo("found survey data file"); + data_file = true; + break; + } + } + if (data_file) { + _state = check_file; + _file.display(); + } else { + _state = show_help; + _index = 0; + displayHelp(); + } + + while (true) { + osEvent e = Thread::signal_wait(0, 250); + if (e.status == osEventSignal) { + if (e.value.signals & buttonSignal) { + _be = _buttons->getButtonEvent(); + + switch (_be) { + case ButtonHandler::sw1_press: + switch (_state) { + case check_file: + _state = show_help; + _index = 0; // need to get index from NVM + displayHelp(); + break; + case confirm: + _state = check_file; + _file.display(); + break; + case show_help: + incrementRatePower(); + _help.updateMsg(formatNewRatePower()); + break; + case in_progress: + // do nothing + break; + case success: + incrementRatePower(); + _success.updateInfo(formatNewRatePower()); + break; + case data: + break; + case failure: + incrementRatePower(); + _failure.updateInfo(formatNewRatePower()); + break; + } + break; + + case ButtonHandler::sw2_press: + switch (_state) { + case check_file: + _state = confirm; + _confirm.display(); + break; + case confirm: + _state = show_help; + logInfo("deleting survey data file"); + _dot->deleteUserFile(_file_name); + _index = 0; + displayHelp(); + break; + case show_help: + _state = in_progress; + _progress.display(); + if (_lora->getNextTx() > 0) + no_channel_ping = true; + else + send_ping = true; + break; + case in_progress: + // do nothing + break; + case success: + _state = in_progress; + _progress.display(); + if (_lora->getNextTx() > 0) + no_channel_ping = true; + else + send_ping = true; + break; + case data: + break; + case failure: + _state = in_progress; + _progress.display(); + if (_lora->getNextTx() > 0) + no_channel_ping = true; + else + send_ping = true; + break; + } + break; + case ButtonHandler::sw1_hold: + return true; + } + } + if (e.value.signals & loraSignal) { + _ls = _lora->getStatus(); + switch (_ls) { + case LoRaHandler::ping_success: + switch (_state) { + case check_file: + break; + case confirm: + break; + case show_help: + break; + case in_progress: + _ping_result = _lora->getPingResults(); + displaySuccess(); + updateData(_data, single, true); + appendDataFile(_data); + if (_send_data) { + _state = data; + if (_lora->getNextTx() > 0) + no_channel_data = true; + else + send_data = true; + } else { + _state = success; + _success.updateSw1(" Power"); + _success.updateSw2("Survey"); + } + break; + case success: + break; + case data: + break; + case failure: + break; + } + break; + + case LoRaHandler::ping_failure: + switch (_state) { + case check_file: + break; + case confirm: + break; + case show_help: + break; + case in_progress: + _state = failure; + _failure.display(); + _failure.updateId(_index); + // mDot::DataRateStr returns format SF_XX - we only want to display the XX part + _success.updateRate(_dot->DataRateStr(_data_rate).substr(3)); + updateData(_data, single, false); + appendDataFile(_data); + _failure.updatePower(_power); + break; + case success: + break; + case data: + break; + case failure: + break; + } + break; + + case LoRaHandler::send_success: + switch (_state) { + case check_file: + break; + case confirm: + break; + case show_help: + break; + case in_progress: + break; + case success: + break; + case data: + _state = success; + _success.updateInfo("Data Send Success"); + _success.updateSw1(" Power"); + _success.updateSw2("Survey"); + break; + case failure: + break; + } + break; + + case LoRaHandler::send_failure: + switch (_state) { + case check_file: + break; + case confirm: + break; + case show_help: + break; + case in_progress: + break; + case success: + break; + case data: + _state = success; + _success.updateInfo("Data Send Failure"); + _success.updateSw1(" Power"); + _success.updateSw2("Survey"); + break; + case failure: + break; + } + break; + } + } + } + + if (no_channel_ping) { + uint32_t t = _lora->getNextTx(); + if (t > 0) { + logInfo("next tx %lu ms", t); + _progress.updateCountdown(t / 1000); + } else { + _progress.display(); + no_channel_ping = false; + send_ping = true; + } + } + if (no_channel_data) { + uint32_t t = _lora->getNextTx(); + if (t > 0) { + logInfo("next tx %lu ms", t); + _success.updateCountdown(t / 1000); + } else { + displaySuccess(); + no_channel_ping = false; + send_ping = true; + } + } + if (send_ping) { + logInfo("sending ping"); + send_ping = false; + _lora->setDataRate(_data_rate); + _lora->setPower(_power); + _lora->ping(); + _index++; + } + if (send_data) { + std::vector<uint8_t> s_data; + logInfo("sending data"); + _success.updateInfo("Data Sending..."); + _lora->setDataRate(_data_rate); + _lora->setPower(_power); + _lora->send(s_data); + } + } +} + +void ModeSingle::displayHelp() { + _help.display(); + _help.updateMode("Survey Single"); + _help.updateSw1(" DR/PWR"); + _help.updateSw2("Survey"); +} + +void ModeSingle::displaySuccess() { + _success.display(); + _success.updateId(_index); + // mDot::DataRateStr returns format SF_XX - we only want to display the XX part + _success.updateRate(_dot->DataRateStr(_data_rate).substr(3)); + _success.updatePower(_power); + _success.updateStats(_ping_result); + // if GPS lock + // display GPS latitude, longitude, and time + // else + // display "no lock" + _success.updateInfo("No GPS Lock"); +} + +std::string ModeSingle::formatNewRatePower() { + std::string msg; + char buf[8]; + size_t size; + + memset(buf, 0, sizeof(buf)); + msg += "New DR="; + msg += _dot->DataRateStr(_data_rate).substr(3); + msg += " P="; + size = snprintf(buf, sizeof(buf), "%u", _power); + msg.append(buf, size); + + return msg; +} + +void ModeSingle::incrementRatePower() { + if (_power == 20) { + _power = 2; + switch (_data_rate) { + case mDot::SF_7: + _data_rate = mDot::SF_8; + break; + case mDot::SF_8: + _data_rate = mDot::SF_9; + break; + case mDot::SF_9: + _data_rate = mDot::SF_10; + break; + case mDot::SF_10: + if (_band == mDot::FB_915) + _data_rate = mDot::SF_7; + else + _data_rate = mDot::SF_11; + break; + case mDot::SF_11: + _data_rate = mDot::SF_12; + break; + case mDot::SF_12: + _data_rate = mDot::SF_7; + break; + } + } else { + _power += 3; + } +} + diff --git a/Mode/ModeSingle.h b/Mode/ModeSingle.h new file mode 100644 index 0000000..df656ba --- /dev/null +++ b/Mode/ModeSingle.h @@ -0,0 +1,44 @@ +#ifndef __MODESINGLE_H__ +#define __MODESINGLE_H__ + +#include "Mode.h" +#include "LayoutHelp.h" +#include "LayoutFile.h" +#include "LayoutConfirm.h" +#include "LayoutSurveyProgress.h" +#include "LayoutSurveySuccess.h" +#include "LayoutSurveyFailure.h" + +class ModeSingle : public Mode { + public: + ModeSingle(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora); + ~ModeSingle(); + + bool start(); + + private: + void displayHelp(); + void displaySuccess(); + std::string formatNewRatePower(); + void incrementRatePower(); + + typedef enum { + check_file = 0, + confirm, + show_help, + in_progress, + success, + data, + failure + } state; + + LayoutHelp _help; + LayoutFile _file; + LayoutConfirm _confirm; + LayoutSurveyProgress _progress; + LayoutSurveySuccess _success; + LayoutSurveyFailure _failure; + DataItem _data; +}; + +#endif @@ -15,15 +15,14 @@ #include "LayoutStartup.h" #include "LayoutScrollSelect.h" #include "LayoutConfig.h" -#include "LayoutDemoHelp.h" -#include "LayoutSingleHelp.h" -#include "LayoutSweepHelp.h" +#include "LayoutHelp.h" // button header #include "ButtonHandler.h" // LoRa header #include "LoRaHandler.h" // mode objects #include "ModeJoin.h" +#include "ModeSingle.h" #include "ModeConfig.h" // misc heders #include <string> @@ -48,6 +47,7 @@ mDot* dot; // Modes ModeJoin* modeJoin; +ModeSingle* modeSingle; ModeConfig* modeConfig; // Serial debug port @@ -64,7 +64,7 @@ void surveySingle(); void surveySweep(); int main() { - debug.baud(115200); + debug.baud(460800); lcd = new DOGS102(lcd_spi, lcd_spi_cs, lcd_cd); lcd_backlight = new NCP5623B(backlight_i2c); @@ -74,15 +74,13 @@ int main() { dot = mDot::getInstance(); lora = new LoRaHandler(main_id); - modeJoin = new ModeJoin(lcd, buttons, dot, lora, dot->getFrequencyBand()); - modeConfig = new ModeConfig(lcd, serial, dot, buttons); - // display startup screen for 3 seconds LayoutStartup ls(lcd); ls.display(); osDelay(3000); // start of temporary stuff! + //dot->setFrequencyBand(mDot::FB_868); if (dot->getFrequencyBand() == mDot::FB_915) dot->setFrequencySubBand(mDot::FSB_7); dot->setJoinMode(mDot::OTA); @@ -91,6 +89,15 @@ int main() { dot->setAck(1); // end of temporary stuff! + modeJoin = new ModeJoin(lcd, buttons, dot, lora); + modeSingle = new ModeSingle(lcd, buttons, dot, lora); + modeConfig = new ModeConfig(lcd, serial, dot, buttons); + + // display startup screen for 3 seconds + LayoutStartup ls(lcd); + ls.display(); + osDelay(3000); + //MTSLog::setLogLevel(MTSLog::TRACE_LEVEL); MTSLog::setLogLevel(MTSLog::INFO_LEVEL); logInfo("displaying main menu"); @@ -126,6 +133,8 @@ void mainMenu() { items.push_back(menu_strings[sweep]); while (true) { + // reset session between modes + dot->resetNetworkSession(); LayoutScrollSelect menu(lcd, items, menu_strings[0], menu_strings[1]); menu.display(); @@ -156,7 +165,7 @@ void mainMenu() { modeConfig->start(); } else if (selected == menu_strings[single]) { if (modeJoin->start()) - surveySingle(); + modeSingle->start(); } else if (selected == menu_strings[sweep]) { if (modeJoin->start()) surveySweep(); @@ -167,12 +176,16 @@ void mainMenu() { } void loraDemo() { - LayoutDemoHelp ldh(lcd); + LayoutHelp lh(lcd); + lh.display(); + lh.updateMode("LoRa Demo"); + lh.updateDescription("Select TX Method"); + lh.updateSw1(" Trigger"); + lh.updateSw2("Interval"); // clear any stale signals osSignalClear(main_id, buttonSignal | loraSignal); - ldh.display(); logInfo("demo mode"); while (true) { @@ -195,42 +208,16 @@ void loraDemo() { } } -void surveySingle() { - LayoutSingleHelp lsh(lcd); - - // clear any stale signals - osSignalClear(main_id, buttonSignal | loraSignal); - - lsh.display(); - logInfo("survey single mode"); - - while (true) { - osEvent e = Thread::signal_wait(buttonSignal); - if (e.status == osEventSignal) { - ButtonHandler::ButtonEvent ev = buttons->getButtonEvent(); - switch (ev) { - case ButtonHandler::sw1_press: - logInfo("datarate/power"); - break; - case ButtonHandler::sw2_press: - logInfo("start survey"); - break; - case ButtonHandler::sw1_hold: - return; - default: - break; - } - } - } -} - void surveySweep() { - LayoutSweepHelp lsh(lcd); + LayoutHelp lh(lcd); + lh.display(); + lh.updateMode("Survey Sweep"); + lh.updateSw1(" Cancel"); + lh.updateSw2("Sweep"); // clear any stale signals osSignalClear(main_id, buttonSignal | loraSignal); - lsh.display(); logInfo("survey sweep mode"); while (true) { |