From a865850fc2093e8d38499c0ba1d0a9a1c2ffaffa Mon Sep 17 00:00:00 2001 From: Thomas Livernet Date: Fri, 17 Jan 2014 15:44:37 +0100 Subject: [PATCH] Initialisation --- Menu/Menu.ino | 847 ++++++++++++++++ ...nu_PAUL-PC_janv.-15-1739-2014_Conflict.ino | 807 +++++++++++++++ ..._THOMAS-PC_janv.-16-2201-2014_Conflict.ino | 816 +++++++++++++++ .../Adafruit_BMP085_U/Adafruit_BMP085_U.cpp | 407 ++++++++ .../Adafruit_BMP085_U/Adafruit_BMP085_U.h | 109 ++ libraries/Adafruit_BMP085_U/README.md | 27 + .../examples/sensorapi/sensorapi.pde | 133 +++ libraries/Adafruit_GFX/Adafruit_GFX.cpp | 480 +++++++++ libraries/Adafruit_GFX/Adafruit_GFX.h | 87 ++ libraries/Adafruit_GFX/README.txt | 11 + libraries/Adafruit_GFX/glcdfont.c | 270 +++++ libraries/Adafruit_GFX/license.txt | 24 + .../Adafruit_PCD8544/Adafruit_PCD8544.cpp | 312 ++++++ libraries/Adafruit_PCD8544/Adafruit_PCD8544.h | 76 ++ libraries/Adafruit_PCD8544/README.txt | 23 + .../examples/pcdtest/pcdtest.pde | 323 ++++++ libraries/Adafruit_PCD8544/license.txt | 26 + libraries/Adafruit_Sensor/Adafruit_Sensor.cpp | 5 + libraries/Adafruit_Sensor/Adafruit_Sensor.h | 150 +++ libraries/Adafruit_Sensor/README.md | 211 ++++ libraries/EEPROMAnything/EEPROMAnything.h | 20 + libraries/Encoder/Encoder.cpp | 10 + libraries/Encoder/Encoder.h | 941 ++++++++++++++++++ libraries/Encoder/examples/Basic/Basic.pde | 29 + .../examples/NoInterrupts/NoInterrupts.pde | 46 + .../Encoder/examples/SpeedTest/SpeedTest.pde | 113 +++ .../Encoder/examples/TwoKnobs/TwoKnobs.pde | 46 + libraries/Encoder/keywords.txt | 4 + libraries/Encoder/utility/direct_pin_read.h | 27 + libraries/Encoder/utility/interrupt_config.h | 87 ++ libraries/Encoder/utility/interrupt_pins.h | 156 +++ libraries/MenuBackend/LICENSE.txt | 458 +++++++++ libraries/MenuBackend/MenuBackend.cpp | 19 + libraries/MenuBackend/MenuBackend.h | 641 ++++++++++++ .../examples/CallbackMenu/CallbackMenu.pde | 162 +++ .../examples/CallbackMenu/printresult.txt | 24 + .../examples/HelloMenu/HelloMenu.pde | 123 +++ .../examples/HelloMenu/printresult.txt | 24 + libraries/MenuBackend/keywords.txt | 59 ++ libraries/RTClib/RTClib.cpp | 246 +++++ libraries/RTClib/RTClib.h | 52 + .../RTClib/examples/datecalc/datecalc.pde | 65 ++ libraries/RTClib/examples/ds1307/ds1307.pde | 65 ++ libraries/RTClib/examples/softrtc/softrtc.pde | 52 + libraries/RTClib/keywords.txt | 34 + .../examples/toneAC_demo/toneAC_demo.pde | 35 + .../toneAC_dual_LED/toneAC_dual_LED.pde | 25 + libraries/toneAC/keywords.txt | 18 + libraries/toneAC/toneAC.cpp | 68 ++ libraries/toneAC/toneAC.h | 111 +++ 50 files changed, 8904 insertions(+) create mode 100644 Menu/Menu.ino create mode 100644 Menu/Menu_PAUL-PC_janv.-15-1739-2014_Conflict.ino create mode 100644 Menu/Menu_THOMAS-PC_janv.-16-2201-2014_Conflict.ino create mode 100644 libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.cpp create mode 100644 libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.h create mode 100644 libraries/Adafruit_BMP085_U/README.md create mode 100644 libraries/Adafruit_BMP085_U/examples/sensorapi/sensorapi.pde create mode 100644 libraries/Adafruit_GFX/Adafruit_GFX.cpp create mode 100644 libraries/Adafruit_GFX/Adafruit_GFX.h create mode 100644 libraries/Adafruit_GFX/README.txt create mode 100644 libraries/Adafruit_GFX/glcdfont.c create mode 100644 libraries/Adafruit_GFX/license.txt create mode 100644 libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp create mode 100644 libraries/Adafruit_PCD8544/Adafruit_PCD8544.h create mode 100644 libraries/Adafruit_PCD8544/README.txt create mode 100644 libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.pde create mode 100644 libraries/Adafruit_PCD8544/license.txt create mode 100644 libraries/Adafruit_Sensor/Adafruit_Sensor.cpp create mode 100644 libraries/Adafruit_Sensor/Adafruit_Sensor.h create mode 100644 libraries/Adafruit_Sensor/README.md create mode 100644 libraries/EEPROMAnything/EEPROMAnything.h create mode 100644 libraries/Encoder/Encoder.cpp create mode 100644 libraries/Encoder/Encoder.h create mode 100644 libraries/Encoder/examples/Basic/Basic.pde create mode 100644 libraries/Encoder/examples/NoInterrupts/NoInterrupts.pde create mode 100644 libraries/Encoder/examples/SpeedTest/SpeedTest.pde create mode 100644 libraries/Encoder/examples/TwoKnobs/TwoKnobs.pde create mode 100644 libraries/Encoder/keywords.txt create mode 100644 libraries/Encoder/utility/direct_pin_read.h create mode 100644 libraries/Encoder/utility/interrupt_config.h create mode 100644 libraries/Encoder/utility/interrupt_pins.h create mode 100644 libraries/MenuBackend/LICENSE.txt create mode 100644 libraries/MenuBackend/MenuBackend.cpp create mode 100644 libraries/MenuBackend/MenuBackend.h create mode 100644 libraries/MenuBackend/examples/CallbackMenu/CallbackMenu.pde create mode 100644 libraries/MenuBackend/examples/CallbackMenu/printresult.txt create mode 100644 libraries/MenuBackend/examples/HelloMenu/HelloMenu.pde create mode 100644 libraries/MenuBackend/examples/HelloMenu/printresult.txt create mode 100644 libraries/MenuBackend/keywords.txt create mode 100644 libraries/RTClib/RTClib.cpp create mode 100644 libraries/RTClib/RTClib.h create mode 100644 libraries/RTClib/examples/datecalc/datecalc.pde create mode 100644 libraries/RTClib/examples/ds1307/ds1307.pde create mode 100644 libraries/RTClib/examples/softrtc/softrtc.pde create mode 100644 libraries/RTClib/keywords.txt create mode 100644 libraries/toneAC/examples/toneAC_demo/toneAC_demo.pde create mode 100644 libraries/toneAC/examples/toneAC_dual_LED/toneAC_dual_LED.pde create mode 100644 libraries/toneAC/keywords.txt create mode 100644 libraries/toneAC/toneAC.cpp create mode 100644 libraries/toneAC/toneAC.h diff --git a/Menu/Menu.ino b/Menu/Menu.ino new file mode 100644 index 0000000..982a866 --- /dev/null +++ b/Menu/Menu.ino @@ -0,0 +1,847 @@ +//#include +//#include +#include +#include +#include +#include +#include //i2c library +#include +#include //bmp085 library, download from url link (1) +#include +#include +#include +#include +//#include +//#include +#include + +RTC_DS1307 rtc; +uint8_t hour; +uint8_t minute; + +//////////////////ENCODER/////////////////////// +#define ENCODER_OPTIMIZE_INTERRUPTS +Encoder knobLeft(2, 3); +long positionLeft = 0; +#define Enter 12 +int lastEnterState = HIGH; +long enterDebounceTime = 0; +long debounceDelay = 200; + +//////////////////MENU///////////////////////// +bool menuUsed = false; +bool menuUsed_last = false; +bool varioUsed = false; + +#define MENU_RIGHT 0 +#define MENU_LEFT 1 +#define MENU_VARIO 2 +//#define MENU_TARE 10 +#define MENU_ALTITUDE 10 +#define MENU_MONTEE 11 +#define MENU_DESCENTE 12 +#define MENU_LIGHT 13 +#define MENU_CONTRASTE 14 +#define MENU_HEURE 15 +#define MENU_MINUTE 16 +#define MENU_CHRONO 20 +#define MENU_ALTIMAX 21 +#define MENU_ALTIMIN 22 +#define MENU_TXCHUTEMAX 23 +#define MENU_TXCHUTEMIN 24 +#define MENU_RECRESET 25 + +//this controls the menu backend and the event generation +MenuBackend menu = MenuBackend(menuUseEvent,menuChangeEvent); + +MenuItem m_vario = MenuItem(NULL, MENU_VARIO); //Vario + MenuItem m_options = MenuItem(NULL, MENU_RIGHT); //Options + MenuItem m_stats = MenuItem(NULL, MENU_RIGHT); //Records + MenuItem m_retour = MenuItem(NULL, MENU_LEFT); //Retour + + //MenuItem m_tare = MenuItem(NULL, MENU_TARE); //Tare + MenuItem m_altitude = MenuItem(NULL, MENU_ALTITUDE); //Altitude + MenuItem m_montee = MenuItem(NULL, MENU_MONTEE); //Montée + MenuItem m_descente = MenuItem(NULL, MENU_DESCENTE); //Descente + MenuItem m_light = MenuItem(NULL, MENU_LIGHT); //eclairage + MenuItem m_contrast = MenuItem(NULL, MENU_CONTRASTE); //contrast + MenuItem m_heure = MenuItem(NULL, MENU_HEURE); //heure + MenuItem m_minute = MenuItem(NULL, MENU_MINUTE); //minute + + MenuItem m_retour2 = MenuItem(NULL, MENU_LEFT); //Retour + MenuItem m_chrono = MenuItem(NULL, MENU_CHRONO); //Chrono + MenuItem m_altimin = MenuItem(NULL, MENU_ALTIMIN); //Altitude min + MenuItem m_altimax = MenuItem(NULL, MENU_ALTIMAX); //Altitude max + MenuItem m_txchutemax = MenuItem(NULL, MENU_TXCHUTEMAX); //Taux de chute max + MenuItem m_txchutemin = MenuItem(NULL, MENU_TXCHUTEMIN); //Taux de chute min + MenuItem m_recreset = MenuItem(NULL, MENU_RECRESET); //Reset records + +//////////////////ECRAN/////////////////////// +#define enablePartialUpdate +#define PIN_SCLK 8 +#define PIN_LIGHT 11 +#define PIN_SCE 7 +#define PIN_RESET 6 +#define PIN_DC 5 +#define PIN_SDIN 4 + +Adafruit_PCD8544 display = Adafruit_PCD8544(PIN_SCLK, PIN_SDIN, PIN_DC, PIN_SCE, PIN_RESET); + +///////////////////////////////////////// variables that You can test and try +//float vario_climb_rate_start = 1; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s) +//float vario_sink_rate_start = -2; //maximum sink beeping value (ex. start sink beep at -1.1m/s) +#define MAX_SAMPLES 10 +//#define UART_SPEED 9600 //define serial transmision speed (9600,19200, etc...) +//uint16_t currentAltitude = 50; + +//uint8_t contrast_default = 50; +bool initialisation = false; + +///////////////////////////////////////// + +/////////////////////VARIO///////////////////////// +//Adafruit_BMP085_Unified bmp085; //set up bmp085 sensor +Adafruit_BMP085_Unified bmp085 = Adafruit_BMP085_Unified(10085); + +#define ALTI_TRIGGER 2 +float Altitude; +int altitude_temp; +uint32_t chrono_start = 0; +uint32_t chrono_stop = 0; +uint8_t chrono_cpt = 0; + +float vario = 0; +bool is_vario_button_push = false; +float Battery_Vcc = 0; //variable to hold the value of Vcc from battery +const float p0 = 1040.00; //Pressure at sea level (Pa) +double average_pressure; +unsigned long get_time1 = millis(); +unsigned long get_time2 = millis(); +unsigned long get_time3 = millis(); +unsigned long get_time4 = millis(); +unsigned long get_time5 = millis(); +boolean push_write_eeprom = false; +boolean thermalling = false; +float my_temperature = 1; +float alt[(MAX_SAMPLES + 1)]; +float tim[(MAX_SAMPLES + 1)]; + +#define memoryBase 32 +struct Conf +{ + float vario_climb_rate_start; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s) + float vario_sink_rate_start; //maximum sink beeping value (ex. start sink beep at -1.1m/s) + int currentAltitude; + uint8_t light_cpt; + uint8_t contrast_default; + int alti_max; + int alti_min; + float txchutemax; + float txchutemin; + uint8_t volume; +} conf = { + 0.4 , -1.1 , 0, 0, 50, 0, 0, 0, 0, 10 +}; + + +inline float Averaging_Filter(float input) // moving average filter function +{ + return average_pressure * 0.94 + input * 0.06; +} + +void renderVario(){ + + display.fillRect(0, 0, 84, 32, WHITE); + // text display tests + display.setCursor(0,0); + + display.setTextColor(BLACK); + display.setTextSize(2); + display.print((int)Altitude); + display.setTextSize(1); + display.print(F("m")); + + DateTime now = rtc.now(); + if (now.second()%2 == 0){ + + display.setCursor(55,0); + renderZero(now.hour()); + display.print(now.hour()); + display.setCursor(66,0); + display.print(F(":")); + display.setCursor(72,0); + renderZero(now.minute()); + display.print(now.minute()); + } + else { + display.setCursor(62,0); + display.print(round(my_temperature)); + display.drawCircle(75, 1, 1, BLACK); + display.setCursor(72,0); + display.print(F(" C")); + } + + display.setCursor(62,18); + Battery_Vcc = readVcc(); // get voltage and prepare in percentage + uint8_t v = round(floor(Battery_Vcc)); + display.print(F(".")); + display.print(round(10 * Battery_Vcc) - (10 * v)); + display.print(F("V")); + + + display.setTextSize(2); + display.setCursor(0,16); + + display.setTextColor(WHITE, BLACK); + + float vario_abs = abs(vario); + display.print((vario < 0)? F("-"): F("+")); + uint8_t m = round(floor(vario_abs)); + display.print(m); + display.print(F(".")); + display.print(round(10 * vario_abs) - (10 * m)); + display.setTextSize(1); + display.setCursor(48,24); + display.print(F("m/s")); + + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,41); + renderChrono(); + + display.display(); +} + +void renderVarioBar(){ + /* + float vario_abs = abs(vario); + display.fillRect(0, 32, 84, 16, WHITE); + if (vario >= 0) + display.fillRect(42, 32, round(vario_abs * 15), 16, BLACK); + else + display.drawRect(42, 32, -round(vario_abs * 15), 16, BLACK); + + display.display(); */ +} + +void renderVolume(uint8_t dir = MENU_RIGHT){ + + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE, BLACK); + + if (dir == MENU_RIGHT) + (conf.volume == 10)? conf.volume = 10 : conf.volume += 2; + else if (dir == MENU_LEFT) + (conf.volume == 0)? conf.volume = 0 : conf.volume -= 2; + + push_write_eeprom = true; + get_time3 = millis(); + get_time2 = millis(); //stop the refresh rendering vario + + display.print(F("Volume:")); + (conf.volume == 0)? display.print(F("Off")) : display.print(conf.volume); + display.display(); +} + +float updateConfItem(float var, uint8_t dir = 2, float increment = 1){ + + //enregistrement de la conf si validation d'un parametre + if (menuUsed_last == true && menuUsed == false){ + menuUsed_last = false; + EEPROM_writeAnything(0, conf); + } + //sinon modification de ce paramêtre + else if (menuUsed){ + menuUsed_last = menuUsed; + if (dir == MENU_RIGHT) + var += increment; + else if (dir == MENU_LEFT) + var -= increment; + } + return var; +} + +void renderMenuDisplayedItem(float value, const __FlashStringHelper *unit, bool integer = false){ + menuUsed = false; + display.setTextColor(BLACK); + if (integer == true) + value = (int)value; + display.print(value); + display.setTextSize(1); + display.print(unit); +} + +void renderZero(int value){ + if (value == 0) + display.print(F("0")); +} + +void renderChrono(){ + if (chrono_start != 0){ + uint32_t chrono_s = chrono_stop; + if (chrono_s == 0){ + DateTime now = rtc.now(); + chrono_s = now.unixtime(); + } + uint32_t s = chrono_s - chrono_start; + uint8_t h = floor(s/3600); + s -= h * 3600; + uint8_t m = floor(s/60); + s -= m * 60; + + //renderZero(h); + display.print(h); + display.print(F(":")); + renderZero(m); + display.print(m); + display.print(F(":")); + renderZero((int)s); + display.print(s); + } +} + +void resetStats(){ + conf.alti_min = 20000; + conf.alti_max = -20000; + conf.txchutemax = 0; + conf.txchutemin = 0; + + altitude_temp = Altitude; + chrono_start = chrono_stop = 0; + chrono_cpt = 0; +} + +void renderMenu(MenuItem newMenuItem, uint8_t dir = 2){ + + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,0); + //display.println(title); + display.setTextSize(1); + display.setTextColor(WHITE, BLACK); + + if (newMenuItem.getShortkey() < 10) + display.println(F("Accueil")); + else if (newMenuItem.getShortkey() >= 10 && newMenuItem.getShortkey() < 20) + display.println(F("Options")); + else if (newMenuItem.getShortkey() >= 20 && newMenuItem.getShortkey() < 30) + display.println(F("Records")); + + display.setTextSize(2); + display.println(newMenuItem.getName()); + + if (!menuUsed) + display.setTextColor(BLACK); + + if (varioUsed && menuUsed){ + varioUsed = false; + menuUsed = false; + } + + //sous-menu (valeur) + if (varioUsed == false){ + + switch(newMenuItem.getShortkey()){ + + case MENU_VARIO: + { + if (menuUsed){ + varioUsed = true; + menuUsed = false; + } + } + break; + /* + else if (newMenuItem.getShortkey() == MENU_TARE){ + display.println(newMenuItem.getName()); + } + */ + case MENU_ALTITUDE: + { + conf.currentAltitude = updateConfItem(conf.currentAltitude, dir, 5); + + display.print(conf.currentAltitude); + display.setTextSize(1); + display.print(F("m")); + } + break; + + case MENU_MONTEE: + { + conf.vario_climb_rate_start = updateConfItem(conf.vario_climb_rate_start, dir, 0.1); + + if (conf.vario_climb_rate_start < 0.1){ + conf.vario_climb_rate_start = 0; + display.print(F("Off")); + } + else { + display.print(conf.vario_climb_rate_start); + display.setTextSize(1); + display.print(F("m/s")); + } + } + break; + + case MENU_DESCENTE: + { + conf.vario_sink_rate_start = updateConfItem(conf.vario_sink_rate_start, dir, 0.1); + + if (conf.vario_sink_rate_start >= 0){ + conf.vario_sink_rate_start = 0; + display.print(F("Off")); + } + else{ + display.print(conf.vario_sink_rate_start); + display.setTextSize(1); + display.print(F("m/s")); + } + } + break; + + case MENU_LIGHT: + { + conf.light_cpt = updateConfItem(conf.light_cpt, dir, -1); + + if (conf.light_cpt <= 0) + conf.light_cpt = 0; + + if (conf.light_cpt >= 5){ + conf.light_cpt = 5; + display.print(F("Off")); + } + else{ + display.print(5 - conf.light_cpt); + } + } + break; + + case MENU_CONTRASTE: + { + conf.contrast_default = updateConfItem(conf.contrast_default, dir, 1); + + if (conf.contrast_default <= 0){ + conf.contrast_default = 0; + } + else if (conf.contrast_default >= 100){ + conf.contrast_default = 100; + } + + display.print(conf.contrast_default); + display.setContrast(conf.contrast_default); + } + break; + + case MENU_HEURE: + case MENU_MINUTE: + { + DateTime now = rtc.now(); + if (menuUsed_last == false){ + hour = now.hour(); + minute = now.minute(); + } + if (menuUsed_last == true && menuUsed == false){ + menuUsed_last = false; + rtc.adjust(DateTime(now.year(), now.month(),now.day(), hour, minute, 0)); + } + //sinon modification de ce paramêtre + else if (menuUsed){ + menuUsed_last = menuUsed; + if (dir == MENU_RIGHT) + (newMenuItem.getShortkey() == MENU_HEURE)? (hour = 23)? hour = 0 : hour ++ : (minute == 59)? minute = 0 : minute ++; + else if (dir == MENU_LEFT) + (newMenuItem.getShortkey() == MENU_HEURE)? (hour == 0)? hour = 23: hour -- : (minute == 0)? minute = 59 : minute --; + } + display.print((newMenuItem.getShortkey() == MENU_HEURE)? hour : minute); + } + break; + + case MENU_CHRONO: + { + menuUsed = false; + display.setTextColor(BLACK); + renderChrono(); + } + break; + + case MENU_ALTIMIN: + { + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.alti_min); + //display.setTextSize(1); + //display.print(F("m")); + renderMenuDisplayedItem(conf.alti_min, F("m"), true); + } + break; + + case MENU_ALTIMAX: + { + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.alti_max); + //display.setTextSize(1); + //display.print(F("m")); + renderMenuDisplayedItem(conf.alti_max, F("m"), true); + } + break; + + case MENU_RECRESET: + { + if (menuUsed){ + menuUsed = false; + resetStats(); + display.print(F("Ok")); + } + } + break; + + case MENU_TXCHUTEMAX: + { + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.txchutemax); + //display.setTextSize(1); + //display.print(F("m/s")); + renderMenuDisplayedItem(conf.txchutemax, F("m/s")); + } + break; + + case MENU_TXCHUTEMIN: + { + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.txchutemin); + //display.setTextSize(1); + //display.print(F("m/s")); + renderMenuDisplayedItem(conf.txchutemin, F("m/s")); + } + break; + } + } + display.display(); +} + +//this function builds the menu and connects the correct items together +void menuSetup() +{ + + m_vario.name = F("Vario"); //Vario + m_options.name = F("Options"); //Options + m_stats.name = F("Stats"); //Stats + m_retour.name = F("Retour"); //Retour + //m_tare.name = F("Tare"); //Tare + m_altitude.name = F("Alti"); //Altitude + m_montee.name = F("Montee"); //Montée + m_descente.name = F("Desc"); //Descente + m_light.name = F("Light"); //eclairage + m_contrast.name = F("Contra"); //eclairage + m_heure.name = F("Heure"); //heure + m_minute.name = F("Minute"); //minute + m_retour2.name = F("Retour"); //Retour + m_chrono.name = F("Chrono"); //Chrono + m_altimin.name = F("AltMin"); //Altitude min + m_altimax.name = F("AltMax"); //Altitude max + m_recreset.name = F("Reset"); //Reset records + m_txchutemax.name = F("Tx max"); //Taux de chute max + m_txchutemin.name = F("Tx min"); //Taux de chute min + + /* + This is the structure of the modelled menu + + Vario + Options + Retour + Tare + Altitude + Montée + Descente + Light + Contra + + */ + + m_vario.addAfter(m_stats); + + m_stats.addAfter(m_options); + m_stats.addRight(m_chrono); + m_chrono.addBefore(m_retour2); + m_chrono.addAfter(m_altimax); + m_altimax.addAfter(m_altimin); + m_altimin.addAfter(m_txchutemin); + m_txchutemin.addAfter(m_txchutemax); + m_txchutemax.addAfter(m_recreset); + m_retour2.addLeft(m_vario); + + m_options.addRight(m_altitude); + m_altitude.addBefore(m_retour); + m_altitude.addAfter(m_montee); + m_montee.addAfter(m_descente); + m_descente.addAfter(m_light); + m_light.addAfter(m_contrast); + m_contrast.addAfter(m_heure); + m_heure.addAfter(m_minute); + m_retour.addLeft(m_vario); + + menu.use(m_vario); +} + +/* + This is an important function + Here all use events are handled + + This is where you define a behaviour for a menu item +*/ +void menuUseEvent(MenuUseEvent used) +{ + if (used.item.getShortkey() == MENU_RIGHT){ + menu.moveRight(); + } + else if (used.item.getShortkey() == MENU_LEFT){ + menu.moveLeft(); + } + else + menuUsed = !menuUsed; + + renderMenu(menu.getCurrent()); +} + +/* + This is an important function + Here we get a notification whenever the user changes the menu + That is, when the menu is navigated +*/ +void menuChangeEvent(MenuChangeEvent changed) +{ + renderMenu(changed.to); +} + +float readVcc() { + long result; + // Read 1.1V reference against AVcc + ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Convert + while (bit_is_set(ADCSRA,ADSC)); + result = ADCL; + result |= ADCH<<8; + return (1126400L / result)/1000; // Back-calculate AVcc in V +} + +void setup() +{ + //Serial.begin(9600); + + //chargement de la configuration + //EEPROM_writeAnything(0, conf); + EEPROM_readAnything(0, conf); + + Wire.begin(); + rtc.begin(); + if (!rtc.isrunning()) { + // following line sets the RTC to the date & time this sketch was compiled + rtc.adjust(DateTime(__DATE__, __TIME__)); + } + + pinMode(PIN_LIGHT, OUTPUT); + + bmp085.begin(); + /* Get a new sensor event */ + sensors_event_t event; + bmp085.getEvent(&event); + average_pressure = event.pressure; //put it in filter and take average + bmp085.getTemperature(&my_temperature); + Altitude = bmp085.pressureToAltitude(p0, average_pressure, my_temperature); //take new altitude in meters + altitude_temp = Altitude; + + display.begin(); + display.setContrast(conf.contrast_default); + + menuSetup(); + //Serial.println("Starting navigation:\r\nLeft: 4 Right: 6 Use: 5"); +} + +void loop() +{ + readButtons(); + analogWrite(PIN_LIGHT, conf.light_cpt * 51); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255 + + float tempo=millis(); + float N1=0; + float N2=0; + float N3=0; + float D1=0; + float D2=0; + + /* Get a new sensor event */ + sensors_event_t event; + bmp085.getEvent(&event); + + average_pressure = Averaging_Filter(event.pressure); //put it in filter and take average + bmp085.getTemperature(&my_temperature); + Altitude = bmp085.pressureToAltitude(p0, average_pressure, my_temperature); //take new altitude in meters + + if (millis() >= (get_time4+1000)) // auto start/stop chrono + { + get_time4 = millis(); + if (chrono_start == 0){ + if (Altitude > altitude_temp + ALTI_TRIGGER || Altitude < altitude_temp - ALTI_TRIGGER){ //si l'altitude sort de sa "zone", le chrono est lancé + DateTime now = rtc.now(); + chrono_start = now.unixtime(); + } + else { // toutes les 15 secondes, la zone d'altitude est mise à jour + chrono_cpt++; + if (chrono_cpt >= 15){ + chrono_cpt = 0; + altitude_temp = Altitude; + } + } + } + else if (chrono_start != 0 && chrono_stop == 0){ + if (altitude_temp - ALTI_TRIGGER/2 < Altitude && altitude_temp + ALTI_TRIGGER/2 > Altitude){ // si l'altitude reste dans la même "zone" 15 secondes, le chrono est stoppé + chrono_cpt++; + if (chrono_cpt >= 15){ + DateTime now = rtc.now(); + chrono_stop = now.unixtime(); + } + } + else { + chrono_cpt = 0; + altitude_temp = Altitude; + } + } + } + + if (Altitude > conf.alti_max) + conf.alti_max = Altitude; + if (Altitude < conf.alti_min) + conf.alti_min = Altitude; + + for(uint8_t cc=1;cc<=MAX_SAMPLES;cc++){ //samples averaging and vario algorithm + alt[(cc-1)]=alt[cc]; + tim[(cc-1)]=tim[cc]; + }; + alt[MAX_SAMPLES]=Altitude; + tim[MAX_SAMPLES]=tempo; + float stime=tim[0]; + for(uint8_t cc=0;cc conf.txchutemin) + conf.txchutemin = vario; + + // make some beep + if (vario < 15 && vario > -15){ + if (vario > conf.vario_climb_rate_start && conf.vario_climb_rate_start != 0) + { + toneAC(900+(100*vario), conf.volume, 200-(vario*10)); //when climbing make faster and shorter beeps + thermalling = true; //ok,we have thermall in our hands + } else if (vario < 0 && thermalling == true) //looks like we jump out the thermall + { + // play_siren(); //oo, we lost thermall play alarm + thermalling = false; + } else if (vario < conf.vario_sink_rate_start && conf.vario_sink_rate_start != 0){ //if you have high performace glider you can change sink beep to -0.95m/s ;) + toneAC(900+(100*vario), conf.volume, 200-(vario*10)); + thermalling = false; + } + } + + if (millis() >= (get_time1+67) && varioUsed) //every second get temperature and battery level + { + get_time1 = millis(); + renderVarioBar(); + } + if (millis() >= (get_time2+1000) && varioUsed) //every second get temperature and battery level + { + get_time2 = millis(); + renderVario(); + } + if (millis() >= (get_time3+5000) && push_write_eeprom) //Write conf in eeprom if request + { + push_write_eeprom = false; + EEPROM_writeAnything(0, conf); + } + +} + +void readButtons(){ + + long newLeft = knobLeft.read(); + if (newLeft != positionLeft) { + if (newLeft%2==0) { + if (newLeft > positionLeft){ //Right + if (!menuUsed && varioUsed == false) + menu.moveDown(); + else if (varioUsed == false) + renderMenu(menu.getCurrent(), MENU_RIGHT); + else if (varioUsed == true) + renderVolume(MENU_RIGHT); + } + else { //Left + if (!menuUsed && varioUsed == false) + menu.moveUp(); + else if (varioUsed == false) + renderMenu(menu.getCurrent(), MENU_LEFT); + else if (varioUsed == true) + renderVolume(MENU_LEFT); + } + } + positionLeft = newLeft; + } + + //if button enter is pressed + int reading = digitalRead(Enter); + if ((millis() - enterDebounceTime) > debounceDelay){ + + // in menu, clic an item + if (reading == LOW && lastEnterState == HIGH && varioUsed == false){ + enterDebounceTime = millis(); + menu.use(); + } + } + // in vario, button enter init timer + if (reading == LOW && lastEnterState == HIGH && varioUsed == true){ + enterDebounceTime = millis(); + get_time5 = millis(); + is_vario_button_push = true; + } + // in vario, stop button enter and go back to menu + if (reading == HIGH && lastEnterState == LOW && varioUsed == true && is_vario_button_push == true){ + enterDebounceTime = millis(); + is_vario_button_push = false; + menu.use(); + } + + lastEnterState = reading; + + // in vario, if button enter is pressed 2 seconds, reset stats + if (millis() >= (get_time5+2000) && is_vario_button_push == true){ + + is_vario_button_push = false; + resetStats(); + + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE, BLACK); + get_time2 = millis(); //stop the refresh rendering vario + display.println(F("Reset")); + display.println(F("stats")); + display.print(F("Ok")); + display.display(); + + toneAC(700, 10, 150); + toneAC(500, 10, 150); + } + +}//end read button diff --git a/Menu/Menu_PAUL-PC_janv.-15-1739-2014_Conflict.ino b/Menu/Menu_PAUL-PC_janv.-15-1739-2014_Conflict.ino new file mode 100644 index 0000000..2ab012b --- /dev/null +++ b/Menu/Menu_PAUL-PC_janv.-15-1739-2014_Conflict.ino @@ -0,0 +1,807 @@ +//#include +//#include +#include +#include +#include +#include +#include //i2c library +#include +#include //bmp085 library, download from url link (1) +#include +#include +#include +#include +//#include +//#include +#include + +RTC_DS1307 rtc; +uint8_t hour; +uint8_t minute; + +//////////////////ENCODER/////////////////////// +#define ENCODER_OPTIMIZE_INTERRUPTS +Encoder knobLeft(2, 3); +long positionLeft = 0; +#define Enter 12 +int lastEnterState = HIGH; +long enterDebounceTime = 0; +long debounceDelay = 200; + +//////////////////MENU///////////////////////// +bool menuUsed = false; +bool menuUsed_last = false; +bool varioUsed = false; + +#define MENU_RIGHT 0 +#define MENU_LEFT 1 +#define MENU_VARIO 2 +//#define MENU_TARE 10 +#define MENU_ALTITUDE 10 +#define MENU_MONTEE 11 +#define MENU_DESCENTE 12 +#define MENU_LIGHT 13 +#define MENU_CONTRASTE 14 +#define MENU_HEURE 15 +#define MENU_MINUTE 16 +#define MENU_CHRONO 20 +#define MENU_ALTIMAX 21 +#define MENU_ALTIMIN 22 +#define MENU_TXCHUTEMAX 23 +#define MENU_TXCHUTEMIN 24 +#define MENU_RECRESET 25 + +//this controls the menu backend and the event generation +MenuBackend menu = MenuBackend(menuUseEvent,menuChangeEvent); + +MenuItem m_vario = MenuItem(NULL, MENU_VARIO); //Vario + MenuItem m_options = MenuItem(NULL, MENU_RIGHT); //Options + MenuItem m_records = MenuItem(NULL, MENU_RIGHT); //Records + MenuItem m_retour = MenuItem(NULL, MENU_LEFT); //Retour + + //MenuItem m_tare = MenuItem(NULL, MENU_TARE); //Tare + MenuItem m_altitude = MenuItem(NULL, MENU_ALTITUDE); //Altitude + MenuItem m_montee = MenuItem(NULL, MENU_MONTEE); //Montée + MenuItem m_descente = MenuItem(NULL, MENU_DESCENTE); //Descente + MenuItem m_light = MenuItem(NULL, MENU_LIGHT); //eclairage + MenuItem m_contrast = MenuItem(NULL, MENU_CONTRASTE); //contrast + MenuItem m_heure = MenuItem(NULL, MENU_HEURE); //heure + MenuItem m_minute = MenuItem(NULL, MENU_MINUTE); //minute + + MenuItem m_retour2 = MenuItem(NULL, MENU_LEFT); //Retour + MenuItem m_chrono = MenuItem(NULL, MENU_CHRONO); //Chrono + MenuItem m_altimin = MenuItem(NULL, MENU_ALTIMIN); //Altitude min + MenuItem m_altimax = MenuItem(NULL, MENU_ALTIMAX); //Altitude max + MenuItem m_txchutemax = MenuItem(NULL, MENU_TXCHUTEMAX); //Taux de chute max + MenuItem m_txchutemin = MenuItem(NULL, MENU_TXCHUTEMIN); //Taux de chute min + MenuItem m_recreset = MenuItem(NULL, MENU_RECRESET); //Reset records + +//////////////////ECRAN/////////////////////// +#define enablePartialUpdate +#define PIN_SCLK 8 +#define PIN_LIGHT 11 +#define PIN_SCE 7 +#define PIN_RESET 6 +#define PIN_DC 5 +#define PIN_SDIN 4 + +Adafruit_PCD8544 display = Adafruit_PCD8544(PIN_SCLK, PIN_SDIN, PIN_DC, PIN_SCE, PIN_RESET); + +///////////////////////////////////////// variables that You can test and try +//float vario_climb_rate_start = 1; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s) +//float vario_sink_rate_start = -2; //maximum sink beeping value (ex. start sink beep at -1.1m/s) +#define MAX_SAMPLES 10 +//#define UART_SPEED 9600 //define serial transmision speed (9600,19200, etc...) +//uint16_t currentAltitude = 50; + +//uint8_t contrast_default = 50; +bool initialisation = false; + +///////////////////////////////////////// + +/////////////////////VARIO///////////////////////// +//Adafruit_BMP085_Unified bmp085; //set up bmp085 sensor +Adafruit_BMP085_Unified bmp085 = Adafruit_BMP085_Unified(10085); + +#define ALTI_TRIGGER 2 +float Altitude; +int altitude_temp; +uint32_t chrono_start = 0; +uint32_t chrono_stop = 0; +uint8_t chrono_cpt = 0; + +float vario = 0; +bool is_vario_button_push = false; +float Battery_Vcc = 0; //variable to hold the value of Vcc from battery +const float p0 = 1040.00; //Pressure at sea level (Pa) +double average_pressure; +unsigned long get_time1 = millis(); +unsigned long get_time2 = millis(); +unsigned long get_time3 = millis(); +unsigned long get_time4 = millis(); +unsigned long get_time5 = millis(); +boolean push_write_eeprom = false; +boolean thermalling = false; +float my_temperature = 1; +float alt[(MAX_SAMPLES + 1)]; +float tim[(MAX_SAMPLES + 1)]; + +#define memoryBase 32 +struct Conf +{ + float vario_climb_rate_start; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s) + float vario_sink_rate_start; //maximum sink beeping value (ex. start sink beep at -1.1m/s) + int currentAltitude; + uint8_t light_cpt; + uint8_t contrast_default; + int alti_max; + int alti_min; + float txchutemax; + float txchutemin; + uint8_t volume; +} conf = { + 0.4 , -1.1 , 0, 0, 50, 0, 0, 0, 0, 10 +}; + + +inline float Averaging_Filter(float input) // moving average filter function +{ + return average_pressure * 0.94 + input * 0.06; +} + +void renderVario(){ + + display.fillRect(0, 0, 84, 32, WHITE); + // text display tests + display.setCursor(0,0); + + display.setTextColor(BLACK); + display.setTextSize(2); + display.print((int)Altitude); + display.setTextSize(1); + display.print(F("m")); + + DateTime now = rtc.now(); + if (now.second()%2 == 0){ + + display.setCursor(55,0); + renderZero(now.hour()); + display.print(now.hour()); + display.setCursor(66,0); + display.print(F(":")); + display.setCursor(72,0); + renderZero(now.minute()); + display.print(now.minute()); + } + else { + display.setCursor(62,0); + display.print(round(my_temperature)); + display.drawCircle(75, 1, 1, BLACK); + display.setCursor(72,0); + display.print(F(" C")); + } + + display.setCursor(62,18); + Battery_Vcc = readVcc(); // get voltage and prepare in percentage + uint8_t v = round(floor(Battery_Vcc)); + display.print(F(".")); + display.print(round(10 * Battery_Vcc) - (10 * v)); + display.print(F("V")); + + + display.setTextSize(2); + display.setCursor(0,16); + + display.setTextColor(WHITE, BLACK); + + float vario_abs = abs(vario); + display.print((vario < 0)? F("-"): F("+")); + uint8_t m = round(floor(vario_abs)); + display.print(m); + display.print(F(".")); + display.print(round(10 * vario_abs) - (10 * m)); + display.setTextSize(1); + display.setCursor(48,24); + display.print(F("m/s")); + + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,41); + renderChrono(); + + display.display(); +} + +void renderVarioBar(){ + /* + float vario_abs = abs(vario); + display.fillRect(0, 32, 84, 16, WHITE); + if (vario >= 0) + display.fillRect(42, 32, round(vario_abs * 15), 16, BLACK); + else + display.drawRect(42, 32, -round(vario_abs * 15), 16, BLACK); + + display.display(); */ +} + +void renderVolume(uint8_t dir = MENU_RIGHT){ + + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE, BLACK); + + if (dir == MENU_RIGHT) + (conf.volume == 10)? conf.volume = 10 : conf.volume += 2; + else if (dir == MENU_LEFT) + (conf.volume == 0)? conf.volume = 0 : conf.volume -= 2; + + push_write_eeprom = true; + get_time3 = millis(); + get_time2 = millis(); //stop the refresh rendering vario + + display.print(F("Volume:")); + (conf.volume == 0)? display.print(F("Off")) : display.print(conf.volume); + display.display(); +} + +float updateConfItem(float var, uint8_t dir = 2, float increment = 1){ + + //enregistrement de la conf si validation d'un parametre + if (menuUsed_last == true && menuUsed == false){ + menuUsed_last = false; + EEPROM_writeAnything(0, conf); + } + //sinon modification de ce paramêtre + else if (menuUsed){ + menuUsed_last = menuUsed; + if (dir == MENU_RIGHT) + var += increment; + else if (dir == MENU_LEFT) + var -= increment; + } + return var; +} + +void renderMenuDisplayedItem(float value, const __FlashStringHelper *unit, bool integer = false){ + menuUsed = false; + display.setTextColor(BLACK); + if (integer == true) + value = (int)value; + display.print(value); + display.setTextSize(1); + display.print(unit); +} + +void renderZero(int value){ + if (value == 0) + display.print(F("0")); +} + +void renderChrono(){ + if (chrono_start != 0){ + uint32_t chrono_s = chrono_stop; + if (chrono_s == 0){ + DateTime now = rtc.now(); + chrono_s = now.unixtime(); + } + uint32_t s = chrono_s - chrono_start; + uint8_t h = floor(s/3600); + s -= h * 3600; + uint8_t m = floor(s/60); + s -= m * 60; + + //renderZero(h); + display.print(h); + display.print(F(":")); + renderZero(m); + display.print(m); + display.print(F(":")); + renderZero((int)s); + display.print(s); + } +} + +void renderMenu(MenuItem newMenuItem, uint8_t dir = 2){ + + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,0); + //display.println(title); + display.setTextSize(1); + display.setTextColor(WHITE, BLACK); + + if (newMenuItem.getShortkey() < 10) + display.println(F("Accueil")); + else if (newMenuItem.getShortkey() >= 10 && newMenuItem.getShortkey() < 20) + display.println(F("Options")); + else if (newMenuItem.getShortkey() >= 20 && newMenuItem.getShortkey() < 30) + display.println(F("Records")); + + display.setTextSize(2); + display.println(newMenuItem.getName()); + + if (!menuUsed) + display.setTextColor(BLACK); + + if (varioUsed && menuUsed){ + varioUsed = false; + menuUsed = false; + } + + //sous-menu (valeur) + if (varioUsed == false){ + + if (newMenuItem.getShortkey() == MENU_VARIO && menuUsed){ + varioUsed = true; + menuUsed = false; + } + /* + else if (newMenuItem.getShortkey() == MENU_TARE){ + display.println(newMenuItem.getName()); + } + */ + else if (newMenuItem.getShortkey() == MENU_ALTITUDE){ + + conf.currentAltitude = updateConfItem(conf.currentAltitude, dir, 5); + + display.print(conf.currentAltitude); + display.setTextSize(1); + display.print(F("m")); + } + + else if (newMenuItem.getShortkey() == MENU_MONTEE){ + + conf.vario_climb_rate_start = updateConfItem(conf.vario_climb_rate_start, dir, 0.1); + + if (conf.vario_climb_rate_start < 0.1){ + conf.vario_climb_rate_start = 0; + display.print(F("Off")); + } + else { + display.print(conf.vario_climb_rate_start); + display.setTextSize(1); + display.print(F("m/s")); + } + } + + else if (newMenuItem.getShortkey() == MENU_DESCENTE){ + + conf.vario_sink_rate_start = updateConfItem(conf.vario_sink_rate_start, dir, 0.1); + + if (conf.vario_sink_rate_start >= 0){ + conf.vario_sink_rate_start = 0; + display.print(F("Off")); + } + else{ + display.print(conf.vario_sink_rate_start); + display.setTextSize(1); + display.print(F("m/s")); + } + } + + else if (newMenuItem.getShortkey() == MENU_LIGHT){ + + conf.light_cpt = updateConfItem(conf.light_cpt, dir, -1); + + if (conf.light_cpt <= 0) + conf.light_cpt = 0; + + if (conf.light_cpt >= 5){ + conf.light_cpt = 5; + display.print(F("Off")); + } + else{ + display.print(5 - conf.light_cpt); + } + } + + else if (newMenuItem.getShortkey() == MENU_CONTRASTE){ + + conf.contrast_default = updateConfItem(conf.contrast_default, dir, 1); + + if (conf.contrast_default <= 0){ + conf.contrast_default = 0; + } + else if (conf.contrast_default >= 100){ + conf.contrast_default = 100; + } + + display.print(conf.contrast_default); + display.setContrast(conf.contrast_default); + } + + else if (newMenuItem.getShortkey() == MENU_HEURE || newMenuItem.getShortkey() == MENU_MINUTE){ + + DateTime now = rtc.now(); + if (menuUsed_last == false){ + hour = now.hour(); + minute = now.minute(); + } + if (menuUsed_last == true && menuUsed == false){ + menuUsed_last = false; + rtc.adjust(DateTime(now.year(), now.month(),now.day(), hour, minute, 0)); + } + //sinon modification de ce paramêtre + else if (menuUsed){ + menuUsed_last = menuUsed; + if (dir == MENU_RIGHT) + (newMenuItem.getShortkey() == MENU_HEURE)? (hour = 23)? hour = 0 : hour ++ : (minute == 59)? minute = 0 : minute ++; + else if (dir == MENU_LEFT) + (newMenuItem.getShortkey() == MENU_HEURE)? (hour == 0)? hour = 23: hour -- : (minute == 0)? minute = 59 : minute --; + } + display.print((newMenuItem.getShortkey() == MENU_HEURE)? hour : minute); + } + + else if (newMenuItem.getShortkey() == MENU_CHRONO){ + menuUsed = false; + display.setTextColor(BLACK); + renderChrono(); + } + + else if (newMenuItem.getShortkey() == MENU_ALTIMIN){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.alti_min); + //display.setTextSize(1); + //display.print(F("m")); + renderMenuDisplayedItem(conf.alti_min, F("m"), true); + } + else if (newMenuItem.getShortkey() == MENU_ALTIMAX){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.alti_max); + //display.setTextSize(1); + //display.print(F("m")); + renderMenuDisplayedItem(conf.alti_max, F("m"), true); + } + else if (newMenuItem.getShortkey() == MENU_RECRESET){ + if (menuUsed){ + menuUsed = false; + conf.alti_min = 20000; + conf.alti_max = -20000; + conf.txchutemax = 0; + conf.txchutemin = 0; + + altitude_temp = Altitude; + chrono_start = chrono_stop = 0; + chrono_cpt = 0; + + display.print(F("Ok")); + } + } + else if (newMenuItem.getShortkey() == MENU_TXCHUTEMAX){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.txchutemax); + //display.setTextSize(1); + //display.print(F("m/s")); + renderMenuDisplayedItem(conf.txchutemax, F("m/s")); + } + else if (newMenuItem.getShortkey() == MENU_TXCHUTEMIN){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.txchutemin); + //display.setTextSize(1); + //display.print(F("m/s")); + renderMenuDisplayedItem(conf.txchutemin, F("m/s")); + } + } + display.display(); +} + +//this function builds the menu and connects the correct items together +void menuSetup() +{ + + m_vario.name = F("Vario"); //Vario + m_options.name = F("Options"); //Options + m_records.name = F("Records"); //Records + m_retour.name = F("Retour"); //Retour + //m_tare.name = F("Tare"); //Tare + m_altitude.name = F("Alti"); //Altitude + m_montee.name = F("Montee"); //Montée + m_descente.name = F("Desc"); //Descente + m_light.name = F("Light"); //eclairage + m_contrast.name = F("Contra"); //eclairage + m_heure.name = F("Heure"); //heure + m_minute.name = F("Minute"); //minute + m_retour2.name = F("Retour"); //Retour + m_chrono.name = F("Chrono"); //Chrono + m_altimin.name = F("AltMin"); //Altitude min + m_altimax.name = F("AltMax"); //Altitude max + m_recreset.name = F("Reset"); //Reset records + m_txchutemax.name = F("Tx max"); //Taux de chute max + m_txchutemin.name = F("Tx min"); //Taux de chute min + + /* + This is the structure of the modelled menu + + Vario + Options + Retour + Tare + Altitude + Montée + Descente + Light + Contra + + */ + + m_vario.addAfter(m_options); + m_options.addAfter(m_records); + m_options.addRight(m_altitude); + m_altitude.addBefore(m_retour); + m_altitude.addAfter(m_montee); + m_montee.addAfter(m_descente); + m_descente.addAfter(m_light); + m_light.addAfter(m_contrast); + m_contrast.addAfter(m_heure); + m_heure.addAfter(m_minute); + m_retour.addLeft(m_vario); + + m_records.addRight(m_chrono); + m_chrono.addBefore(m_retour2); + m_chrono.addAfter(m_altimax); + m_altimax.addAfter(m_altimin); + m_altimin.addAfter(m_txchutemin); + m_txchutemin.addAfter(m_txchutemax); + m_txchutemax.addAfter(m_recreset); + + m_retour2.addLeft(m_vario); + + menu.use(m_vario); + //menu.use(); +} + +/* + This is an important function + Here all use events are handled + + This is where you define a behaviour for a menu item +*/ +void menuUseEvent(MenuUseEvent used) +{ + if (used.item.getShortkey() == MENU_RIGHT){ + menu.moveRight(); + } + else if (used.item.getShortkey() == MENU_LEFT){ + menu.moveLeft(); + } + else + menuUsed = !menuUsed; + + renderMenu(menu.getCurrent()); +} + +/* + This is an important function + Here we get a notification whenever the user changes the menu + That is, when the menu is navigated +*/ +void menuChangeEvent(MenuChangeEvent changed) +{ + renderMenu(changed.to); +} + +float readVcc() { + long result; + // Read 1.1V reference against AVcc + ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Convert + while (bit_is_set(ADCSRA,ADSC)); + result = ADCL; + result |= ADCH<<8; + return (1126400L / result)/1000; // Back-calculate AVcc in V +} + +void setup() +{ + //Serial.begin(9600); + + //chargement de la configuration + //EEPROM_writeAnything(0, conf); + EEPROM_readAnything(0, conf); + + Wire.begin(); + rtc.begin(); + if (!rtc.isrunning()) { + // following line sets the RTC to the date & time this sketch was compiled + rtc.adjust(DateTime(__DATE__, __TIME__)); + } + + pinMode(PIN_LIGHT, OUTPUT); + + bmp085.begin(); + /* Get a new sensor event */ + sensors_event_t event; + bmp085.getEvent(&event); + average_pressure = event.pressure; //put it in filter and take average + bmp085.getTemperature(&my_temperature); + Altitude = bmp085.pressureToAltitude(p0, average_pressure, my_temperature); //take new altitude in meters + altitude_temp = Altitude; + + display.begin(); + display.setContrast(conf.contrast_default); + + menuSetup(); + //Serial.println("Starting navigation:\r\nLeft: 4 Right: 6 Use: 5"); +} + +void loop() +{ + readButtons(); + analogWrite(PIN_LIGHT, conf.light_cpt * 51); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255 + + float tempo=millis(); + float N1=0; + float N2=0; + float N3=0; + float D1=0; + float D2=0; + + /* Get a new sensor event */ + sensors_event_t event; + bmp085.getEvent(&event); + + average_pressure = Averaging_Filter(event.pressure); //put it in filter and take average + bmp085.getTemperature(&my_temperature); + Altitude = bmp085.pressureToAltitude(p0, average_pressure, my_temperature); //take new altitude in meters + + if (millis() >= (get_time4+1000)) // auto start/stop chrono + { + get_time4 = millis(); + if (chrono_start == 0){ + if (Altitude > altitude_temp + ALTI_TRIGGER || Altitude < altitude_temp - ALTI_TRIGGER){ //si l'altitude sort de sa "zone", le chrono est lancé + DateTime now = rtc.now(); + chrono_start = now.unixtime(); + } + else { // toutes les 15 secondes, la zone d'altitude est mise à jour + chrono_cpt++; + if (chrono_cpt >= 15){ + chrono_cpt = 0; + altitude_temp = Altitude; + } + } + } + else if (chrono_start != 0 && chrono_stop == 0){ + if (altitude_temp - ALTI_TRIGGER/2 < Altitude && altitude_temp + ALTI_TRIGGER/2 > Altitude){ // si l'altitude reste dans la même "zone" 10 secondes, le chrono est stoppé + chrono_cpt++; + if (chrono_cpt >= 15){ + DateTime now = rtc.now(); + chrono_stop = now.unixtime(); + } + } + else { + chrono_cpt = 0; + altitude_temp = Altitude; + } + } + } + + if (Altitude > conf.alti_max) + conf.alti_max = Altitude; + if (Altitude < conf.alti_min) + conf.alti_min = Altitude; + + for(uint8_t cc=1;cc<=MAX_SAMPLES;cc++){ //samples averaging and vario algorithm + alt[(cc-1)]=alt[cc]; + tim[(cc-1)]=tim[cc]; + }; + alt[MAX_SAMPLES]=Altitude; + tim[MAX_SAMPLES]=tempo; + float stime=tim[0]; + for(uint8_t cc=0;cc conf.txchutemin) + conf.txchutemin = vario; + + // make some beep + if (vario < 15 && vario > -15){ + if (vario > conf.vario_climb_rate_start && conf.vario_climb_rate_start != 0) + { + toneAC(900+(100*vario), conf.volume, 200-(vario*10)); //when climbing make faster and shorter beeps + thermalling = true; //ok,we have thermall in our hands + } else if (vario < 0 && thermalling == true) //looks like we jump out the thermall + { + // play_siren(); //oo, we lost thermall play alarm + thermalling = false; + } else if (vario < conf.vario_sink_rate_start && conf.vario_sink_rate_start != 0){ //if you have high performace glider you can change sink beep to -0.95m/s ;) + toneAC(900+(100*vario), conf.volume, 200-(vario*10)); + thermalling = false; + } + } + + if (millis() >= (get_time1+67) && varioUsed) //every second get temperature and battery level + { + get_time1 = millis(); + renderVarioBar(); + } + if (millis() >= (get_time2+1000) && varioUsed) //every second get temperature and battery level + { + get_time2 = millis(); + renderVario(); + } + if (millis() >= (get_time3+5000) && push_write_eeprom) //Write conf in eeprom if request + { + push_write_eeprom = false; + EEPROM_writeAnything(0, conf); + } + +} + +void readButtons(){ + + long newLeft = knobLeft.read(); + if (newLeft != positionLeft) { + if (newLeft%2==0) { + if (newLeft > positionLeft){ //Right + if (!menuUsed && varioUsed == false) + menu.moveDown(); + else if (varioUsed == false) + renderMenu(menu.getCurrent(), MENU_RIGHT); + else if (varioUsed == true) + renderVolume(MENU_RIGHT); + } + else { //Left + if (!menuUsed && varioUsed == false) + menu.moveUp(); + else if (varioUsed == false) + renderMenu(menu.getCurrent(), MENU_LEFT); + else if (varioUsed == true) + renderVolume(MENU_LEFT); + } + } + positionLeft = newLeft; + } + + //if button enter is pressed + int reading = digitalRead(Enter); + if ((millis() - enterDebounceTime) > debounceDelay){ + + // in menu, clic an item + if (reading == LOW && lastEnterState == HIGH && varioUsed == false){ + enterDebounceTime = millis(); + menu.use(); + } + + // in vario, button enter init timer + if (reading == LOW && lastEnterState == HIGH && varioUsed == true){ + enterDebounceTime = millis(); + get_time5 = millis(); + is_vario_button_push = true; + } + // in vario, stop button enter and go back to menu + if (reading == HIGH && lastEnterState == LOW && varioUsed == true && is_vario_button_push == true){ + enterDebounceTime = millis(); + is_vario_button_push = false; + menu.use(); + } + } + lastEnterState = reading; + + // in vario, if button enter is pressed 2 seconds + if (millis() >= (get_time5+2000) && is_vario_button_push == true){ + + is_vario_button_push = false; + + conf.volume = 10; + toneAC(500, conf.volume, 100); + toneAC(500, conf.volume, 100); + conf.volume = 0; + } + +}//end read button diff --git a/Menu/Menu_THOMAS-PC_janv.-16-2201-2014_Conflict.ino b/Menu/Menu_THOMAS-PC_janv.-16-2201-2014_Conflict.ino new file mode 100644 index 0000000..e901f31 --- /dev/null +++ b/Menu/Menu_THOMAS-PC_janv.-16-2201-2014_Conflict.ino @@ -0,0 +1,816 @@ +//#include +//#include +#include +#include +#include +#include +#include //i2c library +#include +#include //bmp085 library, download from url link (1) +#include +#include +#include +#include +//#include +//#include +#include + +RTC_DS1307 rtc; +uint8_t hour; +uint8_t minute; + +//////////////////ENCODER/////////////////////// +#define ENCODER_OPTIMIZE_INTERRUPTS +Encoder knobLeft(2, 3); +long positionLeft = 0; +#define Enter 12 +int lastEnterState = HIGH; +long enterDebounceTime = 0; +long debounceDelay = 200; + +//////////////////MENU///////////////////////// +bool menuUsed = false; +bool menuUsed_last = false; +bool varioUsed = false; + +#define MENU_RIGHT 0 +#define MENU_LEFT 1 +#define MENU_VARIO 2 +//#define MENU_TARE 10 +#define MENU_ALTITUDE 10 +#define MENU_MONTEE 11 +#define MENU_DESCENTE 12 +#define MENU_LIGHT 13 +#define MENU_CONTRASTE 14 +#define MENU_HEURE 15 +#define MENU_MINUTE 16 +#define MENU_CHRONO 20 +#define MENU_ALTIMAX 21 +#define MENU_ALTIMIN 22 +#define MENU_TXCHUTEMAX 23 +#define MENU_TXCHUTEMIN 24 +#define MENU_RECRESET 25 + +//this controls the menu backend and the event generation +MenuBackend menu = MenuBackend(menuUseEvent,menuChangeEvent); + +MenuItem m_vario = MenuItem(NULL, MENU_VARIO); //Vario + MenuItem m_options = MenuItem(NULL, MENU_RIGHT); //Options + MenuItem m_stats = MenuItem(NULL, MENU_RIGHT); //Records + MenuItem m_retour = MenuItem(NULL, MENU_LEFT); //Retour + + //MenuItem m_tare = MenuItem(NULL, MENU_TARE); //Tare + MenuItem m_altitude = MenuItem(NULL, MENU_ALTITUDE); //Altitude + MenuItem m_montee = MenuItem(NULL, MENU_MONTEE); //Montée + MenuItem m_descente = MenuItem(NULL, MENU_DESCENTE); //Descente + MenuItem m_light = MenuItem(NULL, MENU_LIGHT); //eclairage + MenuItem m_contrast = MenuItem(NULL, MENU_CONTRASTE); //contrast + MenuItem m_heure = MenuItem(NULL, MENU_HEURE); //heure + MenuItem m_minute = MenuItem(NULL, MENU_MINUTE); //minute + + MenuItem m_retour2 = MenuItem(NULL, MENU_LEFT); //Retour + MenuItem m_chrono = MenuItem(NULL, MENU_CHRONO); //Chrono + MenuItem m_altimin = MenuItem(NULL, MENU_ALTIMIN); //Altitude min + MenuItem m_altimax = MenuItem(NULL, MENU_ALTIMAX); //Altitude max + MenuItem m_txchutemax = MenuItem(NULL, MENU_TXCHUTEMAX); //Taux de chute max + MenuItem m_txchutemin = MenuItem(NULL, MENU_TXCHUTEMIN); //Taux de chute min + MenuItem m_recreset = MenuItem(NULL, MENU_RECRESET); //Reset records + +//////////////////ECRAN/////////////////////// +#define enablePartialUpdate +#define PIN_SCLK 8 +#define PIN_LIGHT 11 +#define PIN_SCE 7 +#define PIN_RESET 6 +#define PIN_DC 5 +#define PIN_SDIN 4 + +Adafruit_PCD8544 display = Adafruit_PCD8544(PIN_SCLK, PIN_SDIN, PIN_DC, PIN_SCE, PIN_RESET); + +///////////////////////////////////////// variables that You can test and try +//float vario_climb_rate_start = 1; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s) +//float vario_sink_rate_start = -2; //maximum sink beeping value (ex. start sink beep at -1.1m/s) +#define MAX_SAMPLES 10 +//#define UART_SPEED 9600 //define serial transmision speed (9600,19200, etc...) +//uint16_t currentAltitude = 50; + +//uint8_t contrast_default = 50; +bool initialisation = false; + +///////////////////////////////////////// + +/////////////////////VARIO///////////////////////// +//Adafruit_BMP085_Unified bmp085; //set up bmp085 sensor +Adafruit_BMP085_Unified bmp085 = Adafruit_BMP085_Unified(10085); + +#define ALTI_TRIGGER 2 +float Altitude; +int altitude_temp; +uint32_t chrono_start = 0; +uint32_t chrono_stop = 0; +uint8_t chrono_cpt = 0; + +float vario = 0; +bool is_vario_button_push = false; +float Battery_Vcc = 0; //variable to hold the value of Vcc from battery +const float p0 = 1040.00; //Pressure at sea level (Pa) +double average_pressure; +unsigned long get_time1 = millis(); +unsigned long get_time2 = millis(); +unsigned long get_time3 = millis(); +unsigned long get_time4 = millis(); +unsigned long get_time5 = millis(); +boolean push_write_eeprom = false; +boolean thermalling = false; +float my_temperature = 1; +float alt[(MAX_SAMPLES + 1)]; +float tim[(MAX_SAMPLES + 1)]; + +#define memoryBase 32 +struct Conf +{ + float vario_climb_rate_start; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s) + float vario_sink_rate_start; //maximum sink beeping value (ex. start sink beep at -1.1m/s) + int currentAltitude; + uint8_t light_cpt; + uint8_t contrast_default; + int alti_max; + int alti_min; + float txchutemax; + float txchutemin; + uint8_t volume; +} conf = { + 0.4 , -1.1 , 0, 0, 50, 0, 0, 0, 0, 10 +}; + + +inline float Averaging_Filter(float input) // moving average filter function +{ + return average_pressure * 0.94 + input * 0.06; +} + +void renderVario(){ + + display.fillRect(0, 0, 84, 32, WHITE); + // text display tests + display.setCursor(0,0); + + display.setTextColor(BLACK); + display.setTextSize(2); + display.print((int)Altitude); + display.setTextSize(1); + display.print(F("m")); + + DateTime now = rtc.now(); + if (now.second()%2 == 0){ + + display.setCursor(55,0); + renderZero(now.hour()); + display.print(now.hour()); + display.setCursor(66,0); + display.print(F(":")); + display.setCursor(72,0); + renderZero(now.minute()); + display.print(now.minute()); + } + else { + display.setCursor(62,0); + display.print(round(my_temperature)); + display.drawCircle(75, 1, 1, BLACK); + display.setCursor(72,0); + display.print(F(" C")); + } + + display.setCursor(62,18); + Battery_Vcc = readVcc(); // get voltage and prepare in percentage + uint8_t v = round(floor(Battery_Vcc)); + display.print(F(".")); + display.print(round(10 * Battery_Vcc) - (10 * v)); + display.print(F("V")); + + + display.setTextSize(2); + display.setCursor(0,16); + + display.setTextColor(WHITE, BLACK); + + float vario_abs = abs(vario); + display.print((vario < 0)? F("-"): F("+")); + uint8_t m = round(floor(vario_abs)); + display.print(m); + display.print(F(".")); + display.print(round(10 * vario_abs) - (10 * m)); + display.setTextSize(1); + display.setCursor(48,24); + display.print(F("m/s")); + + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,41); + renderChrono(); + + display.display(); +} + +void renderVarioBar(){ + /* + float vario_abs = abs(vario); + display.fillRect(0, 32, 84, 16, WHITE); + if (vario >= 0) + display.fillRect(42, 32, round(vario_abs * 15), 16, BLACK); + else + display.drawRect(42, 32, -round(vario_abs * 15), 16, BLACK); + + display.display(); */ +} + +void renderVolume(uint8_t dir = MENU_RIGHT){ + + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE, BLACK); + + if (dir == MENU_RIGHT) + (conf.volume == 10)? conf.volume = 10 : conf.volume += 2; + else if (dir == MENU_LEFT) + (conf.volume == 0)? conf.volume = 0 : conf.volume -= 2; + + push_write_eeprom = true; + get_time3 = millis(); + get_time2 = millis(); //stop the refresh rendering vario + + display.print(F("Volume:")); + (conf.volume == 0)? display.print(F("Off")) : display.print(conf.volume); + display.display(); +} + +float updateConfItem(float var, uint8_t dir = 2, float increment = 1){ + + //enregistrement de la conf si validation d'un parametre + if (menuUsed_last == true && menuUsed == false){ + menuUsed_last = false; + EEPROM_writeAnything(0, conf); + } + //sinon modification de ce paramêtre + else if (menuUsed){ + menuUsed_last = menuUsed; + if (dir == MENU_RIGHT) + var += increment; + else if (dir == MENU_LEFT) + var -= increment; + } + return var; +} + +void renderMenuDisplayedItem(float value, const __FlashStringHelper *unit, bool integer = false){ + menuUsed = false; + display.setTextColor(BLACK); + if (integer == true) + value = (int)value; + display.print(value); + display.setTextSize(1); + display.print(unit); +} + +void renderZero(int value){ + if (value == 0) + display.print(F("0")); +} + +void renderChrono(){ + if (chrono_start != 0){ + uint32_t chrono_s = chrono_stop; + if (chrono_s == 0){ + DateTime now = rtc.now(); + chrono_s = now.unixtime(); + } + uint32_t s = chrono_s - chrono_start; + uint8_t h = floor(s/3600); + s -= h * 3600; + uint8_t m = floor(s/60); + s -= m * 60; + + //renderZero(h); + display.print(h); + display.print(F(":")); + renderZero(m); + display.print(m); + display.print(F(":")); + renderZero((int)s); + display.print(s); + } +} + +void resetStats(){ + conf.alti_min = 20000; + conf.alti_max = -20000; + conf.txchutemax = 0; + conf.txchutemin = 0; + + altitude_temp = Altitude; + chrono_start = chrono_stop = 0; + chrono_cpt = 0; +} + +void renderMenu(MenuItem newMenuItem, uint8_t dir = 2){ + + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,0); + //display.println(title); + display.setTextSize(1); + display.setTextColor(WHITE, BLACK); + + if (newMenuItem.getShortkey() < 10) + display.println(F("Accueil")); + else if (newMenuItem.getShortkey() >= 10 && newMenuItem.getShortkey() < 20) + display.println(F("Options")); + else if (newMenuItem.getShortkey() >= 20 && newMenuItem.getShortkey() < 30) + display.println(F("Records")); + + display.setTextSize(2); + display.println(newMenuItem.getName()); + + if (!menuUsed) + display.setTextColor(BLACK); + + if (varioUsed && menuUsed){ + varioUsed = false; + menuUsed = false; + } + + //sous-menu (valeur) + if (varioUsed == false){ + + if (newMenuItem.getShortkey() == MENU_VARIO && menuUsed){ + varioUsed = true; + menuUsed = false; + } + /* + else if (newMenuItem.getShortkey() == MENU_TARE){ + display.println(newMenuItem.getName()); + } + */ + else if (newMenuItem.getShortkey() == MENU_ALTITUDE){ + + conf.currentAltitude = updateConfItem(conf.currentAltitude, dir, 5); + + display.print(conf.currentAltitude); + display.setTextSize(1); + display.print(F("m")); + } + + else if (newMenuItem.getShortkey() == MENU_MONTEE){ + + conf.vario_climb_rate_start = updateConfItem(conf.vario_climb_rate_start, dir, 0.1); + + if (conf.vario_climb_rate_start < 0.1){ + conf.vario_climb_rate_start = 0; + display.print(F("Off")); + } + else { + display.print(conf.vario_climb_rate_start); + display.setTextSize(1); + display.print(F("m/s")); + } + } + + else if (newMenuItem.getShortkey() == MENU_DESCENTE){ + + conf.vario_sink_rate_start = updateConfItem(conf.vario_sink_rate_start, dir, 0.1); + + if (conf.vario_sink_rate_start >= 0){ + conf.vario_sink_rate_start = 0; + display.print(F("Off")); + } + else{ + display.print(conf.vario_sink_rate_start); + display.setTextSize(1); + display.print(F("m/s")); + } + } + + else if (newMenuItem.getShortkey() == MENU_LIGHT){ + + conf.light_cpt = updateConfItem(conf.light_cpt, dir, -1); + + if (conf.light_cpt <= 0) + conf.light_cpt = 0; + + if (conf.light_cpt >= 5){ + conf.light_cpt = 5; + display.print(F("Off")); + } + else{ + display.print(5 - conf.light_cpt); + } + } + + else if (newMenuItem.getShortkey() == MENU_CONTRASTE){ + + conf.contrast_default = updateConfItem(conf.contrast_default, dir, 1); + + if (conf.contrast_default <= 0){ + conf.contrast_default = 0; + } + else if (conf.contrast_default >= 100){ + conf.contrast_default = 100; + } + + display.print(conf.contrast_default); + display.setContrast(conf.contrast_default); + } + + else if (newMenuItem.getShortkey() == MENU_HEURE || newMenuItem.getShortkey() == MENU_MINUTE){ + + DateTime now = rtc.now(); + if (menuUsed_last == false){ + hour = now.hour(); + minute = now.minute(); + } + if (menuUsed_last == true && menuUsed == false){ + menuUsed_last = false; + rtc.adjust(DateTime(now.year(), now.month(),now.day(), hour, minute, 0)); + } + //sinon modification de ce paramêtre + else if (menuUsed){ + menuUsed_last = menuUsed; + if (dir == MENU_RIGHT) + (newMenuItem.getShortkey() == MENU_HEURE)? (hour = 23)? hour = 0 : hour ++ : (minute == 59)? minute = 0 : minute ++; + else if (dir == MENU_LEFT) + (newMenuItem.getShortkey() == MENU_HEURE)? (hour == 0)? hour = 23: hour -- : (minute == 0)? minute = 59 : minute --; + } + display.print((newMenuItem.getShortkey() == MENU_HEURE)? hour : minute); + } + + else if (newMenuItem.getShortkey() == MENU_CHRONO){ + menuUsed = false; + display.setTextColor(BLACK); + renderChrono(); + } + + else if (newMenuItem.getShortkey() == MENU_ALTIMIN){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.alti_min); + //display.setTextSize(1); + //display.print(F("m")); + renderMenuDisplayedItem(conf.alti_min, F("m"), true); + } + else if (newMenuItem.getShortkey() == MENU_ALTIMAX){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.alti_max); + //display.setTextSize(1); + //display.print(F("m")); + renderMenuDisplayedItem(conf.alti_max, F("m"), true); + } + else if (newMenuItem.getShortkey() == MENU_RECRESET){ + if (menuUsed){ + menuUsed = false; + resetStats(); + display.print(F("Ok")); + } + } + else if (newMenuItem.getShortkey() == MENU_TXCHUTEMAX){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.txchutemax); + //display.setTextSize(1); + //display.print(F("m/s")); + renderMenuDisplayedItem(conf.txchutemax, F("m/s")); + } + else if (newMenuItem.getShortkey() == MENU_TXCHUTEMIN){ + //menuUsed = false; + //display.setTextColor(BLACK); + //display.print(conf.txchutemin); + //display.setTextSize(1); + //display.print(F("m/s")); + renderMenuDisplayedItem(conf.txchutemin, F("m/s")); + } + } + display.display(); +} + +//this function builds the menu and connects the correct items together +void menuSetup() +{ + + m_vario.name = F("Vario"); //Vario + m_options.name = F("Options"); //Options + m_stats.name = F("Stats"); //Stats + m_retour.name = F("Retour"); //Retour + //m_tare.name = F("Tare"); //Tare + m_altitude.name = F("Alti"); //Altitude + m_montee.name = F("Montee"); //Montée + m_descente.name = F("Desc"); //Descente + m_light.name = F("Light"); //eclairage + m_contrast.name = F("Contra"); //eclairage + m_heure.name = F("Heure"); //heure + m_minute.name = F("Minute"); //minute + m_retour2.name = F("Retour"); //Retour + m_chrono.name = F("Chrono"); //Chrono + m_altimin.name = F("AltMin"); //Altitude min + m_altimax.name = F("AltMax"); //Altitude max + m_recreset.name = F("Reset"); //Reset records + m_txchutemax.name = F("Tx max"); //Taux de chute max + m_txchutemin.name = F("Tx min"); //Taux de chute min + + /* + This is the structure of the modelled menu + + Vario + Options + Retour + Tare + Altitude + Montée + Descente + Light + Contra + + */ + + m_vario.addAfter(m_stats); + + m_stats.addAfter(m_options); + m_stats.addRight(m_chrono); + m_chrono.addBefore(m_retour2); + m_chrono.addAfter(m_altimax); + m_altimax.addAfter(m_altimin); + m_altimin.addAfter(m_txchutemin); + m_txchutemin.addAfter(m_txchutemax); + m_txchutemax.addAfter(m_recreset); + m_retour2.addLeft(m_vario); + + m_options.addRight(m_altitude); + m_altitude.addBefore(m_retour); + m_altitude.addAfter(m_montee); + m_montee.addAfter(m_descente); + m_descente.addAfter(m_light); + m_light.addAfter(m_contrast); + m_contrast.addAfter(m_heure); + m_heure.addAfter(m_minute); + m_retour.addLeft(m_vario); + + menu.use(m_vario); +} + +/* + This is an important function + Here all use events are handled + + This is where you define a behaviour for a menu item +*/ +void menuUseEvent(MenuUseEvent used) +{ + if (used.item.getShortkey() == MENU_RIGHT){ + menu.moveRight(); + } + else if (used.item.getShortkey() == MENU_LEFT){ + menu.moveLeft(); + } + else + menuUsed = !menuUsed; + + renderMenu(menu.getCurrent()); +} + +/* + This is an important function + Here we get a notification whenever the user changes the menu + That is, when the menu is navigated +*/ +void menuChangeEvent(MenuChangeEvent changed) +{ + renderMenu(changed.to); +} + +float readVcc() { + long result; + // Read 1.1V reference against AVcc + ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Convert + while (bit_is_set(ADCSRA,ADSC)); + result = ADCL; + result |= ADCH<<8; + return (1126400L / result)/1000; // Back-calculate AVcc in V +} + +void setup() +{ + //Serial.begin(9600); + + //chargement de la configuration + //EEPROM_writeAnything(0, conf); + EEPROM_readAnything(0, conf); + + Wire.begin(); + rtc.begin(); + if (!rtc.isrunning()) { + // following line sets the RTC to the date & time this sketch was compiled + rtc.adjust(DateTime(__DATE__, __TIME__)); + } + + pinMode(PIN_LIGHT, OUTPUT); + + bmp085.begin(); + /* Get a new sensor event */ + sensors_event_t event; + bmp085.getEvent(&event); + average_pressure = event.pressure; //put it in filter and take average + bmp085.getTemperature(&my_temperature); + Altitude = bmp085.pressureToAltitude(p0, average_pressure, my_temperature); //take new altitude in meters + altitude_temp = Altitude; + + display.begin(); + display.setContrast(conf.contrast_default); + + menuSetup(); + //Serial.println("Starting navigation:\r\nLeft: 4 Right: 6 Use: 5"); +} + +void loop() +{ + readButtons(); + analogWrite(PIN_LIGHT, conf.light_cpt * 51); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255 + + float tempo=millis(); + float N1=0; + float N2=0; + float N3=0; + float D1=0; + float D2=0; + + /* Get a new sensor event */ + sensors_event_t event; + bmp085.getEvent(&event); + + average_pressure = Averaging_Filter(event.pressure); //put it in filter and take average + bmp085.getTemperature(&my_temperature); + Altitude = bmp085.pressureToAltitude(p0, average_pressure, my_temperature); //take new altitude in meters + + if (millis() >= (get_time4+1000)) // auto start/stop chrono + { + get_time4 = millis(); + if (chrono_start == 0){ + if (Altitude > altitude_temp + ALTI_TRIGGER || Altitude < altitude_temp - ALTI_TRIGGER){ //si l'altitude sort de sa "zone", le chrono est lancé + DateTime now = rtc.now(); + chrono_start = now.unixtime(); + } + else { // toutes les 15 secondes, la zone d'altitude est mise à jour + chrono_cpt++; + if (chrono_cpt >= 15){ + chrono_cpt = 0; + altitude_temp = Altitude; + } + } + } + else if (chrono_start != 0 && chrono_stop == 0){ + if (altitude_temp - ALTI_TRIGGER/2 < Altitude && altitude_temp + ALTI_TRIGGER/2 > Altitude){ // si l'altitude reste dans la même "zone" 15 secondes, le chrono est stoppé + chrono_cpt++; + if (chrono_cpt >= 15){ + DateTime now = rtc.now(); + chrono_stop = now.unixtime(); + } + } + else { + chrono_cpt = 0; + altitude_temp = Altitude; + } + } + } + + if (Altitude > conf.alti_max) + conf.alti_max = Altitude; + if (Altitude < conf.alti_min) + conf.alti_min = Altitude; + + for(uint8_t cc=1;cc<=MAX_SAMPLES;cc++){ //samples averaging and vario algorithm + alt[(cc-1)]=alt[cc]; + tim[(cc-1)]=tim[cc]; + }; + alt[MAX_SAMPLES]=Altitude; + tim[MAX_SAMPLES]=tempo; + float stime=tim[0]; + for(uint8_t cc=0;cc conf.txchutemin) + conf.txchutemin = vario; + + // make some beep + if (vario < 15 && vario > -15){ + if (vario > conf.vario_climb_rate_start && conf.vario_climb_rate_start != 0) + { + toneAC(900+(100*vario), conf.volume, 200-(vario*10)); //when climbing make faster and shorter beeps + thermalling = true; //ok,we have thermall in our hands + } else if (vario < 0 && thermalling == true) //looks like we jump out the thermall + { + // play_siren(); //oo, we lost thermall play alarm + thermalling = false; + } else if (vario < conf.vario_sink_rate_start && conf.vario_sink_rate_start != 0){ //if you have high performace glider you can change sink beep to -0.95m/s ;) + toneAC(900+(100*vario), conf.volume, 200-(vario*10)); + thermalling = false; + } + } + + if (millis() >= (get_time1+67) && varioUsed) //every second get temperature and battery level + { + get_time1 = millis(); + renderVarioBar(); + } + if (millis() >= (get_time2+1000) && varioUsed) //every second get temperature and battery level + { + get_time2 = millis(); + renderVario(); + } + if (millis() >= (get_time3+5000) && push_write_eeprom) //Write conf in eeprom if request + { + push_write_eeprom = false; + EEPROM_writeAnything(0, conf); + } + +} + +void readButtons(){ + + long newLeft = knobLeft.read(); + if (newLeft != positionLeft) { + if (newLeft%2==0) { + if (newLeft > positionLeft){ //Right + if (!menuUsed && varioUsed == false) + menu.moveDown(); + else if (varioUsed == false) + renderMenu(menu.getCurrent(), MENU_RIGHT); + else if (varioUsed == true) + renderVolume(MENU_RIGHT); + } + else { //Left + if (!menuUsed && varioUsed == false) + menu.moveUp(); + else if (varioUsed == false) + renderMenu(menu.getCurrent(), MENU_LEFT); + else if (varioUsed == true) + renderVolume(MENU_LEFT); + } + } + positionLeft = newLeft; + } + + //if button enter is pressed + int reading = digitalRead(Enter); + if ((millis() - enterDebounceTime) > debounceDelay){ + + // in menu, clic an item + if (reading == LOW && lastEnterState == HIGH && varioUsed == false){ + enterDebounceTime = millis(); + menu.use(); + } + // in vario, button enter init timer + if (reading == LOW && lastEnterState == HIGH && varioUsed == true){ + enterDebounceTime = millis(); + get_time5 = millis(); + is_vario_button_push = true; + } + // in vario, stop button enter and go back to menu + if (reading == HIGH && lastEnterState == LOW && varioUsed == true && is_vario_button_push == true){ + enterDebounceTime = millis(); + is_vario_button_push = false; + menu.use(); + } + } + lastEnterState = reading; + + // in vario, if button enter is pressed 2 seconds, reset stats + if (millis() >= (get_time5+2000) && is_vario_button_push == true){ + + is_vario_button_push = false; + resetStats(); + + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE, BLACK); + get_time2 = millis(); //stop the refresh rendering vario + display.println(F("Reset")); + display.println(F("stats")); + display.print(F("Ok")); + display.display(); + + toneAC(500, 10, 100); + toneAC(500, 10, 100); + } + +}//end read button diff --git a/libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.cpp b/libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.cpp new file mode 100644 index 0000000..13633b4 --- /dev/null +++ b/libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + This is a library for the BMP085 pressure sensor + + Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout + ----> http://www.adafruit.com/products/391 + ----> http://www.adafruit.com/products/1603 + + These displays use I2C to communicate, 2 pins are required to interface. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ***************************************************************************/ +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include +#include +#include + +#include "Adafruit_BMP085_U.h" + +static bmp085_calib_data _bmp085_coeffs; // Last read accelerometer data will be available here +static uint8_t _bmp085Mode; + +#define BMP085_USE_DATASHEET_VALS (0) /* Set to 1 for sanity check */ + +/*************************************************************************** + PRIVATE FUNCTIONS + ***************************************************************************/ + +/**************************************************************************/ +/*! + @brief Writes an 8 bit value over I2C +*/ +/**************************************************************************/ +static void writeCommand(byte reg, byte value) +{ + Wire.beginTransmission((uint8_t)BMP085_ADDRESS); + #if ARDUINO >= 100 + Wire.write((uint8_t)reg); + Wire.write((uint8_t)value); + #else + Wire.send(reg); + Wire.send(value); + #endif + Wire.endTransmission(); +} + +/**************************************************************************/ +/*! + @brief Reads an 8 bit value over I2C +*/ +/**************************************************************************/ +static void read8(byte reg, uint8_t *value) +{ + Wire.beginTransmission((uint8_t)BMP085_ADDRESS); + #if ARDUINO >= 100 + Wire.write((uint8_t)reg); + #else + Wire.send(reg); + #endif + Wire.endTransmission(); + Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1); + #if ARDUINO >= 100 + *value = Wire.read(); + #else + *value = Wire.receive(); + #endif + Wire.endTransmission(); +} + +/**************************************************************************/ +/*! + @brief Reads a 16 bit value over I2C +*/ +/**************************************************************************/ +static void read16(byte reg, uint16_t *value) +{ + Wire.beginTransmission((uint8_t)BMP085_ADDRESS); + #if ARDUINO >= 100 + Wire.write((uint8_t)reg); + #else + Wire.send(reg); + #endif + Wire.endTransmission(); + Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2); + #if ARDUINO >= 100 + *value = (Wire.read() << 8) | Wire.read(); + #else + *value = (Wire.receive() << 8) | Wire.receive(); + #endif + Wire.endTransmission(); +} + +/**************************************************************************/ +/*! + @brief Reads a signed 16 bit value over I2C +*/ +/**************************************************************************/ +static void readS16(byte reg, int16_t *value) +{ + uint16_t i; + read16(reg, &i); + *value = (int16_t)i; +} + +/**************************************************************************/ +/*! + @brief Reads the factory-set coefficients +*/ +/**************************************************************************/ +static void readCoefficients(void) +{ + #if BMP085_USE_DATASHEET_VALS + _bmp085_coeffs.ac1 = 408; + _bmp085_coeffs.ac2 = -72; + _bmp085_coeffs.ac3 = -14383; + _bmp085_coeffs.ac4 = 32741; + _bmp085_coeffs.ac5 = 32757; + _bmp085_coeffs.ac6 = 23153; + _bmp085_coeffs.b1 = 6190; + _bmp085_coeffs.b2 = 4; + _bmp085_coeffs.mb = -32768; + _bmp085_coeffs.mc = -8711; + _bmp085_coeffs.md = 2868; + _bmp085Mode = 0; + #else + readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1); + readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2); + readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3); + read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4); + read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5); + read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6); + readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1); + readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2); + readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb); + readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc); + readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md); + #endif +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +static void readRawTemperature(int32_t *temperature) +{ + #if BMP085_USE_DATASHEET_VALS + *temperature = 27898; + #else + uint16_t t; + writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD); + delay(5); + read16(BMP085_REGISTER_TEMPDATA, &t); + *temperature = t; + #endif +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +static void readRawPressure(int32_t *pressure) +{ + #if BMP085_USE_DATASHEET_VALS + *pressure = 23843; + #else + uint8_t p8; + uint16_t p16; + int32_t p32; + + writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6)); + switch(_bmp085Mode) + { + case BMP085_MODE_ULTRALOWPOWER: + delay(5); + break; + case BMP085_MODE_STANDARD: + delay(8); + break; + case BMP085_MODE_HIGHRES: + delay(14); + break; + case BMP085_MODE_ULTRAHIGHRES: + default: + delay(26); + break; + } + + read16(BMP085_REGISTER_PRESSUREDATA, &p16); + p32 = (uint32_t)p16 << 8; + read8(BMP085_REGISTER_PRESSUREDATA+2, &p8); + p32 += p8; + p32 >>= (8 - _bmp085Mode); + + *pressure = p32; + #endif +} + +/*************************************************************************** + CONSTRUCTOR + ***************************************************************************/ + +/**************************************************************************/ +/*! + @brief Instantiates a new Adafruit_BMP085_Unified class +*/ +/**************************************************************************/ +Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) { + _sensorID = sensorID; +} + +/*************************************************************************** + PUBLIC FUNCTIONS + ***************************************************************************/ + +/**************************************************************************/ +/*! + @brief Setups the HW +*/ +/**************************************************************************/ +bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode) +{ + // Enable I2C + Wire.begin(); + + /* Mode boundary check */ + if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0)) + { + mode = BMP085_MODE_ULTRAHIGHRES; + } + + /* Make sure we have the right device */ + uint8_t id; + read8(BMP085_REGISTER_CHIPID, &id); + if(id != 0x55) + { + return false; + } + + /* Set the mode indicator */ + _bmp085Mode = mode; + + /* Coefficients need to be read once */ + readCoefficients(); + + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the compensated pressure level in kPa +*/ +/**************************************************************************/ +void Adafruit_BMP085_Unified::getPressure(float *pressure) +{ + int32_t ut = 0, up = 0, compp = 0; + int32_t x1, x2, b5, b6, x3, b3, p; + uint32_t b4, b7; + + /* Get the raw pressure and temperature values */ + readRawTemperature(&ut); + readRawPressure(&up); + + /* Temperature compensation */ + x1 = (ut - (int32_t)(_bmp085_coeffs.ac6))*((int32_t)(_bmp085_coeffs.ac5))/pow(2,15); + x2 = ((int32_t)(_bmp085_coeffs.mc*pow(2,11)))/(x1+(int32_t)(_bmp085_coeffs.md)); + b5 = x1 + x2; + + /* Pressure compensation */ + b6 = b5 - 4000; + x1 = (_bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11; + x2 = (_bmp085_coeffs.ac2 * b6) >> 11; + x3 = x1 + x2; + b3 = (((((int32_t) _bmp085_coeffs.ac1) * 4 + x3) << _bmp085Mode) + 2) >> 2; + x1 = (_bmp085_coeffs.ac3 * b6) >> 13; + x2 = (_bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16; + x3 = ((x1 + x2) + 2) >> 2; + b4 = (_bmp085_coeffs.ac4 * (uint32_t) (x3 + 32768)) >> 15; + b7 = ((uint32_t) (up - b3) * (50000 >> _bmp085Mode)); + + if (b7 < 0x80000000) + { + p = (b7 << 1) / b4; + } + else + { + p = (b7 / b4) << 1; + } + + x1 = (p >> 8) * (p >> 8); + x1 = (x1 * 3038) >> 16; + x2 = (-7357 * p) >> 16; + compp = p + ((x1 + x2 + 3791) >> 4); + + /* Assign compensated pressure value */ + *pressure = compp; +} + +/**************************************************************************/ +/*! + @brief Reads the temperatures in degrees Celsius +*/ +/**************************************************************************/ +void Adafruit_BMP085_Unified::getTemperature(float *temp) +{ + int32_t UT, X1, X2, B5; // following ds convention + float t; + + readRawTemperature(&UT); + + #if BMP085_USE_DATASHEET_VALS + // use datasheet numbers! + UT = 27898; + _bmp085_coeffs.ac6 = 23153; + _bmp085_coeffs.ac5 = 32757; + _bmp085_coeffs.mc = -8711; + _bmp085_coeffs.md = 2868; + #endif + + // step 1 + X1 = (UT - (int32_t)_bmp085_coeffs.ac6) * ((int32_t)_bmp085_coeffs.ac5) / pow(2,15); + X2 = ((int32_t)_bmp085_coeffs.mc * pow(2,11)) / (X1+(int32_t)_bmp085_coeffs.md); + B5 = X1 + X2; + t = (B5+8)/pow(2,4); + t /= 10; + + *temp = t; +} + +/**************************************************************************/ +/*! + Calculates the altitude (in meters) from the specified atmospheric + pressure (in hPa), sea-level pressure (in hPa), and temperature (in °C) + + @param seaLevel Sea-level pressure in hPa + @param atmospheric Atmospheric pressure in hPa + @param temp Temperature in degrees Celsius +*/ +/**************************************************************************/ +float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric, float temp) +{ + /* Hyposometric formula: */ + /* */ + /* ((P0/P)^(1/5.257) - 1) * (T + 273.15) */ + /* h = ------------------------------------- */ + /* 0.0065 */ + /* */ + /* where: h = height (in meters) */ + /* P0 = sea-level pressure (in hPa) */ + /* P = atmospheric pressure (in hPa) */ + /* T = temperature (in °C) */ + + return (((float)pow((seaLevel/atmospheric), 0.190223F) - 1.0F) + * (temp + 273.15F)) / 0.0065F; +} + +/**************************************************************************/ +/*! + @brief Provides the sensor_t data for this sensor +*/ +/**************************************************************************/ +void Adafruit_BMP085_Unified::getSensor(sensor_t *sensor) +{ + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy (sensor->name, "BMP085", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name)- 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_PRESSURE; + sensor->min_delay = 0; + sensor->max_value = 300.0F; // 300..1100 hPa + sensor->min_value = 1100.0F; + sensor->resolution = 0.01F; // Datasheet states 0.01 hPa resolution +} + +/**************************************************************************/ +/*! + @brief Reads the sensor and returns the data as a sensors_event_t +*/ +/**************************************************************************/ +void Adafruit_BMP085_Unified::getEvent(sensors_event_t *event) +{ + float pressure_kPa; + + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_PRESSURE; + event->timestamp = 0; + getPressure(&pressure_kPa); + event->pressure = pressure_kPa / 100.0F; /* kPa to hPa */ +} diff --git a/libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.h b/libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.h new file mode 100644 index 0000000..67bd007 --- /dev/null +++ b/libraries/Adafruit_BMP085_U/Adafruit_BMP085_U.h @@ -0,0 +1,109 @@ +/*************************************************************************** + This is a library for the BMP085 pressure sensor + + Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout + ----> http://www.adafruit.com/products/391 + ----> http://www.adafruit.com/products/1603 + + These displays use I2C to communicate, 2 pins are required to interface. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ***************************************************************************/ +#ifndef __BMP085_H__ +#define __BMP085_H__ + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include +#include + +/*========================================================================= + I2C ADDRESS/BITS + -----------------------------------------------------------------------*/ + #define BMP085_ADDRESS (0x77) +/*=========================================================================*/ + +/*========================================================================= + REGISTERS + -----------------------------------------------------------------------*/ + enum + { + BMP085_REGISTER_CAL_AC1 = 0xAA, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_AC2 = 0xAC, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_AC3 = 0xAE, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_AC4 = 0xB0, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_AC5 = 0xB2, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_AC6 = 0xB4, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_B1 = 0xB6, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_B2 = 0xB8, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_MB = 0xBA, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_MC = 0xBC, // R Calibration data (16 bits) + BMP085_REGISTER_CAL_MD = 0xBE, // R Calibration data (16 bits) + BMP085_REGISTER_CHIPID = 0xD0, + BMP085_REGISTER_VERSION = 0xD1, + BMP085_REGISTER_SOFTRESET = 0xE0, + BMP085_REGISTER_CONTROL = 0xF4, + BMP085_REGISTER_TEMPDATA = 0xF6, + BMP085_REGISTER_PRESSUREDATA = 0xF6, + BMP085_REGISTER_READTEMPCMD = 0x2E, + BMP085_REGISTER_READPRESSURECMD = 0x34 + }; +/*=========================================================================*/ + +/*========================================================================= + MODE SETTINGS + -----------------------------------------------------------------------*/ + typedef enum + { + BMP085_MODE_ULTRALOWPOWER = 0, + BMP085_MODE_STANDARD = 1, + BMP085_MODE_HIGHRES = 2, + BMP085_MODE_ULTRAHIGHRES = 3 + } bmp085_mode_t; +/*=========================================================================*/ + +/*========================================================================= + CALIBRATION DATA + -----------------------------------------------------------------------*/ + typedef struct + { + int16_t ac1; + int16_t ac2; + int16_t ac3; + uint16_t ac4; + uint16_t ac5; + uint16_t ac6; + int16_t b1; + int16_t b2; + int16_t mb; + int16_t mc; + int16_t md; + } bmp085_calib_data; +/*=========================================================================*/ + +class Adafruit_BMP085_Unified : public Adafruit_Sensor +{ + public: + Adafruit_BMP085_Unified(int32_t sensorID = -1); + + bool begin(bmp085_mode_t mode = BMP085_MODE_ULTRAHIGHRES); + void getTemperature(float *temp); + void getPressure(float *pressure); + float pressureToAltitude(float seaLevel, float atmospheric, float temp); + void getEvent(sensors_event_t*); + void getSensor(sensor_t*); + + private: + int32_t _sensorID; +}; + +#endif diff --git a/libraries/Adafruit_BMP085_U/README.md b/libraries/Adafruit_BMP085_U/README.md new file mode 100644 index 0000000..0b70b25 --- /dev/null +++ b/libraries/Adafruit_BMP085_U/README.md @@ -0,0 +1,27 @@ +#Adafruit Unified BMP085 Driver (Barometric Pressure Sensor) # + +This driver is for the Adafruit BMP085 Breakout (http://www.adafruit.com/products/391), and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor). + +## About the BMP085 ## + +This precision sensor from Bosch is the best low-cost sensing solution for measuring barometric pressure and temperature. Because pressure changes with altitude you can also use it as an altimeter! + +## What is the Adafruit Unified Sensor Library? ## + +The Adafruit Unified Sensor Library ([Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type. + +It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class). + +This is imporant useful for two reasons: + +1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023. + +2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks when working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc. + +Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean. + +## About this Driver ## + +Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit! + +Written by Kevin (KTOWN) Townsend for Adafruit Industries. \ No newline at end of file diff --git a/libraries/Adafruit_BMP085_U/examples/sensorapi/sensorapi.pde b/libraries/Adafruit_BMP085_U/examples/sensorapi/sensorapi.pde new file mode 100644 index 0000000..73d5150 --- /dev/null +++ b/libraries/Adafruit_BMP085_U/examples/sensorapi/sensorapi.pde @@ -0,0 +1,133 @@ +#include +#include +#include + +/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor), + which provides a common 'type' for sensor data and some helper functions. + + To use this driver you will also need to download the Adafruit_Sensor + library and include it in your libraries folder. + + You should also assign a unique ID to this sensor for use with + the Adafruit Sensor API so that you can identify this particular + sensor in any data logs, etc. To assign a unique ID, simply + provide an appropriate value in the constructor below (12345 + is used by default in this example). + + Connections + =========== + Connect SCL to analog 5 + Connect SDA to analog 4 + Connect VDD to 3.3V DC + Connect GROUND to common ground + + History + ======= + 2013/JUN/17 - Updated altitude calculations (KTOWN) + 2013/FEB/13 - First version (KTOWN) +*/ + +Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085); + +/**************************************************************************/ +/* + Displays some basic information on this sensor from the unified + sensor API sensor_t type (see Adafruit_Sensor for more information) +*/ +/**************************************************************************/ +void displaySensorDetails(void) +{ + sensor_t sensor; + bmp.getSensor(&sensor); + Serial.println("------------------------------------"); + Serial.print ("Sensor: "); Serial.println(sensor.name); + Serial.print ("Driver Ver: "); Serial.println(sensor.version); + Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); + Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" hPa"); + Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" hPa"); + Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" hPa"); + Serial.println("------------------------------------"); + Serial.println(""); + delay(500); +} + +/**************************************************************************/ +/* + Arduino setup function (automatically called at startup) +*/ +/**************************************************************************/ +void setup(void) +{ + Serial.begin(9600); + Serial.println("Pressure Sensor Test"); Serial.println(""); + + /* Initialise the sensor */ + if(!bmp.begin()) + { + /* There was a problem detecting the BMP085 ... check your connections */ + Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!"); + while(1); + } + + /* Display some basic information on this sensor */ + displaySensorDetails(); +} + +/**************************************************************************/ +/* + Arduino loop function, called once 'setup' is complete (your own code + should go here) +*/ +/**************************************************************************/ +void loop(void) +{ + /* Get a new sensor event */ + sensors_event_t event; + bmp.getEvent(&event); + + /* Display the results (barometric pressure is measure in hPa) */ + if (event.pressure) + { + /* Display atmospheric pressue in hPa */ + Serial.print("Pressure: "); + Serial.print(event.pressure); + Serial.println(" hPa"); + + /* Calculating altitude with reasonable accuracy requires pressure * + * sea level pressure for your position at the moment the data is * + * converted, as well as the ambient temperature in degress * + * celcius. If you don't have these values, a 'generic' value of * + * 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA * + * in sensors.h), but this isn't ideal and will give variable * + * results from one day to the next. * + * * + * You can usually find the current SLP value by looking at weather * + * websites or from environmental information centers near any major * + * airport. * + * * + * For example, for Paris, France you can check the current mean * + * pressure and sea level at: http://bit.ly/16Au8ol */ + + /* First we get the current temperature from the BMP085 */ + float temperature; + bmp.getTemperature(&temperature); + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.println(" C"); + + /* Then convert the atmospheric pressure, SLP and temp to altitude */ + /* Update this next line with the current SLP for better results */ + float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA; + Serial.print("Altitude: "); + Serial.print(bmp.pressureToAltitude(seaLevelPressure, + event.pressure, + temperature)); + Serial.println(" m"); + Serial.println(""); + } + else + { + Serial.println("Sensor error"); + } + delay(1000); +} diff --git a/libraries/Adafruit_GFX/Adafruit_GFX.cpp b/libraries/Adafruit_GFX/Adafruit_GFX.cpp new file mode 100644 index 0000000..f043a4d --- /dev/null +++ b/libraries/Adafruit_GFX/Adafruit_GFX.cpp @@ -0,0 +1,480 @@ +/* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "Adafruit_GFX.h" +#include "glcdfont.c" +#ifdef __AVR__ + #include +#else + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif + +Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): + WIDTH(w), HEIGHT(h) +{ + _width = WIDTH; + _height = HEIGHT; + rotation = 0; + cursor_y = cursor_x = 0; + textsize = 1; + textcolor = textbgcolor = 0xFFFF; + wrap = true; +} + +// Draw a circle outline +void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + drawPixel(x0 , y0+r, color); + drawPixel(x0 , y0-r, color); + drawPixel(x0+r, y0 , color); + drawPixel(x0-r, y0 , color); + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 - x, y0 + y, color); + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 - x, y0 - y, color); + drawPixel(x0 + y, y0 + x, color); + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 + y, y0 - x, color); + drawPixel(x0 - y, y0 - x, color); + } +} + +void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, + int16_t r, uint8_t cornername, uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 + y, y0 + x, color); + } + if (cornername & 0x2) { + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 + y, y0 - x, color); + } + if (cornername & 0x8) { + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 - x, y0 + y, color); + } + if (cornername & 0x1) { + drawPixel(x0 - y, y0 - x, color); + drawPixel(x0 - x, y0 - y, color); + } + } +} + +void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { + drawFastVLine(x0, y0-r, 2*r+1, color); + fillCircleHelper(x0, y0, r, 3, 0, color); +} + +// Used to do circles and roundrects +void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, + uint8_t cornername, int16_t delta, uint16_t color) { + + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + if (cornername & 0x1) { + drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); + drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); + } + if (cornername & 0x2) { + drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); + drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); + } + } +} + +// Bresenham's algorithm - thx wikpedia +void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, + int16_t x1, int16_t y1, + uint16_t color) { + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + swap(x0, y0); + swap(x1, y1); + } + + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0<=x1; x0++) { + if (steep) { + drawPixel(y0, x0, color); + } else { + drawPixel(x0, y0, color); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +// Draw a rectangle +void Adafruit_GFX::drawRect(int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t color) { + drawFastHLine(x, y, w, color); + drawFastHLine(x, y+h-1, w, color); + drawFastVLine(x, y, h, color); + drawFastVLine(x+w-1, y, h, color); +} + +void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, + int16_t h, uint16_t color) { + // Update in subclasses if desired! + drawLine(x, y, x, y+h-1, color); +} + +void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, + int16_t w, uint16_t color) { + // Update in subclasses if desired! + drawLine(x, y, x+w-1, y, color); +} + +void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + // Update in subclasses if desired! + for (int16_t i=x; i= y1 >= y0) + if (y0 > y1) { + swap(y0, y1); swap(x0, x1); + } + if (y1 > y2) { + swap(y2, y1); swap(x2, x1); + } + if (y0 > y1) { + swap(y0, y1); swap(x0, x1); + } + + if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if(x1 < a) a = x1; + else if(x1 > b) b = x1; + if(x2 < a) a = x2; + else if(x2 > b) b = x2; + drawFastHLine(a, y0, b-a+1, color); + return; + } + + int16_t + dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1, + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if(y1 == y2) last = y1; // Include y1 scanline + else last = y1-1; // Skip it + + for(y=y0; y<=last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) swap(a,b); + drawFastHLine(a, y, b-a+1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for(; y<=y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) swap(a,b); + drawFastHLine(a, y, b-a+1, color); + } +} + +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, + const uint8_t *bitmap, int16_t w, int16_t h, + uint16_t color) { + + int16_t i, j, byteWidth = (w + 7) / 8; + + for(j=0; j> (i & 7))) { + drawPixel(x+i, y+j, color); + } + } + } +} + +#if ARDUINO >= 100 +size_t Adafruit_GFX::write(uint8_t c) { +#else +void Adafruit_GFX::write(uint8_t c) { +#endif + if (c == '\n') { + cursor_y += textsize*8; + cursor_x = 0; + } else if (c == '\r') { + // skip em + } else { + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); + cursor_x += textsize*6; + if (wrap && (cursor_x > (_width - textsize*6))) { + cursor_y += textsize*8; + cursor_x = 0; + } + } +#if ARDUINO >= 100 + return 1; +#endif +} + +// Draw a character +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg, uint8_t size) { + + if((x >= _width) || // Clip right + (y >= _height) || // Clip bottom + ((x + 6 * size - 1) < 0) || // Clip left + ((y + 8 * size - 1) < 0)) // Clip top + return; + + for (int8_t i=0; i<6; i++ ) { + uint8_t line; + if (i == 5) + line = 0x0; + else + line = pgm_read_byte(font+(c*5)+i); + for (int8_t j = 0; j<8; j++) { + if (line & 0x1) { + if (size == 1) // default size + drawPixel(x+i, y+j, color); + else { // big size + fillRect(x+(i*size), y+(j*size), size, size, color); + } + } else if (bg != color) { + if (size == 1) // default size + drawPixel(x+i, y+j, bg); + else { // big size + fillRect(x+i*size, y+j*size, size, size, bg); + } + } + line >>= 1; + } + } +} + +void Adafruit_GFX::setCursor(int16_t x, int16_t y) { + cursor_x = x; + cursor_y = y; +} + +void Adafruit_GFX::setTextSize(uint8_t s) { + textsize = (s > 0) ? s : 1; +} + +void Adafruit_GFX::setTextColor(uint16_t c) { + // For 'transparent' background, we'll set the bg + // to the same as fg instead of using a flag + textcolor = textbgcolor = c; +} + +void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { + textcolor = c; + textbgcolor = b; +} + +void Adafruit_GFX::setTextWrap(boolean w) { + wrap = w; +} + +uint8_t Adafruit_GFX::getRotation(void) { + return rotation; +} + +void Adafruit_GFX::setRotation(uint8_t x) { + rotation = (x & 3); + switch(rotation) { + case 0: + case 2: + _width = WIDTH; + _height = HEIGHT; + break; + case 1: + case 3: + _width = HEIGHT; + _height = WIDTH; + break; + } +} + +// Return the size of the display (per current rotation) +int16_t Adafruit_GFX::width(void) { + return _width; +} + +int16_t Adafruit_GFX::height(void) { + return _height; +} + +void Adafruit_GFX::invertDisplay(boolean i) { + // Do nothing, must be subclassed if supported +} + diff --git a/libraries/Adafruit_GFX/Adafruit_GFX.h b/libraries/Adafruit_GFX/Adafruit_GFX.h new file mode 100644 index 0000000..7d049e7 --- /dev/null +++ b/libraries/Adafruit_GFX/Adafruit_GFX.h @@ -0,0 +1,87 @@ +#ifndef _ADAFRUIT_GFX_H +#define _ADAFRUIT_GFX_H + +#if ARDUINO >= 100 + #include "Arduino.h" + #include "Print.h" +#else + #include "WProgram.h" +#endif + +#define swap(a, b) { int16_t t = a; a = b; b = t; } + +class Adafruit_GFX : public Print { + + public: + + Adafruit_GFX(int16_t w, int16_t h); // Constructor + + // This MUST be defined by the subclass: + virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; + + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void + drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color), + drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), + drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), + drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), + fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), + fillScreen(uint16_t color), + invertDisplay(boolean i); + + // These exist only with Adafruit_GFX (no subclass overrides) + void + drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), + drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, + uint16_t color), + fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), + fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, + int16_t delta, uint16_t color), + drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color), + fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color), + drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, + int16_t radius, uint16_t color), + fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, + int16_t radius, uint16_t color), + drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, + int16_t w, int16_t h, uint16_t color), + drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, + uint16_t bg, uint8_t size), + setCursor(int16_t x, int16_t y), + setTextColor(uint16_t c), + setTextColor(uint16_t c, uint16_t bg), + setTextSize(uint8_t s), + setTextWrap(boolean w), + setRotation(uint8_t r); + +#if ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + + int16_t + height(void), + width(void); + + uint8_t getRotation(void); + + protected: + const int16_t + WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes + int16_t + _width, _height, // Display w/h as modified by current rotation + cursor_x, cursor_y; + uint16_t + textcolor, textbgcolor; + uint8_t + textsize, + rotation; + boolean + wrap; // If set, 'wrap' text at right edge of display +}; + +#endif // _ADAFRUIT_GFX_H diff --git a/libraries/Adafruit_GFX/README.txt b/libraries/Adafruit_GFX/README.txt new file mode 100644 index 0000000..39ccbec --- /dev/null +++ b/libraries/Adafruit_GFX/README.txt @@ -0,0 +1,11 @@ +This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information. +All text above must be included in any redistribution. + +To download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX. Confirm that the Adafruit_GFX folder contains Adafruit_GFX.cpp and Adafruit_GFX.h + +Place the Adafruit_GFX library folder your /Libraries/ folder. You may need to create the Libraries subfolder if its your first library. Restart the IDE. diff --git a/libraries/Adafruit_GFX/glcdfont.c b/libraries/Adafruit_GFX/glcdfont.c new file mode 100644 index 0000000..d016b93 --- /dev/null +++ b/libraries/Adafruit_GFX/glcdfont.c @@ -0,0 +1,270 @@ +#ifndef FONT5X7_H +#define FONT5X7_H + +#ifdef __AVR__ + #include + #include +#else + #define PROGMEM +#endif + +// Standard ASCII 5x7 font + +static const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x21, 0x54, 0x54, 0x78, 0x41, + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0xF0, 0x29, 0x24, 0x29, 0xF0, + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x32, 0x48, 0x48, 0x48, 0x32, + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x39, 0x44, 0x44, 0x44, 0x39, + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0xAA, 0x00, 0x55, 0x00, 0xAA, + 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0x7C, 0x2A, 0x2A, 0x3E, 0x14, + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif // FONT5X7_H diff --git a/libraries/Adafruit_GFX/license.txt b/libraries/Adafruit_GFX/license.txt new file mode 100644 index 0000000..7492e93 --- /dev/null +++ b/libraries/Adafruit_GFX/license.txt @@ -0,0 +1,24 @@ +Software License Agreement (BSD License) + +Copyright (c) 2012 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp b/libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp new file mode 100644 index 0000000..a3d9cf2 --- /dev/null +++ b/libraries/Adafruit_PCD8544/Adafruit_PCD8544.cpp @@ -0,0 +1,312 @@ +/********************************************************************* +This is a library for our Monochrome Nokia 5110 LCD Displays + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/products/338 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above, and the splash screen below must be included in any redistribution +*********************************************************************/ + +//#include +#include +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include +#include + +#include +#include "Adafruit_PCD8544.h" + +// the memory buffer for the LCD +uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, +0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF, +0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, +0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87, +0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, +0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, +0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, +0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +// reduces how much is refreshed, which speeds it up! +// originally derived from Steve Evans/JCW's mod but cleaned up and +// optimized +//#define enablePartialUpdate + +#ifdef enablePartialUpdate +static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax; +#endif + + + +static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) { +#ifdef enablePartialUpdate + if (xmin < xUpdateMin) xUpdateMin = xmin; + if (xmax > xUpdateMax) xUpdateMax = xmax; + if (ymin < yUpdateMin) yUpdateMin = ymin; + if (ymax > yUpdateMax) yUpdateMax = ymax; +#endif +} + +Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, + int8_t CS, int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) { + _din = DIN; + _sclk = SCLK; + _dc = DC; + _rst = RST; + _cs = CS; +} + +Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, + int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) { + _din = DIN; + _sclk = SCLK; + _dc = DC; + _rst = RST; + _cs = -1; +} + + +// the most basic function, set a single pixel +void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) { + if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT)) + return; + + // x is which column + if (color) + pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8); + else + pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); + + updateBoundingBox(x,y,x,y); +} + + +// the most basic function, get a single pixel +uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) { + if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT)) + return 0; + + return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1; +} + + +void Adafruit_PCD8544::begin(uint8_t contrast) { + // set pin directions + pinMode(_din, OUTPUT); + pinMode(_sclk, OUTPUT); + pinMode(_dc, OUTPUT); + if (_rst > 0) + pinMode(_rst, OUTPUT); + if (_cs > 0) + pinMode(_cs, OUTPUT); + + // toggle RST low to reset + if (_rst > 0) { + digitalWrite(_rst, LOW); + _delay_ms(500); + digitalWrite(_rst, HIGH); + } + + clkport = portOutputRegister(digitalPinToPort(_sclk)); + clkpinmask = digitalPinToBitMask(_sclk); + mosiport = portOutputRegister(digitalPinToPort(_din)); + mosipinmask = digitalPinToBitMask(_din); + csport = portOutputRegister(digitalPinToPort(_cs)); + cspinmask = digitalPinToBitMask(_cs); + dcport = portOutputRegister(digitalPinToPort(_dc)); + dcpinmask = digitalPinToBitMask(_dc); + + // get into the EXTENDED mode! + command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION ); + + // LCD bias select (4 is optimal?) + command(PCD8544_SETBIAS | 0x4); + + // set VOP + if (contrast > 0x7f) + contrast = 0x7f; + + command( PCD8544_SETVOP | contrast); // Experimentally determined + + + // normal mode + command(PCD8544_FUNCTIONSET); + + // Set display to Normal + command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL); + + // initial display line + // set page address + // set column address + // write display data + + // set up a bounding box for screen updates + + updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); + // Push out pcd8544_buffer to the Display (will show the AFI logo) + display(); +} + + +inline void Adafruit_PCD8544::fastSPIwrite(uint8_t d) { + + for(uint8_t bit = 0x80; bit; bit >>= 1) { + *clkport &= ~clkpinmask; + if(d & bit) *mosiport |= mosipinmask; + else *mosiport &= ~mosipinmask; + *clkport |= clkpinmask; + } +} + +inline void Adafruit_PCD8544::slowSPIwrite(uint8_t c) { + shiftOut(_din, _sclk, MSBFIRST, c); +} + +void Adafruit_PCD8544::command(uint8_t c) { + digitalWrite(_dc, LOW); + if (_cs > 0) + digitalWrite(_cs, LOW); + fastSPIwrite(c); + if (_cs > 0) + digitalWrite(_cs, HIGH); +} + +void Adafruit_PCD8544::data(uint8_t c) { + digitalWrite(_dc, HIGH); + if (_cs > 0) + digitalWrite(_cs, LOW); + fastSPIwrite(c); + if (_cs > 0) + digitalWrite(_cs, HIGH); +} + +void Adafruit_PCD8544::setContrast(uint8_t val) { + if (val > 0x7f) { + val = 0x7f; + } + command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION ); + command( PCD8544_SETVOP | val); + command(PCD8544_FUNCTIONSET); + + } + + + +void Adafruit_PCD8544::display(void) { + uint8_t col, maxcol, p; + + for(p = 0; p < 6; p++) { +#ifdef enablePartialUpdate + // check if this page is part of update + if ( yUpdateMin >= ((p+1)*8) ) { + continue; // nope, skip it! + } + if (yUpdateMax < p*8) { + break; + }d +#endif + + command(PCD8544_SETYADDR | p); + + +#ifdef enablePartialUpdate + col = xUpdateMin; + maxcol = xUpdateMax; +#else + // start at the beginning of the row + col = 0; + maxcol = LCDWIDTH-1; +#endif + + command(PCD8544_SETXADDR | col); + + digitalWrite(_dc, HIGH); + if (_cs > 0) + digitalWrite(_cs, LOW); + for(; col <= maxcol; col++) { + //uart_putw_dec(col); + //uart_putchar(' '); + fastSPIwrite(pcd8544_buffer[(LCDWIDTH*p)+col]); + } + if (_cs > 0) + digitalWrite(_cs, HIGH); + + } + + command(PCD8544_SETYADDR ); // no idea why this is necessary but it is to finish the last byte? +#ifdef enablePartialUpdate + xUpdateMin = LCDWIDTH - 1; + xUpdateMax = 0; + yUpdateMin = LCDHEIGHT-1; + yUpdateMax = 0; +#endif + +} + +// clear everything +void Adafruit_PCD8544::clearDisplay(void) { + memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8); + updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); + cursor_y = cursor_x = 0; +} + +/* +// this doesnt touch the buffer, just clears the display RAM - might be handy +void Adafruit_PCD8544::clearDisplay(void) { + + uint8_t p, c; + + for(p = 0; p < 8; p++) { + + st7565_command(CMD_SET_PAGE | p); + for(c = 0; c < 129; c++) { + //uart_putw_dec(c); + //uart_putchar(' '); + st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf)); + st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf)); + st7565_data(0x0); + } + } + +} + +*/ diff --git a/libraries/Adafruit_PCD8544/Adafruit_PCD8544.h b/libraries/Adafruit_PCD8544/Adafruit_PCD8544.h new file mode 100644 index 0000000..1e234f5 --- /dev/null +++ b/libraries/Adafruit_PCD8544/Adafruit_PCD8544.h @@ -0,0 +1,76 @@ +/********************************************************************* +This is a library for our Monochrome Nokia 5110 LCD Displays + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/products/338 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above, and the splash screen must be included in any redistribution +*********************************************************************/ + +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" + #include "pins_arduino.h" +#endif + +#define BLACK 1 +#define WHITE 0 + +#define LCDWIDTH 84 +#define LCDHEIGHT 48 + +#define PCD8544_POWERDOWN 0x04 +#define PCD8544_ENTRYMODE 0x02 +#define PCD8544_EXTENDEDINSTRUCTION 0x01 + +#define PCD8544_DISPLAYBLANK 0x0 +#define PCD8544_DISPLAYNORMAL 0x4 +#define PCD8544_DISPLAYALLON 0x1 +#define PCD8544_DISPLAYINVERTED 0x5 + +// H = 0 +#define PCD8544_FUNCTIONSET 0x20 +#define PCD8544_DISPLAYCONTROL 0x08 +#define PCD8544_SETYADDR 0x40 +#define PCD8544_SETXADDR 0x80 + +// H = 1 +#define PCD8544_SETTEMP 0x04 +#define PCD8544_SETBIAS 0x10 +#define PCD8544_SETVOP 0x80 + +class Adafruit_PCD8544 : public Adafruit_GFX { + public: + Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, int8_t CS, int8_t RST); + Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, int8_t RST); + + void begin(uint8_t contrast = 40); + + void command(uint8_t c); + void data(uint8_t c); + + void setContrast(uint8_t val); + void clearDisplay(void); + void display(); + + void drawPixel(int16_t x, int16_t y, uint16_t color); + uint8_t getPixel(int8_t x, int8_t y); + + private: + int8_t _din, _sclk, _dc, _rst, _cs; + volatile uint8_t *mosiport, *clkport, *csport, *dcport; + uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask; + + void slowSPIwrite(uint8_t c); + void fastSPIwrite(uint8_t c); +}; diff --git a/libraries/Adafruit_PCD8544/README.txt b/libraries/Adafruit_PCD8544/README.txt new file mode 100644 index 0000000..d75f730 --- /dev/null +++ b/libraries/Adafruit_PCD8544/README.txt @@ -0,0 +1,23 @@ +This is a library for our Monochrome Nokia 5110 LCD Displays + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/products/338 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution + +To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_PCD8544. Check that the Adafruit_PCD8544 folder contains Adafruit_PCD8544.cpp and Adafruit_PCD8544.h + +Place the Adafruit_PCD8544 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. + +You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from +https://github.com/adafruit/Adafruit-GFX-Library +and download/install that library as well \ No newline at end of file diff --git a/libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.pde b/libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.pde new file mode 100644 index 0000000..4853f78 --- /dev/null +++ b/libraries/Adafruit_PCD8544/examples/pcdtest/pcdtest.pde @@ -0,0 +1,323 @@ +/********************************************************************* +This is an example sketch for our Monochrome Nokia 5110 LCD Displays + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/products/338 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above, and the splash screen must be included in any redistribution +*********************************************************************/ + +#include +#include + +// pin 7 - Serial clock out (SCLK) +// pin 6 - Serial data out (DIN) +// pin 5 - Data/Command select (D/C) +// pin 4 - LCD chip select (CS) +// pin 3 - LCD reset (RST) +Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3); + +#define NUMFLAKES 10 +#define XPOS 0 +#define YPOS 1 +#define DELTAY 2 + + +#define LOGO16_GLCD_HEIGHT 16 +#define LOGO16_GLCD_WIDTH 16 + +static unsigned char PROGMEM logo16_glcd_bmp[] = +{ B00000000, B11000000, + B00000001, B11000000, + B00000001, B11000000, + B00000011, B11100000, + B11110011, B11100000, + B11111110, B11111000, + B01111110, B11111111, + B00110011, B10011111, + B00011111, B11111100, + B00001101, B01110000, + B00011011, B10100000, + B00111111, B11100000, + B00111111, B11110000, + B01111100, B11110000, + B01110000, B01110000, + B00000000, B00110000 }; + +void setup() { + Serial.begin(9600); + + display.begin(); + // init done + + // you can change the contrast around to adapt the display + // for the best viewing! + display.setContrast(50); + + display.display(); // show splashscreen + delay(2000); + display.clearDisplay(); // clears the screen and buffer + + // draw a single pixel + display.drawPixel(10, 10, BLACK); + display.display(); + delay(2000); + display.clearDisplay(); + + // draw many lines + testdrawline(); + display.display(); + delay(2000); + display.clearDisplay(); + + // draw rectangles + testdrawrect(); + display.display(); + delay(2000); + display.clearDisplay(); + + // draw multiple rectangles + testfillrect(); + display.display(); + delay(2000); + display.clearDisplay(); + + // draw mulitple circles + testdrawcircle(); + display.display(); + delay(2000); + display.clearDisplay(); + + // draw a circle, 10 pixel radius + display.fillCircle(display.width()/2, display.height()/2, 10, BLACK); + display.display(); + delay(2000); + display.clearDisplay(); + + testdrawroundrect(); + delay(2000); + display.clearDisplay(); + + testfillroundrect(); + delay(2000); + display.clearDisplay(); + + testdrawtriangle(); + delay(2000); + display.clearDisplay(); + + testfilltriangle(); + delay(2000); + display.clearDisplay(); + + // draw the first ~12 characters in the font + testdrawchar(); + display.display(); + delay(2000); + display.clearDisplay(); + + // text display tests + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,0); + display.println("Hello, world!"); + display.setTextColor(WHITE, BLACK); // 'inverted' text + display.println(3.141592); + display.setTextSize(2); + display.setTextColor(BLACK); + display.print("0x"); display.println(0xDEADBEEF, HEX); + display.display(); + delay(2000); + + // miniature bitmap display + display.clearDisplay(); + display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); + display.display(); + + // invert the display + display.invertDisplay(true); + delay(1000); + display.invertDisplay(false); + delay(1000); + + // draw a bitmap icon and 'animate' movement + testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); +} + + +void loop() { + +} + + +void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { + uint8_t icons[NUMFLAKES][3]; + srandom(666); // whatever seed + + // initialize + for (uint8_t f=0; f< NUMFLAKES; f++) { + icons[f][XPOS] = random() % display.width(); + icons[f][YPOS] = 0; + icons[f][DELTAY] = random() % 5 + 1; + + Serial.print("x: "); + Serial.print(icons[f][XPOS], DEC); + Serial.print(" y: "); + Serial.print(icons[f][YPOS], DEC); + Serial.print(" dy: "); + Serial.println(icons[f][DELTAY], DEC); + } + + while (1) { + // draw each icon + for (uint8_t f=0; f< NUMFLAKES; f++) { + display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); + } + display.display(); + delay(200); + + // then erase it + move it + for (uint8_t f=0; f< NUMFLAKES; f++) { + display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); + // move it + icons[f][YPOS] += icons[f][DELTAY]; + // if its gone, reinit + if (icons[f][YPOS] > display.height()) { + icons[f][XPOS] = random() % display.width(); + icons[f][YPOS] = 0; + icons[f][DELTAY] = random() % 5 + 1; + } + } + } +} + + +void testdrawchar(void) { + display.setTextSize(1); + display.setTextColor(BLACK); + display.setCursor(0,0); + + for (uint8_t i=0; i < 168; i++) { + if (i == '\n') continue; + display.write(i); + //if ((i > 0) && (i % 14 == 0)) + //display.println(); + } + display.display(); +} + +void testdrawcircle(void) { + for (int16_t i=0; i0; i-=5) { + display.fillTriangle(display.width()/2, display.height()/2-i, + display.width()/2-i, display.height()/2+i, + display.width()/2+i, display.height()/2+i, color); + if (color == WHITE) color = BLACK; + else color = WHITE; + display.display(); + } +} + +void testdrawroundrect(void) { + for (int16_t i=0; i=0; i-=4) { + display.drawLine(0, display.height()-1, display.width()-1, i, BLACK); + display.display(); + } + delay(250); + + display.clearDisplay(); + for (int16_t i=display.width()-1; i>=0; i-=4) { + display.drawLine(display.width()-1, display.height()-1, i, 0, BLACK); + display.display(); + } + for (int16_t i=display.height()-1; i>=0; i-=4) { + display.drawLine(display.width()-1, display.height()-1, 0, i, BLACK); + display.display(); + } + delay(250); + + display.clearDisplay(); + for (int16_t i=0; i + +void Adafruit_Sensor::constructor() { +} diff --git a/libraries/Adafruit_Sensor/Adafruit_Sensor.h b/libraries/Adafruit_Sensor/Adafruit_Sensor.h new file mode 100644 index 0000000..967c9e9 --- /dev/null +++ b/libraries/Adafruit_Sensor/Adafruit_Sensor.h @@ -0,0 +1,150 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software< /span> +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and + * extended sensor support to include color, voltage and current */ + +#ifndef _ADAFRUIT_SENSOR_H +#define _ADAFRUIT_SENSOR_H + +#if ARDUINO >= 100 + #include "Arduino.h" + #include "Print.h" +#else + #include "WProgram.h" +#endif + +/* Intentionally modeled after sensors.h in the Android API: + * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */ + +/* Constants */ +#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ +#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ +#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ +#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) +#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */ +#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */ +#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ +#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */ +#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */ + +/** Sensor types */ +typedef enum +{ + SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */ + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17) +} sensors_type_t; + +/** struct sensors_vec_s is used to return a vector in a common format. */ +typedef struct { + union { + float v[3]; + struct { + float x; + float y; + float z; + }; + /* Orientation sensors */ + struct { + float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */ + float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */ + float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */ + }; + }; + int8_t status; + uint8_t reserved[3]; +} sensors_vec_t; + +/** struct sensors_color_s is used to return color data in a common format. */ +typedef struct { + union { + float c[3]; + /* RGB color space */ + struct { + float r; /**< Red component */ + float g; /**< Green component */ + float b; /**< Blue component */ + }; + }; + uint32_t rgba; /**< 24-bit RGBA value */ +} sensors_color_t; + +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common format. */ +typedef struct +{ + int32_t version; /**< must be sizeof(struct sensors_event_t) */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< sensor type */ + int32_t reserved0; /**< reserved */ + int32_t timestamp; /**< time is in milliseconds */ + union + { + float data[4]; + sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */ + sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ + sensors_vec_t orientation; /**< orientation values are in degrees */ + sensors_vec_t gyro; /**< gyroscope values are in rad/s */ + float temperature; /**< temperature is in degrees centigrade (Celsius) */ + float distance; /**< distance in centimeters */ + float light; /**< light in SI lux units */ + float pressure; /**< pressure in hectopascal (hPa) */ + float relative_humidity; /**< relative humidity in percent */ + float current; /**< current in milliamps (mA) */ + float voltage; /**< voltage in volts (V) */ + sensors_color_t color; /**< color in RGB component values */ + }; +} sensors_event_t; + +/* Sensor details (40 bytes) */ +/** struct sensor_s is used to describe basic information about a specific sensor. */ +typedef struct +{ + char name[12]; /**< sensor name */ + int32_t version; /**< version of the hardware + driver */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */ + float max_value; /**< maximum value of this sensor's value in SI units */ + float min_value; /**< minimum value of this sensor's value in SI units */ + float resolution; /**< smallest difference between two values reported by this sensor */ + int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */ +} sensor_t; + +class Adafruit_Sensor { + public: + // Constructor(s) + // Adafruit_Sensor(); + void constructor(); + + // These must be defined by the subclass + virtual void getEvent(sensors_event_t*); + virtual void getSensor(sensor_t*); +}; + +#endif diff --git a/libraries/Adafruit_Sensor/README.md b/libraries/Adafruit_Sensor/README.md new file mode 100644 index 0000000..40767d7 --- /dev/null +++ b/libraries/Adafruit_Sensor/README.md @@ -0,0 +1,211 @@ +# Adafruit Unified Sensor Driver # + +Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing. + +One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road. + +Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement. + +By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse. + +The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire. + +## Unified Sensor Drivers ## + +The following drivers are based on the Adafruit Unified Sensor Driver: + +**Accelerometers** + - [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345) + - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC) + +**Gyroscope** + - [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U) + +**Light** + - [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561) + +**Magnetometers** + - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC) + +**Barometric Pressure** + - [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified) + +## How Does it Work? ## + +Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values: + +**Sensor Types (sensors\_type\_t)** + +These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc. + +``` +/** Sensor types */ +typedef enum +{ + SENSOR_TYPE_ACCELEROMETER = (1), + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = (10), + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17) +} sensors_type_t; +``` + +**Sensor Details (sensor\_t)** + +This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer. + +``` +/* Sensor details (40 bytes) */ +/** struct sensor_s is used to describe basic information about a specific sensor. */ +typedef struct +{ + char name[12]; + int32_t version; + int32_t sensor_id; + int32_t type; + float max_value; + float min_value; + float resolution; + int32_t min_delay; +} sensor_t; +``` + +The individual fields are intended to be used as follows: + +- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2") +- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver +- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network +- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h +- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit) +- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit) +- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit) +- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate + +**Sensor Data/Events (sensors\_event\_t)** + +This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales. + +``` +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common format. */ +typedef struct +{ + int32_t version; + int32_t sensor_id; + int32_t type; + int32_t reserved0; + int32_t timestamp; + union + { + float data[4]; + sensors_vec_t acceleration; + sensors_vec_t magnetic; + sensors_vec_t orientation; + sensors_vec_t gyro; + float temperature; + float distance; + float light; + float pressure; + float relative_humidity; + float current; + float voltage; + sensors_color_t color; + }; +} sensors_event_t; +``` +It includes the following fields: + +- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future +- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!) +- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h +- **timestamp**: time in milliseconds when the sensor value was read +- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below) + +**Required Functions** + +In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions: + +``` +void getEvent(sensors_event_t*); +``` +Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data. + +``` +void getSensor(sensor_t*); +``` +Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc. + +**Standardised SI values for sensors\_event\_t** + +A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales: + +- **acceleration**: values are in **meter per second per second** (m/s^2) +- **magnetic**: values are in **micro-Tesla** (uT) +- **orientation**: values are in **degrees** +- **gyro**: values are in **rad/s** +- **temperature**: values in **degrees centigrade** (Celsius) +- **distance**: values are in **centimeters** +- **light**: values are in **SI lux** units +- **pressure**: values are in **hectopascal** (hPa) +- **relative\_humidity**: values are in **percent** +- **current**: values are in **milliamps** (mA) +- **voltage**: values are in **volts** (V) +- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format + +## The Unified Driver Abstraction Layer in Practice ## + +Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created. + +Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t). + +An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below: + +``` + Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345); + ... + /* Get a new sensor event */ + sensors_event_t event; + tsl.getEvent(&event); + + /* Display the results (light is measured in lux) */ + if (event.light) + { + Serial.print(event.light); Serial.println(" lux"); + } + else + { + /* If event.light = 0 lux the sensor is probably saturated + and no reliable data could be generated! */ + Serial.println("Sensor overload"); + } +``` + +Similarly, we can get the basic technical capabilities of this sensor with the following code: + +``` + sensor_t sensor; + + sensor_t sensor; + tsl.getSensor(&sensor); + + /* Display the sensor details */ + Serial.println("------------------------------------"); + Serial.print ("Sensor: "); Serial.println(sensor.name); + Serial.print ("Driver Ver: "); Serial.println(sensor.version); + Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); + Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux"); + Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux"); + Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux"); + Serial.println("------------------------------------"); + Serial.println(""); +``` diff --git a/libraries/EEPROMAnything/EEPROMAnything.h b/libraries/EEPROMAnything/EEPROMAnything.h new file mode 100644 index 0000000..bc70898 --- /dev/null +++ b/libraries/EEPROMAnything/EEPROMAnything.h @@ -0,0 +1,20 @@ +#include +#include // for type definitions + +template int EEPROM_writeAnything(int ee, const T& value) +{ + const byte* p = (const byte*)(const void*)&value; + unsigned int i; + for (i = 0; i < sizeof(value); i++) + EEPROM.write(ee++, *p++); + return i; +} + +template int EEPROM_readAnything(int ee, T& value) +{ + byte* p = (byte*)(void*)&value; + unsigned int i; + for (i = 0; i < sizeof(value); i++) + *p++ = EEPROM.read(ee++); + return i; +} \ No newline at end of file diff --git a/libraries/Encoder/Encoder.cpp b/libraries/Encoder/Encoder.cpp new file mode 100644 index 0000000..6911b4f --- /dev/null +++ b/libraries/Encoder/Encoder.cpp @@ -0,0 +1,10 @@ + +#include "Encoder.h" + +// Yes, all the code is in the header file, to provide the user +// configure options with #define (before they include it), and +// to facilitate some crafty optimizations! + +Encoder_internal_state_t * Encoder::interruptArgs[]; + + diff --git a/libraries/Encoder/Encoder.h b/libraries/Encoder/Encoder.h new file mode 100644 index 0000000..b51d3bf --- /dev/null +++ b/libraries/Encoder/Encoder.h @@ -0,0 +1,941 @@ +/* Encoder Library, for measuring quadrature encoded signals + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * Copyright (c) 2011,2013 PJRC.COM, LLC - Paul Stoffregen + * + * Version 1.1 - expand to support boards with up to 60 interrupts + * Version 1.0 - initial release + * + * 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 Encoder_h_ +#define Encoder_h_ + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#elif defined(WIRING) +#include "Wiring.h" +#else +#include "WProgram.h" +#include "pins_arduino.h" +#endif + +#include "utility/direct_pin_read.h" + +#if defined(ENCODER_USE_INTERRUPTS) || !defined(ENCODER_DO_NOT_USE_INTERRUPTS) +#define ENCODER_USE_INTERRUPTS +#define ENCODER_ARGLIST_SIZE CORE_NUM_INTERRUPT +#include "utility/interrupt_pins.h" +#ifdef ENCODER_OPTIMIZE_INTERRUPTS +#include "utility/interrupt_config.h" +#endif +#else +#define ENCODER_ARGLIST_SIZE 0 +#endif + + + +// All the data needed by interrupts is consolidated into this ugly struct +// to facilitate assembly language optimizing of the speed critical update. +// The assembly code uses auto-incrementing addressing modes, so the struct +// must remain in exactly this order. +typedef struct { + volatile IO_REG_TYPE * pin1_register; + volatile IO_REG_TYPE * pin2_register; + IO_REG_TYPE pin1_bitmask; + IO_REG_TYPE pin2_bitmask; + uint8_t state; + int32_t position; +} Encoder_internal_state_t; + +class Encoder +{ +public: + Encoder(uint8_t pin1, uint8_t pin2) { + #ifdef INPUT_PULLUP + pinMode(pin1, INPUT_PULLUP); + pinMode(pin2, INPUT_PULLUP); + #else + pinMode(pin1, INPUT); + digitalWrite(pin1, HIGH); + pinMode(pin2, INPUT); + digitalWrite(pin2, HIGH); + #endif + encoder.pin1_register = PIN_TO_BASEREG(pin1); + encoder.pin1_bitmask = PIN_TO_BITMASK(pin1); + encoder.pin2_register = PIN_TO_BASEREG(pin2); + encoder.pin2_bitmask = PIN_TO_BITMASK(pin2); + encoder.position = 0; + // allow time for a passive R-C filter to charge + // through the pullup resistors, before reading + // the initial state + delayMicroseconds(2000); + uint8_t s = 0; + if (DIRECT_PIN_READ(encoder.pin1_register, encoder.pin1_bitmask)) s |= 1; + if (DIRECT_PIN_READ(encoder.pin2_register, encoder.pin2_bitmask)) s |= 2; + encoder.state = s; +#ifdef ENCODER_USE_INTERRUPTS + interrupts_in_use = attach_interrupt(pin1, &encoder); + interrupts_in_use += attach_interrupt(pin2, &encoder); +#endif + //update_finishup(); // to force linker to include the code (does not work) + } + + +#ifdef ENCODER_USE_INTERRUPTS + inline int32_t read() { + if (interrupts_in_use < 2) { + noInterrupts(); + update(&encoder); + } else { + noInterrupts(); + } + int32_t ret = encoder.position; + interrupts(); + return ret; + } + inline void write(int32_t p) { + noInterrupts(); + encoder.position = p; + interrupts(); + } +#else + inline int32_t read() { + update(&encoder); + return encoder.position; + } + inline void write(int32_t p) { + encoder.position = p; + } +#endif +private: + Encoder_internal_state_t encoder; +#ifdef ENCODER_USE_INTERRUPTS + uint8_t interrupts_in_use; +#endif +public: + static Encoder_internal_state_t * interruptArgs[ENCODER_ARGLIST_SIZE]; + +// _______ _______ +// Pin1 ______| |_______| |______ Pin1 +// negative <--- _______ _______ __ --> positive +// Pin2 __| |_______| |_______| Pin2 + + // new new old old + // pin2 pin1 pin2 pin1 Result + // ---- ---- ---- ---- ------ + // 0 0 0 0 no movement + // 0 0 0 1 +1 + // 0 0 1 0 -1 + // 0 0 1 1 +2 (assume pin1 edges only) + // 0 1 0 0 -1 + // 0 1 0 1 no movement + // 0 1 1 0 -2 (assume pin1 edges only) + // 0 1 1 1 +1 + // 1 0 0 0 +1 + // 1 0 0 1 -2 (assume pin1 edges only) + // 1 0 1 0 no movement + // 1 0 1 1 -1 + // 1 1 0 0 +2 (assume pin1 edges only) + // 1 1 0 1 -1 + // 1 1 1 0 +1 + // 1 1 1 1 no movement +/* + // Simple, easy-to-read "documentation" version :-) + // + void update(void) { + uint8_t s = state & 3; + if (digitalRead(pin1)) s |= 4; + if (digitalRead(pin2)) s |= 8; + switch (s) { + case 0: case 5: case 10: case 15: + break; + case 1: case 7: case 8: case 14: + position++; break; + case 2: case 4: case 11: case 13: + position--; break; + case 3: case 12: + position += 2; break; + default: + position -= 2; break; + } + state = (s >> 2); + } +*/ + +private: + static void update(Encoder_internal_state_t *arg) { +#if defined(__AVR__) + // The compiler believes this is just 1 line of code, so + // it will inline this function into each interrupt + // handler. That's a tiny bit faster, but grows the code. + // Especially when used with ENCODER_OPTIMIZE_INTERRUPTS, + // the inline nature allows the ISR prologue and epilogue + // to only save/restore necessary registers, for very nice + // speed increase. + asm volatile ( + "ld r30, X+" "\n\t" + "ld r31, X+" "\n\t" + "ld r24, Z" "\n\t" // r24 = pin1 input + "ld r30, X+" "\n\t" + "ld r31, X+" "\n\t" + "ld r25, Z" "\n\t" // r25 = pin2 input + "ld r30, X+" "\n\t" // r30 = pin1 mask + "ld r31, X+" "\n\t" // r31 = pin2 mask + "ld r22, X" "\n\t" // r22 = state + "andi r22, 3" "\n\t" + "and r24, r30" "\n\t" + "breq L%=1" "\n\t" // if (pin1) + "ori r22, 4" "\n\t" // state |= 4 + "L%=1:" "and r25, r31" "\n\t" + "breq L%=2" "\n\t" // if (pin2) + "ori r22, 8" "\n\t" // state |= 8 + "L%=2:" "ldi r30, lo8(pm(L%=table))" "\n\t" + "ldi r31, hi8(pm(L%=table))" "\n\t" + "add r30, r22" "\n\t" + "adc r31, __zero_reg__" "\n\t" + "asr r22" "\n\t" + "asr r22" "\n\t" + "st X+, r22" "\n\t" // store new state + "ld r22, X+" "\n\t" + "ld r23, X+" "\n\t" + "ld r24, X+" "\n\t" + "ld r25, X+" "\n\t" + "ijmp" "\n\t" // jumps to update_finishup() + // TODO move this table to another static function, + // so it doesn't get needlessly duplicated. Easier + // said than done, due to linker issues and inlining + "L%=table:" "\n\t" + "rjmp L%=end" "\n\t" // 0 + "rjmp L%=plus1" "\n\t" // 1 + "rjmp L%=minus1" "\n\t" // 2 + "rjmp L%=plus2" "\n\t" // 3 + "rjmp L%=minus1" "\n\t" // 4 + "rjmp L%=end" "\n\t" // 5 + "rjmp L%=minus2" "\n\t" // 6 + "rjmp L%=plus1" "\n\t" // 7 + "rjmp L%=plus1" "\n\t" // 8 + "rjmp L%=minus2" "\n\t" // 9 + "rjmp L%=end" "\n\t" // 10 + "rjmp L%=minus1" "\n\t" // 11 + "rjmp L%=plus2" "\n\t" // 12 + "rjmp L%=minus1" "\n\t" // 13 + "rjmp L%=plus1" "\n\t" // 14 + "rjmp L%=end" "\n\t" // 15 + "L%=minus2:" "\n\t" + "subi r22, 2" "\n\t" + "sbci r23, 0" "\n\t" + "sbci r24, 0" "\n\t" + "sbci r25, 0" "\n\t" + "rjmp L%=store" "\n\t" + "L%=minus1:" "\n\t" + "subi r22, 1" "\n\t" + "sbci r23, 0" "\n\t" + "sbci r24, 0" "\n\t" + "sbci r25, 0" "\n\t" + "rjmp L%=store" "\n\t" + "L%=plus2:" "\n\t" + "subi r22, 254" "\n\t" + "rjmp L%=z" "\n\t" + "L%=plus1:" "\n\t" + "subi r22, 255" "\n\t" + "L%=z:" "sbci r23, 255" "\n\t" + "sbci r24, 255" "\n\t" + "sbci r25, 255" "\n\t" + "L%=store:" "\n\t" + "st -X, r25" "\n\t" + "st -X, r24" "\n\t" + "st -X, r23" "\n\t" + "st -X, r22" "\n\t" + "L%=end:" "\n" + : : "x" (arg) : "r22", "r23", "r24", "r25", "r30", "r31"); +#else + uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask); + uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask); + uint8_t state = arg->state & 3; + if (p1val) state |= 4; + if (p2val) state |= 8; + arg->state = (state >> 2); + switch (state) { + case 1: case 7: case 8: case 14: + arg->position++; + return; + case 2: case 4: case 11: case 13: + arg->position--; + return; + case 3: case 12: + arg->position += 2; + return; + case 6: case 9: + arg->position += 2; + return; + } +#endif + } +/* +#if defined(__AVR__) + // TODO: this must be a no inline function + // even noinline does not seem to solve difficult + // problems with this. Oh well, it was only meant + // to shrink code size - there's no performance + // improvement in this, only code size reduction. + __attribute__((noinline)) void update_finishup(void) { + asm volatile ( + "ldi r30, lo8(pm(Ltable))" "\n\t" + "ldi r31, hi8(pm(Ltable))" "\n\t" + "Ltable:" "\n\t" + "rjmp L%=end" "\n\t" // 0 + "rjmp L%=plus1" "\n\t" // 1 + "rjmp L%=minus1" "\n\t" // 2 + "rjmp L%=plus2" "\n\t" // 3 + "rjmp L%=minus1" "\n\t" // 4 + "rjmp L%=end" "\n\t" // 5 + "rjmp L%=minus2" "\n\t" // 6 + "rjmp L%=plus1" "\n\t" // 7 + "rjmp L%=plus1" "\n\t" // 8 + "rjmp L%=minus2" "\n\t" // 9 + "rjmp L%=end" "\n\t" // 10 + "rjmp L%=minus1" "\n\t" // 11 + "rjmp L%=plus2" "\n\t" // 12 + "rjmp L%=minus1" "\n\t" // 13 + "rjmp L%=plus1" "\n\t" // 14 + "rjmp L%=end" "\n\t" // 15 + "L%=minus2:" "\n\t" + "subi r22, 2" "\n\t" + "sbci r23, 0" "\n\t" + "sbci r24, 0" "\n\t" + "sbci r25, 0" "\n\t" + "rjmp L%=store" "\n\t" + "L%=minus1:" "\n\t" + "subi r22, 1" "\n\t" + "sbci r23, 0" "\n\t" + "sbci r24, 0" "\n\t" + "sbci r25, 0" "\n\t" + "rjmp L%=store" "\n\t" + "L%=plus2:" "\n\t" + "subi r22, 254" "\n\t" + "rjmp L%=z" "\n\t" + "L%=plus1:" "\n\t" + "subi r22, 255" "\n\t" + "L%=z:" "sbci r23, 255" "\n\t" + "sbci r24, 255" "\n\t" + "sbci r25, 255" "\n\t" + "L%=store:" "\n\t" + "st -X, r25" "\n\t" + "st -X, r24" "\n\t" + "st -X, r23" "\n\t" + "st -X, r22" "\n\t" + "L%=end:" "\n" + : : : "r22", "r23", "r24", "r25", "r30", "r31"); + } +#endif +*/ + + +#ifdef ENCODER_USE_INTERRUPTS + // this giant function is an unfortunate consequence of Arduino's + // attachInterrupt function not supporting any way to pass a pointer + // or other context to the attached function. + static uint8_t attach_interrupt(uint8_t pin, Encoder_internal_state_t *state) { + switch (pin) { + #ifdef CORE_INT0_PIN + case CORE_INT0_PIN: + interruptArgs[0] = state; + attachInterrupt(0, isr0, CHANGE); + break; + #endif + #ifdef CORE_INT1_PIN + case CORE_INT1_PIN: + interruptArgs[1] = state; + attachInterrupt(1, isr1, CHANGE); + break; + #endif + #ifdef CORE_INT2_PIN + case CORE_INT2_PIN: + interruptArgs[2] = state; + attachInterrupt(2, isr2, CHANGE); + break; + #endif + #ifdef CORE_INT3_PIN + case CORE_INT3_PIN: + interruptArgs[3] = state; + attachInterrupt(3, isr3, CHANGE); + break; + #endif + #ifdef CORE_INT4_PIN + case CORE_INT4_PIN: + interruptArgs[4] = state; + attachInterrupt(4, isr4, CHANGE); + break; + #endif + #ifdef CORE_INT5_PIN + case CORE_INT5_PIN: + interruptArgs[5] = state; + attachInterrupt(5, isr5, CHANGE); + break; + #endif + #ifdef CORE_INT6_PIN + case CORE_INT6_PIN: + interruptArgs[6] = state; + attachInterrupt(6, isr6, CHANGE); + break; + #endif + #ifdef CORE_INT7_PIN + case CORE_INT7_PIN: + interruptArgs[7] = state; + attachInterrupt(7, isr7, CHANGE); + break; + #endif + #ifdef CORE_INT8_PIN + case CORE_INT8_PIN: + interruptArgs[8] = state; + attachInterrupt(8, isr8, CHANGE); + break; + #endif + #ifdef CORE_INT9_PIN + case CORE_INT9_PIN: + interruptArgs[9] = state; + attachInterrupt(9, isr9, CHANGE); + break; + #endif + #ifdef CORE_INT10_PIN + case CORE_INT10_PIN: + interruptArgs[10] = state; + attachInterrupt(10, isr10, CHANGE); + break; + #endif + #ifdef CORE_INT11_PIN + case CORE_INT11_PIN: + interruptArgs[11] = state; + attachInterrupt(11, isr11, CHANGE); + break; + #endif + #ifdef CORE_INT12_PIN + case CORE_INT12_PIN: + interruptArgs[12] = state; + attachInterrupt(12, isr12, CHANGE); + break; + #endif + #ifdef CORE_INT13_PIN + case CORE_INT13_PIN: + interruptArgs[13] = state; + attachInterrupt(13, isr13, CHANGE); + break; + #endif + #ifdef CORE_INT14_PIN + case CORE_INT14_PIN: + interruptArgs[14] = state; + attachInterrupt(14, isr14, CHANGE); + break; + #endif + #ifdef CORE_INT15_PIN + case CORE_INT15_PIN: + interruptArgs[15] = state; + attachInterrupt(15, isr15, CHANGE); + break; + #endif + #ifdef CORE_INT16_PIN + case CORE_INT16_PIN: + interruptArgs[16] = state; + attachInterrupt(16, isr16, CHANGE); + break; + #endif + #ifdef CORE_INT17_PIN + case CORE_INT17_PIN: + interruptArgs[17] = state; + attachInterrupt(17, isr17, CHANGE); + break; + #endif + #ifdef CORE_INT18_PIN + case CORE_INT18_PIN: + interruptArgs[18] = state; + attachInterrupt(18, isr18, CHANGE); + break; + #endif + #ifdef CORE_INT19_PIN + case CORE_INT19_PIN: + interruptArgs[19] = state; + attachInterrupt(19, isr19, CHANGE); + break; + #endif + #ifdef CORE_INT20_PIN + case CORE_INT20_PIN: + interruptArgs[20] = state; + attachInterrupt(20, isr20, CHANGE); + break; + #endif + #ifdef CORE_INT21_PIN + case CORE_INT21_PIN: + interruptArgs[21] = state; + attachInterrupt(21, isr21, CHANGE); + break; + #endif + #ifdef CORE_INT22_PIN + case CORE_INT22_PIN: + interruptArgs[22] = state; + attachInterrupt(22, isr22, CHANGE); + break; + #endif + #ifdef CORE_INT23_PIN + case CORE_INT23_PIN: + interruptArgs[23] = state; + attachInterrupt(23, isr23, CHANGE); + break; + #endif + #ifdef CORE_INT24_PIN + case CORE_INT24_PIN: + interruptArgs[24] = state; + attachInterrupt(24, isr24, CHANGE); + break; + #endif + #ifdef CORE_INT25_PIN + case CORE_INT25_PIN: + interruptArgs[25] = state; + attachInterrupt(25, isr25, CHANGE); + break; + #endif + #ifdef CORE_INT26_PIN + case CORE_INT26_PIN: + interruptArgs[26] = state; + attachInterrupt(26, isr26, CHANGE); + break; + #endif + #ifdef CORE_INT27_PIN + case CORE_INT27_PIN: + interruptArgs[27] = state; + attachInterrupt(27, isr27, CHANGE); + break; + #endif + #ifdef CORE_INT28_PIN + case CORE_INT28_PIN: + interruptArgs[28] = state; + attachInterrupt(28, isr28, CHANGE); + break; + #endif + #ifdef CORE_INT29_PIN + case CORE_INT29_PIN: + interruptArgs[29] = state; + attachInterrupt(29, isr29, CHANGE); + break; + #endif + + #ifdef CORE_INT30_PIN + case CORE_INT30_PIN: + interruptArgs[30] = state; + attachInterrupt(30, isr30, CHANGE); + break; + #endif + #ifdef CORE_INT31_PIN + case CORE_INT31_PIN: + interruptArgs[31] = state; + attachInterrupt(31, isr31, CHANGE); + break; + #endif + #ifdef CORE_INT32_PIN + case CORE_INT32_PIN: + interruptArgs[32] = state; + attachInterrupt(32, isr32, CHANGE); + break; + #endif + #ifdef CORE_INT33_PIN + case CORE_INT33_PIN: + interruptArgs[33] = state; + attachInterrupt(33, isr33, CHANGE); + break; + #endif + #ifdef CORE_INT34_PIN + case CORE_INT34_PIN: + interruptArgs[34] = state; + attachInterrupt(34, isr34, CHANGE); + break; + #endif + #ifdef CORE_INT35_PIN + case CORE_INT35_PIN: + interruptArgs[35] = state; + attachInterrupt(35, isr35, CHANGE); + break; + #endif + #ifdef CORE_INT36_PIN + case CORE_INT36_PIN: + interruptArgs[36] = state; + attachInterrupt(36, isr36, CHANGE); + break; + #endif + #ifdef CORE_INT37_PIN + case CORE_INT37_PIN: + interruptArgs[37] = state; + attachInterrupt(37, isr37, CHANGE); + break; + #endif + #ifdef CORE_INT38_PIN + case CORE_INT38_PIN: + interruptArgs[38] = state; + attachInterrupt(38, isr38, CHANGE); + break; + #endif + #ifdef CORE_INT39_PIN + case CORE_INT39_PIN: + interruptArgs[39] = state; + attachInterrupt(39, isr39, CHANGE); + break; + #endif + #ifdef CORE_INT40_PIN + case CORE_INT40_PIN: + interruptArgs[40] = state; + attachInterrupt(40, isr40, CHANGE); + break; + #endif + #ifdef CORE_INT41_PIN + case CORE_INT41_PIN: + interruptArgs[41] = state; + attachInterrupt(41, isr41, CHANGE); + break; + #endif + #ifdef CORE_INT42_PIN + case CORE_INT42_PIN: + interruptArgs[42] = state; + attachInterrupt(42, isr42, CHANGE); + break; + #endif + #ifdef CORE_INT43_PIN + case CORE_INT43_PIN: + interruptArgs[43] = state; + attachInterrupt(43, isr43, CHANGE); + break; + #endif + #ifdef CORE_INT44_PIN + case CORE_INT44_PIN: + interruptArgs[44] = state; + attachInterrupt(44, isr44, CHANGE); + break; + #endif + #ifdef CORE_INT45_PIN + case CORE_INT45_PIN: + interruptArgs[45] = state; + attachInterrupt(45, isr45, CHANGE); + break; + #endif + #ifdef CORE_INT46_PIN + case CORE_INT46_PIN: + interruptArgs[46] = state; + attachInterrupt(46, isr46, CHANGE); + break; + #endif + #ifdef CORE_INT47_PIN + case CORE_INT47_PIN: + interruptArgs[47] = state; + attachInterrupt(47, isr47, CHANGE); + break; + #endif + #ifdef CORE_INT48_PIN + case CORE_INT48_PIN: + interruptArgs[48] = state; + attachInterrupt(48, isr48, CHANGE); + break; + #endif + #ifdef CORE_INT49_PIN + case CORE_INT49_PIN: + interruptArgs[49] = state; + attachInterrupt(49, isr49, CHANGE); + break; + #endif + #ifdef CORE_INT50_PIN + case CORE_INT50_PIN: + interruptArgs[50] = state; + attachInterrupt(50, isr50, CHANGE); + break; + #endif + #ifdef CORE_INT51_PIN + case CORE_INT51_PIN: + interruptArgs[51] = state; + attachInterrupt(51, isr51, CHANGE); + break; + #endif + #ifdef CORE_INT52_PIN + case CORE_INT52_PIN: + interruptArgs[52] = state; + attachInterrupt(52, isr52, CHANGE); + break; + #endif + #ifdef CORE_INT53_PIN + case CORE_INT53_PIN: + interruptArgs[53] = state; + attachInterrupt(53, isr53, CHANGE); + break; + #endif + #ifdef CORE_INT54_PIN + case CORE_INT54_PIN: + interruptArgs[54] = state; + attachInterrupt(54, isr54, CHANGE); + break; + #endif + #ifdef CORE_INT55_PIN + case CORE_INT55_PIN: + interruptArgs[55] = state; + attachInterrupt(55, isr55, CHANGE); + break; + #endif + #ifdef CORE_INT56_PIN + case CORE_INT56_PIN: + interruptArgs[56] = state; + attachInterrupt(56, isr56, CHANGE); + break; + #endif + #ifdef CORE_INT57_PIN + case CORE_INT57_PIN: + interruptArgs[57] = state; + attachInterrupt(57, isr57, CHANGE); + break; + #endif + #ifdef CORE_INT58_PIN + case CORE_INT58_PIN: + interruptArgs[58] = state; + attachInterrupt(58, isr58, CHANGE); + break; + #endif + #ifdef CORE_INT59_PIN + case CORE_INT59_PIN: + interruptArgs[59] = state; + attachInterrupt(59, isr59, CHANGE); + break; + #endif + default: + return 0; + } + return 1; + } +#endif // ENCODER_USE_INTERRUPTS + + +#if defined(ENCODER_USE_INTERRUPTS) && !defined(ENCODER_OPTIMIZE_INTERRUPTS) + #ifdef CORE_INT0_PIN + static void isr0(void) { update(interruptArgs[0]); } + #endif + #ifdef CORE_INT1_PIN + static void isr1(void) { update(interruptArgs[1]); } + #endif + #ifdef CORE_INT2_PIN + static void isr2(void) { update(interruptArgs[2]); } + #endif + #ifdef CORE_INT3_PIN + static void isr3(void) { update(interruptArgs[3]); } + #endif + #ifdef CORE_INT4_PIN + static void isr4(void) { update(interruptArgs[4]); } + #endif + #ifdef CORE_INT5_PIN + static void isr5(void) { update(interruptArgs[5]); } + #endif + #ifdef CORE_INT6_PIN + static void isr6(void) { update(interruptArgs[6]); } + #endif + #ifdef CORE_INT7_PIN + static void isr7(void) { update(interruptArgs[7]); } + #endif + #ifdef CORE_INT8_PIN + static void isr8(void) { update(interruptArgs[8]); } + #endif + #ifdef CORE_INT9_PIN + static void isr9(void) { update(interruptArgs[9]); } + #endif + #ifdef CORE_INT10_PIN + static void isr10(void) { update(interruptArgs[10]); } + #endif + #ifdef CORE_INT11_PIN + static void isr11(void) { update(interruptArgs[11]); } + #endif + #ifdef CORE_INT12_PIN + static void isr12(void) { update(interruptArgs[12]); } + #endif + #ifdef CORE_INT13_PIN + static void isr13(void) { update(interruptArgs[13]); } + #endif + #ifdef CORE_INT14_PIN + static void isr14(void) { update(interruptArgs[14]); } + #endif + #ifdef CORE_INT15_PIN + static void isr15(void) { update(interruptArgs[15]); } + #endif + #ifdef CORE_INT16_PIN + static void isr16(void) { update(interruptArgs[16]); } + #endif + #ifdef CORE_INT17_PIN + static void isr17(void) { update(interruptArgs[17]); } + #endif + #ifdef CORE_INT18_PIN + static void isr18(void) { update(interruptArgs[18]); } + #endif + #ifdef CORE_INT19_PIN + static void isr19(void) { update(interruptArgs[19]); } + #endif + #ifdef CORE_INT20_PIN + static void isr20(void) { update(interruptArgs[20]); } + #endif + #ifdef CORE_INT21_PIN + static void isr21(void) { update(interruptArgs[21]); } + #endif + #ifdef CORE_INT22_PIN + static void isr22(void) { update(interruptArgs[22]); } + #endif + #ifdef CORE_INT23_PIN + static void isr23(void) { update(interruptArgs[23]); } + #endif + #ifdef CORE_INT24_PIN + static void isr24(void) { update(interruptArgs[24]); } + #endif + #ifdef CORE_INT25_PIN + static void isr25(void) { update(interruptArgs[25]); } + #endif + #ifdef CORE_INT26_PIN + static void isr26(void) { update(interruptArgs[26]); } + #endif + #ifdef CORE_INT27_PIN + static void isr27(void) { update(interruptArgs[27]); } + #endif + #ifdef CORE_INT28_PIN + static void isr28(void) { update(interruptArgs[28]); } + #endif + #ifdef CORE_INT29_PIN + static void isr29(void) { update(interruptArgs[29]); } + #endif + #ifdef CORE_INT30_PIN + static void isr30(void) { update(interruptArgs[30]); } + #endif + #ifdef CORE_INT31_PIN + static void isr31(void) { update(interruptArgs[31]); } + #endif + #ifdef CORE_INT32_PIN + static void isr32(void) { update(interruptArgs[32]); } + #endif + #ifdef CORE_INT33_PIN + static void isr33(void) { update(interruptArgs[33]); } + #endif + #ifdef CORE_INT34_PIN + static void isr34(void) { update(interruptArgs[34]); } + #endif + #ifdef CORE_INT35_PIN + static void isr35(void) { update(interruptArgs[35]); } + #endif + #ifdef CORE_INT36_PIN + static void isr36(void) { update(interruptArgs[36]); } + #endif + #ifdef CORE_INT37_PIN + static void isr37(void) { update(interruptArgs[37]); } + #endif + #ifdef CORE_INT38_PIN + static void isr38(void) { update(interruptArgs[38]); } + #endif + #ifdef CORE_INT39_PIN + static void isr39(void) { update(interruptArgs[39]); } + #endif + #ifdef CORE_INT40_PIN + static void isr40(void) { update(interruptArgs[40]); } + #endif + #ifdef CORE_INT41_PIN + static void isr41(void) { update(interruptArgs[41]); } + #endif + #ifdef CORE_INT42_PIN + static void isr42(void) { update(interruptArgs[42]); } + #endif + #ifdef CORE_INT43_PIN + static void isr43(void) { update(interruptArgs[43]); } + #endif + #ifdef CORE_INT44_PIN + static void isr44(void) { update(interruptArgs[44]); } + #endif + #ifdef CORE_INT45_PIN + static void isr45(void) { update(interruptArgs[45]); } + #endif + #ifdef CORE_INT46_PIN + static void isr46(void) { update(interruptArgs[46]); } + #endif + #ifdef CORE_INT47_PIN + static void isr47(void) { update(interruptArgs[47]); } + #endif + #ifdef CORE_INT48_PIN + static void isr48(void) { update(interruptArgs[48]); } + #endif + #ifdef CORE_INT49_PIN + static void isr49(void) { update(interruptArgs[49]); } + #endif + #ifdef CORE_INT50_PIN + static void isr50(void) { update(interruptArgs[50]); } + #endif + #ifdef CORE_INT51_PIN + static void isr51(void) { update(interruptArgs[51]); } + #endif + #ifdef CORE_INT52_PIN + static void isr52(void) { update(interruptArgs[52]); } + #endif + #ifdef CORE_INT53_PIN + static void isr53(void) { update(interruptArgs[53]); } + #endif + #ifdef CORE_INT54_PIN + static void isr54(void) { update(interruptArgs[54]); } + #endif + #ifdef CORE_INT55_PIN + static void isr55(void) { update(interruptArgs[55]); } + #endif + #ifdef CORE_INT56_PIN + static void isr56(void) { update(interruptArgs[56]); } + #endif + #ifdef CORE_INT57_PIN + static void isr57(void) { update(interruptArgs[57]); } + #endif + #ifdef CORE_INT58_PIN + static void isr58(void) { update(interruptArgs[58]); } + #endif + #ifdef CORE_INT59_PIN + static void isr59(void) { update(interruptArgs[59]); } + #endif +#endif +}; + +#if defined(ENCODER_USE_INTERRUPTS) && defined(ENCODER_OPTIMIZE_INTERRUPTS) +#if defined(__AVR__) +#if defined(INT0_vect) && CORE_NUM_INTERRUPT > 0 +ISR(INT0_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(0)]); } +#endif +#if defined(INT1_vect) && CORE_NUM_INTERRUPT > 1 +ISR(INT1_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(1)]); } +#endif +#if defined(INT2_vect) && CORE_NUM_INTERRUPT > 2 +ISR(INT2_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(2)]); } +#endif +#if defined(INT3_vect) && CORE_NUM_INTERRUPT > 3 +ISR(INT3_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(3)]); } +#endif +#if defined(INT4_vect) && CORE_NUM_INTERRUPT > 4 +ISR(INT4_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(4)]); } +#endif +#if defined(INT5_vect) && CORE_NUM_INTERRUPT > 5 +ISR(INT5_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(5)]); } +#endif +#if defined(INT6_vect) && CORE_NUM_INTERRUPT > 6 +ISR(INT6_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(6)]); } +#endif +#if defined(INT7_vect) && CORE_NUM_INTERRUPT > 7 +ISR(INT7_vect) { Encoder::update(Encoder::interruptArgs[SCRAMBLE_INT_ORDER(7)]); } +#endif +#endif // AVR +#endif // ENCODER_OPTIMIZE_INTERRUPTS + + +#endif diff --git a/libraries/Encoder/examples/Basic/Basic.pde b/libraries/Encoder/examples/Basic/Basic.pde new file mode 100644 index 0000000..3394b58 --- /dev/null +++ b/libraries/Encoder/examples/Basic/Basic.pde @@ -0,0 +1,29 @@ +/* Encoder Library - Basic Example + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + +#include + +// Change these two numbers to the pins connected to your encoder. +// Best Performance: both pins have interrupt capability +// Good Performance: only the first pin has interrupt capability +// Low Performance: neither pin has interrupt capability +Encoder myEnc(5, 6); +// avoid using pins with LEDs attached + +void setup() { + Serial.begin(9600); + Serial.println("Basic Encoder Test:"); +} + +long oldPosition = -999; + +void loop() { + long newPosition = myEnc.read(); + if (newPosition != oldPosition) { + oldPosition = newPosition; + Serial.println(newPosition); + } +} diff --git a/libraries/Encoder/examples/NoInterrupts/NoInterrupts.pde b/libraries/Encoder/examples/NoInterrupts/NoInterrupts.pde new file mode 100644 index 0000000..b890652 --- /dev/null +++ b/libraries/Encoder/examples/NoInterrupts/NoInterrupts.pde @@ -0,0 +1,46 @@ +/* Encoder Library - NoInterrupts Example + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + +// If you define ENCODER_DO_NOT_USE_INTERRUPTS *before* including +// Encoder, the library will never use interrupts. This is mainly +// useful to reduce the size of the library when you are using it +// with pins that do not support interrupts. Without interrupts, +// your program must call the read() function rapidly, or risk +// missing changes in position. +#define ENCODER_DO_NOT_USE_INTERRUPTS +#include + +// Beware of Serial.print() speed. Without interrupts, if you +// transmit too much data with Serial.print() it can slow your +// reading from Encoder. Arduino 1.0 has improved transmit code. +// Using the fastest baud rate also helps. Teensy has USB packet +// buffering. But all boards can experience problems if you print +// too much and fill up buffers. + +// Change these two numbers to the pins connected to your encoder. +// With ENCODER_DO_NOT_USE_INTERRUPTS, no interrupts are ever +// used, even if the pin has interrupt capability +Encoder myEnc(5, 6); +// avoid using pins with LEDs attached + +void setup() { + Serial.begin(9600); + Serial.println("Basic NoInterrupts Test:"); +} + +long position = -999; + +void loop() { + long newPos = myEnc.read(); + if (newPos != position) { + position = newPos; + Serial.println(position); + } + // With any substantial delay added, Encoder can only track + // very slow motion. You may uncomment this line to see + // how badly a delay affects your encoder. + //delay(50); +} diff --git a/libraries/Encoder/examples/SpeedTest/SpeedTest.pde b/libraries/Encoder/examples/SpeedTest/SpeedTest.pde new file mode 100644 index 0000000..76cf350 --- /dev/null +++ b/libraries/Encoder/examples/SpeedTest/SpeedTest.pde @@ -0,0 +1,113 @@ +/* Encoder Library - SpeedTest - for measuring maximum Encoder speed + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + + +// This SpeedTest example provides a simple way to verify how much +// CPU time Encoder is consuming. Connect a DC voltmeter to the +// output pin and measure the voltage while the encoder is stopped +// or running at a very slow speed. Even though the pin is rapidly +// pulsing, a DC voltmeter will show the average voltage. Due to +// software timing, it will read a number much less than a steady +// logic high, but this number will give you a baseline reading +// for output with minimal interrupt overhead. Then increase the +// encoder speed. The voltage will decrease as the processor spends +// more time in Encoder's interrupt routines counting the pulses +// and less time pulsing the output pin. When the voltage is +// close to zero and will not decrease any farther, you have reached +// the absolute speed limit. Or, if using a mechanical system where +// you reach a speed limit imposed by your motors or other hardware, +// the amount this voltage has decreased, compared to the baseline, +// should give you a good approximation of the portion of available +// CPU time Encoder is consuming at your maximum speed. + +// Encoder requires low latency interrupt response. Available CPU +// time does NOT necessarily prove or guarantee correct performance. +// If another library, like NewSoftSerial, is disabling interrupts +// for lengthy periods of time, Encoder can be prevented from +// properly counting the intput signals while interrupt are disabled. + + +// This optional setting causes Encoder to use more optimized code, +// but the downside is a conflict if any other part of your sketch +// or any other library you're using requires attachInterrupt(). +// It must be defined before Encoder.h is included. +//#define ENCODER_OPTIMIZE_INTERRUPTS + +#include +#include "pins_arduino.h" + +// Change these two numbers to the pins connected to your encoder +// or shift register circuit which emulates a quadrature encoder +// case 1: both pins are interrupts +// case 2: only first pin used as interrupt +Encoder myEnc(5, 6); + +// Connect a DC voltmeter to this pin. +const int outputPin = 12; + +/* This simple circuit, using a Dual Flip-Flop chip, can emulate + quadrature encoder signals. The clock can come from a fancy + function generator or a cheap 555 timer chip. The clock + frequency can be measured with another board running FreqCount + http://www.pjrc.com/teensy/td_libs_FreqCount.html + + +5V + | Quadrature Encoder Signal Emulator + Clock | + Input o----*-------------------------- ---------------------------o Output1 + | |14 | | + | _______|_______ | | _______________ + | | CD4013 | | | | CD4013 | + | 5 | | 1 | | 9 | | 13 + ---------| D Q |-----|----*----| D Q |------o Output2 + | | | | | | | + | | 3 | | | 11 | | + | ----|> Clk | ---------|> Clk | + | | | | | + | 6 | | 8 | | + | ----| S | ----| S | + | | | | | | | + | | 4 | _ | 2 | 10 | _ | 12 + | *----| R Q |--- *----| R Q |---- + | | | | | | | | + | | |_______________| | |_______________| | + | | | | | + | | | 7 | | + | | | | | + -------------------------------------------------------------- + | | | + | | | + ----- ----- ----- + --- --- --- + - - - +*/ + + +void setup() { + pinMode(outputPin, OUTPUT); +} + +#if defined(__AVR__) +#define REGTYPE unsigned char +#elif defined(__PIC32MX__) +#define REGTYPE unsigned long +#endif + +void loop() { + volatile int count = 0; + volatile REGTYPE *reg = portOutputRegister(digitalPinToPort(outputPin)); + REGTYPE mask = digitalPinToBitMask(outputPin); + + while (1) { + myEnc.read(); // Read the encoder while interrupts are enabled. + noInterrupts(); + *reg |= mask; // Pulse the pin high, while interrupts are disabled. + count = count + 1; + *reg &= ~mask; + interrupts(); + } +} + diff --git a/libraries/Encoder/examples/TwoKnobs/TwoKnobs.pde b/libraries/Encoder/examples/TwoKnobs/TwoKnobs.pde new file mode 100644 index 0000000..306b33e --- /dev/null +++ b/libraries/Encoder/examples/TwoKnobs/TwoKnobs.pde @@ -0,0 +1,46 @@ +/* Encoder Library - TwoKnobs Example + * http://www.pjrc.com/teensy/td_libs_Encoder.html + * + * This example code is in the public domain. + */ + +#include + +// Change these pin numbers to the pins connected to your encoder. +// Best Performance: both pins have interrupt capability +// Good Performance: only the first pin has interrupt capability +// Low Performance: neither pin has interrupt capability +Encoder knobLeft(5, 6); +Encoder knobRight(7, 8); +// avoid using pins with LEDs attached + +void setup() { + Serial.begin(9600); + Serial.println("TwoKnobs Encoder Test:"); +} + +long positionLeft = -999; +long positionRight = -999; + +void loop() { + long newLeft, newRight; + newLeft = knobLeft.read(); + newRight = knobRight.read(); + if (newLeft != positionLeft || newRight != positionRight) { + Serial.print("Left = "); + Serial.print(newLeft); + Serial.print(", Right = "); + Serial.print(newRight); + Serial.println(); + positionLeft = newLeft; + positionRight = newRight; + } + // if a character is sent from the serial monitor, + // reset both back to zero. + if (Serial.available()) { + Serial.read(); + Serial.println("Reset both knobs to zero"); + knobLeft.write(0); + knobRight.write(0); + } +} diff --git a/libraries/Encoder/keywords.txt b/libraries/Encoder/keywords.txt new file mode 100644 index 0000000..a4baa01 --- /dev/null +++ b/libraries/Encoder/keywords.txt @@ -0,0 +1,4 @@ +ENCODER_USE_INTERRUPTS LITERAL1 +ENCODER_OPTIMIZE_INTERRUPTS LITERAL1 +ENCODER_DO_NOT_USE_INTERRUPTS LITERAL1 +Encoder KEYWORD1 diff --git a/libraries/Encoder/utility/direct_pin_read.h b/libraries/Encoder/utility/direct_pin_read.h new file mode 100644 index 0000000..4d6614c --- /dev/null +++ b/libraries/Encoder/utility/direct_pin_read.h @@ -0,0 +1,27 @@ +#ifndef direct_pin_read_h_ +#define direct_pin_read_h_ + +#if defined(__AVR__) || defined(__MK20DX128__) + +#define IO_REG_TYPE uint8_t +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(__SAM3X8E__) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) + +#elif defined(__PIC32MX__) + +#define IO_REG_TYPE uint32_t +#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define DIRECT_PIN_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) + +#endif + +#endif diff --git a/libraries/Encoder/utility/interrupt_config.h b/libraries/Encoder/utility/interrupt_config.h new file mode 100644 index 0000000..cde6adf --- /dev/null +++ b/libraries/Encoder/utility/interrupt_config.h @@ -0,0 +1,87 @@ +#if defined(__AVR__) + +#include +#include + +#define attachInterrupt(num, func, mode) enableInterrupt(num) +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define SCRAMBLE_INT_ORDER(num) ((num < 4) ? num + 2 : ((num < 6) ? num - 4 : num)) +#define DESCRAMBLE_INT_ORDER(num) ((num < 2) ? num + 4 : ((num < 6) ? num - 2 : num)) +#else +#define SCRAMBLE_INT_ORDER(num) (num) +#define DESCRAMBLE_INT_ORDER(num) (num) +#endif + +static void enableInterrupt(uint8_t num) +{ + switch (DESCRAMBLE_INT_ORDER(num)) { + #if defined(EICRA) && defined(EIMSK) + case 0: + EICRA = (EICRA & 0xFC) | 0x01; + EIMSK |= 0x01; + return; + case 1: + EICRA = (EICRA & 0xF3) | 0x04; + EIMSK |= 0x02; + return; + case 2: + EICRA = (EICRA & 0xCF) | 0x10; + EIMSK |= 0x04; + return; + case 3: + EICRA = (EICRA & 0x3F) | 0x40; + EIMSK |= 0x08; + return; + #elif defined(MCUCR) && defined(GICR) + case 0: + MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + GICR |= (1 << INT0); + return; + case 1: + MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + GICR |= (1 << INT1); + return; + #elif defined(MCUCR) && defined(GIMSK) + case 0: + MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + GIMSK |= (1 << INT0); + return; + case 1: + MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + GIMSK |= (1 << INT1); + return; + #endif + #if defined(EICRB) && defined(EIMSK) + case 4: + EICRB = (EICRB & 0xFC) | 0x01; + EIMSK |= 0x10; + return; + case 5: + EICRB = (EICRB & 0xF3) | 0x04; + EIMSK |= 0x20; + return; + case 6: + EICRB = (EICRB & 0xCF) | 0x10; + EIMSK |= 0x40; + return; + case 7: + EICRB = (EICRB & 0x3F) | 0x40; + EIMSK |= 0x80; + return; + #endif + } +} + +#elif defined(__PIC32MX__) + +#ifdef ENCODER_OPTIMIZE_INTERRUPTS +#undef ENCODER_OPTIMIZE_INTERRUPTS +#endif + +#else + +#ifdef ENCODER_OPTIMIZE_INTERRUPTS +#undef ENCODER_OPTIMIZE_INTERRUPTS +#endif + +#endif diff --git a/libraries/Encoder/utility/interrupt_pins.h b/libraries/Encoder/utility/interrupt_pins.h new file mode 100644 index 0000000..e677c4f --- /dev/null +++ b/libraries/Encoder/utility/interrupt_pins.h @@ -0,0 +1,156 @@ +// interrupt pins for known boards + +// Teensy (and maybe others) define these automatically +#if !defined(CORE_NUM_INTERRUPT) + +// Wiring boards +#if defined(WIRING) + #define CORE_NUM_INTERRUPT NUM_EXTERNAL_INTERRUPTS + #if NUM_EXTERNAL_INTERRUPTS > 0 + #define CORE_INT0_PIN EI0 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 1 + #define CORE_INT1_PIN EI1 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 2 + #define CORE_INT2_PIN EI2 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 3 + #define CORE_INT3_PIN EI3 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 4 + #define CORE_INT4_PIN EI4 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 5 + #define CORE_INT5_PIN EI5 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 6 + #define CORE_INT6_PIN EI6 + #endif + #if NUM_EXTERNAL_INTERRUPTS > 7 + #define CORE_INT7_PIN EI7 + #endif + +// Arduino Uno, Duemilanove, Diecimila, LilyPad, Mini, Fio, etc... +#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) + #define CORE_NUM_INTERRUPT 2 + #define CORE_INT0_PIN 2 + #define CORE_INT1_PIN 3 + +// Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + #define CORE_NUM_INTERRUPT 6 + #define CORE_INT0_PIN 2 + #define CORE_INT1_PIN 3 + #define CORE_INT2_PIN 21 + #define CORE_INT3_PIN 20 + #define CORE_INT4_PIN 19 + #define CORE_INT5_PIN 18 + +// Arduino Leonardo (untested) +#elif defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY) + #define CORE_NUM_INTERRUPT 4 + #define CORE_INT0_PIN 3 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 0 + #define CORE_INT3_PIN 1 + +// Sanguino (untested) +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) + #define CORE_NUM_INTERRUPT 3 + #define CORE_INT0_PIN 10 + #define CORE_INT1_PIN 11 + #define CORE_INT2_PIN 2 + +// Chipkit Uno32 - attachInterrupt may not support CHANGE option +#elif defined(__PIC32MX__) && defined(_BOARD_UNO_) + #define CORE_NUM_INTERRUPT 5 + #define CORE_INT0_PIN 38 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 7 + #define CORE_INT3_PIN 8 + #define CORE_INT4_PIN 35 + +// Chipkit Uno32 - attachInterrupt may not support CHANGE option +#elif defined(__PIC32MX__) && defined(_BOARD_MEGA_) + #define CORE_NUM_INTERRUPT 5 + #define CORE_INT0_PIN 3 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 7 + #define CORE_INT3_PIN 21 + #define CORE_INT4_PIN 20 + +// http://hlt.media.mit.edu/?p=1229 +#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + #define CORE_NUM_INTERRUPT 1 + #define CORE_INT0_PIN 2 + +// Arduino Due (untested) +#elif defined(__SAM3X8E__) + #define CORE_NUM_INTERRUPT 54 + #define CORE_INT0_PIN 0 + #define CORE_INT1_PIN 1 + #define CORE_INT2_PIN 2 + #define CORE_INT3_PIN 3 + #define CORE_INT4_PIN 4 + #define CORE_INT5_PIN 5 + #define CORE_INT6_PIN 6 + #define CORE_INT7_PIN 7 + #define CORE_INT8_PIN 8 + #define CORE_INT9_PIN 9 + #define CORE_INT10_PIN 10 + #define CORE_INT11_PIN 11 + #define CORE_INT12_PIN 12 + #define CORE_INT13_PIN 13 + #define CORE_INT14_PIN 14 + #define CORE_INT15_PIN 15 + #define CORE_INT16_PIN 16 + #define CORE_INT17_PIN 17 + #define CORE_INT18_PIN 18 + #define CORE_INT19_PIN 19 + #define CORE_INT20_PIN 20 + #define CORE_INT21_PIN 21 + #define CORE_INT22_PIN 22 + #define CORE_INT23_PIN 23 + #define CORE_INT24_PIN 24 + #define CORE_INT25_PIN 25 + #define CORE_INT26_PIN 26 + #define CORE_INT27_PIN 27 + #define CORE_INT28_PIN 28 + #define CORE_INT29_PIN 29 + #define CORE_INT30_PIN 30 + #define CORE_INT31_PIN 31 + #define CORE_INT32_PIN 32 + #define CORE_INT33_PIN 33 + #define CORE_INT34_PIN 34 + #define CORE_INT35_PIN 35 + #define CORE_INT36_PIN 36 + #define CORE_INT37_PIN 37 + #define CORE_INT38_PIN 38 + #define CORE_INT39_PIN 39 + #define CORE_INT40_PIN 40 + #define CORE_INT41_PIN 41 + #define CORE_INT42_PIN 42 + #define CORE_INT43_PIN 43 + #define CORE_INT44_PIN 44 + #define CORE_INT45_PIN 45 + #define CORE_INT46_PIN 46 + #define CORE_INT47_PIN 47 + #define CORE_INT48_PIN 48 + #define CORE_INT49_PIN 49 + #define CORE_INT50_PIN 50 + #define CORE_INT51_PIN 51 + #define CORE_INT52_PIN 52 + #define CORE_INT53_PIN 53 + +#endif +#endif + +#if !defined(CORE_NUM_INTERRUPT) +#error "Interrupts are unknown for this board, please add to this code" +#endif +#if CORE_NUM_INTERRUPT <= 0 +#error "Encoder requires interrupt pins, but this board does not have any :(" +#error "You could try defining ENCODER_DO_NOT_USE_INTERRUPTS as a kludge." +#endif + diff --git a/libraries/MenuBackend/LICENSE.txt b/libraries/MenuBackend/LICENSE.txt new file mode 100644 index 0000000..77cec6d --- /dev/null +++ b/libraries/MenuBackend/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/libraries/MenuBackend/MenuBackend.cpp b/libraries/MenuBackend/MenuBackend.cpp new file mode 100644 index 0000000..e078c50 --- /dev/null +++ b/libraries/MenuBackend/MenuBackend.cpp @@ -0,0 +1,19 @@ +/* $Id: MenuBackend.cpp 1198 2011-06-14 21:08:27Z bhagman $ +|| +|| @author Alexander Brevig +|| @url http://wiring.org.co/ +|| @contribution Adrian Brzezinski +|| @contribution Bernhard Benum +|| @contribution Brett Hagman +|| +|| @description +|| | Provides an easy way of making menus. +|| | +|| | Wiring Cross-platform Library +|| # +|| +|| @license Please see cores/Common/License.txt. +|| +*/ + +#include "MenuBackend.h" \ No newline at end of file diff --git a/libraries/MenuBackend/MenuBackend.h b/libraries/MenuBackend/MenuBackend.h new file mode 100644 index 0000000..ed43ac3 --- /dev/null +++ b/libraries/MenuBackend/MenuBackend.h @@ -0,0 +1,641 @@ +/* $Id: MenuBackend.h 1231 2011-08-25 10:57:49Z abrevig $ +|| +|| @author Alexander Brevig +|| @url http://wiring.org.co/ +|| @contribution Adrian Brzezinski +|| @contribution Bernhard Benum +|| @contribution Brett Hagman +|| @contribution Ryan Michael +|| +|| @description +|| | Provides an easy way of making menus. +|| | +|| | Wiring Cross-platform Library +|| # +|| +|| @license Please see cores/Common/License.txt. +|| +*/ + +#ifndef MENUBACKEND_H +#define MENUBACKEND_H +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +class MenuBackend; //forward declaration of the menu backend +class MenuItem; //forward declaration of the menu item + +struct MenuChangeEvent +{ + const MenuItem &from; + const MenuItem &to; +}; + +struct MenuUseEvent +{ + MenuItem &item; +}; + +struct MenuItemChangeEvent +{ + const MenuItem &item; +}; + +struct MenuMoveEvent +{ + const MenuItem &item; +}; + +typedef void (*cb_change)(MenuChangeEvent); +typedef void (*cb_use)(MenuUseEvent); +typedef void (*cb_move)(MenuMoveEvent); + + +/* + A menu item will be a container for an item that is a part of a menu + Each such item has a logical position in the hierarchy as well as a text and maybe a mnemonic shortkey +*/ +class MenuItem +{ + public: + const __FlashStringHelper *name; + + /* + || @constructor + || | Basic item with a name and an optional mnemonic [File (f)] + || # + || + || @example + || | MenuItem file = MenuItem("File",'F'); + || # + || + || @parameter itemName the name of the item + || @parameter shortKey the mnemonic 'shortkey' + */ + MenuItem(const __FlashStringHelper *itemName, uint8_t shortKey = 0) : name(itemName), shortkey(shortKey) + { + before = right = after = left = 0; + menuBackend = 0; + } + + /* + || @description + || | Register a backend for this item to use for callbacks and such + || # + || + || @parameter mb the menu backend that controls this item + */ + inline void registerBackend(MenuBackend &mb) + { + menuBackend = &mb; + } + + //void use(){} //update some internal data / statistics + /* + || @description + || | Get the name of this item + || # + || + || @return The name of this item + */ + inline const __FlashStringHelper * getName() const + { + return name; + } + /* + || @description + || | Get the shortkey of this item + || # + || + || @return The shortkey of this item + */ + inline uint8_t getShortkey() const + { + return shortkey; + } + /* + || @description + || | Check to see if this item has a shorkey + || # + || + || @return true if this item has a shorkey + */ + inline const bool hasShortkey() const + { + return (shortkey != '\0'); + } + + /* + || @description + || | Check to see if this item has children + || # + || + || @return true if the item has children + */ + inline const bool hasChildren() const + { + return (before || right || after || left); + } + + /* + || @description + || | Get the item 'before' this item + || # + || + || @return the item before this + */ + inline MenuItem *getBefore() const + { + return before; + } + /* + || @description + || | Get the item 'right' of this item + || # + || + || @return the item right of this + */ + inline MenuItem *getRight() const + { + return right; + } + /* + || @description + || | Get the item 'after' this item + || # + || + || @return the item after this + */ + inline MenuItem *getAfter() const + { + return after; + } + /* + || @description + || | Get the item 'left' of this item + || # + || + || @return the item left of this + */ + inline MenuItem *getLeft() const + { + return left; + } + + //default vertical menu + /* + || @description + || | Add an item after this item in the hierarchy + || # + || + || @parameter mi the item to add + || @return the item sent as parameter for chaining + */ + MenuItem &add(MenuItem &mi) + { + return addAfter(mi); + } + + /* + || @description + || | Add an item before this item in the hierarchy + || # + || + || @parameter mi the item to add + || @return the item sent as parameter for chaining + */ + MenuItem &addBefore(MenuItem &mi) + { + mi.after = this; + before = &mi; + return mi; + } + /* + || @description + || | Add an item right to this item in the hierarchy + || # + || + || @parameter mi the item to add + || @return the item sent as parameter for chaining + */ + MenuItem &addRight(MenuItem &mi) + { + mi.left = this; + right = &mi; + return mi; + } + /* + || @description + || | Add an item after this item in the hierarchy + || # + || + || @parameter mi the item to add + || @return the item sent as parameter for chaining + */ + MenuItem &addAfter(MenuItem &mi) + { + mi.before = this; + after = &mi; + return mi; + } + /* + || @description + || | Add an item left of this item in the hierarchy + || # + || + || @parameter mi the item to add + || @return the item sent as parameter for chaining + */ + MenuItem &addLeft(MenuItem &mi) + { + mi.right = this; + left = &mi; + return mi; + } + /* + || @description + || | Set a callback to be fired before any 'move' function is called with this item + || | as the current MenuItem. + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onChangeFrom(cb_change cb) + { + cb_onChangeFrom = cb; + return *this; + } + /* + || @description + || | Set a callback to be fired after any 'move' function is called with this item + || | as the resulting MenuItem. + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onChangeTo(cb_change cb) + { + cb_onChangeTo = cb; + return *this; + } + + /* + || @description + || | Set a callback to be fired when 'moveUp' is called with this item as the current MenuItem + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onUp(cb_move cb) + { + cb_onUp = cb; + return *this; + } + /* + || @description + || | Set a callback to be fired when 'moveDown' is called with this item as the current MenuItem + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onDown(cb_move cb) + { + cb_onDown = cb; + return *this; + } + /* + || @description + || | Set a callback to be fired when 'moveLeft' is called with this item as the current MenuItem + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onLeft(cb_move cb) + { + cb_onLeft = cb; + return *this; + } + /* + || @description + || | Set a callback to be fired when 'moveRight' is called with this item as the current MenuItem + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onRight(cb_move cb) + { + cb_onRight = cb; + return *this; + } + /* + || @description + || | Set a callback to be fired when 'use' is called with this item as the current MenuItem + || # + || + || @paramter cb The callback to be fired + || @return this MenuItem + */ + MenuItem &onUse(cb_use cb) + { + cb_onUse = cb; + return *this; + } + + protected: + uint8_t shortkey; + + MenuItem *before; + MenuItem *right; + MenuItem *after; + MenuItem *left; + + cb_change cb_onChangeFrom; + cb_change cb_onChangeTo; + cb_move cb_onUp; + cb_move cb_onDown; + cb_move cb_onLeft; + cb_move cb_onRight; + cb_use cb_onUse; + + MenuBackend *menuBackend; + + private: + friend class MenuBackend; + + MenuItem *moveUp() + { + return before; + } + + MenuItem *moveDown() + { + return after; + } + + MenuItem *moveLeft() + { + return left; + } + + MenuItem *moveRight() + { + return right; + } + +}; + +class MenuBackend +{ + public: + MenuBackend(cb_use menuUse, cb_change menuChange = 0) : root(F("MenuRoot")) + { + current = &root; + cb_menuChange = menuChange; + cb_menuUse = menuUse; + } + + /* + || @description + || | Get the root of this menu + || # + || + || @return the root item + */ + MenuItem &getRoot() + { + return root; + } + /* + || @description + || | Get the current item of this menu + || # + || + || @return the current item + */ + MenuItem &getCurrent() + { + return *current; + } + + /* + || @description + || | Move up in the menu structure, will fire move event + || # + */ + void moveUp() + { + if (current->cb_onUp) + { + MenuMoveEvent mme = { *current }; + (*current->cb_onUp)(mme); + } + setCurrent(current->moveUp()); + } + /* + || @description + || | Move down in the menu structure, will fire move event + || # + */ + void moveDown() + { + if (current->cb_onDown) + { + MenuMoveEvent mme = { *current }; + (*current->cb_onDown)(mme); + } + setCurrent(current->moveDown()); + } + /* + || @description + || | Move left in the menu structure, will fire move event + || # + */ + void moveLeft() + { + if (current->cb_onLeft) + { + MenuMoveEvent mme = { *current }; + (*current->cb_onLeft)(mme); + } + setCurrent(current->moveLeft()); + } + /* + || @description + || | Move right in the menu structure, will fire move event + || # + */ + void moveRight() + { + if (current->cb_onRight) + { + MenuMoveEvent mme = { *current }; + (*current->cb_onRight)(mme); + } + setCurrent(current->moveRight()); + } + /* + || @description + || | Use an item + || # + || + || @parameter item is the item to use + */ + void use(MenuItem &item) + { + setCurrent(&item); + use(); + } + /* + || @description + || | Use an item per its shortkey + || # + || + || @parameter shortkey the shortkey of the target item + */ + void use(uint8_t shortkey) + { + recursiveSearch(shortkey, &root); + use(); + } + /* + || @description + || | Use an item, will fire use event + || # + */ + void use() + { + //current->use(); + if (current->cb_onUse) + { + MenuUseEvent mue = { *current }; + (*current->cb_onUse)(mue); + } + if (cb_menuUse) + { + MenuUseEvent mue = { *current }; + cb_menuUse(mue); + } + } + /* + || @description + || | Select an item, will fire change event + || # + */ + void select(MenuItem &item) + { + setCurrent(&item); + } + + private: + void setCurrent(MenuItem *next) + { + if (next) + { + MenuChangeEvent mce = { *current, *next }; + if (current->cb_onChangeFrom) + { + (*current->cb_onChangeFrom)(mce); + } + if (next->cb_onChangeTo) + { + (*next->cb_onChangeTo)(mce); + } + if (cb_menuChange) + { + (*cb_menuChange)(mce); + } + current = next; + } + } + + void foundShortkeyItem(MenuItem *mi) + { + current = mi; + } + + char canSearch(uint8_t shortkey, MenuItem *m) + { + if (m == 0) + { + return 0; + } + else + { + if (m->getShortkey() == shortkey) + { + foundShortkeyItem(m); + return 1; + } + return -1; + } + } + + void rSAfter(uint8_t shortkey, MenuItem *m) + { + if (canSearch(shortkey, m) != 1) + { + rSAfter(shortkey, m->getAfter()); + rSRight(shortkey, m->getRight()); + rSLeft(shortkey, m->getLeft()); + } + } + + void rSRight(uint8_t shortkey, MenuItem *m) + { + if (canSearch(shortkey, m) != 1) + { + rSAfter(shortkey, m->getAfter()); + rSRight(shortkey, m->getRight()); + rSBefore(shortkey, m->getBefore()); + } + } + + void rSLeft(uint8_t shortkey, MenuItem *m) + { + if (canSearch(shortkey, m) != 1) + { + rSAfter(shortkey, m->getAfter()); + rSLeft(shortkey, m->getLeft()); + rSBefore(shortkey, m->getBefore()); + } + } + + void rSBefore(uint8_t shortkey, MenuItem *m) + { + if (canSearch(shortkey, m) != 1) + { + rSRight(shortkey, m->getRight()); + rSLeft(shortkey, m->getLeft()); + rSBefore(shortkey, m->getBefore()); + } + } + + void recursiveSearch(uint8_t shortkey, MenuItem *m) + { + if (canSearch(shortkey, m) != 1) + { + rSAfter(shortkey, m->getAfter()); + rSRight(shortkey, m->getRight()); + rSLeft(shortkey, m->getLeft()); + rSBefore(shortkey, m->getBefore()); + } + } + + MenuItem root; + MenuItem *current; + + cb_change cb_menuChange; + cb_use cb_menuUse; +}; + +#endif +// MENUBACKEND_H diff --git a/libraries/MenuBackend/examples/CallbackMenu/CallbackMenu.pde b/libraries/MenuBackend/examples/CallbackMenu/CallbackMenu.pde new file mode 100644 index 0000000..1244039 --- /dev/null +++ b/libraries/MenuBackend/examples/CallbackMenu/CallbackMenu.pde @@ -0,0 +1,162 @@ +/** + * HelloMenu + * by BREVIG http://alexanderbrevig.com + * modified kerinin@gmail.com + * + * This is the structure of the modelled menu + * + * Settings + * Pin + * Debug + * Options + * Delay (D) + * 100 ms + * 200 ms + * 300 ms + * 400 ms + */ + +#include + +//this controls the menu backend and the event generation +MenuBackend menu = MenuBackend(menuUseEvent,menuChangeEvent); + //beneath is list of menu items needed to build the menu + MenuItem settings = MenuItem(menu, "Settings", 1); + MenuItem pin = MenuItem(menu, "Pin", 2); + MenuItem debug = MenuItem(menu, "Debug", 2); + MenuItem options = MenuItem(menu, "Options", 1); + MenuItem setDelay = MenuItem(menu, "Delay",'D', 2); + MenuItem d100 = MenuItem(menu, "100 ms", 3); + MenuItem d200 = MenuItem(menu, "200 ms", 3); + MenuItem d300 = MenuItem(menu, "300 ms", 3); + MenuItem d400 = MenuItem(menu, "400 ms", 3); + +//this function builds the menu and connects the correct items together +void menuSetup() +{ + Serial.println("Setting up menu..."); + //add the file menu to the menu root + menu.getRoot() + .onLeft(handleInvalidMove) + .onRight(handleInvalidMove) + .onUp(handleInvalidMove) + .add(settings); + + //setup the settings menu item + settings.addAfter(options); + options.addAfter(settings); + + settings.onLeft(handleInvalidMove).addRight(pin); //chain settings to pin on right + debug.addLeft(settings); //also go to settings left for debug + //we want looping both up and down + pin.addBefore(debug); + pin.addAfter(debug); + debug.addBefore(pin); + debug.addAfter(pin); + + options.onLeft(handleInvalidMove).addRight(setDelay); //chain options to delay on right + setDelay.addRight(d100); + d100.addBefore(d100); //loop to d400 + d100.onChangeTo(handleDelayChange).onRight(handleSetDelay).addAfter(d200); + d200.onChangeTo(handleDelayChange).onRight(handleSetDelay).addAfter(d300); + d300.onChangeTo(handleDelayChange).onRight(handleSetDelay).addAfter(d400); + d400.onChangeTo(handleDelayChange).onRight(handleSetDelay).addAfter(d100); //loop back to d100 + //we want left to always be bak to delay + d100.addLeft(setDelay); + d200.addLeft(setDelay); + d300.addLeft(setDelay); + d400.addLeft(setDelay); +} + +/* + This function is called when you try to go someone + you don't belong +*/ +void handleInvalidMove(MenuMoveEvent menu) +{ + Serial.println("You cannot go there. It is not a place"); +} + +/* + This function is called when we change to + a 'delay' menu item. +*/ +void handleDelayChange(MenuChangeEvent changed) +{ + Serial.print("Selected delay changed from "); + Serial.print(changed.from.getName()); + Serial.print(" to "); + Serial.println(changed.to.getName()); +} + +/* + This function is called when moveRight() is called + with a delay menu item as the current menu. + + You could use this to change the value or something + similar +*/ +void handleSetDelay(MenuMoveEvent menu) +{ + Serial.print("Change delay to "); + Serial.print(menu.item.getName()); + Serial.println(" NOW!"); +} + +/* + This is an important function + Here all use events are handled + + This is where you define a behaviour for a menu item +*/ +void menuUseEvent(MenuUseEvent used) +{ + Serial.print("Menu use "); + Serial.println(used.item.getName()); + + if (used.item.isEqual(setDelay)) //comparison agains a known item + { + Serial.println("menuUseEvent found Delay (D)"); + } +} + +/* + This is an important function + Here we get a notification whenever the user changes the menu + That is, when the menu is navigated +*/ +void menuChangeEvent(MenuChangeEvent changed) +{ + Serial.print("Menu change "); + Serial.print(changed.from.getName()); + Serial.print(" "); + Serial.println(changed.to.getName()); +} + +void setup() +{ + Serial.begin(9600); + + menuSetup(); + Serial.println("Starting navigation:\r\nUp: w Down: s Left: a Right: d Use: e"); + + //fire Delay : menu.use('D'); + //bail back to Options by moving up one logical level after a D : menu.moveRelativeLevels(-1); +} + +void loop() +{ + if (Serial.available()) + { + byte read = Serial.read(); + switch (read) + { + case 'w': menu.moveUp(); break; + case 's': menu.moveDown(); break; + case 'd': menu.moveRight(); break; + case 'a': menu.moveLeft(); break; + case 'e': menu.use(); break; + } + } +} + diff --git a/libraries/MenuBackend/examples/CallbackMenu/printresult.txt b/libraries/MenuBackend/examples/CallbackMenu/printresult.txt new file mode 100644 index 0000000..1928167 --- /dev/null +++ b/libraries/MenuBackend/examples/CallbackMenu/printresult.txt @@ -0,0 +1,24 @@ +Setting up menu... +Starting navigation (see source for description): +Menu change MenuRoot File +Menu change File New +Menu change New Open +Menu change Open Examples +Menu change Examples ArduinoISP +Menu use ArduinoISP +menuUseEvent found ArduinoISP +Menu change ArduinoISP Examples +Menu change Examples Open +Menu change Open New +Menu change New File +Menu change File Edit +Menu change Edit Sketch +Menu change Sketch Verify +Menu use Verify +Menu change Verify Sketch +Menu change Sketch Edit +Menu change Edit File +Menu change File New +Menu use New +Menu use Verify +menuUseEvent found Verify (V) \ No newline at end of file diff --git a/libraries/MenuBackend/examples/HelloMenu/HelloMenu.pde b/libraries/MenuBackend/examples/HelloMenu/HelloMenu.pde new file mode 100644 index 0000000..ea31ed8 --- /dev/null +++ b/libraries/MenuBackend/examples/HelloMenu/HelloMenu.pde @@ -0,0 +1,123 @@ +/** + * HelloMenu + * by BREVIG http://alexanderbrevig.com + * + * This is the structure of the modelled menu + * + * Settings + * Pin + * Debug + * Options + * Delay (D) + * 100 ms + * 200 ms + * 300 ms + * 400 ms + */ + +#include + +//this controls the menu backend and the event generation +MenuBackend menu = MenuBackend(menuUseEvent,menuChangeEvent); + //beneath is list of menu items needed to build the menu + MenuItem settings = MenuItem(menu, "Settings", 1); + MenuItem pin = MenuItem(menu, "Pin", 2); + MenuItem debug = MenuItem(menu, "Debug", 2); + MenuItem options = MenuItem(menu, "Options", 1); + MenuItem setDelay = MenuItem(menu, "Delay",'D', 2); + MenuItem d100 = MenuItem(menu, "100 ms", 3); + MenuItem d200 = MenuItem(menu, "200 ms", 3); + MenuItem d300 = MenuItem(menu, "300 ms", 3); + MenuItem d400 = MenuItem(menu, "400 ms", 3); + +//this function builds the menu and connects the correct items together +void menuSetup() +{ + Serial.println("Setting up menu..."); + //add the file menu to the menu root + menu.getRoot().add(settings); + //setup the settings menu item + settings.addAfter(options); + options.addAfter(settings); + + settings.addLeft(settings); //loop back if left on settings + settings.addRight(pin); //chain settings to pin on right + debug.addLeft(settings); //also go to settings left for debug + //we want looping both up and down + pin.addBefore(debug); + pin.addAfter(debug); + debug.addBefore(pin); + debug.addAfter(pin); + + options.addLeft(options); //loop back if left on settings + options.addRight(setDelay); //chain options to delay on right + setDelay.addRight(d100); + d100.addBefore(d100); //loop to d400 + d100.addAfter(d200); + d200.addAfter(d300); + d300.addAfter(d400); + d400.addAfter(d100); //loop back to d100 + //we want left to always be bak to delay + d100.addLeft(setDelay); + d200.addLeft(setDelay); + d300.addLeft(setDelay); + d400.addLeft(setDelay); +} + +/* + This is an important function + Here all use events are handled + + This is where you define a behaviour for a menu item +*/ +void menuUseEvent(MenuUseEvent used) +{ + Serial.print("Menu use "); + Serial.println(used.item.getName()); + + if (used.item.isEqual(setDelay)) //comparison agains a known item + { + Serial.println("menuUseEvent found Delay (D)"); + } +} + +/* + This is an important function + Here we get a notification whenever the user changes the menu + That is, when the menu is navigated +*/ +void menuChangeEvent(MenuChangeEvent changed) +{ + Serial.print("Menu change "); + Serial.print(changed.from.getName()); + Serial.print(" "); + Serial.println(changed.to.getName()); +} + +void setup() +{ + Serial.begin(9600); + + menuSetup(); + Serial.println("Starting navigation:\r\nUp: w Down: s Left: a Right: d Use: e"); + + //fire Delay : menu.use('D'); + //bail back to Options by moving up one logical level after a D : menu.moveRelativeLevels(-1); +} + +void loop() +{ + if (Serial.available()) + { + byte read = Serial.read(); + switch (read) + { + case 'w': menu.moveUp(); break; + case 's': menu.moveDown(); break; + case 'd': menu.moveRight(); break; + case 'a': menu.moveLeft(); break; + case 'e': menu.use(); break; + } + } +} + diff --git a/libraries/MenuBackend/examples/HelloMenu/printresult.txt b/libraries/MenuBackend/examples/HelloMenu/printresult.txt new file mode 100644 index 0000000..1928167 --- /dev/null +++ b/libraries/MenuBackend/examples/HelloMenu/printresult.txt @@ -0,0 +1,24 @@ +Setting up menu... +Starting navigation (see source for description): +Menu change MenuRoot File +Menu change File New +Menu change New Open +Menu change Open Examples +Menu change Examples ArduinoISP +Menu use ArduinoISP +menuUseEvent found ArduinoISP +Menu change ArduinoISP Examples +Menu change Examples Open +Menu change Open New +Menu change New File +Menu change File Edit +Menu change Edit Sketch +Menu change Sketch Verify +Menu use Verify +Menu change Verify Sketch +Menu change Sketch Edit +Menu change Edit File +Menu change File New +Menu use New +Menu use Verify +menuUseEvent found Verify (V) \ No newline at end of file diff --git a/libraries/MenuBackend/keywords.txt b/libraries/MenuBackend/keywords.txt new file mode 100644 index 0000000..3a04972 --- /dev/null +++ b/libraries/MenuBackend/keywords.txt @@ -0,0 +1,59 @@ +####################################### +# Syntax Coloring Map For MenuBackend +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +MenuBackend KEYWORD1 +MenuItem KEYWORD1 +MenuChangeEvent KEYWORD1 +MenuUseEvent KEYWORD1 +MenuItemChangeEvent KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +registerBackend KEYWORD2 +moveRelativeLevels KEYWORD2 +moveToLevel KEYWORD2 +fireItemChangedEvent KEYWORD2 +getValue KEYWORD2 +setValue KEYWORD2 +increment KEYWORD2 +decrement KEYWORD2 +setLevel KEYWORD2 +getLevel KEYWORD2 +hasShortkey KEYWORD2 +getShortkey KEYWORD2 +getRoot KEYWORD2 +getCurrent KEYWORD2 +getName KEYWORD2 +getBack KEYWORD2 +getBefore KEYWORD2 +getRight KEYWORD2 +getAfter KEYWORD2 +getLeft KEYWORD2 +use KEYWORD2 +select KEYWORD2 +moveBack KEYWORD2 +moveUp KEYWORD2 +moveDown KEYWORD2 +moveLeft KEYWORD2 +moveRight KEYWORD2 +add KEYWORD2 +addBefore KEYWORD2 +addRight KEYWORD2 +addAfter KEYWORD2 +addLeft KEYWORD2 +from KEYWORD2 +to KEYWORD2 +item KEYWORD2 +isEqual KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/RTClib/RTClib.cpp b/libraries/RTClib/RTClib.cpp new file mode 100644 index 0000000..37a7d37 --- /dev/null +++ b/libraries/RTClib/RTClib.cpp @@ -0,0 +1,246 @@ +// Code by JeeLabs http://news.jeelabs.org/code/ +// Released to the public domain! Enjoy! + +#include +#include "RTClib.h" +#ifdef __AVR__ + #include + #define WIRE Wire +#else + #define PROGMEM + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) + #define WIRE Wire1 +#endif + +#define DS1307_ADDRESS 0x68 +#define SECONDS_PER_DAY 86400L + +#define SECONDS_FROM_1970_TO_2000 946684800 + +#if (ARDUINO >= 100) + #include // capital A so it is error prone on case-sensitive filesystems +#else + #include +#endif + +//////////////////////////////////////////////////////////////////////////////// +// utility code, some of this could be exposed in the DateTime API if needed + +const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; + +// number of days since 2000/01/01, valid for 2001..2099 +static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { + if (y >= 2000) + y -= 2000; + uint16_t days = d; + for (uint8_t i = 1; i < m; ++i) + days += pgm_read_byte(daysInMonth + i - 1); + if (m > 2 && y % 4 == 0) + ++days; + return days + 365 * y + (y + 3) / 4 - 1; +} + +static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { + return ((days * 24L + h) * 60 + m) * 60 + s; +} + +//////////////////////////////////////////////////////////////////////////////// +// DateTime implementation - ignores time zones and DST changes +// NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second + +DateTime::DateTime (uint32_t t) { + t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 + + ss = t % 60; + t /= 60; + mm = t % 60; + t /= 60; + hh = t % 24; + uint16_t days = t / 24; + uint8_t leap; + for (yOff = 0; ; ++yOff) { + leap = yOff % 4 == 0; + if (days < 365 + leap) + break; + days -= 365 + leap; + } + for (m = 1; ; ++m) { + uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1); + if (leap && m == 2) + ++daysPerMonth; + if (days < daysPerMonth) + break; + days -= daysPerMonth; + } + d = days + 1; +} + +DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) { + if (year >= 2000) + year -= 2000; + yOff = year; + m = month; + d = day; + hh = hour; + mm = min; + ss = sec; +} + +static uint8_t conv2d(const char* p) { + uint8_t v = 0; + if ('0' <= *p && *p <= '9') + v = *p - '0'; + return 10 * v + *++p - '0'; +} + +// A convenient constructor for using "the compiler's time": +// DateTime now (__DATE__, __TIME__); +// NOTE: using PSTR would further reduce the RAM footprint +DateTime::DateTime (const char* date, const char* time) { + // sample input: date = "Dec 26 2009", time = "12:34:56" + yOff = conv2d(date + 9); + // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec + switch (date[0]) { + case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break; + case 'F': m = 2; break; + case 'A': m = date[2] == 'r' ? 4 : 8; break; + case 'M': m = date[2] == 'r' ? 3 : 5; break; + case 'S': m = 9; break; + case 'O': m = 10; break; + case 'N': m = 11; break; + case 'D': m = 12; break; + } + d = conv2d(date + 4); + hh = conv2d(time); + mm = conv2d(time + 3); + ss = conv2d(time + 6); +} + +uint8_t DateTime::dayOfWeek() const { + uint16_t day = date2days(yOff, m, d); + return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 +} + +uint32_t DateTime::unixtime(void) const { + uint32_t t; + uint16_t days = date2days(yOff, m, d); + t = time2long(days, hh, mm, ss); + t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000 + + return t; +} + +//////////////////////////////////////////////////////////////////////////////// +// RTC_DS1307 implementation + +static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); } +static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); } + +uint8_t RTC_DS1307::begin(void) { + return 1; +} + + +#if (ARDUINO >= 100) + +uint8_t RTC_DS1307::isrunning(void) { + WIRE.beginTransmission(DS1307_ADDRESS); + WIRE.write(0); + WIRE.endTransmission(); + + WIRE.requestFrom(DS1307_ADDRESS, 1); + uint8_t ss = WIRE.read(); + return !(ss>>7); +} + +void RTC_DS1307::adjust(const DateTime& dt) { + WIRE.beginTransmission(DS1307_ADDRESS); + WIRE.write(0); + WIRE.write(bin2bcd(dt.second())); + WIRE.write(bin2bcd(dt.minute())); + WIRE.write(bin2bcd(dt.hour())); + WIRE.write(bin2bcd(0)); + WIRE.write(bin2bcd(dt.day())); + WIRE.write(bin2bcd(dt.month())); + WIRE.write(bin2bcd(dt.year() - 2000)); + WIRE.write(0); + WIRE.endTransmission(); +} + +DateTime RTC_DS1307::now() { + WIRE.beginTransmission(DS1307_ADDRESS); + WIRE.write(0); + WIRE.endTransmission(); + + WIRE.requestFrom(DS1307_ADDRESS, 7); + uint8_t ss = bcd2bin(WIRE.read() & 0x7F); + uint8_t mm = bcd2bin(WIRE.read()); + uint8_t hh = bcd2bin(WIRE.read()); + WIRE.read(); + uint8_t d = bcd2bin(WIRE.read()); + uint8_t m = bcd2bin(WIRE.read()); + uint16_t y = bcd2bin(WIRE.read()) + 2000; + + return DateTime (y, m, d, hh, mm, ss); +} + +#else + +uint8_t RTC_DS1307::isrunning(void) { + WIRE.beginTransmission(DS1307_ADDRESS); + WIRE.send(0); + WIRE.endTransmission(); + + WIRE.requestFrom(DS1307_ADDRESS, 1); + uint8_t ss = WIRE.receive(); + return !(ss>>7); +} + +void RTC_DS1307::adjust(const DateTime& dt) { + WIRE.beginTransmission(DS1307_ADDRESS); + WIRE.send(0); + WIRE.send(bin2bcd(dt.second())); + WIRE.send(bin2bcd(dt.minute())); + WIRE.send(bin2bcd(dt.hour())); + WIRE.send(bin2bcd(0)); + WIRE.send(bin2bcd(dt.day())); + WIRE.send(bin2bcd(dt.month())); + WIRE.send(bin2bcd(dt.year() - 2000)); + WIRE.send(0); + WIRE.endTransmission(); +} + +DateTime RTC_DS1307::now() { + WIRE.beginTransmission(DS1307_ADDRESS); + WIRE.send(0); + WIRE.endTransmission(); + + WIRE.requestFrom(DS1307_ADDRESS, 7); + uint8_t ss = bcd2bin(WIRE.receive() & 0x7F); + uint8_t mm = bcd2bin(WIRE.receive()); + uint8_t hh = bcd2bin(WIRE.receive()); + WIRE.receive(); + uint8_t d = bcd2bin(WIRE.receive()); + uint8_t m = bcd2bin(WIRE.receive()); + uint16_t y = bcd2bin(WIRE.receive()) + 2000; + + return DateTime (y, m, d, hh, mm, ss); +} + +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// RTC_Millis implementation + +long RTC_Millis::offset = 0; + +void RTC_Millis::adjust(const DateTime& dt) { + offset = dt.unixtime() - millis() / 1000; +} + +DateTime RTC_Millis::now() { + return (uint32_t)(offset + millis() / 1000); +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/libraries/RTClib/RTClib.h b/libraries/RTClib/RTClib.h new file mode 100644 index 0000000..a9301af --- /dev/null +++ b/libraries/RTClib/RTClib.h @@ -0,0 +1,52 @@ +// Code by JeeLabs http://news.jeelabs.org/code/ +// Released to the public domain! Enjoy! + +#ifndef _RTCLIB_H_ +#define _RTCLIB_H_ + +// Simple general-purpose date/time class (no TZ / DST / leap second handling!) +class DateTime { +public: + DateTime (uint32_t t =0); + DateTime (uint16_t year, uint8_t month, uint8_t day, + uint8_t hour =0, uint8_t min =0, uint8_t sec =0); + DateTime (const char* date, const char* time); + uint16_t year() const { return 2000 + yOff; } + uint8_t month() const { return m; } + uint8_t day() const { return d; } + uint8_t hour() const { return hh; } + uint8_t minute() const { return mm; } + uint8_t second() const { return ss; } + uint8_t dayOfWeek() const; + + // 32-bit times as seconds since 1/1/2000 + long secondstime() const; + // 32-bit times as seconds since 1/1/1970 + uint32_t unixtime(void) const; + +protected: + uint8_t yOff, m, d, hh, mm, ss; +}; + +// RTC based on the DS1307 chip connected via I2C and the Wire library +class RTC_DS1307 { +public: + static uint8_t begin(void); + static void adjust(const DateTime& dt); + uint8_t isrunning(void); + static DateTime now(); +}; + +// RTC using the internal millis() clock, has to be initialized before use +// NOTE: this clock won't be correct once the millis() timer rolls over (>49d?) +class RTC_Millis { +public: + static void begin(const DateTime& dt) { adjust(dt); } + static void adjust(const DateTime& dt); + static DateTime now(); + +protected: + static long offset; +}; + +#endif // _RTCLIB_H_ diff --git a/libraries/RTClib/examples/datecalc/datecalc.pde b/libraries/RTClib/examples/datecalc/datecalc.pde new file mode 100644 index 0000000..98d992c --- /dev/null +++ b/libraries/RTClib/examples/datecalc/datecalc.pde @@ -0,0 +1,65 @@ +// Simple date conversions and calculations + +#include +#include "RTClib.h" + +void showDate(const char* txt, const DateTime& dt) { + Serial.print(txt); + Serial.print(' '); + Serial.print(dt.year(), DEC); + Serial.print('/'); + Serial.print(dt.month(), DEC); + Serial.print('/'); + Serial.print(dt.day(), DEC); + Serial.print(' '); + Serial.print(dt.hour(), DEC); + Serial.print(':'); + Serial.print(dt.minute(), DEC); + Serial.print(':'); + Serial.print(dt.second(), DEC); + + Serial.print(" = "); + Serial.print(dt.unixtime()); + Serial.print("s / "); + Serial.print(dt.unixtime() / 86400L); + Serial.print("d since 1970"); + + Serial.println(); +} + +void setup () { + Serial.begin(57600); + + DateTime dt0 (0, 1, 1, 0, 0, 0); + showDate("dt0", dt0); + + DateTime dt1 (1, 1, 1, 0, 0, 0); + showDate("dt1", dt1); + + DateTime dt2 (2009, 1, 1, 0, 0, 0); + showDate("dt2", dt2); + + DateTime dt3 (2009, 1, 2, 0, 0, 0); + showDate("dt3", dt3); + + DateTime dt4 (2009, 1, 27, 0, 0, 0); + showDate("dt4", dt4); + + DateTime dt5 (2009, 2, 27, 0, 0, 0); + showDate("dt5", dt5); + + DateTime dt6 (2009, 12, 27, 0, 0, 0); + showDate("dt6", dt6); + + DateTime dt7 (dt6.unixtime() + 3600); // one hour later + showDate("dt7", dt7); + + DateTime dt8 (dt6.unixtime() + 86400L); // one day later + showDate("dt8", dt8); + + DateTime dt9 (dt6.unixtime() + 7 * 86400L); // one week later + showDate("dt9", dt9); +} + +void loop () { +} diff --git a/libraries/RTClib/examples/ds1307/ds1307.pde b/libraries/RTClib/examples/ds1307/ds1307.pde new file mode 100644 index 0000000..6d841a2 --- /dev/null +++ b/libraries/RTClib/examples/ds1307/ds1307.pde @@ -0,0 +1,65 @@ +// Date and time functions using a DS1307 RTC connected via I2C and Wire lib + +#include +#include "RTClib.h" + +RTC_DS1307 rtc; + +void setup () { + Serial.begin(57600); +#ifdef AVR + Wire.begin(); +#else + Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due +#endif + rtc.begin(); + + if (! rtc.isrunning()) { + Serial.println("RTC is NOT running!"); + // following line sets the RTC to the date & time this sketch was compiled + rtc.adjust(DateTime(__DATE__, __TIME__)); + } +} + +void loop () { + DateTime now = rtc.now(); + + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(' '); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); + + Serial.print(" since midnight 1/1/1970 = "); + Serial.print(now.unixtime()); + Serial.print("s = "); + Serial.print(now.unixtime() / 86400L); + Serial.println("d"); + + // calculate a date which is 7 days and 30 seconds into the future + DateTime future (now.unixtime() + 7 * 86400L + 30); + + Serial.print(" now + 7d + 30s: "); + Serial.print(future.year(), DEC); + Serial.print('/'); + Serial.print(future.month(), DEC); + Serial.print('/'); + Serial.print(future.day(), DEC); + Serial.print(' '); + Serial.print(future.hour(), DEC); + Serial.print(':'); + Serial.print(future.minute(), DEC); + Serial.print(':'); + Serial.print(future.second(), DEC); + Serial.println(); + + Serial.println(); + delay(3000); +} diff --git a/libraries/RTClib/examples/softrtc/softrtc.pde b/libraries/RTClib/examples/softrtc/softrtc.pde new file mode 100644 index 0000000..0a6ba06 --- /dev/null +++ b/libraries/RTClib/examples/softrtc/softrtc.pde @@ -0,0 +1,52 @@ +// Date and time functions using just software, based on millis() & timer + +#include +#include "RTClib.h" + +RTC_Millis rtc; + +void setup () { + Serial.begin(57600); + // following line sets the RTC to the date & time this sketch was compiled + rtc.begin(DateTime(__DATE__, __TIME__)); +} + +void loop () { + DateTime now = rtc.now(); + + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(' '); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); + + Serial.print(" seconds since 1970: "); + Serial.println(now.unixtime()); + + // calculate a date which is 7 days and 30 seconds into the future + DateTime future (now.unixtime() + 7 * 86400L + 30); + + Serial.print(" now + 7d + 30s: "); + Serial.print(future.year(), DEC); + Serial.print('/'); + Serial.print(future.month(), DEC); + Serial.print('/'); + Serial.print(future.day(), DEC); + Serial.print(' '); + Serial.print(future.hour(), DEC); + Serial.print(':'); + Serial.print(future.minute(), DEC); + Serial.print(':'); + Serial.print(future.second(), DEC); + Serial.println(); + + Serial.println(); + delay(3000); +} diff --git a/libraries/RTClib/keywords.txt b/libraries/RTClib/keywords.txt new file mode 100644 index 0000000..f0bdeac --- /dev/null +++ b/libraries/RTClib/keywords.txt @@ -0,0 +1,34 @@ +####################################### +# Syntax Coloring Map For RTC +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DateTime KEYWORD1 +RTC_DS1307 KEYWORD1 +RTC_Millis KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +year KEYWORD2 +month KEYWORD2 +day KEYWORD2 +hour KEYWORD2 +minute KEYWORD2 +second KEYWORD2 +dayOfWeek KEYWORD2 +secondstime KEYWORD2 +unixtime KEYWORD2 +begin KEYWORD2 +adjust KEYWORD2 +isrunning KEYWORD2 +now KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/toneAC/examples/toneAC_demo/toneAC_demo.pde b/libraries/toneAC/examples/toneAC_demo/toneAC_demo.pde new file mode 100644 index 0000000..f91cae4 --- /dev/null +++ b/libraries/toneAC/examples/toneAC_demo/toneAC_demo.pde @@ -0,0 +1,35 @@ +// --------------------------------------------------------------------------- +// Connect your piezo buzzer (without internal oscillator) or speaker to these pins: +// Pins 9 & 10 - ATmega328, ATmega128, ATmega640, ATmega8, Uno, Leonardo, etc. +// Pins 11 & 12 - ATmega2560/2561, ATmega1280/1281, Mega +// Pins 12 & 13 - ATmega1284P, ATmega644 +// Pins 14 & 15 - Teensy 2.0 +// Pins 25 & 26 - Teensy++ 2.0 +// Be sure to include an inline 100 ohm resistor on one pin as you normally do when connecting a piezo or speaker. +// --------------------------------------------------------------------------- + +#include + +// Melody liberated from the toneMelody Arduino example sketch by Tom Igoe. +int melody[] = { 262, 196, 196, 220, 196, 0, 247, 262 }; +int noteDurations[] = { 4, 8, 8, 4, 4, 4, 4, 4 }; + +void setup() {} // Nothing to setup, just start playing! + +void loop() { + for (unsigned long freq = 125; freq <= 15000; freq += 10) { + toneAC(freq); // Play the frequency (125 Hz to 15 kHz sweep in 10 Hz steps). + delay(1); // Wait 1 ms so you can hear it. + } + toneAC(); // Turn off toneAC, can also use noToneAC(). + + delay(1000); // Wait a second. + + for (int thisNote = 0; thisNote < 8; thisNote++) { + int noteDuration = 1000/noteDurations[thisNote]; + toneAC(melody[thisNote], 10, noteDuration, true); // Play thisNote at full volume for noteDuration in the background. + delay(noteDuration * 4 / 3); // Wait while the tone plays in the background, plus another 33% delay between notes. + } + + while(1); // Stop (so it doesn't repeat forever driving you crazy--you're welcome). +} \ No newline at end of file diff --git a/libraries/toneAC/examples/toneAC_dual_LED/toneAC_dual_LED.pde b/libraries/toneAC/examples/toneAC_dual_LED/toneAC_dual_LED.pde new file mode 100644 index 0000000..b0fcf31 --- /dev/null +++ b/libraries/toneAC/examples/toneAC_dual_LED/toneAC_dual_LED.pde @@ -0,0 +1,25 @@ +// --------------------------------------------------------------------------- +// Connect a two-pin dual LED to the following pins with inline 220 ohm resistor. +// Pins 9 & 10 - ATmega328, ATmega128, ATmega640, ATmega8, Uno, Leonardo, etc. +// Pins 11 & 12 - ATmega2560/2561, ATmega1280/1281, Mega +// Pins 12 & 13 - ATmega1284P, ATmega644 +// Pins 14 & 15 - Teensy 2.0 +// Pins 25 & 26 - Teensy++ 2.0 +// Connect the center lead of a potentiometer to analog pin A0 and the other two leads to +5V and ground. +// --------------------------------------------------------------------------- + +#include + +unsigned long timestamp = 0; // Stores when the next time the routine is set to run. + +void setup() {} + +void loop() { + if (millis() > timestamp) { // Is it time yet? + timestamp += 500; // Set the next time routine will run. 500 ms because the lowest frequency is 2 Hz, which is a half second. + int pot = analogRead(A0); // Read the potentiometer connected to analog pin A0 to control alternating flashing speed. + int freq = map(pot, 0, 1023, 2, 40); // Convert pot analog values to a range from 2 to 40 Hz. + toneAC(freq, 10, 0, true); // Set the frequency and have it run forever in the background (next event should take over in 500 ms). + } + /* Do a bunch of other stuff here, it won't affect toneAC doing its thing. */ +} diff --git a/libraries/toneAC/keywords.txt b/libraries/toneAC/keywords.txt new file mode 100644 index 0000000..0157d52 --- /dev/null +++ b/libraries/toneAC/keywords.txt @@ -0,0 +1,18 @@ +################################### +# Syntax Coloring Map For toneAC +################################### + +################################### +# Datatypes (KEYWORD1) +################################### + +################################### +# Methods and Functions (KEYWORD2) +################################### + +toneAC KEYWORD2 +noToneAC KEYWORD2 + +################################### +# Constants (LITERAL1) +################################### diff --git a/libraries/toneAC/toneAC.cpp b/libraries/toneAC/toneAC.cpp new file mode 100644 index 0000000..d73f345 --- /dev/null +++ b/libraries/toneAC/toneAC.cpp @@ -0,0 +1,68 @@ +// --------------------------------------------------------------------------- +// Created by Tim Eckel - teckel@leethost.com +// Copyright 2013 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html +// +// See "toneAC.h" for purpose, syntax, version history, links, and more. +// --------------------------------------------------------------------------- + +#include "toneAC.h" + +unsigned long _tAC_time; // Used to track end note with timer when playing note in the background. +#ifndef TONEAC_TINY +uint8_t _tAC_volume[] = { 200, 100, 67, 50, 40, 33, 29, 22, 11, 2 }; // Duty for linear volume control. +#endif + +#ifndef TONEAC_TINY +void toneAC(unsigned long frequency, uint8_t volume, unsigned long length, uint8_t background) { + if (frequency == 0 || volume == 0) { noToneAC(); return; } // If frequency or volume are 0, turn off sound and return. + if (volume > 10) volume = 10; // Make sure volume is in range (1 to 10). +#else +void toneAC(unsigned long frequency, unsigned long length) { + if (frequency == 0) { noToneAC(); return; } // If frequency is 0, turn off sound and return. +#endif + + PWMT1DREG |= _BV(PWMT1AMASK) | _BV(PWMT1BMASK); // Set timer 1 PWM pins to OUTPUT (because analogWrite does it too). + + uint8_t prescaler = _BV(CS10); // Try using prescaler 1 first. + unsigned long top = F_CPU / frequency / 2 - 1; // Calculate the top. + if (top > 65535) { // If not in the range for prescaler 1, use prescaler 256 (122 Hz and lower @ 16 MHz). + prescaler = _BV(CS12); // Set the 256 prescaler bit. + top = top / 256 - 1; // Calculate the top using prescaler 256. + } +#ifndef TONEAC_TINY + unsigned int duty = top / _tAC_volume[volume - 1]; // Calculate the duty cycle (volume). +#else + unsigned int duty = top >> 1; // 50% duty cycle (loudest and highest quality). +#endif + +#ifndef TONEAC_TINY + if (length > 0 && background) { // Background tone playing, returns control to your sketch. +#else + if (length > 0) { // Background tone playing, returns control to your sketch. +#endif + _tAC_time = millis() + length; // Set when the note should end. + TIMSK1 |= _BV(OCIE1A); // Activate the timer interrupt. + } + + ICR1 = top; // Set the top. + if (TCNT1 > top) TCNT1 = top; // Counter over the top, put within range. + TCCR1B = _BV(WGM13) | prescaler; // Set PWM, phase and frequency corrected (top=ICR1) and prescaler. + OCR1A = OCR1B = duty; // Set the duty cycle (volume). + TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(COM1B0); // Inverted/non-inverted mode (AC). + +#ifndef TONEAC_TINY + if (length > 0 && !background) { delay(length); noToneAC(); } // Just a simple delay, doesn't return control till finished. +#endif +} + +void noToneAC() { + TIMSK1 &= ~_BV(OCIE1A); // Remove the timer interrupt. + TCCR1B = _BV(CS11); // Default clock prescaler of 8. + TCCR1A = _BV(WGM10); // Set to defaults so PWM can work like normal (PWM, phase corrected, 8bit). + PWMT1PORT &= ~_BV(PWMT1AMASK); // Set timer 1 PWM pins to LOW. + PWMT1PORT &= ~_BV(PWMT1BMASK); // Other timer 1 PWM pin also to LOW. +} + +ISR(TIMER1_COMPA_vect) { // Timer interrupt vector. + if (millis() >= _tAC_time) noToneAC(); // Check to see if it's time for the note to end. +} \ No newline at end of file diff --git a/libraries/toneAC/toneAC.h b/libraries/toneAC/toneAC.h new file mode 100644 index 0000000..c88b53a --- /dev/null +++ b/libraries/toneAC/toneAC.h @@ -0,0 +1,111 @@ +// --------------------------------------------------------------------------- +// toneAC Library - v1.2 - 01/27/2013 +// +// AUTHOR/LICENSE: +// Created by Tim Eckel - teckel@leethost.com +// Copyright 2013 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html +// +// LINKS: +// Project home: http://code.google.com/p/arduino-tone-ac/ +// Blog: http://arduino.cc/forum/index.php/topic,142097.msg1066968.html +// +// DISCLAIMER: +// This software is furnished "as is", without technical support, and with no +// warranty, express or implied, as to its usefulness for any purpose. +// +// PURPOSE: +// Replacement to the standard tone library with the advantage of nearly twice +// the volume, higher frequencies (even if running at a lower clock speed), +// higher quality (less clicking), nearly 1.5k smaller compiled code and less +// stress on the speaker. Disadvantages are that it must use certain pins and +// it uses two pins instead of one. But, if you're flexible with your pin +// choices, this is a great upgrade. It also uses timer 1 instead of timer 2, +// which may free up a conflict you have with the tone library. It exclusively +// uses port registers for the fastest and smallest code possible. +// +// USAGE: +// Connection is very similar to a piezo or standard speaker. Except, instead +// of connecting one speaker wire to ground you connect both speaker wires to +// Arduino pins. The pins you connect to are specific, as toneAC lets the +// ATmega microcontroller do all the pin timing and switching. This is +// important due to the high switching speed possible with toneAC and to make +// sure the pins are alyways perfectly out of phase with each other +// (push/pull). See the below CONNECTION section for which pins to use for +// different Arduinos. Just as usual when connecting a speaker, make sure you +// add an inline 100 ohm resistor between one of the pins and the speaker wire. +// +// CONNECTION: +// Pins 9 & 10 - ATmega328, ATmega128, ATmega640, ATmega8, Uno, Leonardo, etc. +// Pins 11 & 12 - ATmega2560/2561, ATmega1280/1281, Mega +// Pins 12 & 13 - ATmega1284P, ATmega644 +// Pins 14 & 15 - Teensy 2.0 +// Pins 25 & 26 - Teensy++ 2.0 +// +// SYNTAX: +// toneAC( frequency [, volume [, length [, background ]]] ) - Play a note. +// Parameters: +// * frequency - Play the specified frequency indefinitely, turn off with toneAC(). +// * volume - [optional] Set a volume level. (default: 10, range: 0 to 10 [0 = off]) +// * length - [optional] Set the length to play in milliseconds. (default: 0 [forever], range: 0 to 2^32-1) +// * background - [optional] Play note in background or pause till finished? (default: false, values: true/false) +// toneAC() - Stop playing. +// noToneAC() - Same as toneAC(). +// +// HISTORY: +// 01/27/2013 v1.2 - Fixed a counter error which went "over the top" and caused +// periods of silence (thanks Krodal). For advanced users needing tight code, +// the TONEAC_TINY switch in toneAC.h activates a version of toneAC() that +// saves 110 bytes. With TONEAC_TINY, the syntax is toneAC(frequency, length) +// while playing the note at full volume forever in the background. Added +// support for the ATmega 640, 644, 1281, 1284P and 2561 microcontrollers. +// +// 01/16/2013 v1.1 - Option to play notes in background, returning control back +// to your sketch for processing while note plays (similar to the way the tone +// library works). Volume is now linear and in the range from 0-10. Now uses +// prescaler 256 instead of 64 for frequencies below 122 Hz so it can go down +// to 1 Hz no matter what speed the CPU is clocked at (helpful if using toneAC +// to control a two-pin dual LED). +// +// 01/11/2013 v1.0 - Initial release. +// +// --------------------------------------------------------------------------- + +#ifndef toneAC_h + #define toneAC_h + + #if defined(ARDUINO) && ARDUINO >= 100 + #include + #else + #include + #endif + + //#define TONEAC_TINY // Uncomment to use alternate function toneAC(frequency, length) that saves 110 bytes. + + #if defined (__AVR_ATmega32U4__) || defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) + #define PWMT1AMASK DDB5 + #define PWMT1BMASK DDB6 + #define PWMT1DREG DDRB + #define PWMT1PORT PORTB + #elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) + #define PWMT1AMASK DDD4 + #define PWMT1BMASK DDD5 + #define PWMT1DREG DDRD + #define PWMT1PORT PORTD + #else + #define PWMT1AMASK DDB1 + #define PWMT1BMASK DDB2 + #define PWMT1DREG DDRB + #define PWMT1PORT PORTB + #endif + + #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__) + #define TIMSK1 TIMSK + #endif + + #ifndef TONEAC_TINY + void toneAC(unsigned long frequency = 0, uint8_t volume = 10, unsigned long length = 0, uint8_t background = false); + #else + void toneAC(unsigned long frequency = 0, unsigned long length = 0); + #endif + void noToneAC(); +#endif \ No newline at end of file