From 6c5ea5a39f25ed1dd186602509e609dd853f0ac0 Mon Sep 17 00:00:00 2001 From: hg Date: Wed, 18 Jun 2014 01:41:12 +0200 Subject: [PATCH] Fixed bugs. Began to implement Fan Control. --- src/GCFanProfile.h | 29 +++++ src/GrowControl.cpp | 96 ++++++++++++++--- src/GrowControl.h | 31 +++++- src/IPCManager.cpp | 12 ++- src/LCD.cpp | 2 +- src/LCD.h | 8 +- src/config.mk | 1 + src/fanprofile/Dummy2Profile.cpp | 18 ++++ src/fanprofile/Dummy2Profile.h | 23 ++++ src/fanprofile/DummyProfile.cpp | 18 ++++ src/fanprofile/DummyProfile.h | 23 ++++ src/fanprofile/config.mk | 3 + src/lcdpages/FanLevelSettings.cpp | 140 +++++++++++++++++++++++++ src/lcdpages/FanLevelSettings.h | 41 ++++++++ src/lcdpages/FanProfileSettings.cpp | 116 ++++++++++++++++++++ src/lcdpages/FanProfileSettings.h | 41 ++++++++ src/lcdpages/FanSettings.cpp | 76 +++++++++++++- src/lcdpages/FanSettings.h | 12 +++ src/lcdpages/FanUpperLimitSettings.cpp | 117 +++++++++++++++++++++ src/lcdpages/FanUpperLimitSettings.h | 39 +++++++ src/lcdpages/MainPage.cpp | 55 ++++++---- src/lcdpages/config.mk | 5 +- src/main.cpp | 2 +- 23 files changed, 862 insertions(+), 46 deletions(-) create mode 100644 src/GCFanProfile.h create mode 100644 src/fanprofile/Dummy2Profile.cpp create mode 100644 src/fanprofile/Dummy2Profile.h create mode 100644 src/fanprofile/DummyProfile.cpp create mode 100644 src/fanprofile/DummyProfile.h create mode 100644 src/fanprofile/config.mk create mode 100644 src/lcdpages/FanLevelSettings.cpp create mode 100644 src/lcdpages/FanLevelSettings.h create mode 100644 src/lcdpages/FanProfileSettings.cpp create mode 100644 src/lcdpages/FanProfileSettings.h create mode 100644 src/lcdpages/FanUpperLimitSettings.cpp create mode 100644 src/lcdpages/FanUpperLimitSettings.h diff --git a/src/GCFanProfile.h b/src/GCFanProfile.h new file mode 100644 index 0000000..b099331 --- /dev/null +++ b/src/GCFanProfile.h @@ -0,0 +1,29 @@ +/* + * GCFanProfile.h + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#ifndef GCFANPROFILE_H_ +#define GCFANPROFILE_H_ + +#include + +namespace growcontrol { + +class GCFanProfile { +private: + std::string name; + +public: + GCFanProfile(std::string name) : name(name) {} + virtual ~GCFanProfile() {} + + std::string getName() { return name; } +public: +}; + +} /* namespace growcontrol */ + +#endif /* GCFANPROFILE_H_ */ diff --git a/src/GrowControl.cpp b/src/GrowControl.cpp index 9c832fc..3b89878 100644 --- a/src/GrowControl.cpp +++ b/src/GrowControl.cpp @@ -13,13 +13,21 @@ #include #include #include +#include +#include +#include +#include "fanprofile/DummyProfile.h" +#include "fanprofile/Dummy2Profile.h" namespace growcontrol { log4cpp::Category& GrowControl::logger = log4cpp::Category::getInstance("growcontrol"); -GrowControl::GrowControl() { +GrowControl::GrowControl() : lcd(*this) { + fanProfiles.push_back(new DummyProfile()); + fanProfiles.push_back(new Dummy2Profile()); + fan1ActiveProfile = fanProfiles.at(0); } GrowControl::~GrowControl() { @@ -107,8 +115,8 @@ void GrowControl::newDeviceCallback(TfConnection& conn, TfDevice& device) { && device.getDeviceState() == TfDeviceState::AVAILABLE ) { io16Bricklet = (TfIO16Bricklet*)&device; io16Bricklet->connect(); - io16Bricklet->setPortConfiguration('a', 0x7F, 'o', false); - io16Bricklet->setPort('a', 1); + io16Bricklet->setPortConfiguration('a', fan1PinMask, 'o', false); + setFan1Level(fan1Level); logger << log4cpp::Priority::INFO << "Added io16 device " << device.getDeviceName(true) << "."; } break; @@ -187,14 +195,16 @@ double GrowControl::getHum1() { return ret; } -int GrowControl::getFan1() { +unsigned GrowControl::getFan1Level(bool force) { std::lock_guard lock(controlMutex); - int ret = 0; + unsigned ret = 0; + if (force) { + return fan1Level; + } if (hum1Bricklet != nullptr) { if (hum1Bricklet->getDeviceState() == TfDeviceState::CONNECTED) { try { - // ToDo - throw GCException("Fan not implemented yet.", GCErrorCode::NOT_INITIALIZED); + ret = fan1Level; } catch (TfError &e) { std::ostringstream ss; ss << "unknown exception while getting fan1: " << e.what(); @@ -210,6 +220,64 @@ int GrowControl::getFan1() { } +bool GrowControl::isFan1Connected() { + return (io16Bricklet != nullptr && io16Bricklet->getDeviceState() == TfDeviceState::CONNECTED); +} + +void GrowControl::setFan1Level(unsigned level) { + if (level > fan1UpperLimit) { + level = fan1UpperLimit; + } + if (level != fan1Level) { + fan1Level = level; + if (isFan1Connected()) { + if (fan1Level <= 0) { + io16Bricklet->setPort('a', fan1PinMask, false); + } else { + io16Bricklet->setPort('a', fan1PinMask, false); + usleep(100000); // Wait for 100 ms (Just to be sure) + io16Bricklet->setPort('a', 1 << (fan1Level - 1), true); + } + } + } +} + +unsigned GrowControl::getFan1UpperLimit() { + return fan1UpperLimit; +} + +void GrowControl::setFan1UpperLimit(unsigned limit) { + fan1UpperLimit = limit; + if (fan1Level > fan1UpperLimit) { + setFan1Level(fan1UpperLimit); + } +} + +unsigned GrowControl::getFan1Max() { + return fan1Max; +} + +bool GrowControl::getFan1AutoMode() { + return fan1AutoMode; +} + +void GrowControl::setFan1AutoMode(bool mode) { + fan1AutoMode = mode; +} + +GCFanProfile* GrowControl::getFan1Profile() { + return fan1ActiveProfile; +} + +void GrowControl::setFan1Profile(GCFanProfile* profile) { + fan1ActiveProfile = profile; +} + +const std::vector& GrowControl::getFanProfiles() { + return fanProfiles; +} + + void GrowControl::shutdownController() { std::lock_guard lock(controlMutex); mainLoopFlag = false; @@ -222,6 +290,7 @@ void GrowControl::mainLoop() { // Fetch sensor values GCSensorsInfo sensorValues; + sensorValues.timestamp = std::chrono::system_clock::now(); try { sensorValues.temp1.value = getTemp1(); sensorValues.temp1.valid = true; @@ -244,17 +313,20 @@ void GrowControl::mainLoop() { sensorValues.hum1.error = e; } try { - sensorValues.fan1.value = getFan1(); - sensorValues.fan1.valid = true; + sensorValues.fan1UpperLimit = getFan1UpperLimit(); + sensorValues.fan1AutoMode = getFan1AutoMode(); + sensorValues.fan1Profile = getFan1Profile(); + sensorValues.fan1Level.value = getFan1Level(); + sensorValues.fan1Level.valid = true; } catch (GCException &e) { - sensorValues.fan1.valid = false; - sensorValues.fan1.error = e; + sensorValues.fan1Level.valid = false; + sensorValues.fan1Level.error = e; } lcd.controlMainLoopCallback(sensorValues); if (mainLoopFlag) { - sleep(sleepDuration); + std::this_thread::sleep_until(sensorValues.timestamp + std::chrono::seconds(1)); } } diff --git a/src/GrowControl.h b/src/GrowControl.h index edce64c..e5bbe02 100644 --- a/src/GrowControl.h +++ b/src/GrowControl.h @@ -13,11 +13,16 @@ #include #include #include "LCD.h" +#include +#include +#include using namespace tfcppsimple; namespace growcontrol { +class GCFanProfile; + template struct CGSensorValue { @@ -27,10 +32,14 @@ struct CGSensorValue { }; struct GCSensorsInfo { + std::chrono::system_clock::time_point timestamp; CGSensorValue temp1; CGSensorValue temp2; CGSensorValue hum1; - CGSensorValue fan1; + CGSensorValue fan1Level; + int fan1UpperLimit; + bool fan1AutoMode; + GCFanProfile* fan1Profile; }; @@ -52,6 +61,13 @@ private: unsigned int sleepDuration = 1; bool mainLoopFlag = true; + unsigned fan1Max = 7; + unsigned fan1UpperLimit = 7; + uint8_t fan1PinMask = 0x7F; + bool fan1AutoMode = true; + unsigned fan1Level = 0; + GCFanProfile* fan1ActiveProfile = nullptr; + std::vector fanProfiles; public: @@ -71,7 +87,18 @@ public: double getHum1(); - int getFan1(); + bool isFan1Connected(); + unsigned getFan1Level(bool force = false); + void setFan1Level(unsigned level); + unsigned getFan1UpperLimit(); + void setFan1UpperLimit(unsigned limit); + unsigned getFan1Max(); + bool getFan1AutoMode(); + void setFan1AutoMode(bool mode); + GCFanProfile* getFan1Profile(); + void setFan1Profile(GCFanProfile* profile); + const std::vector& getFanProfiles(); + void shutdownController(); }; diff --git a/src/IPCManager.cpp b/src/IPCManager.cpp index 4cd8cdb..211adb6 100644 --- a/src/IPCManager.cpp +++ b/src/IPCManager.cpp @@ -17,6 +17,7 @@ #include #include #include +#include namespace growcontrol { @@ -51,7 +52,7 @@ void IPCManager::workerThreadFunc(IPCManager* obj, int socket, std::thread* self logger << log4cpp::Priority::INFO << "ipc connection closed by peer."; loopFlag = false; } else if (rsize < 0) { // Error while receive - logger << log4cpp::Priority::ERROR << "error during ipc recv."; + logger << log4cpp::Priority::ERROR << "error during ipc recv: " << strerror(errno); loopFlag = false; } else { // Check if '\0' appears in command (our end-of-command) @@ -106,7 +107,7 @@ void IPCManager::init(GrowControl& growControl, std::string socketPath) { this->socketPath = socketPath; // Create Socket if ((socketFD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - logger << log4cpp::Priority::ERROR << "Could not create socket"; + logger << log4cpp::Priority::ERROR << "Could not create socket: " << strerror(errno); throw GCException("Could not create socket", GCErrorCode::OTHER_ERROR); } // Create address struct @@ -117,12 +118,12 @@ void IPCManager::init(GrowControl& growControl, std::string socketPath) { unlink(local.sun_path); // bind socket if (bind(socketFD, (struct sockaddr *)&local, sizeof(local)) == -1) { - logger << log4cpp::Priority::ERROR << "Could not bind socket"; + logger << log4cpp::Priority::ERROR << "Could not bind socket: " << strerror(errno); throw GCException("Could not bind socket", GCErrorCode::OTHER_ERROR); } // mark as listen connection if (listen(socketFD, 5) == -1) { - logger << log4cpp::Priority::ERROR << "Could not switch socket to accepting mode"; + logger << log4cpp::Priority::ERROR << "Could not switch socket to accepting mode: " << strerror(errno); throw GCException("Could not switch socket to accepting mode", GCErrorCode::OTHER_ERROR); } logger << log4cpp::Priority::INFO << "Successfully created new ipc socket " << socketPath << "."; @@ -138,6 +139,8 @@ IPCManager::~IPCManager() { void IPCManager::shutdown() { + /* There's a deadlock somewhere + if (configFlag) { if (socketFD > 0) { close(socketFD); @@ -155,6 +158,7 @@ void IPCManager::shutdown() { } configFlag = false; } + */ } diff --git a/src/LCD.cpp b/src/LCD.cpp index 67d28a9..0653ccc 100644 --- a/src/LCD.cpp +++ b/src/LCD.cpp @@ -12,7 +12,7 @@ namespace growcontrol { log4cpp::Category& LCD::logger = log4cpp::Category::getInstance("growcontrol"); -LCD::LCD() : pageRoot(*this) { +LCD::LCD(GrowControl& controller) : controller(controller), pageRoot(*this) { activePage = &pageRoot; for (int t = 0; t < 4; t++) { for (int i = 0; i < 20; i++) { diff --git a/src/LCD.h b/src/LCD.h index d8b03ce..019c3b2 100644 --- a/src/LCD.h +++ b/src/LCD.h @@ -17,6 +17,7 @@ using namespace tfcppsimple; namespace growcontrol { +class GrowControl; struct GCSensorsInfo; class LCD : public TfLCD20x4Listener, public TfDeviceStateListener { @@ -29,14 +30,15 @@ private: char lcdBuffer[4][21]; bool lineFlags[4] = {false, false, false, false}; int lcdLightCountdown = 0; - int lcdLightMaxCountdown = 10; + int lcdLightMaxCountdown = 30; bool lcdLightCountdownFlag = false; LCDPage* activePage = nullptr; + GrowControl& controller; MainPage pageRoot; public: - LCD(); + LCD(GrowControl& controller); virtual ~LCD(); void setTfObject(TfLCD20x4Bricklet& lcd); @@ -54,6 +56,8 @@ public: void resetLightCountdown(); void setLight(bool light); + GrowControl& getGrowControl() { return controller; } + void controlMainLoopCallback(GCSensorsInfo& sensors); bool isLCDConnected(); diff --git a/src/config.mk b/src/config.mk index b3be13b..a4da2ff 100644 --- a/src/config.mk +++ b/src/config.mk @@ -6,3 +6,4 @@ SRC_FILES += src/main.cpp \ include src/lcdpages/config.mk include src/third-party/config.mk +include src/fanprofile/config.mk diff --git a/src/fanprofile/Dummy2Profile.cpp b/src/fanprofile/Dummy2Profile.cpp new file mode 100644 index 0000000..f65269c --- /dev/null +++ b/src/fanprofile/Dummy2Profile.cpp @@ -0,0 +1,18 @@ +/* + * Dummy2Profile.cpp + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#include "Dummy2Profile.h" + +namespace growcontrol { + +Dummy2Profile::Dummy2Profile() : GCFanProfile("Dummy2") { +} + +Dummy2Profile::~Dummy2Profile() { +} + +} /* namespace growcontrol */ diff --git a/src/fanprofile/Dummy2Profile.h b/src/fanprofile/Dummy2Profile.h new file mode 100644 index 0000000..5bedcfd --- /dev/null +++ b/src/fanprofile/Dummy2Profile.h @@ -0,0 +1,23 @@ +/* + * Dummy2Profile.h + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#ifndef DUMMY2PROFILE_H_ +#define DUMMY2PROFILE_H_ + +#include "../GCFanProfile.h" + +namespace growcontrol { + +class Dummy2Profile: public GCFanProfile { +public: + Dummy2Profile(); + virtual ~Dummy2Profile(); +}; + +} /* namespace growcontrol */ + +#endif /* DUMMY2PROFILE_H_ */ diff --git a/src/fanprofile/DummyProfile.cpp b/src/fanprofile/DummyProfile.cpp new file mode 100644 index 0000000..7536e94 --- /dev/null +++ b/src/fanprofile/DummyProfile.cpp @@ -0,0 +1,18 @@ +/* + * DummyProfile.cpp + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#include "DummyProfile.h" + +namespace growcontrol { + +DummyProfile::DummyProfile() : GCFanProfile("Dummy") { +} + +DummyProfile::~DummyProfile() { +} + +} /* namespace growcontrol */ diff --git a/src/fanprofile/DummyProfile.h b/src/fanprofile/DummyProfile.h new file mode 100644 index 0000000..63a7fee --- /dev/null +++ b/src/fanprofile/DummyProfile.h @@ -0,0 +1,23 @@ +/* + * DummyProfile.h + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#ifndef DUMMYPROFILE_H_ +#define DUMMYPROFILE_H_ + +#include "../GCFanProfile.h" + +namespace growcontrol { + +class DummyProfile: public GCFanProfile { +public: + DummyProfile(); + virtual ~DummyProfile(); +}; + +} /* namespace growcontrol */ + +#endif /* DUMMYPROFILE_H_ */ diff --git a/src/fanprofile/config.mk b/src/fanprofile/config.mk new file mode 100644 index 0000000..da4b909 --- /dev/null +++ b/src/fanprofile/config.mk @@ -0,0 +1,3 @@ + +SRC_FILES += src/fanprofile/DummyProfile.cpp \ + src/fanprofile/Dummy2Profile.cpp diff --git a/src/lcdpages/FanLevelSettings.cpp b/src/lcdpages/FanLevelSettings.cpp new file mode 100644 index 0000000..4c171b6 --- /dev/null +++ b/src/lcdpages/FanLevelSettings.cpp @@ -0,0 +1,140 @@ +/* + * FanLevelSettings.cpp + * + * Created on: 17.06.2014 + * Author: matzman + */ + +#include "FanLevelSettings.h" +#include "../LCD.h" +#include "../GrowControl.h" +#include "../GCException.h" +#include +#include +#include + +namespace growcontrol { + +FanLevelSettings::FanLevelSettings(LCD& lcd, LCDPage* parent) : LCDPage(lcd, parent) { +} + +FanLevelSettings::~FanLevelSettings() { +} + +void FanLevelSettings::fillItemVector(unsigned upperLimit) { + if (lastUpperLimit != upperLimit) { + items.clear(); + items.push_back("Auto"); + items.push_back("Off"); + for (unsigned t = 1; t <= upperLimit; t++) { + std::ostringstream ss; + ss << t; + items.push_back(ss.str()); + } + lastUpperLimit = upperLimit; + } +} + + + +void FanLevelSettings::reset() { + itemsStart = 0; + cursorPos = 0; +} + +void FanLevelSettings::refreshDisplay() { + if (lcd.isLCDConnected()) { + fillItemVector(lcd.getGrowControl().getFan1UpperLimit()); + int diff = (items.size()-1) - (itemsStart + cursorPos); + if (diff < -3) { + reset(); + } else if (diff < 0) { + cursorPos += diff; + } + if (lcd.getGrowControl().getFan1AutoMode()) { + activePos = 0; + } else { + activePos = lcd.getGrowControl().getFan1Level(true) + 1; + } + char buffer[21]; + lcd.writeLine(0, "Fan Level:"); + for (unsigned t = itemsStart; t < items.size() && t < itemsStart + 3; t++) { + char cursor = ' '; + if (t == itemsStart + cursorPos) { + cursor = 0x7e; + } + char navhint = ' '; + if (t == itemsStart && t >0 ) { + navhint = '<'; + } else if (t == itemsStart + 2 && items.size() - itemsStart > 3) { + navhint = '>'; + } + char aPosHint1 = ' '; + char aPosHint2 = ' '; + if (t == activePos) { + aPosHint1 = '*'; + aPosHint2 = '*'; + } + snprintf(buffer, 21, "%c %c%c%.14s%c", navhint, cursor, aPosHint1, items.at(t).c_str(), aPosHint2); + lcd.writeLine(t - itemsStart + 1, buffer); + } + try { + lcd.writeLCDBuffer(); + } catch (GCException &e) { + } + } +} + +void FanLevelSettings::buttonStateCallback(uint8_t button, bool state) { + if (state) { + bool refresh = false; + switch (button) { + case 0: // enter + { + unsigned pos = itemsStart + cursorPos; + if (pos != activePos) { + if (pos == 0) { + lcd.getGrowControl().setFan1AutoMode(true); + } else { + lcd.getGrowControl().setFan1AutoMode(false); + lcd.getGrowControl().setFan1Level(pos-1); + } + } + refresh = true; + } + break; + case 1: // up + if (cursorPos > 0) { + cursorPos--; + } else if (cursorPos == 0 && itemsStart > 0) { + itemsStart--; + } + refresh = true; + break; + case 2: // down + if (cursorPos < 2) { + cursorPos++; + } else if (cursorPos == 2 && items.size() - itemsStart > 3) { + itemsStart++; + } + refresh = true; + break; + case 3: // cancel + lcd.setActivePage(*parent, true); + break; + default: + break; + } + if (refresh) { + refreshDisplay(); + } + } +} + +void FanLevelSettings::stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate) { +} + +void FanLevelSettings::controlMainLoopCallback(GCSensorsInfo& sensors) { +} + +} /* namespace growcontrol */ diff --git a/src/lcdpages/FanLevelSettings.h b/src/lcdpages/FanLevelSettings.h new file mode 100644 index 0000000..b6d049a --- /dev/null +++ b/src/lcdpages/FanLevelSettings.h @@ -0,0 +1,41 @@ +/* + * FanLevelSettings.h + * + * Created on: 17.06.2014 + * Author: matzman + */ + +#ifndef FANLEVELSETTINGS_H_ +#define FANLEVELSETTINGS_H_ + +#include "../LCDPage.h" +#include +#include + +namespace growcontrol { + +class FanLevelSettings: public LCDPage { +private: + std::vector items; + unsigned itemsStart = 0; + unsigned cursorPos = 0; + unsigned lastUpperLimit = 0; + unsigned activePos = 0; + + void fillItemVector(unsigned upperLimit); + +public: + FanLevelSettings(LCD& lcd, LCDPage* parent); + virtual ~FanLevelSettings(); + + virtual void reset(); + virtual void refreshDisplay(); + + virtual void buttonStateCallback(uint8_t button, bool state); + virtual void stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate); + virtual void controlMainLoopCallback(GCSensorsInfo& sensors); +}; + +} /* namespace growcontrol */ + +#endif /* FANLEVELSETTINGS_H_ */ diff --git a/src/lcdpages/FanProfileSettings.cpp b/src/lcdpages/FanProfileSettings.cpp new file mode 100644 index 0000000..ab19419 --- /dev/null +++ b/src/lcdpages/FanProfileSettings.cpp @@ -0,0 +1,116 @@ +/* + * FanProfileSettings.cpp + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#include "FanProfileSettings.h" +#include "../GCFanProfile.h" +#include "../LCD.h" +#include "../GrowControl.h" +#include "../GCException.h" +#include +#include +#include + +namespace growcontrol { + +FanProfileSettings::FanProfileSettings(LCD& lcd, LCDPage* parent) : LCDPage(lcd, parent) { +} + +FanProfileSettings::~FanProfileSettings() { +} + + + +void FanProfileSettings::reset() { + itemsStart = 0; + cursorPos = 0; +} + +void FanProfileSettings::refreshDisplay() { + if (items.size() == 0) { + items = lcd.getGrowControl().getFanProfiles(); + } + if (lcd.isLCDConnected()) { + auto activeProfile = lcd.getGrowControl().getFan1Profile(); + char buffer[21]; + lcd.writeLine(0, "Fan Profiles:"); + for (unsigned t = itemsStart; t < items.size() && t < itemsStart + 3; t++) { + auto ai = items.at(t); + char cursor = ' '; + if (t == itemsStart + cursorPos) { + cursor = 0x7e; + } + char navhint = ' '; + if (t == itemsStart && t >0 ) { + navhint = '<'; + } else if (t == itemsStart + 2 && items.size() - itemsStart > 3) { + navhint = '>'; + } + char aPosHint1 = ' '; + char aPosHint2 = ' '; + if (ai == activeProfile) { + aPosHint1 = '*'; + aPosHint2 = '*'; + } + snprintf(buffer, 21, "%c %c%c%.14s%c", navhint, cursor, aPosHint1, ai->getName().c_str(), aPosHint2); + lcd.writeLine(t - itemsStart + 1, buffer); + } + try { + lcd.writeLCDBuffer(); + } catch (GCException &e) { + } + } +} + +void FanProfileSettings::buttonStateCallback(uint8_t button, bool state) { + if (state) { + bool refresh = false; + switch (button) { + case 0: // enter + { + unsigned pos = itemsStart + cursorPos; + auto pi = items.at(pos); + if (lastActiveProfile != pi) { + lcd.getGrowControl().setFan1Profile(pi); + } + refresh = true; + } + break; + case 1: // up + if (cursorPos > 0) { + cursorPos--; + } else if (cursorPos == 0 && itemsStart > 0) { + itemsStart--; + } + refresh = true; + break; + case 2: // down + if (cursorPos < 2) { + cursorPos++; + } else if (cursorPos == 2 && items.size() - itemsStart > 3) { + itemsStart++; + } + refresh = true; + break; + case 3: // cancel + lcd.setActivePage(*parent, true); + break; + default: + break; + } + if (refresh) { + refreshDisplay(); + } + } +} + +void FanProfileSettings::stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate) { +} + +void FanProfileSettings::controlMainLoopCallback(GCSensorsInfo& sensors) { +} + +} /* namespace growcontrol */ diff --git a/src/lcdpages/FanProfileSettings.h b/src/lcdpages/FanProfileSettings.h new file mode 100644 index 0000000..8ed2adc --- /dev/null +++ b/src/lcdpages/FanProfileSettings.h @@ -0,0 +1,41 @@ +/* + * FanProfileSettings.h + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#ifndef FANPROFILESETTINGS_H_ +#define FANPROFILESETTINGS_H_ + +#include "../LCDPage.h" +#include +#include + + +namespace growcontrol { + +class GCFanProfile; + +class FanProfileSettings: public LCDPage { +public: + std::vector items; + unsigned itemsStart = 0; + unsigned cursorPos = 0; + GCFanProfile* lastActiveProfile = nullptr; + +public: + FanProfileSettings(LCD& lcd, LCDPage* parent); + virtual ~FanProfileSettings(); + + virtual void reset(); + virtual void refreshDisplay(); + + virtual void buttonStateCallback(uint8_t button, bool state); + virtual void stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate); + virtual void controlMainLoopCallback(GCSensorsInfo& sensors); +}; + +} /* namespace growcontrol */ + +#endif /* FANPROFILESETTINGS_H_ */ diff --git a/src/lcdpages/FanSettings.cpp b/src/lcdpages/FanSettings.cpp index e524d9f..a95ca09 100644 --- a/src/lcdpages/FanSettings.cpp +++ b/src/lcdpages/FanSettings.cpp @@ -11,21 +11,41 @@ namespace growcontrol { -FanSettings::FanSettings(LCD& lcd, LCDPage* parent) : LCDPage(lcd, parent) { +FanSettings::FanSettings(LCD& lcd, LCDPage* parent) + : LCDPage(lcd, parent), levelSettings(lcd, this) + , upperLimitSettings(lcd, this), profileSettings(lcd, this) { + items.push_back("Fan Level"); + items.push_back("Fan Profile"); + items.push_back("Upper Limit"); + items.push_back("Back"); } FanSettings::~FanSettings() { } void FanSettings::reset() { + itemsStart = 0; + cursorPos = 0; } void FanSettings::refreshDisplay() { if (lcd.isLCDConnected()) { - - lcd.clearDisplay(); + char buffer[21]; lcd.writeLine(0, "Fan Settings:"); - lcd.writeLine(1, " ToDo"); + for (unsigned t = itemsStart; t < items.size() && t < itemsStart + 3; t++) { + char cursor = ' '; + if (t == itemsStart + cursorPos) { + cursor = 0x7e; + } + char navhint = ' '; + if (t == itemsStart && t >0 ) { + navhint = '<'; + } else if (t == itemsStart + 2 && items.size() - itemsStart > 3) { + navhint = '>'; + } + snprintf(buffer, 21, "%c %c%-17.17s", navhint, cursor, items.at(t).c_str()); + lcd.writeLine(t - itemsStart + 1, buffer); + } try { lcd.writeLCDBuffer(); } catch (GCException &e) { @@ -35,7 +55,53 @@ void FanSettings::refreshDisplay() { void FanSettings::buttonStateCallback(uint8_t button, bool state) { if (state) { - lcd.setActivePage(*parent); + bool refresh = false; + switch (button) { + case 0: // enter + switch (itemsStart + cursorPos) { + case 0: // Fan Settings + lcd.setActivePage(levelSettings, true); + break; + case 1: // Profiles + lcd.setActivePage(profileSettings, true); + break; + case 2: // Upper Limit + lcd.setActivePage(upperLimitSettings, true); + break; + case 3: // back + lcd.setActivePage(*parent, true); + break; + default: + break; + } + break; + case 1: // up + if (cursorPos > 0) { + cursorPos--; + refresh = true; + } else if (cursorPos == 0 && itemsStart > 0) { + itemsStart--; + refresh = true; + } + break; + case 2: // down + if (cursorPos < 2 && cursorPos < items.size() - 1 ) { + cursorPos++; + refresh = true; + } else if (cursorPos == 2 && items.size() - itemsStart > 3) { + itemsStart++; + refresh = true; + } + break; + case 3: // cancel + lcd.setActivePage(*parent, true); + break; + default: + break; + } + if (refresh) { + refreshDisplay(); + } } } diff --git a/src/lcdpages/FanSettings.h b/src/lcdpages/FanSettings.h index aee1dcc..0dd844f 100644 --- a/src/lcdpages/FanSettings.h +++ b/src/lcdpages/FanSettings.h @@ -9,11 +9,23 @@ #define FANSETTINGS_H_ #include "../LCDPage.h" +#include "FanLevelSettings.h" +#include "FanUpperLimitSettings.h" +#include "FanProfileSettings.h" #include namespace growcontrol { class FanSettings : public LCDPage { +private: + std::vector items; + unsigned itemsStart = 0; + unsigned cursorPos = 0; + + FanLevelSettings levelSettings; + FanUpperLimitSettings upperLimitSettings; + FanProfileSettings profileSettings; + public: FanSettings(LCD& lcd, LCDPage* parent); virtual ~FanSettings(); diff --git a/src/lcdpages/FanUpperLimitSettings.cpp b/src/lcdpages/FanUpperLimitSettings.cpp new file mode 100644 index 0000000..8dcdcb8 --- /dev/null +++ b/src/lcdpages/FanUpperLimitSettings.cpp @@ -0,0 +1,117 @@ +/* + * FanUpperLimitSettings.cpp + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#include "FanUpperLimitSettings.h" +#include "../LCD.h" +#include "../GrowControl.h" +#include "../GCException.h" +#include +#include +#include + +namespace growcontrol { + +FanUpperLimitSettings::FanUpperLimitSettings(LCD& lcd, LCDPage* parent) : LCDPage(lcd, parent) { +} + +FanUpperLimitSettings::~FanUpperLimitSettings() { +} + + + +void FanUpperLimitSettings::reset() { + itemsStart = 0; + cursorPos = 0; +} + +void FanUpperLimitSettings::refreshDisplay() { + if (items.size() == 0) { + for (unsigned t = 1; t <= lcd.getGrowControl().getFan1Max(); t++) { + std::ostringstream ss; + ss << t; + items.push_back(ss.str()); + } + } + if (lcd.isLCDConnected()) { + activePos = lcd.getGrowControl().getFan1UpperLimit() - 1; + char buffer[21]; + lcd.writeLine(0, "Fan Upper Limit:"); + for (unsigned t = itemsStart; t < items.size() && t < itemsStart + 3; t++) { + char cursor = ' '; + if (t == itemsStart + cursorPos) { + cursor = 0x7e; + } + char navhint = ' '; + if (t == itemsStart && t >0 ) { + navhint = '<'; + } else if (t == itemsStart + 2 && items.size() - itemsStart > 3) { + navhint = '>'; + } + char aPosHint1 = ' '; + char aPosHint2 = ' '; + if (t == activePos) { + aPosHint1 = '*'; + aPosHint2 = '*'; + } + snprintf(buffer, 21, "%c %c%c%.14s%c", navhint, cursor, aPosHint1, items.at(t).c_str(), aPosHint2); + lcd.writeLine(t - itemsStart + 1, buffer); + } + try { + lcd.writeLCDBuffer(); + } catch (GCException &e) { + } + } +} + +void FanUpperLimitSettings::buttonStateCallback(uint8_t button, bool state) { + if (state) { + bool refresh = false; + switch (button) { + case 0: // enter + { + unsigned pos = itemsStart + cursorPos; + if (pos != activePos) { + lcd.getGrowControl().setFan1UpperLimit(pos+1); + } + refresh = true; + } + break; + case 1: // up + if (cursorPos > 0) { + cursorPos--; + } else if (cursorPos == 0 && itemsStart > 0) { + itemsStart--; + } + refresh = true; + break; + case 2: // down + if (cursorPos < 2) { + cursorPos++; + } else if (cursorPos == 2 && items.size() - itemsStart > 3) { + itemsStart++; + } + refresh = true; + break; + case 3: // cancel + lcd.setActivePage(*parent, true); + break; + default: + break; + } + if (refresh) { + refreshDisplay(); + } + } +} + +void FanUpperLimitSettings::stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate) { +} + +void FanUpperLimitSettings::controlMainLoopCallback(GCSensorsInfo& sensors) { +} + +} /* namespace growcontrol */ diff --git a/src/lcdpages/FanUpperLimitSettings.h b/src/lcdpages/FanUpperLimitSettings.h new file mode 100644 index 0000000..600422b --- /dev/null +++ b/src/lcdpages/FanUpperLimitSettings.h @@ -0,0 +1,39 @@ +/* + * FanUpperLimitSettings.h + * + * Created on: 18.06.2014 + * Author: matzman + */ + +#ifndef FanUpperLimitSettings_H_ +#define FanUpperLimitSettings_H_ + +#include "../LCDPage.h" +#include +#include + +namespace growcontrol { + +class FanUpperLimitSettings: public LCDPage { +private: + std::vector items; + unsigned itemsStart = 0; + unsigned cursorPos = 0; + unsigned lastUpperLimit = 0; + unsigned activePos = 0; + +public: + FanUpperLimitSettings(LCD& lcd, LCDPage* parent); + virtual ~FanUpperLimitSettings(); + + virtual void reset(); + virtual void refreshDisplay(); + + virtual void buttonStateCallback(uint8_t button, bool state); + virtual void stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate); + virtual void controlMainLoopCallback(GCSensorsInfo& sensors); +}; + +} /* namespace growcontrol */ + +#endif /* FanUpperLimitSettings_H_ */ diff --git a/src/lcdpages/MainPage.cpp b/src/lcdpages/MainPage.cpp index 3b36b69..123237f 100644 --- a/src/lcdpages/MainPage.cpp +++ b/src/lcdpages/MainPage.cpp @@ -7,7 +7,14 @@ #include "MainPage.h" #include "../GrowControl.h" +#include "../GCFanProfile.h" #include +#include +#include +#include +#include +#include +#include namespace growcontrol { @@ -71,9 +78,6 @@ void MainPage::controlMainLoopCallback(GCSensorsInfo& sensors) { snprintf(temp1, 21, "%4.2lf%cC", sensors.temp1.value, 0xdf); } else { switch (sensors.temp1.error.getErrorCode()) { - case GCErrorCode::SENSOR_DISCONNECTED: - snprintf(temp1, 21, "DISCON"); - break; default: snprintf(temp1, 21, " ERROR"); break; @@ -84,9 +88,6 @@ void MainPage::controlMainLoopCallback(GCSensorsInfo& sensors) { snprintf(temp2, 21, "%4.2lf%cC", sensors.temp2.value, 0xdf); } else { switch (sensors.temp2.error.getErrorCode()) { - case GCErrorCode::SENSOR_DISCONNECTED: - snprintf(temp2, 21, "DISCON"); - break; default: snprintf(temp2, 21, " ERROR"); break; @@ -97,33 +98,51 @@ void MainPage::controlMainLoopCallback(GCSensorsInfo& sensors) { snprintf(hum1, 21, "%4.1lf%% ", sensors.hum1.value); } else { switch (sensors.hum1.error.getErrorCode()) { - case GCErrorCode::SENSOR_DISCONNECTED: - snprintf(hum1, 21, "DISCON"); - break; default: snprintf(hum1, 21, "ERROR "); break; } } // fan1 - if (sensors.fan1.valid) { - snprintf(fan1, 21, "ToDo"); + if (sensors.fan1Level.valid) { + std::ostringstream ss; + if (sensors.fan1Level.value == 0) { + ss << "off"; + } else { + ss << sensors.fan1Level.value; + } + if (sensors.fan1AutoMode) { + auto profile = lcd.getGrowControl().getFan1Profile(); + if (profile == nullptr) { + ss << " (Auto?)"; + } else { + ss << " (" << profile->getName() << ")"; + } + } else { + ss << " (Manual)"; + } + std::string fanString = ss.str(); + snprintf(fan1, 21, fanString.c_str()); } else { - switch (sensors.fan1.error.getErrorCode()) { - case GCErrorCode::SENSOR_DISCONNECTED: - snprintf(fan1, 21, "DISCON"); - break; + switch (sensors.fan1Level.error.getErrorCode()) { default: snprintf(fan1, 21, " ERROR"); break; } } + // date + std::chrono::system_clock::time_point test; + auto time = std::chrono::system_clock::to_time_t(sensors.timestamp); + auto ltime = std::localtime(&time); + strftime(buffer[0], 20, " %d.%m.%y %H:%M:%S ", ltime ); + // line 0 + snprintf(buffer[1], 21, "T: %7.7s %7.7s ", temp1, temp2); // line 1 - snprintf(buffer[0], 21, "T: %7.7s %7.7s ", temp1, temp2); + snprintf(buffer[1], 21, "T: %7.7s %7.7s ", temp1, temp2); // line 2 - snprintf(buffer[1], 21, "Humidity: %5.5s ", hum1); + snprintf(buffer[2], 21, "Humidity: %5.5s ", hum1); // line 3 - snprintf(buffer[2], 21, "Fan: %-15.15s", fan1); + snprintf(buffer[3], 21, "Fan: %-15.15s", fan1); refreshDisplay(); } diff --git a/src/lcdpages/config.mk b/src/lcdpages/config.mk index ee96f3f..8acba5c 100644 --- a/src/lcdpages/config.mk +++ b/src/lcdpages/config.mk @@ -3,4 +3,7 @@ SRC_FILES += src/lcdpages/MainPage.cpp \ src/lcdpages/MainMenu.cpp \ src/lcdpages/AboutPage.cpp \ src/lcdpages/FanSettings.cpp \ - src/lcdpages/PCSettings.cpp + src/lcdpages/PCSettings.cpp \ + src/lcdpages/FanLevelSettings.cpp \ + src/lcdpages/FanUpperLimitSettings.cpp \ + src/lcdpages/FanProfileSettings.cpp diff --git a/src/main.cpp b/src/main.cpp index 09f9a3e..56baf0b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ using namespace growcontrol; static log4cpp::Category& logger = log4cpp::Category::getInstance("growcontrol"); std::string pidFile = "/var/run/growcontrold.pid"; -std::string socketPath = "/var/run/growcontrol.socket"; +std::string socketPath = "/opt/growcontrol/growcontrold.socket"; std::string log4cppConfig = "log4cpp.config"; std::string host = "localhost"; uint16_t port = 4223;