Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit f589611b6b0c05b30fd72b94d68b2282e7206e76 @dmalec committed Jun 20, 2012
Showing with 425 additions and 0 deletions.
  1. +295 −0 OledTrainSchedule.ino
  2. +23 −0 README.md
  3. +61 −0 ScheduleEntry.cpp
  4. +46 −0 ScheduleEntry.h
@@ -0,0 +1,295 @@
+// --------------------------------------------------------------------------------
+// An Arduino sketch to display a random train schedule on an OLED.
+//
+// MIT license.
+//
+// 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.
+//
+// **********************************************************
+// Designed for the Adafruit OLED Breakout Board - 16-bit Color 0.96" w/microSD holder
+// http://www.adafruit.com/products/684
+// **********************************************************
+//
+// --------------------------------------------------------------------------------
+// Dependencies
+// --------------------------------------------------------------------------------
+// Adafruit Industries's core graphics library:
+// https://github.com/adafruit/Adafruit-GFX-Library
+// Adafruit Industries's SSD1331 OLED driver library:
+// https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino
+// Adafruit Industries's DS1307 RTC library:
+// https://github.com/adafruit/RTClib
+// --------------------------------------------------------------------------------
+#include <Adafruit_GFX.h>
+#include <Adafruit_SSD1331.h>
+#include <SPI.h>
+#include <Wire.h>
+#include <RTClib.h>
+#include "ScheduleEntry.h"
+
+//! The array of city names to choose from.
+/*!
+ When adding or removing cities, adjust the NUMBER_OF_CITIES to match.
+ City names of 10 characters or less work best for the screen size.
+*/
+const int NUMBER_OF_CITIES = 20;
+const char *names_of_cities[NUMBER_OF_CITIES] = {
+ "ALBANY",
+ "BERKELEY",
+ "BOSTON",
+ "BUFFALO",
+ "CHICAGO",
+ "DENVER",
+ "DETROIT",
+ "D.C.",
+ "DURAND",
+ "HOBOKEN",
+ "L.A.",
+ "MILWAUKEE",
+ "NEW HAVEN",
+ "NEWARK",
+ "NEW YORK",
+ "PROVIDENCE",
+ "SEATTLE",
+ "ST. LOUIS",
+ "SYRACUSE",
+ "TRENTON"
+};
+
+//! The current display screen.
+uint8_t current_screen_index;
+
+//! The timestamp of the last screen change.
+long last_screen_change_tstamp;
+
+//! The number of seconds to display each screen.
+const uint8_t seconds_to_display_screen = 5;
+
+//! The number of seconds to display departed entries.
+const uint8_t seconds_to_display_departed_entries = 60;
+
+//! Number of entries per screen, 6 fits nicely.
+const uint8_t number_of_entries_per_screen = 6;
+
+//! Number of screens to show.
+const uint8_t number_of_screens = 3;
+
+//! Maximum number of minutes past current time to schedule departure times.
+const uint8_t minutes_until_departure = 15;
+
+//! Percentage of late departures.
+const uint8_t percent_late_departures = 30;
+
+//! MAximum number of minutes to be late.
+const long minutes_late = 10;
+
+//! Number of total entries.
+const uint8_t number_of_entries = number_of_screens * number_of_entries_per_screen;
+
+//! The array of all destinations
+ScheduleEntry schedule_entries[number_of_entries];
+
+//! Configure the SSD1331 display to use hardware SPI pins, from the example sketch.
+#define cs 10
+#define rst 9
+#define dc 8
+Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);
+
+//! Colors used by the sketch.
+#define BLACK 0x0000
+#define BLUE 0x001F
+#define RED 0xF800
+#define GREEN 0x07E0
+#define WHITE 0xFFFF
+
+//! Mock real time clock for keeping time.
+RTC_Millis rtc;
+
+//! The current time per the real time clock.
+DateTime now;
+
+//! Perform all initialization.
+void setup(void) {
+ // Initialize the serial connection for debugging.
+ Serial.begin(9600);
+ Serial.println(F("Serial initialized"));
+
+ // Use Pin 0 to seed the random number generator.
+ randomSeed(analogRead(0));
+
+ // Initialize the real time clock and time variables.
+ rtc.begin(DateTime(__DATE__, __TIME__));
+ now = rtc.now();
+ last_screen_change_tstamp = now.unixtime();
+
+ // Initialize the schedule entries.
+ for (uint8_t i=0; i<number_of_entries; i++) {
+ generate_new_entry(i);
+ }
+
+ // Initialize the OLED.
+ display.begin();
+ display.fillScreen(BLACK);
+
+ // Render page 0 of entries.
+ current_screen_index = 0;
+ display_current_screen();
+
+ // Draw the bottom blue bar.
+ display.fillRect(0, 56, 96, 8, BLUE);
+ display.setTextColor(WHITE);
+
+ // Draw the town name.
+ display.setCursor(0, 56);
+ display.print(F("BRICKVILLE"));
+}
+
+void loop(void) {
+ now = rtc.now();
+ static int old_minute;
+
+ // Update the clock in the bottom banner if needed.
+ if (old_minute != now.minute()) {
+ // Erase the old time.
+ display.fillRect(64, 56, 32, 8, BLUE);
+
+ // Draw the new time.
+ display.setCursor(64, 56);
+ display.setTextColor(WHITE);
+ print_time(now.hour(), now.minute());
+
+ // Update the timestamp.
+ old_minute = now.minute();
+ }
+
+ // At the configured interval, change to the next screen of entries.
+ if (now.unixtime() - last_screen_change_tstamp >= seconds_to_display_screen) {
+ current_screen_index++;
+
+ // Wrap around to the first screen if at the last screen.
+ if (current_screen_index >= number_of_screens) {
+ current_screen_index = 0;
+ }
+
+ display_current_screen();
+
+ // Update the timestamp.
+ last_screen_change_tstamp = now.unixtime();
+ }
+
+ // Regenerate entries that departed more than the configured number of minutes ago.
+ for (int i=0; i<number_of_entries; i++) {
+ if ((now.unixtime() > schedule_entries[i].getActualTstamp()) &&
+ (now.unixtime() - schedule_entries[i].getActualTstamp() >= seconds_to_display_departed_entries)) {
+ generate_new_entry(i);
+ }
+ }
+
+ delay(100);
+}
+
+//! Randomly generate a new entry.
+void generate_new_entry(uint8_t index) {
+ // Randomly choose a scheduled departure time.
+ long total_minutes = 1 + random(minutes_until_departure);
+
+ // Calculate the hours and minutes.
+ uint8_t hours = total_minutes / 60;
+ uint8_t minutes = total_minutes % 60;
+
+ // Add to the current time.
+ hours += now.hour();
+ minutes += now.minute();
+
+ // Account for minute wrap around.
+ if (minutes > 59) {
+ minutes -= 60;
+ hours++;
+ }
+
+ // Account for hours wrap around.
+ if (hours > 23) {
+ hours -= 24;
+ }
+
+ // Randomly choose some departures as late.
+ if (random(100) > percent_late_departures) {
+ schedule_entries[index].setActualTstamp(now.unixtime() + (uint32_t)(total_minutes * 60));
+ } else {
+ schedule_entries[index].setActualTstamp(now.unixtime() + (uint32_t)((total_minutes + random(minutes_late)) * 60));
+ }
+
+ // Populate the schedule entry with the new values.
+ schedule_entries[index].setScheduledTstamp(now.unixtime() + (uint32_t)(total_minutes * 60));
+ schedule_entries[index].setHours(hours);
+ schedule_entries[index].setMinutes(minutes);
+ schedule_entries[index].setCityIndex(random(NUMBER_OF_CITIES));
+
+ // Debugging output.
+ Serial.print(F("New Entry ("));
+ Serial.print(index);
+ Serial.print(F(") "));
+ Serial.print(names_of_cities[schedule_entries[index].getCityIndex()]);
+ Serial.print(F(" "));
+ Serial.print(schedule_entries[index].getHours());
+ Serial.print(F(":"));
+ Serial.print(schedule_entries[index].getMinutes());
+ Serial.print(F(" "));
+ Serial.print(schedule_entries[index].getScheduledTstamp());
+ Serial.print(F("/"));
+ Serial.print(schedule_entries[index].getActualTstamp());
+ Serial.println();
+}
+
+//! Display the current page of entries.
+void display_current_screen() {
+ uint8_t schedule_index;
+
+ // Erase the schedule area
+ display.fillRect(0, 0, 96, 56, BLACK);
+
+ for (int row = 0; row < number_of_entries_per_screen; row++) {
+ schedule_index = current_screen_index * number_of_entries_per_screen + row;
+
+ // Display the city name in white.
+ display.setTextColor(WHITE);
+ display.setCursor(0, row * 8);
+ display.print(names_of_cities[schedule_entries[schedule_index].getCityIndex()]);
+
+ display.setCursor(64, row * 8);
+ if (now.unixtime() > schedule_entries[schedule_index].getActualTstamp()) {
+ // If the entry is departed, display a green DPRTD instead of time.
+ display.setTextColor(GREEN);
+ display.print(F("DPRTD"));
+ } else {
+ // If the entry is late, display the time in red, otherwise in white.
+ if (now.unixtime() > schedule_entries[schedule_index].getScheduledTstamp()) {
+ display.setTextColor(RED);
+ } else {
+ display.setTextColor(WHITE);
+ }
+ print_time(schedule_entries[schedule_index].getHours(), schedule_entries[schedule_index].getMinutes());
+ }
+ }
+}
+
+//! Utility function to print a zero padded time.
+void print_time(uint8_t hours, uint8_t minutes) {
+ if (hours < 10) {
+ display.print('0');
+ }
+ display.print(hours);
+
+ display.print(':');
+
+ if (minutes < 10) {
+ display.print('0');
+ }
+ display.print(minutes);
+}
@@ -0,0 +1,23 @@
+OledTrainSchedule
+==============
+
+An Arduino sketch to display a random train schedule on an OLED.
+
+Requirements
+------------
+* An Arduino
+* An [Adafruit OLED Breakout Board - 16-bit Color 0.96" w/microSD holder](http://www.adafruit.com/products/684)
+* Arduino IDE 1.0 or 1.0.1
+
+Dependencies
+------------
+* [Adafruit Industries's core graphics library](https://github.com/adafruit/Adafruit-GFX-Library)
+* [Adafruit Industries's SSD1331 OLED driver library](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino)
+* [Adafruit Industries's DS1307 RTC library](https://github.com/adafruit/RTClib)
+
+Installing
+----------
+1. Download the most recent ZIP of the project
+2. Extract the archive
+3. Rename the folder to OledTrainSchedule
+3. Open the sketch in the Arduino IDE
@@ -0,0 +1,61 @@
+// --------------------------------------------------------------------------------
+// MIT license.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+// --------------------------------------------------------------------------------
+#include "ScheduleEntry.h"
+
+//! Class Constructor.
+ScheduleEntry::ScheduleEntry() {
+ _scheduled_tstamp = 0;
+ _actual_tstamp = 0;
+ _hours = 0;
+ _minutes = 0;
+ _city_index = 0;
+}
+
+void ScheduleEntry::setScheduledTstamp(uint32_t scheduled_tstamp) {
+ _scheduled_tstamp = scheduled_tstamp;
+}
+
+uint32_t ScheduleEntry::getScheduledTstamp() {
+ return _scheduled_tstamp;
+}
+
+void ScheduleEntry::setActualTstamp(uint32_t actual_tstamp) {
+ _actual_tstamp = actual_tstamp;
+}
+
+uint32_t ScheduleEntry::getActualTstamp() {
+ return _actual_tstamp;
+}
+
+void ScheduleEntry::setHours(uint8_t hours) {
+ _hours = hours;
+}
+
+uint8_t ScheduleEntry::getHours() {
+ return _hours;
+}
+
+void ScheduleEntry::setMinutes(uint8_t minutes) {
+ _minutes = minutes;
+}
+
+uint8_t ScheduleEntry::getMinutes() {
+ return _minutes;
+}
+
+void ScheduleEntry::setCityIndex(uint8_t city_index) {
+ _city_index = city_index;
+}
+
+uint8_t ScheduleEntry::getCityIndex() {
+ return _city_index;
+}
Oops, something went wrong.

0 comments on commit f589611

Please sign in to comment.