Created
May 14, 2018 02:48
-
-
Save MCJack123/cb8c047f8ba3b8ca40499483bc0bc47a to your computer and use it in GitHub Desktop.
Two-line menu system supporting HD44780 LCDs with ncurses simulation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Pololu Corporation. For more information, see http://www.pololu.com/ | |
#ifdef __arm__ | |
#include "PololuHD44780.h" | |
#define LCD_CLEAR 0x01 | |
#define LCD_SHOW_BLINK 0x0F | |
#define LCD_SHOW_SOLID 0x0E | |
#define LCD_HIDE 0x0C | |
#define LCD_CURSOR_L 0x10 | |
#define LCD_CURSOR_R 0x14 | |
#define LCD_SHIFT_L 0x18 | |
#define LCD_SHIFT_R 0x1C | |
PololuHD44780Base::PololuHD44780Base() | |
{ | |
initialized = false; | |
} | |
void PololuHD44780Base::init2() | |
{ | |
// The startup procedure comes from Figure 24 of the HD44780 datasheet. The | |
// delay times in the later part of this function come from Table 6. | |
initPins(); | |
// We need to wait at least 15 ms after VCC reaches 4.5 V. | |
// | |
// Assumption: The AVR's power-on reset is already configured to wait for | |
// tens of milliseconds, so no delay is needed here. | |
sendCommand4Bit(3); // Function set | |
_delay_us(4200); // Needs to be at least 4.1 ms. | |
sendCommand4Bit(3); // Function set | |
_delay_us(150); // Needs to be at least 100 us. | |
sendCommand4Bit(3); // Function set | |
sendCommand4Bit(0b0010); // 4-bit interface | |
sendCommand(0b00101000); // 4-bit, 2 line, 5x8 dots font | |
setDisplayControl(0b000); // display off, cursor off, blinking off | |
clear(); | |
setEntryMode(0b10); // cursor shifts right, no auto-scrolling | |
setDisplayControl(0b100); // display on, cursor off, blinking off | |
} | |
void PololuHD44780Base::sendAndDelay(uint8_t data, bool rsValue, bool only4bit) | |
{ | |
init(); | |
send(data, rsValue, only4bit); | |
// Every data transfer or command takes at least 37 us to complete, and most | |
// of them only take that long according to the HD44780 datasheet. We delay | |
// for 37 us here so we don't have to do it in lots of other places. | |
// | |
// NOTE: If we add support for configurations where the R/W line is | |
// connected, then this delay and others like it should be disabled, and we | |
// should instead wait for the busy flag before sending the next command. | |
_delay_us(37); | |
} | |
size_t PololuHD44780Base::write(uint8_t data) | |
{ | |
sendData(data); | |
return 1; | |
} | |
size_t PololuHD44780Base::write(const uint8_t * buffer, size_t length) | |
{ | |
size_t n = length; | |
while (n--) | |
{ | |
sendData(*buffer++); | |
} | |
return length; | |
} | |
void PololuHD44780Base::clear() | |
{ | |
sendCommand(LCD_CLEAR); | |
// It's not clear how long this command takes because it doesn't say in | |
// Table 6 of the HD44780 datasheet. A good guess is that it takes 1.52 ms, | |
// since the Return Home command does. | |
_delay_us(2000); | |
} | |
void PololuHD44780Base::gotoXY(uint8_t x, uint8_t y) | |
{ | |
// Each entry is the RAM address of a line, with its most | |
// significant bit set for convenience. | |
const uint8_t line_mem[] = {0x80, 0xC0, 0x94, 0xD4}; | |
// Avoid out-of-bounds array access. | |
if (y > 3) { y = 3; } | |
sendCommand(line_mem[y] + x); | |
// This could take up to 37 us according to Table 6 of the HD44780 datasheet. | |
_delay_us(37); | |
} | |
void PololuHD44780Base::loadCustomCharacter(const uint8_t * picture, uint8_t number) | |
{ | |
uint8_t address = number * 8; | |
for(uint8_t i = 0; i < 8; i++) | |
{ | |
// Set CG RAM address. | |
sendCommand(0b01000000 | (address + i)); | |
// Write character data. | |
sendData(pgm_read_byte(picture + i)); | |
} | |
} | |
void PololuHD44780Base::loadCustomCharacterFromRam(const uint8_t * picture, uint8_t number) | |
{ | |
uint8_t address = number * 8; | |
for(uint8_t i = 0; i < 8; i++) | |
{ | |
// Set CG RAM address. | |
sendCommand(0b01000000 | (address + i)); | |
// Write character data. | |
sendData(picture[i]); | |
} | |
} | |
void PololuHD44780Base::setDisplayControl(uint8_t displayControl) | |
{ | |
sendCommand(0b00001000 | displayControl); | |
this->displayControl = displayControl; | |
} | |
void PololuHD44780Base::cursorSolid() | |
{ | |
setDisplayControl((displayControl | 0b010) & ~0b001); | |
} | |
void PololuHD44780Base::cursorBlinking() | |
{ | |
setDisplayControl((displayControl | 0b001) & ~0b010); | |
} | |
void PololuHD44780Base::hideCursor() | |
{ | |
setDisplayControl(displayControl & ~0b011); | |
} | |
void PololuHD44780Base::noDisplay() | |
{ | |
setDisplayControl(displayControl & ~0b100); | |
} | |
void PololuHD44780Base::display() | |
{ | |
setDisplayControl(displayControl | 0b100); | |
} | |
void PololuHD44780Base::noCursor() | |
{ | |
setDisplayControl(displayControl & ~0b010); | |
} | |
void PololuHD44780Base::cursor() | |
{ | |
setDisplayControl(displayControl | 0b010); | |
} | |
void PololuHD44780Base::noBlink() | |
{ | |
setDisplayControl(displayControl & ~0b001); | |
} | |
void PololuHD44780Base::blink() | |
{ | |
setDisplayControl(displayControl | 0b001); | |
} | |
void PololuHD44780Base::scrollDisplayLeft() | |
{ | |
sendCommand(0b00011000); | |
} | |
void PololuHD44780Base::scrollDisplayRight() | |
{ | |
sendCommand(0b00011100); | |
} | |
void PololuHD44780Base::home() | |
{ | |
sendCommand(0b00000010); | |
_delay_us(1600); // needs to be at least 1.52 ms | |
} | |
void PololuHD44780Base::setEntryMode(uint8_t entryMode) | |
{ | |
sendCommand(0b00000100 | entryMode); | |
this->entryMode = entryMode; | |
} | |
void PololuHD44780Base::leftToRight() | |
{ | |
setEntryMode(entryMode | 0b10); | |
} | |
void PololuHD44780Base::rightToLeft() | |
{ | |
setEntryMode(entryMode & ~0b10); | |
} | |
void PololuHD44780Base::autoscroll() | |
{ | |
setEntryMode(entryMode | 0b01); | |
} | |
void PololuHD44780Base::noAutoscroll() | |
{ | |
setEntryMode(entryMode & ~0b01); | |
} | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Pololu Corporation. For more information, see http://www.pololu.com/ | |
/*! \file PololuHD44780.h | |
* | |
* This is the main header file for the %PololuHD44780 library. | |
* | |
* For an overview of the library's features, see | |
* https://github.com/pololu/pololu-hd44780-arduino. That is the main | |
* repository for the library, though copies of the library may exist in other | |
* repositories. */ | |
#pragma once | |
#define SCREEN | |
#include <util/delay.h> | |
#include <wiringPi.h> | |
/*! \brief General class for handling the HD44780 protocol. | |
* | |
* This is an abstract class that knows about the HD44780 LCD commands but | |
* does not directly read or write from the actual LCD. To make a usable class, | |
* you need to define a subclass of PololuHD44780Base and implement the | |
* initPins() and send() functions. | |
* | |
* The subclass will inherit all the functions from PololuHD44780Base which are | |
* documented here. It will also inherit all of the functions from the Arduino `Print` class. | |
* For more information about what the `Print` class provides, see the [Arduino print() documentation](http://arduino.cc/en/Serial/Print) or look at [Print.h in the Arduino IDE source code](https://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/Print.h). | |
* | |
* Most users of this library will not need to directly use this class and | |
* should use PololuHD44780 or some other subclass of PololuHD44780Base defined | |
* in a different library. | |
* | |
* ## LCD scrolling ## | |
* | |
* The PololuHD44780Base class provides several functions related to scrolling: | |
* | |
* * scrollDisplayLeft() scrolls everything on the screen one position to the left. | |
* * scrollDisplayRight() scrolls everything on the screen one position to the right. | |
* * autoscroll() and noAutoscroll() control whether auto-scrolling is enabled. | |
* * home() and clear() both reset the scroll position | |
* | |
* The HD44780 actually stores 40 columns internally. By default, the left-most | |
* internal columns are the ones that are actually displayed on the screen, but | |
* the scrolling features allow that correspondence to change. The scrolling | |
* wraps around, so it is possible to display some of the right-most columns on | |
* the screen at the same time as some of the left-most columns. | |
* | |
* For the gotoXY() function, the x coordinate actually corresponds to the | |
* internal column index. The left-most internal column has an x coordinate of | |
* 0, and the right-most has an x coordinate of 39. | |
* | |
* For example, if you are controlling a 2×8 character LCD and you call | |
* scrollDisplayLeft() 35 times (or call scrollDisplayRight() 5 times), then the | |
* X coordinates of the columns displayed, from left to right, will be 35, 36, | |
* 37, 38, 39, 0, 1, and 2. | |
* | |
*/ | |
class PololuHD44780Base | |
{ | |
public: | |
PololuHD44780Base(); | |
/*! Initializes the pins so that the send() function can be called | |
* successfully. This is the first step of initializing the LCD. */ | |
virtual void initPins() = 0; | |
/*! Initialize the LCD if it has not already been initialized. */ | |
void init() | |
{ | |
if (!initialized) | |
{ | |
initialized = true; | |
init2(); | |
} | |
} | |
/*! Reinitialize the LCD. This performs the same initialization that is | |
* done automatically the first time any function is called that writes to | |
* the LCD. This is useful if you want to get it back to a totally clean | |
* state. */ | |
void reinitialize() | |
{ | |
initialized = true; | |
init2(); | |
} | |
/*! Sends data or commands to the LCD. | |
* | |
* The initPins() function will always be called before the first time this | |
* function is called. This function does not need to worry about the | |
* delays necessary to make sure the previous command has finished; that is | |
* taken care of by PololuHD44780Base. | |
* | |
* This function, along with initPins(), comprise the hardware abstraction | |
* layer for the LCD, and must be defined in a subclass of | |
* PololuHD44780Base. All other functions use these two functions to | |
* communicate with the LCD. | |
* | |
* @param data The data to send to the LCD. | |
* @param rsValue True to drive the RS pin high, false to drive it low. | |
* @param only4bits: If true, and the LCD is using a 4-bit interface, only sends | |
* the lower 4 bits of the data. */ | |
virtual void send(uint8_t data, bool rsValue, bool only4bits) = 0; | |
private: | |
void sendAndDelay(uint8_t data, bool rsValue, bool only4bit); | |
/*! Sends an 8-bit command to the LCD. */ | |
void sendCommand(uint8_t cmd) | |
{ | |
sendAndDelay(cmd, false, false); | |
} | |
/*! Sends a 4-bit command to the LCD. */ | |
void sendCommand4Bit(uint8_t cmd) | |
{ | |
sendAndDelay(cmd, false, true); | |
} | |
/*! Sends 8 bits of a data to the LCD. */ | |
void sendData(uint8_t data) | |
{ | |
sendAndDelay(data, true, false); | |
} | |
public: | |
/*! Clear the contents of the LCDs, resets the cursor position to the upper | |
* left, and resets the scroll position. */ | |
void clear(); | |
/*! Defines a custom character. | |
* @param picture A pointer to the character dot pattern, in program space. | |
* @param number A number between 0 and 7. */ | |
void loadCustomCharacter(const uint8_t * picture, uint8_t number); | |
/*! Defines a custom character from RAM. | |
* @param picture A pointer to the character dot pattern, in RAM. | |
* @param number A number between 0 and 7. */ | |
void loadCustomCharacterFromRam(const uint8_t * picture, uint8_t number); | |
/*! This overload of loadCustomCharacter is only provided for compatibility | |
* with OrangutanLCD; a lot of Orangutan code defines an array of chars for | |
* custom character pictures. */ | |
void loadCustomCharacter(const char * picture, uint8_t number) | |
{ | |
loadCustomCharacter((const uint8_t *)picture, number); | |
} | |
/*! Defines a custom character. | |
* This is provided for compatibility with the LiquidCrystal library. */ | |
void createChar(uint8_t number, uint8_t picture[]) | |
{ | |
loadCustomCharacterFromRam(picture, number); | |
} | |
/*! Change the location of the cursor. The cursor (whether visible or invisible), | |
* is the place where the next character written to the LCD will be displayed. | |
* | |
* Note that the scrolling features of the LCD change the correspondence | |
* between the `x` parameter and the physical column that the data is | |
* displayed on. See the "LCD scrolling" section above for more information. | |
* | |
* @param x The number of the column to go to, with 0 being the leftmost column. | |
* @param y The number of the row to go to, with 0 being the top row. */ | |
void gotoXY(uint8_t x, uint8_t y); | |
/*! Changes the location of the cursor. This is just a wrapper around | |
* gotoXY provided for compaitibility with the LiquidCrystal library. */ | |
void setCursor(uint8_t col, uint8_t row) | |
{ | |
gotoXY(col, row); | |
} | |
/*! Turns off the display while preserving its state. | |
* | |
* You can turn the display on again by calling display(). */ | |
void noDisplay(); | |
/*! Turns the display on. This should only be needed if noDisplay() was | |
* previously called. */ | |
void display(); | |
/*! Hides the solid cursor. | |
* | |
* This function clears the LCD's "C" configuration bit without changing | |
* the other bits. | |
* | |
* If the "B" bit is set to 1, a blinking cursor will still be displayed | |
* even after calling this function. For that reason, it is usually better | |
* to call hideCursor() instead. This function is only provided for | |
* compatibility with the LiquidCrystal library. */ | |
void noCursor(); | |
/*! Shows the solid cursor. | |
* | |
* This function sets the LCD's "C" configuration bit without changing the | |
* other bits. | |
* | |
* The cursor will normally be a solid line in the bottom row, but there | |
* could be a blinking rectangle superimposed on it if previous commands | |
* have enabled the blinking cursor. For this reason, it is usually better | |
* to call cursorSolid() or cursorBlinking() instead. This function is only | |
* provided for compatibility with the LiquidCrystal library. */ | |
void cursor(); | |
/*! Hides the blinking cursor. | |
* | |
* This functions clears the LCD's "B" configuration bit without changing | |
* the other bits. | |
* | |
* Calling this function does not enable or disable the solid cursor (a | |
* solid line in the bottom row) so it is usually better to call | |
* hideCursor() or cursorSolid() instead. This function is only provided | |
* for compatibilty with the LiquidCrystal library. */ | |
void noBlink(); | |
/*! Shows the blinking cursor. | |
* | |
* This function sets the LCD's "B" configuration bit without changing the | |
* other bits. | |
* | |
* The cursor will normally be a blinking rectangle, but there could also be | |
* a row of solid black pixels at the bottom if previous commands have | |
* enabled the solid cursor. For this reason, it is usually better to call | |
* cursorSolid() or cursorBlinking() instead. This function is only | |
* provided for compatibilty with the LiquidCrystal library. */ | |
void blink(); | |
/*! Enables a cursor that appears as a solid line in the bottom row. | |
* | |
* This sets the LCD's "C" configuration bit and clears its "B" bit. | |
* | |
* Note that the cursor will not be shown if the display is currently off | |
* (due to a call to noDisplay()), or if the cursor position is not within | |
* the bounds of the screen. */ | |
void cursorSolid(); | |
/*! Enables a cursor that appears as a blinking black rectangle. | |
* | |
* This sets the LCD's "C" and "B" configuration bits. | |
* | |
* Note that the cursor will not be shown if the display is currently off | |
* (due to a call to noDisplay()), or if the cursor position is not within | |
* the bounds of the screen. */ | |
void cursorBlinking(); | |
/*! Hides the solid and blinking cursors. | |
* | |
* This clears the LCD's "C" and "B" configuration bits. */ | |
void hideCursor(); | |
/*! Scrolls everything on the screen one position to the left. | |
* | |
* This command takes about 37 microseconds. */ | |
void scrollDisplayLeft(); | |
/*! Scrolls everything on the screen one position to the right. | |
* | |
* This command takes about 37 microseconds. */ | |
void scrollDisplayRight(); | |
/*! Resets the screen scrolling position back to the default and moves the | |
* cursor to the upper left corner of the screen. | |
* | |
* This command takes about 1600 microseconds, so it would be faster to | |
* instead call scrollDisplayLeft() or scrollDisplayRight() the appropriate | |
* number of times and then call gotoXY(0, 0). */ | |
void home(); | |
/*! Puts the LCD into left-to-right mode: the cursor will shift to the right | |
* after any character is written. This is the default behavior. */ | |
void leftToRight(); | |
/*! Puts the LCD into right-to-left mode: the cursor will shift to the left | |
* after any character is written. */ | |
void rightToLeft(); | |
/*! Turns on auto-scrolling. | |
* | |
* When auto-scrolling is enabled, every time a character is written, the | |
* screen will automatically scroll by one column in the appropriate | |
* direction. */ | |
void autoscroll(); | |
/*! Turns off auto-scrolling. Auto-scrolling is off by default. */ | |
void noAutoscroll(); | |
//void initPrintf(); | |
//void initPrintf(uint8_t lcdWidth, uint8_t lcdHeight); | |
/*! Send an arbitrary command to the LCD. This is here for compatibility | |
* with the LiquidCrystal library. */ | |
void command(uint8_t cmd) | |
{ | |
sendCommand(cmd); | |
} | |
/*! Writes a single character to the LCD. */ | |
virtual size_t write(uint8_t c); | |
/*! Writes multiple characters to the LCD. | |
* | |
* @param buffer Pointer to a string of characters in RAM, not | |
* necessarily null-terminated. | |
* @param size The number of characters to write to the LCD, excluding any | |
* null termination character. */ | |
virtual size_t write(const uint8_t * buffer, size_t size); | |
// This allows us to easily call overrides of write that are | |
// defined in Print. | |
//using Print::write; | |
private: | |
bool initialized; | |
/* The lower three bits of this store the arguments to the | |
* last "Display on/off control" HD44780 command that we sent. | |
* bit 2: D: Whether the display is on. | |
* bit 1: C: Whether the cursor is shown. | |
* bit 0: B: Whether the cursor is blinking. */ | |
uint8_t displayControl; | |
/* The lower two bits of this variable store the arguments to the | |
* last "Entry mode set" HD44780 command that we sent. | |
* bit 1: I/D: 0 for moving the cursor to the left after data is written, | |
* 1 for moving the cursor to the right. | |
* bit 0: 1 for autoscrolling. */ | |
uint8_t entryMode; | |
void setEntryMode(uint8_t entryMode); | |
void setDisplayControl(uint8_t displayControl); | |
void init2(); | |
}; | |
class PololuHD44780 : public PololuHD44780Base | |
{ | |
public: | |
/*! Creates a new instance of PololuHD44780. | |
* | |
* @param rs The pin number for the microcontroller pin that is | |
* connected to the RS pin of the LCD. | |
* @param e The pin number for the microcontroller pin that is | |
* connected to the E pin of the LCD. | |
* @param db4 The pin number for the microcontroller pin that is | |
* connected to the DB4 pin of the LCD. | |
* @param db5 The pin number for the microcontroller pin that is | |
* connected to the DB5 pin of the LCD. | |
* @param db6 The pin number for the microcontroller pin that is | |
* connected to the DB6 pin of the LCD. | |
* @param db7 The pin number for the microcontroller pin that is | |
* connected to the DB7 pin of the LCD. | |
*/ | |
PololuHD44780(uint8_t rs, uint8_t e, uint8_t db4, uint8_t db5, | |
uint8_t db6, uint8_t db7) | |
{ | |
this->rs = rs; | |
this->e = e; | |
this->db4 = db4; | |
this->db5 = db5; | |
this->db6 = db6; | |
this->db7 = db7; | |
} | |
virtual void initPins() | |
{ | |
digitalWrite(e, LOW); | |
pinMode(e, OUTPUT); | |
} | |
virtual void send(uint8_t data, bool rsValue, bool only4bits) | |
{ | |
digitalWrite(rs, rsValue); | |
pinMode(rs, OUTPUT); | |
pinMode(db4, OUTPUT); | |
pinMode(db5, OUTPUT); | |
pinMode(db6, OUTPUT); | |
pinMode(db7, OUTPUT); | |
if (!only4bits) { sendNibble(data >> 4); } | |
sendNibble(data & 0x0F); | |
} | |
private: | |
void sendNibble(uint8_t data) | |
{ | |
digitalWrite(db4, data >> 0 & 1); | |
digitalWrite(db5, data >> 1 & 1); | |
digitalWrite(db6, data >> 2 & 1); | |
digitalWrite(db7, data >> 3 & 1); | |
digitalWrite(e, HIGH); | |
_delay_us(1); // Must be at least 450 ns. | |
digitalWrite(e, LOW); | |
_delay_us(1); // Must be at least 550 ns. | |
} | |
uint8_t rs, e, db4, db5, db6, db7; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// screenio.cpp | |
// cplusplus | |
// | |
// Created by Jack on 5/10/18. | |
// Copyright © 2018 JackMacWindows. All rights reserved. | |
// | |
#include <algorithm> | |
#include "screenio.hpp" | |
#define qd(a, b) ((a - (a % b)) / b) | |
#ifdef SCREEN | |
#define write(x, y, text) screen.gotoXY(x, y); screen.write((const uint8_t *)text.c_str(), text.length()) | |
#else | |
#define write(x, y, text) mvaddstr(y, x, text.c_str()); move(1, SCREEN_WIDTH - 1); refresh() | |
#endif | |
#define incWithMax(num, max) if (num >= max) num = 0; else num++ | |
#define decWithMax(num, max) if (num == 0) num = max - 1; else num-- | |
int scrollpoint = 0; | |
int scrollspeed = 125; | |
std::string currentItem = "*"; | |
std::string currentTitle = "*"; | |
std::string currentText = ""; | |
std::chrono::system_clock::time_point lastScroll = std::chrono::system_clock::now(); | |
//WINDOW * win; | |
void initialize() { | |
#ifdef SCREEN | |
screen.initPins(); | |
screen.hideCursor(); | |
#else | |
initscr(); | |
noecho(); | |
cbreak(); | |
keypad(stdscr, true); | |
nodelay(stdscr, true); | |
//win = newwin(2, SCREEN_WIDTH, 0, 0); | |
//wrefresh(win); | |
#endif | |
} | |
void deinitialize() { | |
#ifndef SCREEN | |
//delwin(win); | |
echo(); | |
nocbreak(); | |
keypad(stdscr, false); | |
nodelay(stdscr, false); | |
endwin(); | |
#endif | |
} | |
void setTitle(std::string title) { | |
if (title.length() > SCREEN_WIDTH) title = title.substr(SCREEN_WIDTH - 3) + "..."; | |
//if (title == currentTitle) return; | |
int spaces = qd((SCREEN_WIDTH - (int)title.length()), 2); | |
if (spaces < 0) spaces = 0; | |
if (title.length() % 2 > 0 && spaces > 0) title.append(" "); | |
currentTitle = std::string(spaces, ' ') + title + std::string(spaces, ' '); | |
assert(currentTitle.length() == SCREEN_WIDTH); | |
write(0, 0, currentTitle); | |
} | |
void setText(std::string text) { | |
int spaces = qd((SCREEN_WIDTH - (int)text.length()), 2); | |
if (spaces < 0) spaces = 0; | |
std::string newText = text.substr(0, SCREEN_WIDTH); | |
if (text.length() % 2 > 0 && spaces > 0) newText.append(" "); | |
newText = std::string(spaces, ' ') + newText + std::string(spaces, ' '); | |
currentText = text; | |
scrollpoint = 0; | |
lastScroll = std::chrono::system_clock::now() + std::chrono::seconds(1); | |
//std::cout << "\"" << newText << "\"=" << newText.length() << "\n"; | |
assert(newText.length() == SCREEN_WIDTH); | |
write(0, 1, newText); | |
} | |
int getButton() { | |
while (true) { | |
if (std::chrono::system_clock::now() - lastScroll >= std::chrono::milliseconds(scrollspeed) && currentText.length() > SCREEN_WIDTH) { | |
if (++scrollpoint > currentText.size() + 4) { | |
scrollpoint = 0; | |
lastScroll = std::chrono::system_clock::now() + std::chrono::seconds(1); | |
} else lastScroll = std::chrono::system_clock::now(); | |
write(0, 1, extractLine(currentText, scrollpoint)); | |
} | |
#ifdef SCREEN | |
if (digitalRead(PIN_LEFT) == HIGH) return BUTTON_LEFT; | |
if (digitalRead(PIN_RIGHT) == HIGH) return BUTTON_RIGHT; | |
if (digitalRead(PIN_OK) == HIGH) return BUTTON_OK; | |
if (digitalRead(PIN_BACK) == HIGH) return BUTTON_BACK; | |
#else | |
int ch = getch(); | |
if (ch == KEY_LEFT) return BUTTON_LEFT; | |
if (ch == KEY_RIGHT) return BUTTON_RIGHT; | |
if (ch == KEY_ENTER || ch == 10) return BUTTON_OK; | |
if (ch == KEY_BACKSPACE || ch == 127) return BUTTON_BACK; | |
#endif | |
} | |
} | |
std::string extractLine(std::string text, int offset) { | |
std::string shortened = ""; | |
std::replace(text.begin(), text.end(), '\n', ' '); | |
if (offset < text.size()) { | |
shortened = text.substr(offset, SCREEN_WIDTH); | |
if (shortened.length() < SCREEN_WIDTH) shortened += std::string((SCREEN_WIDTH - shortened.length() > 4 ? 4 : SCREEN_WIDTH - shortened.length()), ' '); | |
if (shortened.length() < SCREEN_WIDTH) shortened += text.substr(0, SCREEN_WIDTH - shortened.length()); | |
} else { | |
shortened += std::string(4 - (offset - text.length()), ' '); | |
if (shortened.length() < SCREEN_WIDTH) shortened += text.substr(0, SCREEN_WIDTH - shortened.length()); | |
} | |
assert(shortened.length() == SCREEN_WIDTH); | |
return shortened; | |
} | |
int showMenu(std::string title, list items) { | |
setTitle(title); | |
int itemnum = 0; | |
while (true) { | |
currentItem = items[itemnum]; | |
setText(items[itemnum]); | |
int button = getButton(); | |
if (button == BUTTON_LEFT) {decWithMax(itemnum, (int)items.size());} | |
else if (button == BUTTON_RIGHT) {incWithMax(itemnum, (int)items.size() - 1);} | |
else if (button == BUTTON_BACK) return -1; | |
else if (button == BUTTON_OK) return itemnum; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// screenio.hpp | |
// cplusplus | |
// | |
// Created by Jack on 5/10/18. | |
// Copyright © 2018 JackMacWindows. All rights reserved. | |
#ifndef screenio_hpp | |
#define screenio_hpp | |
#include <string> | |
#include <chrono> | |
#include <vector> | |
#define SCREEN_WIDTH 16 | |
#ifdef __arm__ | |
#include "PoluluHD44780.h" | |
// To be filled in | |
PoluluHD44710 screen(0, 0, 0, 0, 0, 0); | |
#define PIN_LEFT 0 | |
#define PIN_RIGHT 0 | |
#define PIN_OK 0 | |
#define PIN_BACK 0 | |
#else | |
#include <ncurses.h> | |
#include <unistd.h> | |
//extern WINDOW * win; | |
#endif | |
typedef std::vector<std::string> list; | |
enum button_presses { | |
BUTTON_NONE, | |
BUTTON_LEFT, | |
BUTTON_RIGHT, | |
BUTTON_BACK, | |
BUTTON_OK | |
}; | |
extern int scrollpoint; | |
extern int scrollspeed; | |
extern std::string currentItem; | |
extern std::string currentTitle; | |
extern std::string currentText; | |
extern std::chrono::system_clock::time_point lastScroll; | |
extern void initialize(); | |
extern void deinitialize(); | |
extern void setTitle(std::string title); | |
extern void setText(std::string text); | |
extern int getButton(); | |
extern std::string extractLine(std::string text, int offset); | |
extern int showMenu(std::string title, list items); | |
#endif /* screenio_hpp */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment