Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: An intrusive boilerplate-free Focus/EEPROM storage class #712

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions src/kaleidoscope/focus_eeprom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Idle-LEDs -- Turn off the LEDs when the keyboard's idle
* Copyright (C) 2018 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once


// TODO: Including EEPROM-Settings should be eliminated by
// adding additional methods to the storage controller API
//
#include <Kaleidoscope-EEPROM-Settings.h>

#include <Kaleidoscope-FocusSerial.h>

namespace kaleidoscope {

// TODO: Give the FocusEEPROMWrapper(s) an appropriate names.
//
template<typename _DatumType,
typename _StoredType,
typename _FocusType>
class BaseFocusEEPROMWrapper {
public:

typedef BaseFocusEEPROMWrapper<_DatumType, _StoredType, _FocusType> ThisType;

typedef _DatumType DatumType;
typedef _StoredType StoredType;
typedef _FocusType FocusType;

BaseFocusEEPROMWrapper(const StoredType datum,
const char *focus_string)
: focus_string_{focus_string},
datum_{datum}
{}

void setup() {

// TODO: Shouldn't EEPROMSettings be wrapped by
// KeyboardHardware.storage()?
focus_address_ = ::EEPROMSettings.requestSlice(sizeof(FocusType));

// Check if the value is initialized and initialize it if necessary
// TODO: Have a storage command that enables this
// KeyboardHardware.storage().isInitialized(focus_address_);
// (checks for uninitialized EEPROM, e.g. FFFF...)
//
//if(!KeyboardHardware.storage().isInitialized(focus_address_)) {
// KeyboardHardware.storage().put(focus_address_, datum_);
//}

KeyboardHardware.storage().get(focus_address_, datum_);
}

bool focusRead(const char *command) {
if (::Focus.handleHelp(command, focus_string_))
return false;

if (strcmp_P(command, focus_string_) != 0)
return false;

if (::Focus.isEOL()) {
::Focus.send((FocusType)datum_);
} else {
FocusType tmpDatum;
::Focus.read(tmpDatum);
datum_ = tmpDatum;
}

return true;
}

ThisType &operator=(DatumType datum) {
datum_ = datum;
this->store();
return *this;
}

void store() {
KeyboardHardware.storage().put(focus_address_, datum_);
}

operator DatumType() {
return datum_;
}

private:

StoredType datum_;
uint16_t focus_address_;
const char *focus_string_;
};

// Use this template if you intent to add Focus/EEPROM capability
// to a member of a base class. In this case the wrapper stores a
// reference to the member.
//
template<typename _DatumType, typename _FocusType = _DatumType>
using ReferenceFocusEEPROMWrapper
= BaseFocusEEPROMWrapper<_DatumType, _DatumType&, _FocusType>;

// Use this template if you want to have a variable that is directly
// wrapped (stored inside the wrapper). In this case the wrapper
// stores the datum (by value).
//
template<typename _DatumType, typename _FocusType = _DatumType>
using ValueFocusEEPROMWrapper
= BaseFocusEEPROMWrapper<_DatumType, _DatumType, _FocusType>;

} // namespace kaleidoscope

// Due to the way the PSTR macro is designed, it does not allow
// for being used at global scope. That's why we have to
// add a temporary lambda function to define a macro that can be evaluated
// anywhere.
//
#define PSTR_ANYWHERE(S) \
[]() -> const char * { \
static const char tmp[] PROGMEM = (S); \
return &tmp[0]; \
}()
30 changes: 30 additions & 0 deletions src/kaleidoscope/plugin/IdleLEDs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,37 @@ EventHandlerResult IdleLEDs::onKeyswitchEvent(Key &mapped_key, KeyAddr key_addr,
return EventHandlerResult::OK;
}

ReferenceFocusEEPROMWrapper<uint32_t, uint16_t>
PersistentIdleLEDs::start_time_focus_{
// The parent class member variable that is
// controlled by the wrapper
//
PersistentIdleLEDs::start_time_,

// Make sure to store the focus string only once
// in PROGMEM.
//
PSTR_ANYWHERE("idleLeds.idleTimeLimit")};

EventHandlerResult PersistentIdleLEDs::onSetup() {
start_time_focus_.setup();
return EventHandlerResult::OK;
}
EventHandlerResult PersistentIdleLEDs::onFocusEvent(const char *command) {
if (start_time_focus_.focusRead(command)) {
return EventHandlerResult::EVENT_CONSUMED;
}

return EventHandlerResult::OK;
}

void PersistentIdleLEDs::setIdleTimeoutSeconds(uint32_t new_limit) {
IdleLEDs::setIdleTimeoutSeconds(new_limit);
start_time_focus_.store();
}

}
}

kaleidoscope::plugin::IdleLEDs IdleLEDs;
kaleidoscope::plugin::PersistentIdleLEDs PersistentIdleLEDs;
23 changes: 22 additions & 1 deletion src/kaleidoscope/plugin/IdleLEDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#pragma once

#include <Kaleidoscope.h>
#include "kaleidoscope/focus_eeprom.h"

namespace kaleidoscope {
namespace plugin {
Expand All @@ -34,10 +35,30 @@ class IdleLEDs: public kaleidoscope::Plugin {
EventHandlerResult beforeEachCycle();
EventHandlerResult onKeyswitchEvent(Key &mapped_key, KeyAddr key_addr, uint8_t key_state);

private:
protected:
static uint32_t start_time_;
};

class PersistentIdleLEDs : public IdleLEDs {
public:

EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *command);

static void setIdleTimeoutSeconds(uint32_t new_limit);

private:
static ReferenceFocusEEPROMWrapper<uint32_t, uint16_t> start_time_focus_;

// Note: If members are added that should themselves be Focus controlled
// and support EEPROM storage without being associated with
// a variable of a parent class, use the ValueFocusEEPROMWrapper
// instead.
//ValueFocusEEPROMWrapper<uint32_t, uint16_t> start_time_focus_;
};

}
}

extern kaleidoscope::plugin::IdleLEDs IdleLEDs;
extern kaleidoscope::plugin::PersistentIdleLEDs PersistentIdleLEDs;