mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Rename FreetronicsLCD to just LCD
This commit is contained in:
197
libraries/LCD/BoolField.cpp
Normal file
197
libraries/LCD/BoolField.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "BoolField.h"
|
||||
|
||||
/**
|
||||
* \class BoolField BoolField.h <BoolField.h>
|
||||
* \brief Field that manages the input of a boolean value.
|
||||
*
|
||||
* BoolField is intended for field values that are modifiable by the user.
|
||||
* Pressing one of Up or Down will toggle the field's current value.
|
||||
*
|
||||
* The following example creates a boolean field that shows the state
|
||||
* of the status LED on D13. When the LED is on (the default), the string
|
||||
* "On" will be displayed on the LCD screen. When the LED is off, the
|
||||
* string "Off" will be displayed instead.
|
||||
*
|
||||
* \code
|
||||
* Form mainForm(lcd);
|
||||
* BoolField ledField(mainForm, "Status LED", "On", "Off", true);
|
||||
* \endcode
|
||||
*
|
||||
* \image html FormBool.png
|
||||
*
|
||||
* To actually toggle the LED, the application's main loop() function
|
||||
* should contain the following code:
|
||||
*
|
||||
* \code
|
||||
* int event = lcd.getButton();
|
||||
* if (mainForm.dispatch(event) == FORM_CHANGED) {
|
||||
* if (mainForm.isCurrent(ledField)) {
|
||||
* if (ledField.value())
|
||||
* digitalWrite(STATUS_LED, HIGH);
|
||||
* else
|
||||
* digitalWrite(STATUS_LED, LOW);
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Use TextField for read-only fields that report boolean values but
|
||||
* which are not modifiable by the user.
|
||||
*
|
||||
* ListField can be used to select between more than two items.
|
||||
*
|
||||
* \sa Field, ListField, TextField
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new boolean field with a specific \a label.
|
||||
*
|
||||
* The field is initially not associated with a Form. The field can be
|
||||
* added to a form later using Form::addField().
|
||||
*
|
||||
* The initial value() will be false.
|
||||
*
|
||||
* \sa Form::addField()
|
||||
*/
|
||||
BoolField::BoolField(const String &label)
|
||||
: Field(label)
|
||||
, _printLen(0)
|
||||
, _value(false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new boolean field with a specific \a label and
|
||||
* attaches it to a \a form.
|
||||
*
|
||||
* The initial value() of the field is set to the parameter \a value.
|
||||
* When value() is true, \a trueLabel will be displayed on the screen.
|
||||
* When value() is false, \a falseLabel will be displayed on the screen.
|
||||
*
|
||||
* \sa value()
|
||||
*/
|
||||
BoolField::BoolField(Form &form, const String &label, const String &trueLabel, const String &falseLabel, bool value)
|
||||
: Field(form, label)
|
||||
, _trueLabel(trueLabel)
|
||||
, _falseLabel(falseLabel)
|
||||
, _printLen(0)
|
||||
, _value(value)
|
||||
{
|
||||
}
|
||||
|
||||
int BoolField::dispatch(int event)
|
||||
{
|
||||
if (event == LCD_BUTTON_UP || event == LCD_BUTTON_DOWN) {
|
||||
setValue(!_value);
|
||||
return FORM_CHANGED;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void BoolField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
printValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bool BoolField::value() const
|
||||
* \brief Returns the current value of this field, true or false.
|
||||
*
|
||||
* \sa setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the current value of this field to \a value.
|
||||
*
|
||||
* \sa value()
|
||||
*/
|
||||
void BoolField::setValue(bool value)
|
||||
{
|
||||
if (value != _value) {
|
||||
_value = value;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn const String &BoolField::trueLabel() const
|
||||
* \brief Returns the string that is displayed when value() is true.
|
||||
*
|
||||
* \sa setTrueLabel(), falseLabel()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the string that is displayed when value() is true to
|
||||
* \a trueLabel.
|
||||
*
|
||||
* \sa trueLabel(), setFalseLabel()
|
||||
*/
|
||||
void BoolField::setTrueLabel(const String &trueLabel)
|
||||
{
|
||||
_trueLabel = trueLabel;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn const String &BoolField::falseLabel() const
|
||||
* \brief Returns the string that is displayed when value() is false.
|
||||
*
|
||||
* \sa setFalseLabel(), trueLabel()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the string that is displayed when value() is false to
|
||||
* \a falseLabel.
|
||||
*
|
||||
* \sa falseLabel(), setTrueLabel()
|
||||
*/
|
||||
void BoolField::setFalseLabel(const String &falseLabel)
|
||||
{
|
||||
_falseLabel = falseLabel;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
void BoolField::printValue()
|
||||
{
|
||||
unsigned int len;
|
||||
lcd()->setCursor(0, 1);
|
||||
if (_value) {
|
||||
lcd()->print(_trueLabel);
|
||||
len = _trueLabel.length();
|
||||
while (len++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = _trueLabel.length();
|
||||
} else {
|
||||
lcd()->print(_falseLabel);
|
||||
len = _falseLabel.length();
|
||||
while (len++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = _falseLabel.length();
|
||||
}
|
||||
}
|
||||
55
libraries/LCD/BoolField.h
Normal file
55
libraries/LCD/BoolField.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BoolField_h
|
||||
#define BoolField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class BoolField : public Field {
|
||||
public:
|
||||
explicit BoolField(const String &label);
|
||||
BoolField(Form &form, const String &label, const String &trueLabel, const String &falseLabel, bool value);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
bool value() const { return _value; }
|
||||
void setValue(bool value);
|
||||
|
||||
const String &trueLabel() const { return _trueLabel; }
|
||||
void setTrueLabel(const String &trueLabel);
|
||||
|
||||
const String &falseLabel() const { return _falseLabel; }
|
||||
void setFalseLabel(const String &falseLabel);
|
||||
|
||||
private:
|
||||
String _trueLabel;
|
||||
String _falseLabel;
|
||||
int _printLen;
|
||||
bool _value;
|
||||
|
||||
void printValue();
|
||||
};
|
||||
|
||||
#endif
|
||||
194
libraries/LCD/Field.cpp
Normal file
194
libraries/LCD/Field.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
/**
|
||||
* \class Field Field.h <Field.h>
|
||||
* \brief Manages a single data input/output field within a Form.
|
||||
*
|
||||
* \sa Form, BoolField, IntField, ListField, TextField, TimeField
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new field with a specific \a label.
|
||||
*
|
||||
* The field is initially not associated with a Form. The field can be
|
||||
* added to a form later using Form::addField().
|
||||
*
|
||||
* \sa Form::addField()
|
||||
*/
|
||||
Field::Field(const String &label)
|
||||
: _label(label)
|
||||
, _form(0)
|
||||
, next(0)
|
||||
, prev(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new field with a specific \a label and attaches
|
||||
* it to a \a form.
|
||||
*/
|
||||
Field::Field(Form &form, const String &label)
|
||||
: _label(label)
|
||||
, _form(0)
|
||||
, next(0)
|
||||
, prev(0)
|
||||
{
|
||||
form.addField(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroys this field and removes it from its owning Form.
|
||||
*
|
||||
* \sa Form::removeField()
|
||||
*/
|
||||
Field::~Field()
|
||||
{
|
||||
if (_form)
|
||||
_form->removeField(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn Form *Field::form() const
|
||||
* \brief Returns the Form that owns this field; null if not associated
|
||||
* with a Form.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Dispatches \a event via this field.
|
||||
*
|
||||
* The \a event is usually obtained from LCD::getButton().
|
||||
*
|
||||
* Returns zero if the \a event has been handled and no further action
|
||||
* is required.
|
||||
*
|
||||
* Returns FORM_CHANGED if the \a event has changed the value of this
|
||||
* field in a manner that may require the application to take further
|
||||
* action based on the new field value.
|
||||
*
|
||||
* Returns -1 if the \a event is not handled by this field, and should
|
||||
* be handled by the Form itself (particularly for Left and Right buttons).
|
||||
* The default implementation returns -1 for all events.
|
||||
*
|
||||
* \sa Form::dispatch(), LCD::getButton()
|
||||
*/
|
||||
int Field::dispatch(int event)
|
||||
{
|
||||
// Nothing to do here.
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enters the field due to form navigation.
|
||||
*
|
||||
* This function is typically called when the user presses Left and Right
|
||||
* buttons to navigate to the field. If \a reverse is true, then navigation
|
||||
* was due to the Left button being pressed.
|
||||
*
|
||||
* This function can assume that the display has been cleared and the
|
||||
* cursor is positioned at (0, 0).
|
||||
*
|
||||
* The default implementation prints the label().
|
||||
*
|
||||
* \sa exitField()
|
||||
*/
|
||||
void Field::enterField(bool reverse)
|
||||
{
|
||||
lcd()->print(_label);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Exits the field due to form navigation.
|
||||
*
|
||||
* This function is typically called when the user presses Left and Right
|
||||
* buttons to navigate from the field.
|
||||
*
|
||||
* \sa enterField()
|
||||
*/
|
||||
void Field::exitField()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn const String &Field::label() const
|
||||
* \brief Returns the label to display in the first line of this field.
|
||||
*
|
||||
* \sa setLabel()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the \a label to display in the first line of this field.
|
||||
*
|
||||
* \sa label()
|
||||
*/
|
||||
void Field::setLabel(const String &label)
|
||||
{
|
||||
if (isCurrent()) {
|
||||
unsigned int prevLen = _label.length();
|
||||
unsigned int newLen = label.length();
|
||||
_label = label;
|
||||
lcd()->setCursor(0, 0);
|
||||
lcd()->print(label);
|
||||
while (newLen++ < prevLen)
|
||||
lcd()->write(' ');
|
||||
updateCursor();
|
||||
} else {
|
||||
_label = label;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if this field is the currently-displayed field in
|
||||
* its owning form; false otherwise.
|
||||
*
|
||||
* This function should be called from property setters in subclasses to
|
||||
* determine if the screen should be updated when a property is modified.
|
||||
*/
|
||||
bool Field::isCurrent() const
|
||||
{
|
||||
if (!_form->isVisible())
|
||||
return false;
|
||||
return _form->currentField() == this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn LiquidCrystal *Field::lcd() const
|
||||
* \brief Returns the LCD that this field is being drawn on.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Updates the cursor position after the label has been drawn
|
||||
* by setLabel().
|
||||
*
|
||||
* The default implementation does nothing. Subclasses that use an LCD
|
||||
* cursor may override this to ensure that the cursor position stays
|
||||
* valid after the label is modified.
|
||||
*
|
||||
* \sa setLabel()
|
||||
*/
|
||||
void Field::updateCursor()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
60
libraries/LCD/Field.h
Normal file
60
libraries/LCD/Field.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Field_h
|
||||
#define Field_h
|
||||
|
||||
#include "Form.h"
|
||||
|
||||
class Field {
|
||||
public:
|
||||
explicit Field(const String &label);
|
||||
Field(Form &form, const String &label);
|
||||
~Field();
|
||||
|
||||
Form *form() const { return _form; }
|
||||
|
||||
virtual int dispatch(int event);
|
||||
|
||||
virtual void enterField(bool reverse);
|
||||
virtual void exitField();
|
||||
|
||||
const String &label() const { return _label; }
|
||||
void setLabel(const String &label);
|
||||
|
||||
bool isCurrent() const;
|
||||
|
||||
protected:
|
||||
LiquidCrystal *lcd() const { return _form->_lcd; }
|
||||
|
||||
virtual void updateCursor();
|
||||
|
||||
private:
|
||||
String _label;
|
||||
Form *_form;
|
||||
Field *next;
|
||||
Field *prev;
|
||||
|
||||
friend class Form;
|
||||
};
|
||||
|
||||
#endif
|
||||
308
libraries/LCD/Form.cpp
Normal file
308
libraries/LCD/Form.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Form.h"
|
||||
#include "Field.h"
|
||||
|
||||
/**
|
||||
* \class Form Form.h <Form.h>
|
||||
* \brief Manager for a form containing data input/output fields.
|
||||
*
|
||||
* See the \ref lcd_form "Form example" for more information on
|
||||
* creating an application that uses forms and fields.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new form and associates it with \a lcd.
|
||||
*
|
||||
* This constructor is typically followed by calls to construct Field
|
||||
* values for each of the fields on the form. For example:
|
||||
*
|
||||
* \code
|
||||
* Form mainForm(lcd);
|
||||
* TextField welcomeField(mainForm, "Form example", "v1.0");
|
||||
* \endcode
|
||||
*
|
||||
* \image html FormText.png
|
||||
*/
|
||||
Form::Form(LiquidCrystal &lcd)
|
||||
: _lcd(&lcd)
|
||||
, first(0)
|
||||
, last(0)
|
||||
, current(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Detaches all remaining fields and destroys this form.
|
||||
*/
|
||||
Form::~Form()
|
||||
{
|
||||
Field *field = first;
|
||||
Field *next;
|
||||
while (field != 0) {
|
||||
next = field->next;
|
||||
field->_form = 0;
|
||||
field->next = 0;
|
||||
field->prev = 0;
|
||||
field = next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Dispatches \a event to the currently active field using
|
||||
* Field::dispatch().
|
||||
*
|
||||
* The \a event is usually obtained from LCD::getButton().
|
||||
*
|
||||
* Returns zero if the \a event has been handled and no further action
|
||||
* is required.
|
||||
*
|
||||
* Returns FORM_CHANGED if one of the fields on the form has changed value
|
||||
* due to the \a event, perhaps requiring the application to take further
|
||||
* action based on the new field value. Use currentField() or isCurrent()
|
||||
* to determine which field has changed.
|
||||
*
|
||||
* \code
|
||||
* int event = lcd.getButton();
|
||||
* if (mainForm.dispatch(event) == FORM_CHANGED) {
|
||||
* if (mainForm.isCurrent(volumeField)) {
|
||||
* // Adjust the volume to match the field.
|
||||
* setVolume(volumeField.value());
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* This function handles the Left and Right buttons to navigate between fields.
|
||||
*
|
||||
* \sa Field::dispatch(), LCD::getButton(), currentField(), isCurrent()
|
||||
*/
|
||||
int Form::dispatch(int event)
|
||||
{
|
||||
if (current) {
|
||||
int exitval = current->dispatch(event);
|
||||
if (exitval >= 0)
|
||||
return exitval;
|
||||
}
|
||||
if (event == LCD_BUTTON_LEFT)
|
||||
prevField();
|
||||
else if (event == LCD_BUTTON_RIGHT)
|
||||
nextField();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Changes to the next field in the "tab order".
|
||||
*
|
||||
* \sa prevField(), defaultField(), currentField()
|
||||
*/
|
||||
void Form::nextField()
|
||||
{
|
||||
Field *field = current;
|
||||
if (!field)
|
||||
field = first;
|
||||
if (field && field->next)
|
||||
field = field->next;
|
||||
else
|
||||
field = first;
|
||||
setCurrentField(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Changes to the previous field in the "tab order".
|
||||
*
|
||||
* \sa nextField(), defaultField(), currentField()
|
||||
*/
|
||||
void Form::prevField()
|
||||
{
|
||||
Field *field = current;
|
||||
if (!field)
|
||||
field = last;
|
||||
if (field && field->prev)
|
||||
field = field->prev;
|
||||
else
|
||||
field = last;
|
||||
setCurrentField(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Changes to default field (i.e., the first field).
|
||||
*
|
||||
* \sa nextField(), prevField(), currentField()
|
||||
*/
|
||||
void Form::defaultField()
|
||||
{
|
||||
setCurrentField(first);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds \a field to this form.
|
||||
*
|
||||
* Usually this function is not required because the field's constructor
|
||||
* will add the field to the form automatically.
|
||||
*
|
||||
* \sa removeField()
|
||||
*/
|
||||
void Form::addField(Field *field)
|
||||
{
|
||||
if (field->_form)
|
||||
return; // Already added to a form.
|
||||
field->_form = this;
|
||||
field->next = 0;
|
||||
field->prev = last;
|
||||
if (last)
|
||||
last->next = field;
|
||||
else
|
||||
first = field;
|
||||
last = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Removes \a field from this form.
|
||||
*
|
||||
* If \a field is the current field on-screen, then either the next or
|
||||
* previous field will be made current.
|
||||
*
|
||||
* \sa addField()
|
||||
*/
|
||||
void Form::removeField(Field *field)
|
||||
{
|
||||
if (field->_form != this)
|
||||
return; // Not a member of this form.
|
||||
if (current == field) {
|
||||
if (field->next)
|
||||
setCurrentField(field->next);
|
||||
else if (field->prev)
|
||||
setCurrentField(field->prev);
|
||||
else
|
||||
setCurrentField(0);
|
||||
}
|
||||
if (field->next)
|
||||
field->next->prev = field->prev;
|
||||
else
|
||||
last = field->prev;
|
||||
if (field->prev)
|
||||
field->prev->next = field->next;
|
||||
else
|
||||
first = field->next;
|
||||
field->_form = 0;
|
||||
field->next = 0;
|
||||
field->prev = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn Field *Form::currentField() const
|
||||
* \brief Returns the current field that is displayed on-screen.
|
||||
*
|
||||
* Returns null if the form has no fields, or setCurrentField() explicitly
|
||||
* set the current field to null.
|
||||
*
|
||||
* \sa setCurrentField(), isCurrent()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the current \a field that is displayed on-screen.
|
||||
*
|
||||
* Use this function to programmatically force the form to display a
|
||||
* specific field on-screen.
|
||||
*
|
||||
* \sa currentField(), isCurrent()
|
||||
*/
|
||||
void Form::setCurrentField(Field *field)
|
||||
{
|
||||
if (field && field->_form != this)
|
||||
return; // Wrong form.
|
||||
if (visible) {
|
||||
bool reverse = false;
|
||||
if (current) {
|
||||
current->exitField();
|
||||
if (field->next == current)
|
||||
reverse = true;
|
||||
else if (!field->next && current == first)
|
||||
reverse = true;
|
||||
}
|
||||
current = field;
|
||||
_lcd->clear();
|
||||
if (current)
|
||||
current->enterField(reverse);
|
||||
} else {
|
||||
current = field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bool Form::isCurrent(Field &field) const
|
||||
* \brief Returns true if \a field is currently displayed on-screen, false otherwise.
|
||||
*
|
||||
* This function is typically called after dispatch() returns FORM_CHANGED
|
||||
* to determine which field has changed.
|
||||
*
|
||||
* \sa currentField(), setCurrentField()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Shows the form, or does nothing if the form is already on-screen.
|
||||
*
|
||||
* When the form is shown, the screen will be cleared and the currentField()
|
||||
* will be drawn.
|
||||
*
|
||||
* If the form was previously hidden, then the field that was previously
|
||||
* current will be shown again. Call defaultField() before show() to reset
|
||||
* the form to show the first field instead.
|
||||
*
|
||||
* \sa hide(), isVisible(), defaultField()
|
||||
*/
|
||||
void Form::show()
|
||||
{
|
||||
if (!visible) {
|
||||
if (!current)
|
||||
current = first;
|
||||
visible = true;
|
||||
_lcd->clear();
|
||||
if (current)
|
||||
current->enterField(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Hides the form, or does nothing if the form is not on-screen.
|
||||
*
|
||||
* The screen will be cleared to remove the contents of the current field.
|
||||
*
|
||||
* \sa show(), isVisible()
|
||||
*/
|
||||
void Form::hide()
|
||||
{
|
||||
if (visible) {
|
||||
if (current)
|
||||
current->exitField();
|
||||
visible = false;
|
||||
_lcd->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bool Form::isVisible() const
|
||||
* \brief Returns true if the form is shown; false if the form is hidden.
|
||||
*
|
||||
* \sa show(), hide()
|
||||
*/
|
||||
65
libraries/LCD/Form.h
Normal file
65
libraries/LCD/Form.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef Form_h
|
||||
#define Form_h
|
||||
|
||||
#include "LCD.h"
|
||||
|
||||
class Field;
|
||||
|
||||
#define FORM_CHANGED 1
|
||||
|
||||
class Form {
|
||||
public:
|
||||
explicit Form(LiquidCrystal &lcd);
|
||||
~Form();
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void nextField();
|
||||
void prevField();
|
||||
void defaultField();
|
||||
|
||||
void addField(Field *field);
|
||||
void removeField(Field *field);
|
||||
|
||||
Field *currentField() const { return current; }
|
||||
void setCurrentField(Field *field);
|
||||
|
||||
bool isCurrent(Field &field) const { return current == &field; }
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
bool isVisible() const { return visible; }
|
||||
|
||||
private:
|
||||
LiquidCrystal *_lcd;
|
||||
Field *first;
|
||||
Field *last;
|
||||
Field *current;
|
||||
bool visible;
|
||||
|
||||
friend class Field;
|
||||
};
|
||||
|
||||
#endif
|
||||
249
libraries/LCD/IntField.cpp
Normal file
249
libraries/LCD/IntField.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "IntField.h"
|
||||
|
||||
/**
|
||||
* \class IntField IntField.h <IntField.h>
|
||||
* \brief Field that manages the input of an integer value.
|
||||
*
|
||||
* IntField is intended for field values that are modifiable by the user.
|
||||
* Pressing Up adds stepValue() to the current value and pressing Down
|
||||
* subtracts stepValue() from the current value. The value is clamped to
|
||||
* the range minValue() to maxValue().
|
||||
*
|
||||
* The following example creates an integer field with the label "Iterations",
|
||||
* that ranges between 1 and 5, with a stepValue() of 1, and an initial
|
||||
* default value() of 2:
|
||||
*
|
||||
* \code
|
||||
* Form mainForm(lcd);
|
||||
* IntField iterField(mainForm, "Iterations", 1, 5, 1, 2);
|
||||
* \endcode
|
||||
*
|
||||
* IntField can be configured to show a suffix() on the screen after the
|
||||
* integer value(). This is intended for communicating the units in which
|
||||
* the value is expressed. For example:
|
||||
*
|
||||
* \code
|
||||
* IntField volumeField(mainForm, "Volume", 0, 100, 5, 85, "%");
|
||||
* IntField speedField(mainForm, "Speed", 0, 2000, 15, 450, " rpm");
|
||||
* \endcode
|
||||
*
|
||||
* \image html FormInt.png
|
||||
*
|
||||
* Use TextField for read-only fields that report integer values but
|
||||
* which are not modifiable by the user.
|
||||
*
|
||||
* \sa Field, TextField
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new integer field with a specific \a label.
|
||||
*
|
||||
* The field is initially not associated with a Form. The field can be
|
||||
* added to a form later using Form::addField().
|
||||
*
|
||||
* Initially, value() is 0, minValue() is 0, maxValue() is 100,
|
||||
* stepValue() is 1, and suffix() is an empty string.
|
||||
*
|
||||
* \sa Form::addField()
|
||||
*/
|
||||
IntField::IntField(const String &label)
|
||||
: Field(label)
|
||||
, _minValue(0)
|
||||
, _maxValue(100)
|
||||
, _stepValue(1)
|
||||
, _value(0)
|
||||
, _printLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new integer field with a specific \a label,
|
||||
* \a minValue, \a maxValue, \a stepValue, and \a value, and attaches
|
||||
* it to a \a form.
|
||||
*
|
||||
* The suffix() is initially set to an empty string.
|
||||
*/
|
||||
IntField::IntField(Form &form, const String &label, int minValue, int maxValue, int stepValue, int value)
|
||||
: Field(form, label)
|
||||
, _minValue(minValue)
|
||||
, _maxValue(maxValue)
|
||||
, _stepValue(stepValue)
|
||||
, _value(value)
|
||||
, _printLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new integer field with a specific \a label,
|
||||
* \a minValue, \a maxValue, \a stepValue, \a value, and \a suffix
|
||||
* and attaches it to a \a form.
|
||||
*/
|
||||
IntField::IntField(Form &form, const String &label, int minValue, int maxValue, int stepValue, int value, const String &suffix)
|
||||
: Field(form, label)
|
||||
, _minValue(minValue)
|
||||
, _maxValue(maxValue)
|
||||
, _stepValue(stepValue)
|
||||
, _value(value)
|
||||
, _printLen(0)
|
||||
, _suffix(suffix)
|
||||
{
|
||||
}
|
||||
|
||||
int IntField::dispatch(int event)
|
||||
{
|
||||
if (event == LCD_BUTTON_UP) {
|
||||
setValue(_value + _stepValue);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_DOWN) {
|
||||
setValue(_value - _stepValue);
|
||||
return FORM_CHANGED;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void IntField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
printValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn int IntField::minValue() const
|
||||
* \brief Returns the minimum value for the input field.
|
||||
*
|
||||
* \sa setMinValue(), maxValue(), stepValue(), value()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void IntField::setMinValue(int value)
|
||||
* \brief Sets the minimum \a value for the input field.
|
||||
*
|
||||
* The new minimum \a value will be used to clamp the field's value the
|
||||
* next time setValue() is called.
|
||||
*
|
||||
* \sa minValue(), setMaxValue(), setStepValue(), setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn int IntField::maxValue() const
|
||||
* \brief Returns the maximum value for the input field.
|
||||
*
|
||||
* \sa setMaxValue(), minValue(), stepValue(), value()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void IntField::setMaxValue(int value)
|
||||
* \brief Sets the maximum \a value for the input field.
|
||||
*
|
||||
* The new maximum \a value will be used to clamp the field's value the
|
||||
* next time setValue() is called.
|
||||
*
|
||||
* \sa maxValue(), setMinValue(), setStepValue(), setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn int IntField::stepValue() const
|
||||
* \brief Returns the step value to use when increasing or decreasing the
|
||||
* value() due to Up and Down button presses.
|
||||
*
|
||||
* \sa setStepValue(), minValue(), maxValue(), value()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void IntField::setStepValue(int value)
|
||||
* \brief Sets the step value \a value to use when increasing or decreasing
|
||||
* the value() due to Up and Down button presses.
|
||||
*
|
||||
* \sa stepValue(), setMinValue(), setMaxValue(), setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn int IntField::value() const
|
||||
* \brief Returns the current value of this field.
|
||||
*
|
||||
* \sa setValue(), minValue(), maxValue(), stepValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void IntField::setValue(int value)
|
||||
* \brief Sets the current \a value of this field.
|
||||
*
|
||||
* The \a value will be clamped to the range defined by minValue()
|
||||
* and maxValue().
|
||||
*
|
||||
* \sa value(), setMinValue(), setMaxValue(), setStepValue()
|
||||
*/
|
||||
void IntField::setValue(int value)
|
||||
{
|
||||
if (value < _minValue)
|
||||
value = _minValue;
|
||||
else if (value > _maxValue)
|
||||
value = _maxValue;
|
||||
if (value != _value) {
|
||||
_value = value;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn const String &IntField::suffix() const
|
||||
* \brief Returns the suffix string to be displayed after the field's value.
|
||||
*
|
||||
* \sa setSuffix()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the \a suffix string to be displayed after the field's value.
|
||||
*
|
||||
* Suffixes are typically used to indicate the units that the value() is
|
||||
* expressed in. For example:
|
||||
*
|
||||
* \code
|
||||
* field.setSuffix("%");
|
||||
* field.setSuffix(" rpm");
|
||||
* \endcode
|
||||
*
|
||||
* \sa suffix()
|
||||
*/
|
||||
void IntField::setSuffix(const String &suffix)
|
||||
{
|
||||
_suffix = suffix;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
void IntField::printValue()
|
||||
{
|
||||
String str(_value);
|
||||
if (_suffix.length())
|
||||
str += _suffix;
|
||||
lcd()->setCursor(0, 1);
|
||||
lcd()->print(str);
|
||||
unsigned int len = str.length();
|
||||
while (len++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = str.length();
|
||||
}
|
||||
64
libraries/LCD/IntField.h
Normal file
64
libraries/LCD/IntField.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IntField_h
|
||||
#define IntField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class IntField : public Field {
|
||||
public:
|
||||
explicit IntField(const String &label);
|
||||
IntField(Form &form, const String &label, int minValue, int maxValue, int stepValue, int value);
|
||||
IntField(Form &form, const String &label, int minValue, int maxValue, int stepValue, int value, const String &suffix);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
int minValue() const { return _minValue; }
|
||||
void setMinValue(int value) { _minValue = value; }
|
||||
|
||||
int maxValue() const { return _maxValue; }
|
||||
void setMaxValue(int value) { _maxValue = value; }
|
||||
|
||||
int stepValue() const { return _stepValue; }
|
||||
void setStepValue(int value) { _stepValue = value; }
|
||||
|
||||
int value() const { return _value; }
|
||||
void setValue(int value);
|
||||
|
||||
const String &suffix() const { return _suffix; }
|
||||
void setSuffix(const String &suffix);
|
||||
|
||||
private:
|
||||
int _minValue;
|
||||
int _maxValue;
|
||||
int _stepValue;
|
||||
int _value;
|
||||
int _printLen;
|
||||
String _suffix;
|
||||
|
||||
void printValue();
|
||||
};
|
||||
|
||||
#endif
|
||||
340
libraries/LCD/LCD.cpp
Normal file
340
libraries/LCD/LCD.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "LCD.h"
|
||||
#include <avr/pgmspace.h>
|
||||
#include <WProgram.h>
|
||||
|
||||
#define LCD_BACK_LIGHT 3 // LCD backlight is on D3
|
||||
#define LCD_BUTTON_PIN A0 // Button state is on A0
|
||||
|
||||
#define DEBOUNCE_DELAY 10 // Delay in ms to debounce buttons
|
||||
|
||||
/**
|
||||
* \class LCD LCD.h <LCD.h>
|
||||
* \brief Enhanced library for Freetronics 16x2 LCD shields
|
||||
*
|
||||
* This class extends the standard Arduino LiquidCrystal library with
|
||||
* extra functionality for the Freetronics 16x2 LCD shield:
|
||||
*
|
||||
* http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide
|
||||
*
|
||||
* The Freetronics LCD has an additional back light, which is turned
|
||||
* on and off with the display() and noDisplay() functions. The user
|
||||
* can also call enableScreenSaver() to cause the display and back light
|
||||
* to automatically turn off after a specific timeout.
|
||||
* The setScreenSaverMode() function controls which of the display and
|
||||
* back light are disabled when the screen saver activates.
|
||||
*
|
||||
* The Freetronics LCD also has 5 push buttons for Left, Right, Up, Down,
|
||||
* and Select, to assist with the creation of interactive sketches.
|
||||
* The user can call getButton() to get the current button state.
|
||||
* One of the following values may be returned:
|
||||
*
|
||||
* \li LCD_BUTTON_NONE - No button has been pressed, or a button has been
|
||||
* pressed but not yet released.
|
||||
* \li LCD_BUTTON_LEFT - Left button was pressed.
|
||||
* \li LCD_BUTTON_RIGHT - Right button was pressed.
|
||||
* \li LCD_BUTTON_UP - Up button was pressed.
|
||||
* \li LCD_BUTTON_DOWN - Down button was pressed.
|
||||
* \li LCD_BUTTON_SELECT - Select button was pressed.
|
||||
* \li LCD_BUTTON_LEFT_RELEASED - Left button was released.
|
||||
* \li LCD_BUTTON_RIGHT_RELEASED - Right button was released.
|
||||
* \li LCD_BUTTON_UP_RELEASED - Up button was released.
|
||||
* \li LCD_BUTTON_DOWN_RELEASED - Down button was released.
|
||||
* \li LCD_BUTTON_SELECT_RELEASED - Select button was released.
|
||||
*
|
||||
* For convenience, all RELEASED button codes are the negation of their
|
||||
* pressed counterparts. That is, LCD_BUTTON_LEFT_RELEASED == -LCD_BUTTON_LEFT.
|
||||
* LCD_BUTTON_NONE is defined to be zero. Thus, you can check if a
|
||||
* generic button has been pressed with <tt>button > 0</tt> and if a
|
||||
* generic button has been released with <tt>button < 0</tt>.
|
||||
*
|
||||
* See the \ref lcd_hello_world "Hello World" example for more
|
||||
* information on using the LCD class.
|
||||
*
|
||||
* \sa Form
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn LCD::LCD()
|
||||
* \brief Initialize the Freetronics LCD display with the default
|
||||
* pin assignment.
|
||||
*
|
||||
* The following example shows how to initialize the Freetronics
|
||||
* LCD shield:
|
||||
*
|
||||
* \code
|
||||
* LCD lcd;
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn LCD::LCD(uint8_t pin9)
|
||||
* \brief Initialize the Freetronics LCD display for USBDroid.
|
||||
*
|
||||
* On the USBDroid, the D9 pin is used for USB Host functionality.
|
||||
* Either the USB Host's use of D9 must be reassigned to another pin,
|
||||
* or the Freetronics LCD shield must be modified. The following Web
|
||||
* page describes the modifications that are necessary:
|
||||
* http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid
|
||||
*
|
||||
* If you choose to modify the LCD shield, then you must use this version
|
||||
* of the constructor to initialize the shield, passing the alternative
|
||||
* pin as the \a pin9 parameter. Using the recommended pin from the above
|
||||
* Web page of A1, you would initialize the LCD as follows:
|
||||
*
|
||||
* \code
|
||||
* LCD lcd(A1);
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
void LCD::init()
|
||||
{
|
||||
// The Freetronics display is 16x2.
|
||||
begin(16, 2);
|
||||
|
||||
// Set the LCD back light to be initially on.
|
||||
pinMode(LCD_BACK_LIGHT, OUTPUT);
|
||||
digitalWrite(LCD_BACK_LIGHT, HIGH);
|
||||
|
||||
// Initialise button input.
|
||||
pinMode(LCD_BUTTON_PIN, INPUT);
|
||||
digitalWrite(LCD_BUTTON_PIN, LOW);
|
||||
prevButton = LCD_BUTTON_NONE;
|
||||
debounceButton = LCD_BUTTON_NONE;
|
||||
lastDebounce = 0;
|
||||
eatRelease = false;
|
||||
|
||||
// Initialize screen saver.
|
||||
timeout = 0;
|
||||
lastRestore = millis();
|
||||
screenSaved = false;
|
||||
mode = DisplayOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Turns on the display of text on the LCD and the back light.
|
||||
*
|
||||
* If the screen saver is active, then calling this function will
|
||||
* deactivate the screen saver and reset the timeout. Thus, this
|
||||
* function can be called for force the screen to restore.
|
||||
*
|
||||
* \sa noDisplay(), enableScreenSaver(), setScreenSaverMode()
|
||||
*/
|
||||
void LCD::display()
|
||||
{
|
||||
LiquidCrystal::display();
|
||||
digitalWrite(LCD_BACK_LIGHT, HIGH);
|
||||
screenSaved = false;
|
||||
lastRestore = millis();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Turns off the display of text on the LCD and the back light.
|
||||
*
|
||||
* This function can be called to force the screen saver to activate.
|
||||
*
|
||||
* \sa display(), enableScreenSaver(), setScreenSaverMode()
|
||||
*/
|
||||
void LCD::noDisplay()
|
||||
{
|
||||
if (mode == DisplayOff)
|
||||
LiquidCrystal::noDisplay();
|
||||
digitalWrite(LCD_BACK_LIGHT, LOW);
|
||||
screenSaved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \enum LCD::ScreenSaverMode
|
||||
* \brief Screen saver mode that controls the display and back light.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \var LCD::DisplayOff
|
||||
* \brief Turn off both the display and the backlight when the screen saver
|
||||
* is activated.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \var LCD::BacklightOff
|
||||
* \brief Turn off the back light but leave the display on when the screen
|
||||
* saver is activated.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \var LCD::BacklightOnSelect
|
||||
* \brief Same as BacklightOff but the screen saver is only deactivated when
|
||||
* Select is pressed; other buttons have no effect.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn ScreenSaverMode LCD::screenSaverMode() const
|
||||
* \brief Returns the current screen saver mode; default is DisplayOff.
|
||||
*
|
||||
* \sa setScreenSaverMode(), enableScreenSaver()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the current screen saver \a mode.
|
||||
*
|
||||
* \sa screenSaverMode(), enableScreenSaver()
|
||||
*/
|
||||
void LCD::setScreenSaverMode(ScreenSaverMode mode)
|
||||
{
|
||||
if (this->mode != mode) {
|
||||
this->mode = mode;
|
||||
if (screenSaved)
|
||||
noDisplay();
|
||||
else
|
||||
display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enables the screen saver and causes it to activate after
|
||||
* \a timeoutSecs of inactivity on the buttons.
|
||||
*
|
||||
* If \a timeoutSecs is less than or equal to zero, then the call
|
||||
* is equivalent to calling disableScreenSaver().
|
||||
*
|
||||
* For the screen saver to work, the application must regularly call
|
||||
* getButton() to fetch the LCD's button state even if no buttons
|
||||
* are pressed.
|
||||
*
|
||||
* If the \a timeoutSecs parameter is not supplied, the default is 10 seconds.
|
||||
*
|
||||
* \sa disableScreenSaver(), display(), getButton(), isScreenSaved()
|
||||
*/
|
||||
void LCD::enableScreenSaver(int timeoutSecs)
|
||||
{
|
||||
if (timeoutSecs < 0)
|
||||
timeout = 0;
|
||||
else
|
||||
timeout = ((unsigned long)timeoutSecs) * 1000;
|
||||
display();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disables the screen saver.
|
||||
*
|
||||
* \sa enableScreenSaver(), display(), isScreenSaved()
|
||||
*/
|
||||
void LCD::disableScreenSaver()
|
||||
{
|
||||
timeout = 0;
|
||||
display();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bool LCD::isScreenSaved() const
|
||||
* \brief Returns true if the screen has been saved; false otherwise.
|
||||
*
|
||||
* \sa enableScreenSaver()
|
||||
*/
|
||||
|
||||
// Button mapping table generated by genlookup.c
|
||||
static prog_uint8_t const buttonMappings[] PROGMEM = {
|
||||
2, 0, 0, 0, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
#define mapButton(value) (pgm_read_byte(&(buttonMappings[(value) >> 5])))
|
||||
|
||||
/**
|
||||
* \brief Gets the next button press, release, or idle event.
|
||||
*
|
||||
* If no buttons are pressed, this function will return LCD_BUTTON_NONE.
|
||||
*
|
||||
* When a button is pressed, this function will return one of
|
||||
* LCD_BUTTON_LEFT, LCD_BUTTON_RIGHT, LCD_BUTTON_UP, LCD_BUTTON_DOWN,
|
||||
* or LCD_BUTTON_SELECT. While the button is pressed, this function
|
||||
* will return LCD_BUTTON_NONE until the button is released. When the
|
||||
* button is released, this function will return one of
|
||||
* LCD_BUTTON_LEFT_RELEASED, LCD_BUTTON_RIGHT_RELEASED,
|
||||
* LCD_BUTTON_UP_RELEAED, LCD_BUTTON_DOWN_RELEASED,
|
||||
* or LCD_BUTTON_SELECT_RELEASED.
|
||||
*
|
||||
* If the screen saver is currently active, then it will be deactivated
|
||||
* by this function whenever a button is pressed. If screenSaverMode() is
|
||||
* DisplayOff, the function will "eat" the button press and return
|
||||
* LCD_BUTTON_NONE. The scrren saver can also be deactivated under
|
||||
* program control by calling display().
|
||||
*
|
||||
* This function debounces the button state automatically so there is no
|
||||
* need for the caller to worry about spurious button events.
|
||||
*
|
||||
* \sa enableScreenSaver(), display(), Form::dispatch()
|
||||
*/
|
||||
int LCD::getButton()
|
||||
{
|
||||
// Read the currently pressed button.
|
||||
int button = mapButton(analogRead(LCD_BUTTON_PIN));
|
||||
|
||||
// Debounce the button state.
|
||||
unsigned long currentTime = millis();
|
||||
if (button != debounceButton)
|
||||
lastDebounce = currentTime;
|
||||
debounceButton = button;
|
||||
if ((currentTime - lastDebounce) < DEBOUNCE_DELAY)
|
||||
button = prevButton;
|
||||
|
||||
// Process the button event if the state has changed.
|
||||
if (prevButton == LCD_BUTTON_NONE && button != LCD_BUTTON_NONE) {
|
||||
prevButton = button;
|
||||
if (screenSaved) {
|
||||
// Button pressed when screen saver active.
|
||||
if (mode == BacklightOnSelect) {
|
||||
// Turn on the back light only if Select was pressed.
|
||||
if (button == LCD_BUTTON_SELECT) {
|
||||
digitalWrite(LCD_BACK_LIGHT, HIGH);
|
||||
screenSaved = false;
|
||||
}
|
||||
} else if (mode == DisplayOff) {
|
||||
display();
|
||||
eatRelease = true;
|
||||
return LCD_BUTTON_NONE;
|
||||
} else {
|
||||
display();
|
||||
}
|
||||
} else if (mode == BacklightOnSelect && button != LCD_BUTTON_SELECT) {
|
||||
eatRelease = false;
|
||||
return button;
|
||||
}
|
||||
eatRelease = false;
|
||||
lastRestore = currentTime;
|
||||
return button;
|
||||
} else if (prevButton != LCD_BUTTON_NONE && button == LCD_BUTTON_NONE) {
|
||||
button = -prevButton;
|
||||
prevButton = LCD_BUTTON_NONE;
|
||||
lastRestore = currentTime;
|
||||
if (eatRelease) {
|
||||
eatRelease = false;
|
||||
return LCD_BUTTON_NONE;
|
||||
}
|
||||
return button;
|
||||
} else {
|
||||
if (!screenSaved && prevButton == LCD_BUTTON_NONE &&
|
||||
timeout != 0 && (currentTime - lastRestore) >= timeout)
|
||||
noDisplay(); // Activate screen saver.
|
||||
return LCD_BUTTON_NONE;
|
||||
}
|
||||
}
|
||||
85
libraries/LCD/LCD.h
Normal file
85
libraries/LCD/LCD.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LCD_h
|
||||
#define LCD_h
|
||||
|
||||
// Extended version of the LiquidCrystal library that works specifically
|
||||
// with Freetronics' 16x2 LCD display, including support for the back
|
||||
// light and the Up/Down/Left/Right/Select buttons. More info:
|
||||
//
|
||||
// http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide
|
||||
|
||||
// Include a copy of the standard LiquidCrystal library so we can extend it.
|
||||
#include "utility/LiquidCrystal.h"
|
||||
|
||||
// Button event codes.
|
||||
#define LCD_BUTTON_NONE 0
|
||||
#define LCD_BUTTON_LEFT 1
|
||||
#define LCD_BUTTON_RIGHT 2
|
||||
#define LCD_BUTTON_UP 3
|
||||
#define LCD_BUTTON_DOWN 4
|
||||
#define LCD_BUTTON_SELECT 5
|
||||
#define LCD_BUTTON_LEFT_RELEASED -1
|
||||
#define LCD_BUTTON_RIGHT_RELEASED -2
|
||||
#define LCD_BUTTON_UP_RELEASED -3
|
||||
#define LCD_BUTTON_DOWN_RELEASED -4
|
||||
#define LCD_BUTTON_SELECT_RELEASED -5
|
||||
|
||||
class LCD : public LiquidCrystal {
|
||||
public:
|
||||
LCD() : LiquidCrystal(8, 9, 4, 5, 6, 7) { init(); }
|
||||
LCD(uint8_t pin9) : LiquidCrystal(8, pin9, 4, 5, 6, 7) { init(); }
|
||||
|
||||
void display();
|
||||
void noDisplay();
|
||||
|
||||
enum ScreenSaverMode
|
||||
{
|
||||
DisplayOff,
|
||||
BacklightOff,
|
||||
BacklightOnSelect
|
||||
};
|
||||
|
||||
ScreenSaverMode screenSaverMode() const { return mode; }
|
||||
void setScreenSaverMode(ScreenSaverMode mode);
|
||||
|
||||
void enableScreenSaver(int timeoutSecs = 10);
|
||||
void disableScreenSaver();
|
||||
bool isScreenSaved() const { return screenSaved; }
|
||||
|
||||
int getButton();
|
||||
|
||||
private:
|
||||
int prevButton;
|
||||
int debounceButton;
|
||||
unsigned long timeout;
|
||||
unsigned long lastRestore;
|
||||
unsigned long lastDebounce;
|
||||
bool screenSaved;
|
||||
bool eatRelease;
|
||||
ScreenSaverMode mode;
|
||||
|
||||
void init();
|
||||
};
|
||||
|
||||
#endif
|
||||
207
libraries/LCD/ListField.cpp
Normal file
207
libraries/LCD/ListField.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ListField.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \class ListField ListField.h <ListField.h>
|
||||
* \brief Field that manages selection from a static list of items.
|
||||
*
|
||||
* ListField is intended for selecting an element from a list of items.
|
||||
* Each items is represented by a string within program memory, with the
|
||||
* list terminated by null. For example:
|
||||
*
|
||||
* \code
|
||||
* const char item_Eggs[] PROGMEM = "Eggs";
|
||||
* const char item_Cheese[] PROGMEM = "Cheese";
|
||||
* const char item_Pumpkin[] PROGMEM = "Pumpkin";
|
||||
* ListItem const ingredients[] PROGMEM = {
|
||||
* item_Eggs,
|
||||
* item_Cheese,
|
||||
* item_Pumpkin,
|
||||
* 0
|
||||
* };
|
||||
*
|
||||
* Form mainForm(lcd);
|
||||
* ListField ingredient(mainForm, "Select ingredient", ingredients);
|
||||
* \endcode
|
||||
*
|
||||
* If there are only two items in the list, then BoolField can be used instead.
|
||||
*
|
||||
* \sa Field, BoolField
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new list field with a specific \a label.
|
||||
*
|
||||
* The field is initially not associated with a Form. The field can be
|
||||
* added to a form later using Form::addField().
|
||||
*
|
||||
* Initially, items() is null and value() is -1.
|
||||
*
|
||||
* \sa Form::addField()
|
||||
*/
|
||||
ListField::ListField(const String &label)
|
||||
: Field(label)
|
||||
, _items(0)
|
||||
, _itemCount(0)
|
||||
, _value(-1)
|
||||
, _printLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new list field with a specific \a label,
|
||||
* list of \a items, and \a value, and attaches it to a \a form.
|
||||
*/
|
||||
ListField::ListField(Form &form, const String &label, ListItems items, int value)
|
||||
: Field(form, label)
|
||||
, _items(0)
|
||||
, _itemCount(0)
|
||||
, _value(value)
|
||||
, _printLen(0)
|
||||
{
|
||||
setItems(items);
|
||||
}
|
||||
|
||||
int ListField::dispatch(int event)
|
||||
{
|
||||
if (event == LCD_BUTTON_DOWN) {
|
||||
if (_value >= (_itemCount - 1))
|
||||
setValue(0);
|
||||
else
|
||||
setValue(_value + 1);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_UP) {
|
||||
if (_value <= 0)
|
||||
setValue(_itemCount - 1);
|
||||
else
|
||||
setValue(_value - 1);
|
||||
return FORM_CHANGED;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ListField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
_printLen = 0;
|
||||
printValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn ListItems ListField::items() const
|
||||
* \brief Returns the array of items in this list.
|
||||
*
|
||||
* \sa setItems()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the array of \a items for this list.
|
||||
*
|
||||
* The \a items must be stored within program memory and terminated by null;
|
||||
* for example:
|
||||
*
|
||||
* \code
|
||||
* const char item_Eggs[] PROGMEM = "Eggs";
|
||||
* const char item_Cheese[] PROGMEM = "Cheese";
|
||||
* const char item_Pumpkin[] PROGMEM = "Pumpkin";
|
||||
* ListItem const ingredients[] PROGMEM = {
|
||||
* item_Eggs,
|
||||
* item_Cheese,
|
||||
* item_Pumpkin,
|
||||
* 0
|
||||
* };
|
||||
*
|
||||
* list.setItems(ingredients);
|
||||
* \endcode
|
||||
*
|
||||
* \sa items()
|
||||
*/
|
||||
void ListField::setItems(ListItems items)
|
||||
{
|
||||
_items = items;
|
||||
_itemCount = 0;
|
||||
if (items) {
|
||||
for (;;) {
|
||||
ListItem item = (ListItem)pgm_read_word(items);
|
||||
if (!item)
|
||||
break;
|
||||
++items;
|
||||
++_itemCount;
|
||||
}
|
||||
}
|
||||
if (_value >= _itemCount)
|
||||
_value = _itemCount - 1;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn int ListField::value() const
|
||||
* \brief Returns the value of this list; i.e. the index within items() of the
|
||||
* selected item.
|
||||
*
|
||||
* Returns -1 if the items() array is empty or null.
|
||||
*
|
||||
* \sa setValue(), items()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the \a value of this list; i.e. the index within items() of the
|
||||
* selected item.
|
||||
*
|
||||
* The \a value will be clamped to the range of items().
|
||||
*
|
||||
* \sa value(), items()
|
||||
*/
|
||||
void ListField::setValue(int value)
|
||||
{
|
||||
if (_value != value) {
|
||||
_value = value;
|
||||
if (_value < 0)
|
||||
_value = 0;
|
||||
if (_value >= _itemCount)
|
||||
_value = _itemCount - 1;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
}
|
||||
|
||||
void ListField::printValue()
|
||||
{
|
||||
lcd()->setCursor(0, 1);
|
||||
int len = 0;
|
||||
if (_value >= 0) {
|
||||
ListItem str = (ListItem)pgm_read_word(&(_items[_value]));
|
||||
char ch;
|
||||
while ((ch = pgm_read_byte(str)) != 0) {
|
||||
lcd()->write(ch);
|
||||
++len;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
while (_printLen-- > len)
|
||||
lcd()->write(' ');
|
||||
_printLen = len;
|
||||
}
|
||||
56
libraries/LCD/ListField.h
Normal file
56
libraries/LCD/ListField.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ListField_h
|
||||
#define ListField_h
|
||||
|
||||
#include "Field.h"
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
typedef const prog_char *ListItem;
|
||||
typedef const PROGMEM ListItem *ListItems;
|
||||
|
||||
class ListField : public Field {
|
||||
public:
|
||||
explicit ListField(const String &label);
|
||||
ListField(Form &form, const String &label, ListItems items, int value = 0);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
ListItems items() const { return _items; }
|
||||
void setItems(ListItems items);
|
||||
|
||||
int value() const { return _value; }
|
||||
void setValue(int value);
|
||||
|
||||
private:
|
||||
ListItems _items;
|
||||
int _itemCount;
|
||||
int _value;
|
||||
int _printLen;
|
||||
|
||||
void printValue();
|
||||
};
|
||||
|
||||
#endif
|
||||
115
libraries/LCD/TextField.cpp
Normal file
115
libraries/LCD/TextField.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TextField.h"
|
||||
|
||||
/**
|
||||
* \class TextField TextField.h <TextField.h>
|
||||
* \brief Field that displays a read-only text value.
|
||||
*
|
||||
* This following example displays a text field with the label
|
||||
* "Form example" and a value() of "v1.0".
|
||||
*
|
||||
* \code
|
||||
* Form mainForm(lcd);
|
||||
* TextField welcomeField(mainForm, "Form example", "v1.0");
|
||||
* \endcode
|
||||
*
|
||||
* \image html FormText.png
|
||||
*
|
||||
* As well as static messages, TextField can be used to display read-only
|
||||
* information that is computed at runtime:
|
||||
*
|
||||
* \code
|
||||
* TextField timeField(mainForm, "Time since reset", "0");
|
||||
*
|
||||
* void loop() {
|
||||
* timeField.setValue(millis() / 1000);
|
||||
* mainForm.dispatch(lcd.getButton());
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* For writable fields, use BoolField, IntField, or TimeField.
|
||||
*
|
||||
* \sa Field
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new text field with a specific \a label.
|
||||
*
|
||||
* The field is initially not associated with a Form. The field can be
|
||||
* added to a form later using Form::addField().
|
||||
*
|
||||
* The initial value() will be the empty string.
|
||||
*
|
||||
* \sa Form::addField()
|
||||
*/
|
||||
TextField::TextField(const String &label)
|
||||
: Field(label)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new text field with a specific \a label and \a value
|
||||
* attaches it to a \a form.
|
||||
*
|
||||
* \sa value()
|
||||
*/
|
||||
TextField::TextField(Form &form, const String &label, const String &value)
|
||||
: Field(form, label)
|
||||
, _value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void TextField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
lcd()->setCursor(0, 1);
|
||||
lcd()->print(_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn const String &TextField::value() const
|
||||
* \brief Returns the text value that is currently displayed by this field.
|
||||
*
|
||||
* \sa setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the text \a value that is displayed by this field.
|
||||
*
|
||||
* \sa value()
|
||||
*/
|
||||
void TextField::setValue(const String &value)
|
||||
{
|
||||
if (isCurrent()) {
|
||||
unsigned int prevLen = _value.length();
|
||||
unsigned int newLen = value.length();
|
||||
_value = value;
|
||||
lcd()->setCursor(0, 1);
|
||||
lcd()->print(value);
|
||||
while (newLen++ < prevLen)
|
||||
lcd()->write(' ');
|
||||
} else {
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
42
libraries/LCD/TextField.h
Normal file
42
libraries/LCD/TextField.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef TextField_h
|
||||
#define TextField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class TextField : public Field {
|
||||
public:
|
||||
explicit TextField(const String &label);
|
||||
TextField(Form &form, const String &label, const String &value);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
const String &value() const { return _value; }
|
||||
void setValue(const String &value);
|
||||
|
||||
private:
|
||||
String _value;
|
||||
};
|
||||
|
||||
#endif
|
||||
330
libraries/LCD/TimeField.cpp
Normal file
330
libraries/LCD/TimeField.cpp
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TimeField.h"
|
||||
|
||||
/**
|
||||
* \class TimeField TimeField.h <TimeField.h>
|
||||
* \brief Field that manages the display and editing of a time value.
|
||||
*
|
||||
* TimeField is suitable for displaying wall clock time in 24-hour format,
|
||||
* or for displaying timeouts and durations in seconds. Times are specified
|
||||
* in seconds as an <tt>unsigned long</tt> value. They are displayed
|
||||
* as <tt>HH:MM:SS</tt>, for hours, minutes, and seconds.
|
||||
*
|
||||
* The time field can be either read-only or read-write. When read-write,
|
||||
* the Up, Down, Left, and Right buttons can be used to modify the hour,
|
||||
* minute, and second components of the time value.
|
||||
*
|
||||
* The following example displays the number of hours, minutes, and seconds
|
||||
* since the device was reset, wrapping around after 24 hours:
|
||||
*
|
||||
* \code
|
||||
* Form mainForm(lcd);
|
||||
* TimeField timeField(mainForm, "Time since reset", 24, TIMEFIELD_READ_ONLY);
|
||||
*
|
||||
* void loop() {
|
||||
* timeField.setValue(millis() / 1000);
|
||||
* mainForm.dispatch(lcd.getButton());
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \image html FormTimeRO.png
|
||||
*
|
||||
* A read-write field can be used to ask the user for the duration of an
|
||||
* application count-down timer:
|
||||
*
|
||||
* \code
|
||||
* TimeField durationField(mainForm, "Timer duration", 24, TIMEFIELD_READ_WRITE);
|
||||
* \endcode
|
||||
*
|
||||
* \image html FormTimeRW.png
|
||||
*
|
||||
* \sa Field
|
||||
*/
|
||||
|
||||
#define EDIT_HOUR 0
|
||||
#define EDIT_MINUTE_TENS 1
|
||||
#define EDIT_MINUTE 2
|
||||
#define EDIT_SECOND_TENS 3
|
||||
#define EDIT_SECOND 4
|
||||
|
||||
/**
|
||||
* \brief Constructs a new time field with a specific \a label.
|
||||
*
|
||||
* The field is initially not associated with a Form. The field can be
|
||||
* added to a form later using Form::addField().
|
||||
*
|
||||
* Initially value() is 0, maxHours() is 24, and isReadOnly() is
|
||||
* TIMEFIELD_READ_WRITE.
|
||||
*
|
||||
* \sa Form::addField()
|
||||
*/
|
||||
TimeField::TimeField(const String &label)
|
||||
: Field(label)
|
||||
, _value(0)
|
||||
, _maxHours(24)
|
||||
, _printLen(0)
|
||||
, _readOnly(false)
|
||||
, editField(EDIT_HOUR)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a new boolean field with a specific \a label and
|
||||
* attaches it to a \a form.
|
||||
*
|
||||
* The initial value() of the field will be 0. The value() will be limited
|
||||
* to be less than \a maxHours * 60 * 60 seconds.
|
||||
*
|
||||
* If \a readOnly is TIMEFIELD_READ_ONLY, then the field will display times
|
||||
* but not allow them to be modified by the user. If \a readOnly is
|
||||
* TIMEFIELD_READ_WRITE, then the field will modifiable by the user.
|
||||
*
|
||||
* \sa value()
|
||||
*/
|
||||
TimeField::TimeField(Form &form, const String &label, int maxHours, bool readOnly)
|
||||
: Field(form, label)
|
||||
, _value(0)
|
||||
, _maxHours(maxHours)
|
||||
, _printLen(0)
|
||||
, _readOnly(readOnly)
|
||||
, editField(EDIT_HOUR)
|
||||
{
|
||||
}
|
||||
|
||||
int TimeField::dispatch(int event)
|
||||
{
|
||||
unsigned long newValue;
|
||||
if (_readOnly)
|
||||
return -1;
|
||||
if (event == LCD_BUTTON_UP) {
|
||||
newValue = _value;
|
||||
if (editField == EDIT_HOUR) {
|
||||
newValue += 60 * 60;
|
||||
} else if (editField == EDIT_MINUTE_TENS) {
|
||||
if (((newValue / 60) % 60) >= 50)
|
||||
newValue -= 50 * 60;
|
||||
else
|
||||
newValue += 10 * 60;
|
||||
} else if (editField == EDIT_MINUTE) {
|
||||
if (((newValue / 60) % 60) == 59)
|
||||
newValue -= 59 * 60;
|
||||
else
|
||||
newValue += 60;
|
||||
} else if (editField == EDIT_SECOND_TENS) {
|
||||
if ((newValue % 60) >= 50)
|
||||
newValue -= 50;
|
||||
else
|
||||
newValue += 10;
|
||||
} else {
|
||||
if ((newValue % 60) == 59)
|
||||
newValue -= 59;
|
||||
else
|
||||
newValue += 1;
|
||||
}
|
||||
setValue(newValue);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_DOWN) {
|
||||
newValue = _value;
|
||||
if (editField == EDIT_HOUR) {
|
||||
if (newValue < 60 * 60)
|
||||
newValue += ((unsigned long)(_maxHours - 1)) * 60 * 60;
|
||||
else
|
||||
newValue -= 60 * 60;
|
||||
} else if (editField == EDIT_MINUTE_TENS) {
|
||||
if (((newValue / 60) % 60) < 10)
|
||||
newValue += 50 * 60;
|
||||
else
|
||||
newValue -= 10 * 60;
|
||||
} else if (editField == EDIT_MINUTE) {
|
||||
if (((newValue / 60) % 60) == 0)
|
||||
newValue += 59 * 60;
|
||||
else
|
||||
newValue -= 60;
|
||||
} else if (editField == EDIT_SECOND_TENS) {
|
||||
if ((newValue % 60) < 10)
|
||||
newValue += 50;
|
||||
else
|
||||
newValue -= 10;
|
||||
} else {
|
||||
if ((newValue % 60) == 0)
|
||||
newValue += 59;
|
||||
else
|
||||
newValue -= 1;
|
||||
}
|
||||
setValue(newValue);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_LEFT) {
|
||||
if (editField != EDIT_HOUR) {
|
||||
--editField;
|
||||
printTime();
|
||||
return 0;
|
||||
}
|
||||
} else if (event == LCD_BUTTON_RIGHT) {
|
||||
if (editField != EDIT_SECOND) {
|
||||
++editField;
|
||||
printTime();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TimeField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
if (reverse)
|
||||
editField = EDIT_SECOND;
|
||||
else
|
||||
editField = EDIT_HOUR;
|
||||
printTime();
|
||||
if (!_readOnly)
|
||||
lcd()->cursor();
|
||||
}
|
||||
|
||||
void TimeField::exitField()
|
||||
{
|
||||
if (!_readOnly)
|
||||
lcd()->noCursor();
|
||||
Field::exitField();
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn unsigned long TimeField::value() const
|
||||
* \brief Returns the current value of this time field, in seconds.
|
||||
*
|
||||
* \sa setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the \a value of this time field, in seconds.
|
||||
*
|
||||
* If \a value is greater than or equal to maxHours() * 60 * 60,
|
||||
* then it will be wrapped around to fall within the valid range.
|
||||
*
|
||||
* \sa value(), maxHours()
|
||||
*/
|
||||
void TimeField::setValue(unsigned long value)
|
||||
{
|
||||
unsigned long maxSecs = ((unsigned long)_maxHours) * 60 * 60;
|
||||
value %= maxSecs;
|
||||
if (value != _value) {
|
||||
_value = value;
|
||||
if (isCurrent())
|
||||
printTime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn int TimeField::maxHours() const
|
||||
* \brief Returns the maximum number of hours before the field wraps around.
|
||||
*
|
||||
* \sa setMaxHours(), setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void TimeField::setMaxHours(int maxHours)
|
||||
* \brief Sets the maximum number of hours before the field wraps around
|
||||
* to \a maxHours.
|
||||
*
|
||||
* \sa maxHours(), setValue()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool TimeField::readOnly() const
|
||||
* \brief Returns TIMEFIELD_READ_ONLY (true) or TIMEFIELD_READ_WRITE (false).
|
||||
*
|
||||
* \sa setReadOnly()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets the read-only state of this field to \a value.
|
||||
*
|
||||
* The \a value should be one of TIMEFIELD_READ_ONLY (true) or
|
||||
* TIMEFIELD_READ_WRITE (false). Use of the named constants is recommended.
|
||||
*
|
||||
* \sa readOnly()
|
||||
*/
|
||||
void TimeField::setReadOnly(bool value)
|
||||
{
|
||||
if (_readOnly != value) {
|
||||
_readOnly = value;
|
||||
printTime();
|
||||
if (isCurrent()) {
|
||||
if (value)
|
||||
lcd()->cursor();
|
||||
else
|
||||
lcd()->noCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimeField::printTime()
|
||||
{
|
||||
lcd()->setCursor(0, 1);
|
||||
int col = printField(_value / (60 * 60));
|
||||
int hourCol = col - 1;
|
||||
lcd()->write(':');
|
||||
++col;
|
||||
col += printField((_value / 60) % 60);
|
||||
int minuteCol = col - 1;
|
||||
lcd()->write(':');
|
||||
++col;
|
||||
col += printField(_value % 60);
|
||||
int secondCol = col - 1;
|
||||
int tempCol = col;
|
||||
while (tempCol++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = col;
|
||||
if (!_readOnly) {
|
||||
if (editField == EDIT_HOUR)
|
||||
lcd()->setCursor(hourCol, 1);
|
||||
else if (editField == EDIT_MINUTE_TENS)
|
||||
lcd()->setCursor(minuteCol - 1, 1);
|
||||
else if (editField == EDIT_MINUTE)
|
||||
lcd()->setCursor(minuteCol, 1);
|
||||
else if (editField == EDIT_SECOND_TENS)
|
||||
lcd()->setCursor(secondCol - 1, 1);
|
||||
else
|
||||
lcd()->setCursor(secondCol, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int TimeField::printField(unsigned long value)
|
||||
{
|
||||
if (value < 100) {
|
||||
lcd()->write('0' + (int)(value / 10));
|
||||
lcd()->write('0' + (int)(value % 10));
|
||||
return 2;
|
||||
}
|
||||
unsigned long divisor = 100;
|
||||
while ((value / divisor) >= 10)
|
||||
divisor *= 10;
|
||||
int digits = 0;
|
||||
while (divisor > 0) {
|
||||
lcd()->write('0' + (int)((value / divisor) % 10));
|
||||
divisor /= 10;
|
||||
++digits;
|
||||
}
|
||||
return digits;
|
||||
}
|
||||
61
libraries/LCD/TimeField.h
Normal file
61
libraries/LCD/TimeField.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef TimeField_h
|
||||
#define TimeField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
#define TIMEFIELD_READ_ONLY true
|
||||
#define TIMEFIELD_READ_WRITE false
|
||||
|
||||
class TimeField : public Field {
|
||||
public:
|
||||
explicit TimeField(const String &label);
|
||||
TimeField(Form &form, const String &label, int maxHours, bool readOnly);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
void exitField();
|
||||
|
||||
unsigned long value() const { return _value; }
|
||||
void setValue(unsigned long value);
|
||||
|
||||
int maxHours() const { return _maxHours; }
|
||||
void setMaxHours(int maxHours) { _maxHours = maxHours; }
|
||||
|
||||
bool readOnly() const { return _readOnly; }
|
||||
void setReadOnly(bool value);
|
||||
|
||||
private:
|
||||
unsigned long _value;
|
||||
int _maxHours;
|
||||
int _printLen;
|
||||
bool _readOnly;
|
||||
uint8_t editField;
|
||||
|
||||
void printTime();
|
||||
int printField(unsigned long value);
|
||||
};
|
||||
|
||||
#endif
|
||||
62
libraries/LCD/examples/Form/Form.pde
Normal file
62
libraries/LCD/examples/Form/Form.pde
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
This example demonstrates how to use the Form and Field classes from the
|
||||
LCD library to provide a simple UI on the 16x2 LCD display.
|
||||
|
||||
This example is placed into the public domain.
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LCD.h>
|
||||
#include <Form.h>
|
||||
#include <TextField.h>
|
||||
#include <TimeField.h>
|
||||
#include <IntField.h>
|
||||
#include <BoolField.h>
|
||||
|
||||
// Initialize the LCD
|
||||
LCD lcd;
|
||||
|
||||
// Note: if you are using the USBDroid and have reassigned pin D9 on the LCD shield to some
|
||||
// other pin (e.g. A1), then you will need to initialize the shield with something like:
|
||||
// LCD lcd(A1);
|
||||
// See also: http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid
|
||||
|
||||
// Create the main form and its fields.
|
||||
Form mainForm(lcd);
|
||||
TextField welcomeField(mainForm, "Form example", "v1.0");
|
||||
TimeField timeField(mainForm, "Time since reset", 24, TIMEFIELD_READ_ONLY);
|
||||
IntField volumeField(mainForm, "Volume", 0, 100, 5, 85, "%");
|
||||
BoolField ledField(mainForm, "Status LED", "On", "Off", true);
|
||||
TimeField durationField(mainForm, "Timer duration", 24, TIMEFIELD_READ_WRITE);
|
||||
|
||||
#define STATUS_LED 13
|
||||
|
||||
void setup() {
|
||||
// Status LED initially on.
|
||||
pinMode(STATUS_LED, OUTPUT);
|
||||
digitalWrite(STATUS_LED, HIGH);
|
||||
|
||||
// Enable the screen saver, which will automatically blank the screen after 10 seconds.
|
||||
// The screen will wake up again when a button is pressed or lcd.display() is called.
|
||||
lcd.enableScreenSaver();
|
||||
|
||||
// Show the main form for the first time.
|
||||
mainForm.show();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Update the number of seconds since reset:
|
||||
timeField.setValue(millis() / 1000);
|
||||
|
||||
// Dispatch button events to the main form.
|
||||
int event = lcd.getButton();
|
||||
if (mainForm.dispatch(event) == FORM_CHANGED) {
|
||||
if (mainForm.isCurrent(ledField)) {
|
||||
if (ledField.value())
|
||||
digitalWrite(STATUS_LED, HIGH);
|
||||
else
|
||||
digitalWrite(STATUS_LED, LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
libraries/LCD/examples/Form/FormBool.png
Normal file
BIN
libraries/LCD/examples/Form/FormBool.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 502 KiB |
BIN
libraries/LCD/examples/Form/FormInt.png
Normal file
BIN
libraries/LCD/examples/Form/FormInt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 400 KiB |
BIN
libraries/LCD/examples/Form/FormText.png
Normal file
BIN
libraries/LCD/examples/Form/FormText.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 475 KiB |
BIN
libraries/LCD/examples/Form/FormTimeRO.png
Normal file
BIN
libraries/LCD/examples/Form/FormTimeRO.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 485 KiB |
BIN
libraries/LCD/examples/Form/FormTimeRW.png
Normal file
BIN
libraries/LCD/examples/Form/FormTimeRW.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 453 KiB |
43
libraries/LCD/examples/HelloWorld/HelloWorld.pde
Normal file
43
libraries/LCD/examples/HelloWorld/HelloWorld.pde
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
This example demonstrates how to use the LCD library, which extends the
|
||||
standard LiquidCrystal library to provide support for the Freetronics back light
|
||||
and Up/Down/Left/Right/Select buttons. More information on the shield here:
|
||||
|
||||
http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide
|
||||
|
||||
This example is placed into the public domain.
|
||||
*/
|
||||
|
||||
#include <LCD.h>
|
||||
LCD lcd;
|
||||
|
||||
// Note: if you are using the USBDroid and have reassigned pin D9 on the LCD shield to some
|
||||
// other pin (e.g. A1), then you will need to initialize the shield with something like:
|
||||
// LCD lcd(A1);
|
||||
// See also: http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid
|
||||
|
||||
void setup() {
|
||||
lcd.enableScreenSaver();
|
||||
lcd.print("hello, world!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(millis() / 1000);
|
||||
|
||||
lcd.setCursor(8, 1);
|
||||
int button = lcd.getButton();
|
||||
if (button == LCD_BUTTON_LEFT)
|
||||
lcd.print("LEFT");
|
||||
else if (button == LCD_BUTTON_RIGHT)
|
||||
lcd.print("RIGHT");
|
||||
else if (button == LCD_BUTTON_UP)
|
||||
lcd.print("UP");
|
||||
else if (button == LCD_BUTTON_DOWN)
|
||||
lcd.print("DOWN");
|
||||
else if (button == LCD_BUTTON_SELECT)
|
||||
lcd.print("SELECT");
|
||||
else if (button < 0) // button release
|
||||
lcd.print(" ");
|
||||
}
|
||||
|
||||
BIN
libraries/LCD/examples/HelloWorld/HelloWorld.png
Normal file
BIN
libraries/LCD/examples/HelloWorld/HelloWorld.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 518 KiB |
21
libraries/LCD/keywords.txt
Normal file
21
libraries/LCD/keywords.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
LCD KEYWORD1
|
||||
Form KEYWORD1
|
||||
Field KEYWORD1
|
||||
BoolField KEYWORD1
|
||||
IntField KEYWORD1
|
||||
TextField KEYWORD1
|
||||
TimeField KEYWORD1
|
||||
|
||||
getButton KEYWORD2
|
||||
enableScreenSaver KEYWORD2
|
||||
disableScreenSaver KEYWORD2
|
||||
isScreenSaved KEYWORD2
|
||||
|
||||
show KEYWORD2
|
||||
hide KEYWORD2
|
||||
dispatch KEYWORD2
|
||||
isCurrent KEYWORD2
|
||||
|
||||
setLabel KEYWORD2
|
||||
setValue KEYWORD2
|
||||
value KEYWORD2
|
||||
309
libraries/LCD/utility/LiquidCrystal.cpp
Normal file
309
libraries/LCD/utility/LiquidCrystal.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "LiquidCrystal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "WProgram.h"
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
_rs_pin = rs;
|
||||
_rw_pin = rw;
|
||||
_enable_pin = enable;
|
||||
|
||||
_data_pins[0] = d0;
|
||||
_data_pins[1] = d1;
|
||||
_data_pins[2] = d2;
|
||||
_data_pins[3] = d3;
|
||||
_data_pins[4] = d4;
|
||||
_data_pins[5] = d5;
|
||||
_data_pins[6] = d6;
|
||||
_data_pins[7] = d7;
|
||||
|
||||
pinMode(_rs_pin, OUTPUT);
|
||||
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
|
||||
if (_rw_pin != 255) {
|
||||
pinMode(_rw_pin, OUTPUT);
|
||||
}
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
|
||||
if (fourbitmode)
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
else
|
||||
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
|
||||
begin(16, 1);
|
||||
}
|
||||
|
||||
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
_currline = 0;
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||
delayMicroseconds(50000);
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
digitalWrite(_rs_pin, LOW);
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
//put the LCD into 4 bit or 8 bit mode
|
||||
if (! (_displayfunction & LCD_8BITMODE)) {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02);
|
||||
} else {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// page 45 figure 23
|
||||
|
||||
// Send function set command sequence
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(4500); // wait more than 4.1ms
|
||||
|
||||
// second try
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// third go
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
}
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal::clear()
|
||||
{
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::home()
|
||||
{
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
if ( row > _numlines ) {
|
||||
row = _numlines-1; // we count rows starting w/0
|
||||
}
|
||||
|
||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void LiquidCrystal::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void LiquidCrystal::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void LiquidCrystal::scrollDisplayLeft(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void LiquidCrystal::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void LiquidCrystal::leftToRight(void) {
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void LiquidCrystal::rightToLeft(void) {
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void LiquidCrystal::autoscroll(void) {
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void LiquidCrystal::noAutoscroll(void) {
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void LiquidCrystal::command(uint8_t value) {
|
||||
send(value, LOW);
|
||||
}
|
||||
|
||||
inline void LiquidCrystal::write(uint8_t value) {
|
||||
send(value, HIGH);
|
||||
}
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data, with automatic 4/8-bit selection
|
||||
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
|
||||
digitalWrite(_rs_pin, mode);
|
||||
|
||||
// if there is a RW pin indicated, set it low to Write
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
if (_displayfunction & LCD_8BITMODE) {
|
||||
write8bits(value);
|
||||
} else {
|
||||
write4bits(value>>4);
|
||||
write4bits(value);
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal::pulseEnable(void) {
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(_enable_pin, HIGH);
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void LiquidCrystal::write4bits(uint8_t value) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pinMode(_data_pins[i], OUTPUT);
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
||||
|
||||
void LiquidCrystal::write8bits(uint8_t value) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
pinMode(_data_pins[i], OUTPUT);
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
||||
104
libraries/LCD/utility/LiquidCrystal.h
Normal file
104
libraries/LCD/utility/LiquidCrystal.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#ifndef LiquidCrystal_h
|
||||
#define LiquidCrystal_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
class LiquidCrystal : public Print {
|
||||
public:
|
||||
LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
|
||||
LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
|
||||
|
||||
void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||
|
||||
void clear();
|
||||
void home();
|
||||
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
virtual void write(uint8_t);
|
||||
void command(uint8_t);
|
||||
private:
|
||||
void send(uint8_t, uint8_t);
|
||||
void write4bits(uint8_t);
|
||||
void write8bits(uint8_t);
|
||||
void pulseEnable();
|
||||
|
||||
uint8_t _rs_pin; // LOW: command. HIGH: character.
|
||||
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
|
||||
uint8_t _enable_pin; // activated by a HIGH pulse.
|
||||
uint8_t _data_pins[8];
|
||||
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
|
||||
uint8_t _initialized;
|
||||
|
||||
uint8_t _numlines,_currline;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user