├── libraries ├── IniFileLite │ ├── test │ │ ├── SD.h │ │ ├── Ethernet.h │ │ ├── readme.md │ │ ├── arduino_compat.h │ │ ├── File.h │ │ ├── IPAddress.cpp │ │ ├── readtest.cpp │ │ ├── IPAddress.h │ │ ├── Makefile │ │ ├── test.ini │ │ ├── File.cpp │ │ ├── ini_test.regressiontest │ │ └── ini_test.cpp │ ├── examples │ │ └── IniFileExample │ │ │ ├── net.ini │ │ │ └── IniFileExample.ino │ ├── readme.txt │ ├── IniFileLite.h │ ├── IniFileLite.cpp │ └── LICENSE └── RTClite │ ├── RTClite.h │ └── RTClite.cpp ├── sd ├── sd_master_kickstarter.zip └── readme.txt ├── readme.txt ├── LICENSE └── gameFrame_Game └── gameFrame_Game.ino /libraries/IniFileLite/test/SD.h: -------------------------------------------------------------------------------- 1 | #ifndef _SD_H 2 | #define _SD_H 3 | #include "File.h" 4 | 5 | #endif 6 | 7 | -------------------------------------------------------------------------------- /sd/sd_master_kickstarter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jerware/GameFrame/HEAD/sd/sd_master_kickstarter.zip -------------------------------------------------------------------------------- /libraries/IniFileLite/test/Ethernet.h: -------------------------------------------------------------------------------- 1 | #ifndef _ETHERNET_H 2 | #define _ETHERNET_H 3 | 4 | 5 | #include "IPAddress.h" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /sd/readme.txt: -------------------------------------------------------------------------------- 1 | If files on your microSD become corrupted, Game Frame will show an "SD" error message. 2 | 3 | Try reformatting the microSD using this tool: 4 | https://www.sdcard.org/downloads/formatter/ 5 | 6 | Then extract a fresh copy of the data onto the root. 7 | If that doesn't work, you might need to replace the microSD card with a new one. 8 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/readme.md: -------------------------------------------------------------------------------- 1 | # Test files 2 | 3 | Files to allow the IniFile library to be developed and tested under a 4 | standard g++ environment. 5 | 6 | ## Makefile targets 7 | 8 | make ini_test 9 | Make the test program. 10 | 11 | make run 12 | Make and run the test program. 13 | 14 | make regressiontest 15 | Run regression tests. 16 | 17 | make clean 18 | Remove some non-source files. 19 | 20 | make realclean 21 | Remove all non-versioned files. 22 | 23 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Game Frame Source 2 | ========= 3 | This Arduino source code is for use with Game Frame, a pixel display available from LEDSEQ.COM. 4 | It compiles under Arduino 1.0.1, and requires the following libraries: 5 | 6 | SPI (Distributed with Arduino IDE) 7 | EEPROM (Distributed with Arduino IDE) 8 | RTClite (available in this repository) 9 | IniFileLite (available in this repository) 10 | Adafruit_NeoPixel (https://github.com/adafruit/Adafruit_NeoPixel) 11 | SdFat (https://code.google.com/p/sdfatlib/) -------------------------------------------------------------------------------- /libraries/IniFileLite/test/arduino_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARDUINO_COMPAT_H 2 | #define _ARDUINO_COMPAT_H 3 | 4 | #include 5 | #include 6 | //#include 7 | //#include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | typedef unsigned char uint8_t; 15 | typedef unsigned short uint16_t; 16 | typedef unsigned long uint32_t; 17 | typedef bool boolean; 18 | //#define uint8_t unsigned char 19 | 20 | #define FILE_READ O_RDONLY 21 | #define FILE_WRITE (O_RDWR | O_CREAT) 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/File.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILE_H 2 | #define _FILE_H 3 | 4 | #include "arduino_compat.h" 5 | 6 | class File { 7 | public: 8 | File(void); 9 | File(const char *filename, uint8_t mode); 10 | File(const File &a); 11 | ~File(); 12 | 13 | File& operator=(const File &a); 14 | 15 | void close(void); 16 | 17 | int read(void); 18 | int read(void *buf, int n); 19 | 20 | int peek(void); 21 | bool seek(int pos); 22 | 23 | bool isOpen(void) const; 24 | operator bool() const; 25 | 26 | long size(void); 27 | long position(void); 28 | int available(void); 29 | 30 | private: 31 | FILE *_f; 32 | 33 | }; 34 | 35 | class SDClass { 36 | public: 37 | SDClass(void) { }; 38 | 39 | File open(const char *filename, uint8_t mode) const; 40 | 41 | private: 42 | 43 | }; 44 | 45 | extern SDClass SD; 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /libraries/RTClite/RTClite.h: -------------------------------------------------------------------------------- 1 | // Adapted from public domain code by JeeLabs http://news.jeelabs.org/code/ 2 | 3 | // Simple general-purpose date/time class (no TZ / DST / leap second handling!) 4 | class DateTime { 5 | public: 6 | DateTime(uint32_t t=0); 7 | DateTime(uint16_t year, uint8_t month, uint8_t day, 8 | uint8_t hour=0, uint8_t min=0, uint8_t sec=0); 9 | DateTime(const char* date, const char* time); 10 | uint16_t year() const { return 2000 + yOff; } 11 | uint8_t month() const { return m; } 12 | uint8_t day() const { return d; } 13 | uint8_t hour() const { return hh; } 14 | uint8_t minute() const { return mm; } 15 | uint8_t second() const { return ss; } 16 | uint8_t dayOfWeek() const; 17 | 18 | protected: 19 | uint8_t yOff, m, d, hh, mm, ss; 20 | }; 21 | 22 | // RTC based on the DS1307 chip connected via I2C and the Wire library 23 | class RTC_DS1307 { 24 | public: 25 | static int8_t begin(void); 26 | uint8_t isrunning(void); 27 | static void adjust(const DateTime& dt); 28 | static DateTime now(); 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/IPAddress.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | IPAddress::IPAddress() 5 | { 6 | memset(_address, 0, sizeof(_address)); 7 | } 8 | 9 | IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) 10 | { 11 | _address[0] = first_octet; 12 | _address[1] = second_octet; 13 | _address[2] = third_octet; 14 | _address[3] = fourth_octet; 15 | } 16 | 17 | IPAddress::IPAddress(uint32_t address) 18 | { 19 | memcpy(_address, &address, sizeof(_address)); 20 | } 21 | 22 | IPAddress::IPAddress(const uint8_t *address) 23 | { 24 | memcpy(_address, address, sizeof(_address)); 25 | } 26 | 27 | IPAddress& IPAddress::operator=(const uint8_t *address) 28 | { 29 | memcpy(_address, address, sizeof(_address)); 30 | return *this; 31 | } 32 | 33 | IPAddress& IPAddress::operator=(uint32_t address) 34 | { 35 | memcpy(_address, (const uint8_t *)&address, sizeof(_address)); 36 | return *this; 37 | } 38 | 39 | bool IPAddress::operator==(const uint8_t* addr) 40 | { 41 | return memcmp(addr, _address, sizeof(_address)) == 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/readtest.cpp: -------------------------------------------------------------------------------- 1 | #include "arduino_compat.h" 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "File.h" 7 | #include "IniFile.h" 8 | 9 | enum { 10 | errorFileNotOpen = -1, 11 | errorBufferTooShort = -2, 12 | errorSeekError = -3, 13 | }; 14 | 15 | 16 | int main(void) 17 | { 18 | const int len = 80; 19 | char buffer[len] = {'\0'}; 20 | uint32_t pos = 0; 21 | 22 | IniFile ini("test.ini"); 23 | IniFileState state; 24 | ini.open(); 25 | 26 | state = IniFileState(); 27 | while (ini.getValue("network", "mac", buffer, len, state) == 0) 28 | ; 29 | cout << "Found: " << buffer << endl; 30 | 31 | return 0; 32 | 33 | // ***************************************************************** 34 | const char filename[] = "test.ini"; 35 | File file = SD.open(filename, FILE_READ); 36 | if (!file) { 37 | cout << "Cannot open " << filename << endl; 38 | return 1; 39 | } 40 | while (1) { 41 | int done = IniFile::readLine(file, buffer, len, pos); 42 | //cout << "---\nREAD: " << buffer << endl; 43 | cout << buffer << endl; 44 | //cout << "pos: " << pos << endl; 45 | if (done) { 46 | //cout << "done: " << done << endl; 47 | break; 48 | } 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/IPAddress.h: -------------------------------------------------------------------------------- 1 | #ifndef _IPADDRESS_H 2 | #define _IPADDRESS_H 3 | 4 | #include "arduino_compat.h" 5 | 6 | class IPAddress { 7 | public: 8 | // Constructors 9 | IPAddress(); 10 | IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); 11 | IPAddress(uint32_t address); 12 | IPAddress(const uint8_t *address); 13 | 14 | // Overloaded cast operator to allow IPAddress objects to be used where a pointer 15 | // to a four-byte uint8_t array is expected 16 | operator uint32_t() { return *((uint32_t*)_address); }; 17 | 18 | bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; 19 | bool operator==(const uint8_t* addr); 20 | 21 | // Overloaded index operator to allow getting and setting individual octets of the address 22 | uint8_t operator[](int index) const { return _address[index]; }; 23 | uint8_t& operator[](int index) { return _address[index]; }; 24 | 25 | // Overloaded copy operators to allow initialisation of IPAddress objects from other types 26 | IPAddress& operator=(const uint8_t *address); 27 | IPAddress& operator=(uint32_t address); 28 | 29 | private: 30 | uint8_t _address[4]; // IPv4 address 31 | 32 | uint8_t* raw_address() { return _address; }; 33 | 34 | 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/Makefile: -------------------------------------------------------------------------------- 1 | DIFF = diff 2 | RM = rm -f 3 | CXXFLAGS += -ggdb -Wall -I. 4 | 5 | default: ini_test 6 | 7 | .PHONY : IniFile.h 8 | IniFile.h : ../IniFile.h 9 | echo '' > $@ 10 | echo '#include "arduino_compat.h"' >> $@ 11 | echo '#include ' >> $@ 12 | echo 'using namespace ::std;' >> $@ 13 | cat $< >> $@ 14 | 15 | IniFile.cpp : ../IniFile.cpp 16 | cp $< $@ 17 | 18 | IniFile.o : IniFile.cpp IniFile.h 19 | $(CXX) $(CXXFLAGS) -c $< -o $@ 20 | 21 | File.o : File.cpp File.h 22 | $(CXX) $(CXXFLAGS) -c $< -o $@ 23 | 24 | IPAddress.o : IPAddress.cpp IPAddress.h 25 | $(CXX) $(CXXFLAGS) -c $< -o $@ 26 | 27 | ini_test.o : ini_test.cpp IniFile.h 28 | 29 | ini_test : ini_test.o IniFile.o File.o IPAddress.o 30 | $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ 31 | 32 | # Regression testing. Run as "make regressiontest", should display 33 | # "TEST PASSED" if everything ok. 34 | .PHONY : regressiontest 35 | regressiontest : 36 | $(MAKE) realclean 37 | $(MAKE) ini_test 38 | ./ini_test > ini_test.regressiontest.tmp 39 | $(DIFF) -s -u ini_test.regressiontest ini_test.regressiontest.tmp 40 | -$(RM) ini_test.regressiontest.tmp 41 | @echo 42 | @echo TEST PASSED 43 | 44 | .PHONY : clean 45 | clean : 46 | -$(RM) *.o IniFile.h IniFile.cpp ini_test.regressiontest.tmp 47 | 48 | .PHONY : realclean 49 | realclean : clean 50 | -$(RM) -f ini_test 51 | 52 | readtest : readtest.o File.o IniFile.o IPAddress.o 53 | $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ 54 | 55 | readtest.o : readtest.cpp IniFile.h 56 | 57 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/test.ini: -------------------------------------------------------------------------------- 1 | ; Semi-colon comment 2 | [network] 3 | mac = 01:23:45:67:89:AB 4 | 5 | # hash comment, leading spaces below 6 | gateway = 192.168.1.1 7 | 8 | # extraneous spaces before and after key and value 9 | ip = 192.168.1.2 10 | 11 | hosts allow = example.com 12 | 13 | # A similarly-named section 14 | [network2] 15 | mac = ee:ee:ee:ee:ee:ee 16 | subnet mask=255.255.255.0 17 | 18 | ; Test extra whitespace in keys and value 19 | hosts allow = sloppy.example.com 20 | 21 | [misc] 22 | 23 | string = 123456789012345678901234567890123456789001234567890 24 | string2 = a string with spaces in it 25 | 26 | ; ini file for WwwServerExample 27 | 28 | [mime types] 29 | default = text/plain 30 | htm = text/html 31 | bin = application/octet-stream 32 | pdf = application/pdf 33 | 34 | [/] 35 | ; no access to root of SD filesystem 36 | handler = default 37 | error document 403 = /errordoc/403.htm 38 | 39 | [/www.ini] 40 | handler = default 41 | 42 | [/data] 43 | handler = default 44 | 45 | [/data/private] 46 | ; Block access to this directory 47 | handler = prohibit 48 | error document 403 = /data/private/403.htm 49 | 50 | [/data/noaccess.txt] 51 | ; Block access to this file 52 | handler = prohibit 53 | 54 | [/status] 55 | ; built-in status handler 56 | handler = status 57 | 58 | [/cgi] 59 | ; User-defined handler 60 | handler = cgi 61 | 62 | [/src] 63 | ; A redirect 64 | handler = temporary redirect 65 | location = http://github.com/stevemarple/WwwServer 66 | 67 | [/upload] 68 | allow put = true 69 | -------------------------------------------------------------------------------- /libraries/IniFileLite/examples/IniFileExample/net.ini: -------------------------------------------------------------------------------- 1 | ; Semi-colon comment 2 | [network] 3 | mac = 01:23:45:67:89:AB 4 | 5 | # hash comment, leading spaces below 6 | gateway = 192.168.1.1 7 | 8 | # extraneous spaces before and after key and value 9 | ip = 192.168.1.2 10 | 11 | hosts allow = example.com 12 | 13 | # A similarly-named section 14 | [network2] 15 | mac = ee:ee:ee:ee:ee:ee 16 | subnet mask=255.255.255.0 17 | 18 | ; Test extra whitespace in keys and value 19 | hosts allow = sloppy.example.com 20 | 21 | [misc] 22 | 23 | string = 123456789012345678901234567890123456789001234567890 24 | string2 = a string with spaces in it 25 | 26 | ; ini file for WwwServerExample 27 | 28 | [mime types] 29 | default = text/plain 30 | htm = text/html 31 | bin = application/octet-stream 32 | pdf = application/pdf 33 | 34 | [/] 35 | ; no access to root of SD filesystem 36 | handler = default 37 | error document 403 = /errordoc/403.htm 38 | 39 | [/www.ini] 40 | handler = default 41 | 42 | [/data] 43 | handler = default 44 | 45 | [/data/private] 46 | ; Block access to this directory 47 | handler = prohibit 48 | error document 403 = /data/private/403.htm 49 | 50 | [/data/noaccess.txt] 51 | ; Block access to this file 52 | handler = prohibit 53 | 54 | [/status] 55 | ; built-in status handler 56 | handler = status 57 | 58 | [/cgi] 59 | ; User-defined handler 60 | handler = cgi 61 | 62 | [/src] 63 | ; A redirect 64 | handler = temporary redirect 65 | location = http://github.com/stevemarple/WwwServer 66 | 67 | [/upload] 68 | allow put = true 69 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/File.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "File.h" 6 | 7 | #include // DEBUGGING 8 | using namespace::std; 9 | 10 | SDClass SD; 11 | 12 | File SDClass::open(const char *filename, uint8_t mode) const 13 | { 14 | return File(filename, mode); 15 | } 16 | 17 | File::File(void) 18 | { 19 | _f = NULL; 20 | } 21 | 22 | File::File(const char *filename, uint8_t mode) 23 | { 24 | //cout << "Opening " << filename << " with mode " 25 | // << (mode & O_WRONLY ? "r+" : "r") << endl; 26 | _f = fopen(filename, mode & O_WRONLY ? "r+" : "r"); 27 | } 28 | 29 | File::File(const File &a) 30 | { 31 | _f = a._f; 32 | } 33 | 34 | File::~File() 35 | { 36 | //close(); 37 | } 38 | 39 | File& File::operator=(const File &a) 40 | { 41 | _f = a._f; 42 | return *this; 43 | } 44 | 45 | void File::close(void) 46 | { 47 | if (_f != NULL) 48 | fclose(_f); 49 | _f = NULL; 50 | } 51 | 52 | bool File::isOpen(void) const 53 | { 54 | return _f != NULL; 55 | } 56 | 57 | File::operator bool() const 58 | { 59 | return isOpen(); 60 | } 61 | 62 | 63 | long File::size(void) 64 | { 65 | if (!isOpen()) 66 | return -1; 67 | //return size() - position(); 68 | long cur = ftell(_f); 69 | fseek(_f, 0, SEEK_END); // seek to eof 70 | long sz = ftell(_f); 71 | fseek(_f, cur, SEEK_SET); // return to initial position 72 | return sz; 73 | } 74 | 75 | long File::position(void) 76 | { 77 | if (!isOpen()) 78 | return -1; 79 | return ftell(_f); 80 | } 81 | 82 | 83 | int File::available(void) 84 | { 85 | if (!isOpen()) 86 | return 0; 87 | return size() - position(); 88 | } 89 | 90 | int File::read(void) 91 | { 92 | if (!available()) 93 | return -1; 94 | char c; 95 | fread(&c, 1, 1, _f); 96 | return c; 97 | } 98 | 99 | int File::read(void *buf, int n) 100 | { 101 | return fread(buf, 1, n ,_f); 102 | } 103 | 104 | int File::peek(void) 105 | { 106 | if (!available()) 107 | return -1; 108 | 109 | char c; 110 | fread(&c, 1, 1, _f); 111 | ungetc(c, _f); 112 | return c; 113 | } 114 | 115 | bool File::seek(int pos) 116 | { 117 | if (_f == NULL) 118 | return false; 119 | return (fseek(_f, pos, SEEK_SET) == -1 ? false : true); 120 | } 121 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/ini_test.regressiontest: -------------------------------------------------------------------------------- 1 | *** Testing IniFile(char*) *** 2 | Using file missing.ini 3 | File open? false 4 | Looking for key "mac" 5 | Error: file not open (2) 6 | Looking for key "mac" in section "network" 7 | Error: file not open (2) 8 | Looking for key "mac" in section "network2" 9 | Error: file not open (2) 10 | Looking for key "mac" in section "fake" 11 | Error: file not open (2) 12 | Looking for key "ip" 13 | Error: file not open (2) 14 | Looking for key "gateway" 15 | Error: file not open (2) 16 | Looking for key "hosts allow" in section "network" 17 | Error: file not open (2) 18 | Looking for key "hosts allow" in section "network" 19 | Error: file not open (2) 20 | Looking for key "hosts allow" in section "network2" 21 | Error: file not open (2) 22 | Looking for key "hosts allow" in section "network2" 23 | Error: file not open (2) 24 | Looking for key "string" in section "misc" 25 | Error: file not open (2) 26 | Looking for key "string2" in section "misc" 27 | Error: file not open (2) 28 | ---- 29 | Using file test.ini 30 | File open? true 31 | Looking for key "mac" 32 | Value of mac is "01:23:45:67:89:AB" 33 | Looking for key "mac" in section "network" 34 | Value of mac is "01:23:45:67:89:AB" 35 | Looking for key "mac" in section "network2" 36 | Value of mac is "ee:ee:ee:ee:ee:ee" 37 | Looking for key "mac" in section "fake" 38 | Error: section not found (5) 39 | Looking for key "ip" 40 | Value of ip is "192.168.1.2" 41 | Looking for key "gateway" 42 | Value of gateway is "192.168.1.1" 43 | Looking for key "hosts allow" in section "network" 44 | Value of hosts allow is "example.com" 45 | Looking for key "hosts allow" in section "network" 46 | Value of hosts allow is "example.com" 47 | Looking for key "hosts allow" in section "network2" 48 | Value of hosts allow is "sloppy.example.com" 49 | Looking for key "hosts allow" in section "network2" 50 | Value of hosts allow is "sloppy.example.com" 51 | Looking for key "string" in section "misc" 52 | Value of string is "123456789012345678901234567890123456789001234567890" 53 | Looking for key "string2" in section "misc" 54 | Value of string2 is "a string with spaces in it" 55 | ---- 56 | Done 57 | -------------------------------------------------------------------------------- /libraries/IniFileLite/readme.txt: -------------------------------------------------------------------------------- 1 | On July 13, 2014, Jeremy Williams wrote: 2 | NOTE: This library was edited for compatibility with SdFat and 3 | to reduce memory usage. Some networking functionality has 4 | been disabled. The original library can be found here: 5 | https://github.com/stevemarple/IniFile 6 | ---------- 7 | 8 | IniFile is an Arduino library for parsing INI files. The format is 9 | similar to that seen in Microsoft .ini files but the implementation is 10 | completely independent. IniFile is designed to use minimal memory 11 | requirements, and the only buffer used is one supplied by the user, 12 | thus the user remains in charge of memory usage. 13 | 14 | The ini file is separated into sections, where the section names are 15 | written inside square brackets. If you don't wish to use sections then 16 | pass a NULL pointer for the section name. Under each section are a set 17 | of key-value pairs, separated by an equals sign. Spaces around keys 18 | and values are ignored, but extra spaces inside the key are 19 | significant. Whitespace inside the value string is preserved; if 20 | leading or trailing whitespace is important you must quote the value 21 | string inside the ini file, and you must strip out the quotes 22 | yourself. If multiple entries for the same key exist inside the 23 | selected section (if using) then only the first value is returned. If 24 | a section is defined more than once only the first is used. The ini 25 | file can contain comments, which begin with a semicolon (;) or hash 26 | (#). The user-supplied buffer must be large enough to accomodate the 27 | longest line in the file. 28 | 29 | Example file format: 30 | 31 | -----------------------------------------8<--------------------- 32 | ; Semi-colon comment 33 | [network] 34 | mac = 01:23:45:67:89:AB 35 | 36 | # hash comment, leading spaces below 37 | gateway = 192.168.1.1 38 | 39 | # extraneous spaces before and after key and value 40 | ip = 192.168.1.2 41 | 42 | hosts allow = example.com 43 | 44 | # A similarly-named section 45 | [network2] 46 | mac = ee:ee:ee:ee:ee:ee 47 | subnet mask=255.255.255.0 48 | 49 | ; Extra whitespace around the key and value is permitted 50 | ; (and ignored) 51 | hosts allow = sloppy.example.com 52 | 53 | [misc] 54 | 55 | string = 123456789012345678901234567890123456789001234567890 56 | string2 = a string with spaces in it 57 | 58 | ; This section is a repeat of en existing section and will be ignored. 59 | [network] 60 | mac = 01:23:45:67:89:ab 61 | ip = 192.168.1.2 62 | gateway 63 | 64 | -----------------------------------------8<--------------------- 65 | -------------------------------------------------------------------------------- /libraries/IniFileLite/test/ini_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "IniFile.h" 4 | 5 | using namespace std; 6 | 7 | 8 | const char noError[] = "no error"; 9 | const char fileNotFound[] = "file not found"; 10 | const char fileNotOpen[] = "file not open"; 11 | const char bufferTooSmall[] = "buffer too small"; 12 | const char seekError[] = "seek error"; 13 | const char sectionNotFound[] = "section not found"; 14 | const char keyNotFound[] = "key not found"; 15 | const char unknownError[] = "unknown error"; 16 | const char unknownErrorValue[] = "unknown error value"; 17 | 18 | const char* getErrorMessage(int e) 19 | { 20 | const char *cp = unknownError; 21 | 22 | switch (e) { 23 | case IniFile::errorNoError: 24 | cp = noError; 25 | break; 26 | case IniFile::errorFileNotFound: 27 | cp = fileNotFound; 28 | break; 29 | case IniFile::errorFileNotOpen: 30 | cp = fileNotOpen; 31 | break; 32 | case IniFile::errorBufferTooSmall: 33 | cp = bufferTooSmall; 34 | break; 35 | case IniFile::errorSeekError: 36 | cp = seekError; 37 | break; 38 | case IniFile::errorSectionNotFound: 39 | cp = sectionNotFound; 40 | break; 41 | case IniFile::errorKeyNotFound: 42 | cp = keyNotFound; 43 | break; 44 | default: 45 | cp = unknownErrorValue; 46 | break; 47 | }; 48 | return cp; 49 | } 50 | 51 | void testForKey(IniFile &ini, const char *key, const char *section = NULL) 52 | { 53 | cout << " Looking for key \"" << key << '"'; 54 | if (section) 55 | cout << " in section \"" << section << "\""; 56 | cout << endl; 57 | 58 | const int len = 80; 59 | char buffer[len]; 60 | 61 | bool b = ini.getValue(section, key, buffer, len); 62 | if (b == false) { 63 | int e = ini.getError(); 64 | cout << " Error: " << getErrorMessage(e) << " (" << int(e) << ")" 65 | << endl; 66 | if (b == IniFile::errorBufferTooSmall) 67 | cout << "Buffer too small for line \"" << buffer << "...\"" << endl; 68 | } 69 | else 70 | cout << " Value of " << key << " is \"" << buffer << '"' << endl; 71 | 72 | } 73 | 74 | void runTest(IniFile &ini) 75 | { 76 | cout << "Using file " << ini.getFilename() << endl; 77 | cout << " File open? " << (ini.isOpen() ? "true" : "false") << endl; 78 | 79 | testForKey(ini, "mac"); 80 | testForKey(ini, "mac", "network"); 81 | testForKey(ini, "mac", "network2"); 82 | testForKey(ini, "mac", "fake"); 83 | testForKey(ini, "ip"); 84 | testForKey(ini, "gateway"); 85 | testForKey(ini, "hosts allow", "network"); 86 | testForKey(ini, "hosts allow", "network"); 87 | testForKey(ini, "hosts allow", "network2"); 88 | testForKey(ini, "hosts allow", "network2"); 89 | testForKey(ini, "string", "misc"); 90 | testForKey(ini, "string2", "misc"); 91 | cout << "----" << endl; 92 | 93 | 94 | } 95 | 96 | 97 | int main(void) 98 | { 99 | 100 | // Cannot cleanly pass string constants to IniFile constructor 101 | // because is doesn't take const char*, but that is because 102 | // SD.open() isn't const char*. 103 | char missingIniFilename[] = "missing.ini"; 104 | char testIniFilename[] = "test.ini"; 105 | 106 | // Try the construtor which opens a file 107 | IniFile missingIni(missingIniFilename); 108 | IniFile testIni(testIniFilename); 109 | 110 | cout << "*** Testing IniFile(char*) ***" << endl; 111 | missingIni.open(); 112 | runTest(missingIni); 113 | testIni.open(); 114 | runTest(testIni); 115 | cout << "Done" << endl; 116 | 117 | } 118 | 119 | 120 | -------------------------------------------------------------------------------- /libraries/IniFileLite/examples/IniFileExample/IniFileExample.ino: -------------------------------------------------------------------------------- 1 | #include 2 | //#include 3 | SdFat sd; 4 | #include 5 | #include 6 | #include 7 | 8 | // The select pin used for the SD card 9 | //#define SD_SELECT 4 10 | #define SD_SELECT 22 11 | #define ETHERNET_SELECT 10 12 | 13 | void printErrorMessage(uint8_t e, bool eol = true) 14 | { 15 | switch (e) { 16 | case IniFile::errorNoError: 17 | Serial.print("no error"); 18 | break; 19 | case IniFile::errorFileNotFound: 20 | Serial.print("file not found"); 21 | break; 22 | case IniFile::errorFileNotOpen: 23 | Serial.print("file not open"); 24 | break; 25 | case IniFile::errorBufferTooSmall: 26 | Serial.print("buffer too small"); 27 | break; 28 | case IniFile::errorSeekError: 29 | Serial.print("seek error"); 30 | break; 31 | case IniFile::errorSectionNotFound: 32 | Serial.print("section not found"); 33 | break; 34 | case IniFile::errorKeyNotFound: 35 | Serial.print("key not found"); 36 | break; 37 | case IniFile::errorEndOfFile: 38 | Serial.print("end of file"); 39 | break; 40 | case IniFile::errorUnknownError: 41 | Serial.print("unknown error"); 42 | break; 43 | default: 44 | Serial.print("unknown error value"); 45 | break; 46 | } 47 | if (eol) 48 | Serial.println(); 49 | } 50 | 51 | void setup() 52 | { 53 | // Configure all of the SPI select pins as outputs and make SPI 54 | // devices inactive, otherwise the earlier init routines may fail 55 | // for devices which have not yet been configured. 56 | pinMode(SD_SELECT, OUTPUT); 57 | digitalWrite(SD_SELECT, HIGH); // disable SD card 58 | 59 | pinMode(ETHERNET_SELECT, OUTPUT); 60 | digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet 61 | 62 | const size_t bufferLen = 80; 63 | char buffer[bufferLen]; 64 | 65 | const char *filename = "/net.ini"; 66 | Serial.begin(9600); 67 | SPI.begin(); 68 | if (!sd.begin(SD_SELECT)) 69 | while (1) 70 | Serial.println("SD.begin() failed"); 71 | 72 | IniFile ini(filename); 73 | if (!ini.open()) { 74 | Serial.print("Ini file "); 75 | Serial.print(filename); 76 | Serial.println(" does not exist"); 77 | // Cannot do anything else 78 | while (1) 79 | ; 80 | } 81 | Serial.println("Ini file exists"); 82 | 83 | // Check the file is valid. This can be used to warn if any lines 84 | // are longer than the buffer. 85 | if (!ini.validate(buffer, bufferLen)) { 86 | Serial.print("ini file "); 87 | Serial.print(ini.getFilename()); 88 | Serial.print(" not valid: "); 89 | printErrorMessage(ini.getError()); 90 | // Cannot do anything else 91 | while (1) 92 | ; 93 | } 94 | 95 | // Fetch a value from a key which is present 96 | if (ini.getValue("network", "mac", buffer, bufferLen)) { 97 | Serial.print("section 'network' has an entry 'mac' with value "); 98 | Serial.println(buffer); 99 | } 100 | else { 101 | Serial.print("Could not read 'mac' from section 'network', error was "); 102 | printErrorMessage(ini.getError()); 103 | } 104 | 105 | // Try fetching a value from a missing key (but section is present) 106 | if (ini.getValue("network", "nosuchkey", buffer, bufferLen)) { 107 | Serial.print("section 'network' has an entry 'nosuchkey' with value "); 108 | Serial.println(buffer); 109 | } 110 | else { 111 | Serial.print("Could not read 'nosuchkey' from section 'network', error was "); 112 | printErrorMessage(ini.getError()); 113 | } 114 | 115 | // Try fetching a key from a section which is not present 116 | if (ini.getValue("nosuchsection", "nosuchkey", buffer, bufferLen)) { 117 | Serial.print("section 'nosuchsection' has an entry 'nosuchkey' with value "); 118 | Serial.println(buffer); 119 | } 120 | else { 121 | Serial.print("Could not read 'nosuchkey' from section 'nosuchsection', error was "); 122 | printErrorMessage(ini.getError()); 123 | } 124 | 125 | // Fetch a boolean value 126 | bool allowPut; // variable where result will be stored 127 | bool found = ini.getValue("/upload", "allow put", buffer, bufferLen, allowPut); 128 | if (found) { 129 | Serial.print("The value of 'allow put' in section '/upload' is "); 130 | // Print value, converting boolean to a string 131 | Serial.println(allowPut ? "TRUE" : "FALSE"); 132 | } 133 | else { 134 | Serial.print("Could not get the value of 'allow put' in section '/upload': "); 135 | printErrorMessage(ini.getError()); 136 | } 137 | } 138 | 139 | 140 | void loop() 141 | { 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /libraries/IniFileLite/IniFileLite.h: -------------------------------------------------------------------------------- 1 | #ifndef _INIFILE_H 2 | #define _INIFILE_H 3 | 4 | // Maximum length for filename, excluding NULL char 26 chars allows an 5 | // 8.3 filename instead and 8.3 directory with a leading slash 6 | #define INI_FILE_MAX_FILENAME_LEN 26 7 | 8 | #include "SdFat.h" 9 | //#include "Ethernet.h" 10 | 11 | class IniFileState; 12 | 13 | class IniFile { 14 | public: 15 | enum error_t { 16 | errorNoError = 0, 17 | errorFileNotFound, 18 | errorFileNotOpen, 19 | errorBufferTooSmall, 20 | errorSeekError, 21 | errorSectionNotFound, 22 | errorKeyNotFound, 23 | errorEndOfFile, 24 | errorUnknownError, 25 | }; 26 | 27 | static const uint8_t maxFilenameLen; 28 | 29 | // Create an IniFile object. It isn't opened until open() is called on it. 30 | IniFile(const char* filename, uint8_t mode = O_READ, 31 | bool caseSensitive = false); 32 | ~IniFile(); 33 | 34 | inline bool open(void); // Returns true if open succeeded 35 | inline void close(void); 36 | 37 | inline bool isOpen(void) const; 38 | 39 | inline error_t getError(void) const; 40 | inline void clearError(void) const; 41 | // Get the file mode (FILE_READ/FILE_WRITE) 42 | inline uint8_t getMode(void) const; 43 | 44 | // Get the filename asscoiated with the ini file object 45 | inline const char* getFilename(void) const; 46 | 47 | bool validate(char* buffer, size_t len) const; 48 | 49 | // Get value from the file, but split into many short tasks. Return 50 | // value: false means continue, true means stop. Call getError() to 51 | // find out if any error 52 | bool getValue(const char* section, const char* key, 53 | char* buffer, size_t len, IniFileState &state) const; 54 | 55 | // Get value, as one big task. Return = true means value is present 56 | // in buffer 57 | bool getValue(const char* section, const char* key, 58 | char* buffer, size_t len) const; 59 | 60 | // Get the value as a string, storing the result in a new buffer 61 | // (not the working buffer) 62 | bool getValue(const char* section, const char* key, 63 | char* buffer, size_t len, char *value, size_t vlen) const; 64 | 65 | // Get a boolean value 66 | bool getValue(const char* section, const char* key, 67 | char* buffer, size_t len, bool& b) const; 68 | 69 | // Get an integer value 70 | bool getValue(const char* section, const char* key, 71 | char* buffer, size_t len, int& val) const; 72 | 73 | // Get a uint16_t value 74 | bool getValue(const char* section, const char* key, 75 | char* buffer, size_t len, uint16_t& val) const; 76 | 77 | // Get a long value 78 | bool getValue(const char* section, const char* key, 79 | char* buffer, size_t len, long& val) const; 80 | 81 | bool getValue(const char* section, const char* key, 82 | char* buffer, size_t len, unsigned long& val) const; 83 | 84 | // bool getIPAddress(const char* section, const char* key, 85 | // char* buffer, size_t len, uint8_t* ip) const; 86 | 87 | //#if defined(ARDUINO) && ARDUINO >= 100 88 | // bool getIPAddress(const char* section, const char* key, 89 | // char* buffer, size_t len, IPAddress& ip) const; 90 | //#endif 91 | 92 | // bool getMACAddress(const char* section, const char* key, 93 | // char* buffer, size_t len, uint8_t mac[6]) const; 94 | 95 | // Utility function to read a line from a file, make available to all 96 | //static int8_t readLine(SdBaseFile &file, char *buffer, size_t len, uint32_t &pos); 97 | static error_t readLine(SdBaseFile &file, char *buffer, size_t len, uint32_t &pos); 98 | static bool isCommentChar(char c); 99 | static char* skipWhiteSpace(char* str); 100 | static void removeTrailingWhiteSpace(char* str); 101 | 102 | bool getCaseSensitive(void) const; 103 | void setCaseSensitive(bool cs); 104 | 105 | protected: 106 | // True means stop looking, false means not yet found 107 | bool findSection(const char* section, char* buffer, size_t len, 108 | IniFileState &state) const; 109 | bool findKey(const char* section, const char* key, char* buffer, 110 | size_t len, char** keyptr, IniFileState &state) const; 111 | 112 | 113 | private: 114 | char _filename[INI_FILE_MAX_FILENAME_LEN]; 115 | uint8_t _mode; 116 | mutable error_t _error; 117 | mutable SdBaseFile _file; 118 | bool _caseSensitive; 119 | }; 120 | 121 | bool IniFile::open(void) 122 | { 123 | if (_file.isOpen()) 124 | _file.close(); 125 | _file.open(_filename, _mode); 126 | if (isOpen()) { 127 | _error = errorNoError; 128 | return true; 129 | } 130 | else { 131 | _error = errorFileNotFound; 132 | return false; 133 | } 134 | } 135 | 136 | void IniFile::close(void) 137 | { 138 | if (_file.isOpen()) 139 | _file.close(); 140 | } 141 | 142 | bool IniFile::isOpen(void) const 143 | { 144 | return _file.isOpen(); 145 | } 146 | 147 | IniFile::error_t IniFile::getError(void) const 148 | { 149 | return _error; 150 | } 151 | 152 | void IniFile::clearError(void) const 153 | { 154 | _error = errorNoError; 155 | } 156 | 157 | uint8_t IniFile::getMode(void) const 158 | { 159 | return _mode; 160 | } 161 | 162 | const char* IniFile::getFilename(void) const 163 | { 164 | return _filename; 165 | } 166 | 167 | 168 | 169 | class IniFileState { 170 | public: 171 | IniFileState(); 172 | 173 | private: 174 | enum {funcUnset = 0, 175 | funcFindSection, 176 | funcFindKey, 177 | }; 178 | 179 | uint32_t readLinePosition; 180 | uint8_t getValueState; 181 | 182 | friend class IniFile; 183 | }; 184 | 185 | 186 | #endif 187 | 188 | -------------------------------------------------------------------------------- /libraries/RTClite/RTClite.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is an extremely pared-down version of the RTClib Arduino library with 3 | no dependency on the Wire library. Contains only the essential functions 4 | for setting & reading time from the DS1307 RTC, and implements the 5 | low-level TWI/I2C code internally. Reason being that double-buffered 6 | animation with the RGBmatrixPanel library leaves so little RAM for other 7 | code that the mere act of #including Wire.h would cause it to fail. 8 | So this lets us have a clock and double-buffered animation together. 9 | Some comments were cut for brevity; please refer to the original libraries 10 | for any discussion of their principles of operation. 11 | 12 | The RTC code is adapted from public domain code by JeeLabs 13 | http://news.jeelabs.org/code/ -- several functions were stripped out 14 | (only the stuff needed for implementing nice Spectro clocks was kept), 15 | and Wire library calls were replaced with local code. 16 | 17 | The TWI code is adapted from the Arduino Wire library, specifically the 18 | lower-level twi functions in libraries/Wire/utility/twi.c. All slave- 19 | mode functionality is stripped out, and the separate send/receive buffers 20 | are replaced with a single buffer of the minimum size needed to support 21 | RTC communication. 22 | */ 23 | 24 | #include 25 | #include "RTClite.h" 26 | #include 27 | #include 28 | #include 29 | 30 | #if (ARDUINO >= 100) 31 | #include 32 | #else 33 | #include 34 | #endif 35 | 36 | // -------- TWI/I2C CODE --------------------------------------------------- 37 | 38 | #define TWI_READY 0 39 | #define TWI_MRX 1 40 | #define TWI_MTX 2 41 | #define TWI_STX 4 42 | #ifndef TWI_FREQ 43 | #define TWI_FREQ 100000L 44 | #endif 45 | #ifndef cbi 46 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 47 | #endif 48 | #ifndef sbi 49 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 50 | #endif 51 | 52 | #define TWI_BUFFER_LENGTH 9 53 | static volatile uint8_t 54 | twi_buf[TWI_BUFFER_LENGTH], 55 | twi_bufIdx, 56 | twi_state, 57 | twi_error; 58 | static uint8_t 59 | twi_bufLen, 60 | twi_slarw; 61 | 62 | static void twi_init(void) { 63 | twi_state = TWI_READY; // initialize state 64 | 65 | digitalWrite(SDA, HIGH); // activate internal pullups for twi. 66 | digitalWrite(SCL, HIGH); 67 | 68 | cbi(TWSR, TWPS0); // initialize twi prescaler and bit rate 69 | cbi(TWSR, TWPS1); 70 | TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; 71 | 72 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); // enable twi, acks, interrupt 73 | } 74 | 75 | static void twi_reply(uint8_t ack) { 76 | // transmit master read ready signal, with or without ack 77 | TWCR = ack ? 78 | _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA) : 79 | _BV(TWEN) | _BV(TWIE) | _BV(TWINT); 80 | } 81 | 82 | static void twi_stop(void) { 83 | // send stop condition 84 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); 85 | 86 | // wait for stop condition to be exectued on bus 87 | // TWINT is not set after a stop condition! 88 | while(TWCR & _BV(TWSTO)); 89 | 90 | twi_state = TWI_READY; // update twi state 91 | } 92 | 93 | static void twi_releaseBus(void) { 94 | // release bus 95 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); 96 | 97 | twi_state = TWI_READY; // update twi state 98 | } 99 | 100 | static uint8_t twi_writeTo(uint8_t address, uint8_t length) { 101 | // ensure data will fit into buffer 102 | if(TWI_BUFFER_LENGTH < length) return 1; 103 | 104 | // wait until twi is ready, become master transmitter 105 | while(TWI_READY != twi_state); 106 | twi_state = TWI_MTX; 107 | twi_error = 0xFF; // reset error state (0xFF = no error occured) 108 | 109 | // initialize buffer iteration vars 110 | twi_bufIdx = 0; 111 | twi_bufLen = length; 112 | 113 | // build sla+w, slave device address + w bit 114 | twi_slarw = TW_WRITE; 115 | twi_slarw |= address << 1; 116 | 117 | // send start condition 118 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); 119 | 120 | // wait for write operation to complete 121 | while(TWI_MTX == twi_state); 122 | 123 | if (twi_error == 0xFF) 124 | return 0; // success 125 | else if (twi_error == TW_MT_SLA_NACK) 126 | return 2; // error: address send, nack received 127 | else if (twi_error == TW_MT_DATA_NACK) 128 | return 3; // error: data send, nack received 129 | else 130 | return 4; // other twi error 131 | } 132 | 133 | uint8_t twi_readFrom(uint8_t address, uint8_t length) { 134 | // ensure data will fit into buffer 135 | if(TWI_BUFFER_LENGTH < length) return 0; 136 | 137 | // wait until twi is ready, become master receiver 138 | while(TWI_READY != twi_state); 139 | twi_state = TWI_MRX; 140 | twi_error = 0xFF; // reset error state (0xFF = no error occured) 141 | 142 | // initialize buffer iteration vars 143 | twi_bufIdx = 0; 144 | twi_bufLen = length-1; // This is not intuitive, read on... 145 | // On receive, the previously configured ACK/NACK setting is transmitted in 146 | // response to the received byte before the interrupt is signalled. 147 | // Therefor we must actually set NACK when the _next_ to last byte is 148 | // received, causing that NACK to be sent in response to receiving the last 149 | // expected byte of data. 150 | 151 | // build sla+w, slave device address + w bit 152 | twi_slarw = TW_READ; 153 | twi_slarw |= address << 1; 154 | 155 | // send start condition 156 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); 157 | 158 | // wait for read operation to complete 159 | while(TWI_MRX == twi_state); 160 | 161 | if(twi_bufIdx < length) length = twi_bufIdx; 162 | 163 | return length; 164 | } 165 | 166 | ISR(TWI_vect) { 167 | switch(TW_STATUS) { 168 | // All Master 169 | case TW_START: // sent start condition 170 | case TW_REP_START: // sent repeated start condition 171 | // copy device address and r/w bit to output register and ack 172 | TWDR = twi_slarw; 173 | twi_reply(1); 174 | break; 175 | 176 | // Master Transmitter 177 | case TW_MT_SLA_ACK: // slave receiver acked address 178 | case TW_MT_DATA_ACK: // slave receiver acked data 179 | // if there is data to send, send it, otherwise stop 180 | if(twi_bufIdx < twi_bufLen) { 181 | // copy data to output register and ack 182 | TWDR = twi_buf[twi_bufIdx++]; 183 | twi_reply(1); 184 | } else { 185 | twi_stop(); 186 | } 187 | break; 188 | case TW_MT_SLA_NACK: // address sent, nack received 189 | twi_error = TW_MT_SLA_NACK; 190 | twi_stop(); 191 | break; 192 | case TW_MT_DATA_NACK: // data sent, nack received 193 | twi_error = TW_MT_DATA_NACK; 194 | twi_stop(); 195 | break; 196 | case TW_MT_ARB_LOST: // lost bus arbitration 197 | twi_error = TW_MT_ARB_LOST; 198 | twi_releaseBus(); 199 | break; 200 | 201 | // Master Receiver 202 | case TW_MR_DATA_ACK: // data received, ack sent 203 | // put byte into buffer 204 | twi_buf[twi_bufIdx++] = TWDR; 205 | case TW_MR_SLA_ACK: // address sent, ack received 206 | // ack if more bytes are expected, otherwise nack 207 | twi_reply((twi_bufIdx < twi_bufLen) ? 1 : 0); 208 | break; 209 | case TW_MR_DATA_NACK: // data received, nack sent 210 | // put final byte into buffer 211 | twi_buf[twi_bufIdx++] = TWDR; 212 | case TW_MR_SLA_NACK: // address sent, nack received 213 | twi_stop(); 214 | break; 215 | // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case 216 | 217 | // All 218 | case TW_NO_INFO: // no state information 219 | break; 220 | case TW_BUS_ERROR: // bus error, illegal stop/start 221 | twi_error = TW_BUS_ERROR; 222 | twi_stop(); 223 | break; 224 | } 225 | } 226 | 227 | // -------- RTC CODE ------------------------------------------------------- 228 | 229 | #define DS1307_ADDRESS 0x68 230 | #define SECONDS_FROM_1970_TO_2000 946684800 231 | 232 | const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; 233 | 234 | DateTime::DateTime(uint32_t t) { 235 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 236 | ss = t % 60; 237 | t /= 60; 238 | mm = t % 60; 239 | t /= 60; 240 | hh = t % 24; 241 | 242 | uint16_t days = t / 24; 243 | uint8_t leap; 244 | for(yOff=0; ; ++yOff) { 245 | leap = (yOff % 4 == 0); 246 | if(days < (365 + leap)) break; 247 | days -= 365 + leap; 248 | } 249 | for(m=1; ; ++m) { 250 | uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1); 251 | if(leap && (m == 2)) ++daysPerMonth; 252 | if(days < daysPerMonth) break; 253 | days -= daysPerMonth; 254 | } 255 | d = days + 1; 256 | } 257 | 258 | DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, 259 | uint8_t hour, uint8_t min, uint8_t sec) { 260 | if(year >= 2000) year -= 2000; 261 | yOff = year; 262 | m = month; 263 | d = day; 264 | hh = hour; 265 | mm = min; 266 | ss = sec; 267 | } 268 | 269 | static uint8_t conv2d(const char* p) { 270 | uint8_t v = 0; 271 | if(('0' <= *p) && (*p <= '9')) v = *p - '0'; 272 | return 10 * v + *++p - '0'; 273 | } 274 | 275 | // A convenient constructor for using "the compiler's time": 276 | // DateTime now (__DATE__, __TIME__); 277 | DateTime::DateTime(const char* date, const char* time) { 278 | // sample input: date = "Dec 26 2009", time = "12:34:56" 279 | yOff = conv2d(date + 9); 280 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 281 | switch (date[0]) { 282 | case 'J': m = (date[1]=='a') ? 1 : (m = (date[2]=='n') ? 6 : 7); break; 283 | case 'F': m = 2; break; 284 | case 'A': m = (date[2]=='r') ? 4 : 8; break; 285 | case 'M': m = (date[2]=='r') ? 3 : 5; break; 286 | case 'S': m = 9; break; 287 | case 'O': m = 10; break; 288 | case 'N': m = 11; break; 289 | case 'D': m = 12; break; 290 | } 291 | d = conv2d(date + 4); 292 | hh = conv2d(time); 293 | mm = conv2d(time + 3); 294 | ss = conv2d(time + 6); 295 | } 296 | 297 | // number of days since 2000/01/01, valid for 2001..2099 298 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { 299 | if(y >= 2000) y -= 2000; 300 | uint16_t days = d; 301 | for (uint8_t i = 1; i < m; ++i) 302 | days += pgm_read_byte(daysInMonth + i - 1); 303 | if((m > 2) && ((y % 4) == 0)) ++days; 304 | return days + 365 * y + (y + 3) / 4 - 1; 305 | } 306 | 307 | uint8_t DateTime::dayOfWeek() const { 308 | return (date2days(yOff, m, d) + 6) % 7; // Jan 1, 2000 is a Sat, returns 6 309 | } 310 | 311 | static uint8_t bcd2bin(uint8_t val) { return val - 6 * (val >> 4); } 312 | static uint8_t bin2bcd(uint8_t val) { return val + 6 * (val / 10); } 313 | 314 | int8_t RTC_DS1307::begin(void) { 315 | twi_init(); 316 | return 1; 317 | } 318 | 319 | uint8_t RTC_DS1307::isrunning(void) { 320 | twi_buf[0] = 0; 321 | twi_writeTo(DS1307_ADDRESS, 1); 322 | 323 | // perform blocking read into buffer 324 | (void)twi_readFrom(DS1307_ADDRESS, 1); 325 | uint8_t ss = twi_buf[0]; 326 | return !(ss>>7); 327 | } 328 | 329 | void RTC_DS1307::adjust(const DateTime& dt) { 330 | twi_buf[0] = 0; 331 | twi_buf[1] = bin2bcd(dt.second()); 332 | twi_buf[2] = bin2bcd(dt.minute()); 333 | twi_buf[3] = bin2bcd(dt.hour()); 334 | twi_buf[4] = bin2bcd(0); 335 | twi_buf[5] = bin2bcd(dt.day()); 336 | twi_buf[6] = bin2bcd(dt.month()); 337 | twi_buf[7] = bin2bcd(dt.year() - 2000); 338 | twi_buf[8] = 0; 339 | twi_writeTo(DS1307_ADDRESS, 9); 340 | } 341 | 342 | DateTime RTC_DS1307::now() { 343 | twi_buf[0] = 0; 344 | twi_writeTo(DS1307_ADDRESS, 1); 345 | 346 | (void)twi_readFrom(DS1307_ADDRESS, 7); 347 | 348 | uint8_t ss = bcd2bin(twi_buf[0] & 0x7F); 349 | uint8_t mm = bcd2bin(twi_buf[1]); 350 | uint8_t hh = bcd2bin(twi_buf[2]); 351 | uint8_t d = bcd2bin(twi_buf[4]); // #3 IS SKIPPED 352 | uint8_t m = bcd2bin(twi_buf[5]); 353 | uint16_t y = bcd2bin(twi_buf[6]) + 2000; 354 | 355 | return DateTime(y, m, d, hh, mm, ss); 356 | } 357 | 358 | -------------------------------------------------------------------------------- /libraries/IniFileLite/IniFileLite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | const uint8_t IniFile::maxFilenameLen = INI_FILE_MAX_FILENAME_LEN; 6 | 7 | IniFile::IniFile(const char* filename, uint8_t mode, 8 | bool caseSensitive) 9 | { 10 | if (strlen(filename) <= maxFilenameLen) 11 | strcpy(_filename, filename); 12 | else 13 | _filename[0] = '\0'; 14 | _mode = mode; 15 | _caseSensitive = caseSensitive; 16 | } 17 | 18 | IniFile::~IniFile() 19 | { 20 | //if (_file) 21 | // _file.close(); 22 | } 23 | 24 | 25 | bool IniFile::validate(char* buffer, size_t len) const 26 | { 27 | uint32_t pos = 0; 28 | error_t err; 29 | while ((err = readLine(_file, buffer, len, pos)) == errorNoError) 30 | ; 31 | if (err == errorEndOfFile) { 32 | _error = errorNoError; 33 | return true; 34 | } 35 | else { 36 | _error = err; 37 | return false; 38 | } 39 | } 40 | 41 | bool IniFile::getValue(const char* section, const char* key, 42 | char* buffer, size_t len, IniFileState &state) const 43 | { 44 | bool done = false; 45 | if (!_file.isOpen()) { 46 | _error = errorFileNotOpen; 47 | return true; 48 | } 49 | 50 | switch (state.getValueState) { 51 | case IniFileState::funcUnset: 52 | state.getValueState = (section == NULL ? IniFileState::funcFindKey 53 | : IniFileState::funcFindSection); 54 | state.readLinePosition = 0; 55 | break; 56 | 57 | case IniFileState::funcFindSection: 58 | if (findSection(section, buffer, len, state)) { 59 | if (_error != errorNoError) 60 | return true; 61 | state.getValueState = IniFileState::funcFindKey; 62 | } 63 | break; 64 | 65 | case IniFileState::funcFindKey: 66 | char *cp; 67 | if (findKey(section, key, buffer, len, &cp, state)) { 68 | if (_error != errorNoError) 69 | return true; 70 | // Found key line in correct section 71 | cp = skipWhiteSpace(cp); 72 | removeTrailingWhiteSpace(cp); 73 | 74 | // Copy from cp to buffer, but the strings overlap so strcpy is out 75 | while (*cp != '\0') 76 | *buffer++ = *cp++; 77 | *buffer = '\0'; 78 | return true; 79 | } 80 | break; 81 | 82 | default: 83 | // How did this happen? 84 | _error = errorUnknownError; 85 | done = true; 86 | break; 87 | } 88 | 89 | return done; 90 | } 91 | 92 | bool IniFile::getValue(const char* section, const char* key, 93 | char* buffer, size_t len) const 94 | { 95 | IniFileState state; 96 | while (!getValue(section, key, buffer, len, state)) 97 | ; 98 | return _error == errorNoError; 99 | } 100 | 101 | 102 | bool IniFile::getValue(const char* section, const char* key, 103 | char* buffer, size_t len, char *value, size_t vlen) const 104 | { 105 | if (getValue(section, key, buffer, len) < 0) 106 | return false; // error 107 | if (strlen(buffer) >= vlen) 108 | return false; 109 | strcpy(value, buffer); 110 | return true; 111 | } 112 | 113 | 114 | // For true accept: true, yes, 1 115 | // For false accept: false, no, 0 116 | bool IniFile::getValue(const char* section, const char* key, 117 | char* buffer, size_t len, bool& val) const 118 | { 119 | if (getValue(section, key, buffer, len) < 0) 120 | return false; // error 121 | 122 | if (strcasecmp(buffer, "true") == 0 || 123 | strcasecmp(buffer, "yes") == 0 || 124 | strcasecmp(buffer, "1") == 0) { 125 | val = true; 126 | return true; 127 | } 128 | if (strcasecmp(buffer, "false") == 0 || 129 | strcasecmp(buffer, "no") == 0 || 130 | strcasecmp(buffer, "0") == 0) { 131 | val = false; 132 | return true; 133 | } 134 | return false; // does not match any known strings 135 | } 136 | 137 | bool IniFile::getValue(const char* section, const char* key, 138 | char* buffer, size_t len, int& val) const 139 | { 140 | if (getValue(section, key, buffer, len) < 0) 141 | return false; // error 142 | 143 | val = atoi(buffer); 144 | return true; 145 | } 146 | 147 | bool IniFile::getValue(const char* section, const char* key, \ 148 | char* buffer, size_t len, uint16_t& val) const 149 | { 150 | long longval; 151 | bool r = getValue(section, key, buffer, len, longval); 152 | if (r) 153 | val = uint16_t(longval); 154 | return r; 155 | } 156 | 157 | bool IniFile::getValue(const char* section, const char* key, 158 | char* buffer, size_t len, long& val) const 159 | { 160 | if (getValue(section, key, buffer, len) < 0) 161 | return false; // error 162 | 163 | val = atol(buffer); 164 | return true; 165 | } 166 | 167 | bool IniFile::getValue(const char* section, const char* key, 168 | char* buffer, size_t len, unsigned long& val) const 169 | { 170 | if (getValue(section, key, buffer, len) < 0) 171 | return false; // error 172 | 173 | char *endptr; 174 | unsigned long tmp = strtoul(buffer, &endptr, 10); 175 | if (endptr == buffer) 176 | return false; // no conversion 177 | if (*endptr == '\0') { 178 | val = tmp; 179 | return true; // valid conversion 180 | } 181 | // buffer has trailing non-numeric characters, and since the buffer 182 | // already had whitespace removed discard the entire results 183 | return false; 184 | } 185 | 186 | // bool IniFile::getIPAddress(const char* section, const char* key, 187 | // char* buffer, size_t len, uint8_t* ip) const 188 | // { 189 | // // Need 16 chars minimum: 4 * 3 digits, 3 dots and a null character 190 | // if (len < 16) 191 | // return false; 192 | 193 | // if (getValue(section, key, buffer, len) < 0) 194 | // return false; // error 195 | 196 | // int i = 0; 197 | // char* cp = buffer; 198 | // ip[0] = ip[1] = ip[2] = ip[3] = 0; 199 | // while (*cp != '\0' && i < 4) { 200 | // if (*cp == '.') { 201 | // ++i; 202 | // ++cp; 203 | // continue; 204 | // } 205 | // if (isdigit(*cp)) { 206 | // ip[i] *= 10; 207 | // ip[i] += (*cp - '0'); 208 | // } 209 | // else { 210 | // ip[0] = ip[1] = ip[2] = ip[3] = 0; 211 | // return false; 212 | // } 213 | // ++cp; 214 | // } 215 | // return true; 216 | // } 217 | 218 | 219 | // #if defined(ARDUINO) && ARDUINO >= 100 220 | // bool IniFile::getIPAddress(const char* section, const char* key, 221 | // char* buffer, size_t len, IPAddress& ip) const 222 | // { 223 | // // Need 16 chars minimum: 4 * 3 digits, 3 dots and a null character 224 | // if (len < 16) 225 | // return false; 226 | 227 | // if (getValue(section, key, buffer, len) < 0) 228 | // return false; // error 229 | 230 | // int i = 0; 231 | // char* cp = buffer; 232 | // ip = IPAddress(0, 0, 0, 0); 233 | // while (*cp != '\0' && i < 4) { 234 | // if (*cp == '.') { 235 | // ++i; 236 | // ++cp; 237 | // continue; 238 | // } 239 | // if (isdigit(*cp)) { 240 | // ip[i] *= 10; 241 | // ip[i] += (*cp - '0'); 242 | // } 243 | // else { 244 | // ip = IPAddress(0, 0, 0, 0); 245 | // return false; 246 | // } 247 | // ++cp; 248 | // } 249 | // return true; 250 | // } 251 | // #endif 252 | 253 | // bool IniFile::getMACAddress(const char* section, const char* key, 254 | // char* buffer, size_t len, uint8_t mac[6]) const 255 | // { 256 | // // Need 18 chars: 6 * 2 hex digits, 5 : or - and a null char 257 | // if (len < 18) 258 | // return false; 259 | 260 | // if (getValue(section, key, buffer, len) < 0) 261 | // return false; // error 262 | 263 | // int i = 0; 264 | // char* cp = buffer; 265 | // memset(mac, 0, 6); 266 | 267 | // while (*cp != '\0' && i < 6) { 268 | // if (*cp == ':' || *cp == '-') { 269 | // ++i; 270 | // ++cp; 271 | // continue; 272 | // } 273 | // if (isdigit(*cp)) { 274 | // mac[i] *= 16; // working in hex! 275 | // mac[i] += (*cp - '0'); 276 | // } 277 | // else { 278 | // if (isxdigit(*cp)) { 279 | // mac[i] *= 16; // working in hex! 280 | // mac[i] += (toupper(*cp) - 55); // convert A to 0xA, F to 0xF 281 | // } 282 | // else { 283 | // memset(mac, 0, sizeof(mac)); 284 | // return false; 285 | // } 286 | // } 287 | // ++cp; 288 | // } 289 | // return true; 290 | // } 291 | 292 | //int8_t IniFile::readLine(SdBaseFile &file, char *buffer, size_t len, uint32_t &pos) 293 | IniFile::error_t IniFile::readLine(SdBaseFile &file, char *buffer, size_t len, uint32_t &pos) 294 | { 295 | if (!file.isOpen()) 296 | return errorFileNotOpen; 297 | 298 | if (len < 3) 299 | return errorBufferTooSmall; 300 | 301 | if (!file.seekSet(pos)) 302 | return errorSeekError; 303 | 304 | size_t bytesRead = file.read(buffer, len); 305 | if (!bytesRead) { 306 | buffer[0] = '\0'; 307 | //return 1; // done 308 | return errorEndOfFile; 309 | } 310 | 311 | for (size_t i = 0; i < bytesRead && i < len-1; ++i) { 312 | // Test for '\n' with optional '\r' too 313 | // if (endOfLineTest(buffer, len, i, '\n', '\r') 314 | 315 | if (buffer[i] == '\n' || buffer[i] == '\r') { 316 | char match = buffer[i]; 317 | char otherNewline = (match == '\n' ? '\r' : '\n'); 318 | // end of line, discard any trailing character of the other sort 319 | // of newline 320 | buffer[i] = '\0'; 321 | 322 | if (buffer[i+1] == otherNewline) 323 | ++i; 324 | pos += (i + 1); // skip past newline(s) 325 | //return (i+1 == bytesRead && !file.available()); 326 | return errorNoError; 327 | } 328 | } 329 | if (!file.available()) { 330 | // end of file without a newline 331 | buffer[bytesRead] = '\0'; 332 | // return 1; //done 333 | return errorEndOfFile; 334 | } 335 | 336 | buffer[len-1] = '\0'; // terminate the string 337 | return errorBufferTooSmall; 338 | } 339 | 340 | bool IniFile::isCommentChar(char c) 341 | { 342 | return (c == ';' || c == '#'); 343 | } 344 | 345 | char* IniFile::skipWhiteSpace(char* str) 346 | { 347 | char *cp = str; 348 | while (isspace(*cp)) 349 | ++cp; 350 | return cp; 351 | } 352 | 353 | void IniFile::removeTrailingWhiteSpace(char* str) 354 | { 355 | char *cp = str + strlen(str) - 1; 356 | while (cp >= str && isspace(*cp)) 357 | *cp-- = '\0'; 358 | } 359 | 360 | bool IniFile::findSection(const char* section, char* buffer, size_t len, 361 | IniFileState &state) const 362 | { 363 | if (section == NULL) { 364 | _error = errorSectionNotFound; 365 | return true; 366 | } 367 | 368 | error_t err = IniFile::readLine(_file, buffer, len, state.readLinePosition); 369 | 370 | if (err != errorNoError && err != errorEndOfFile) { 371 | // Signal to caller to stop looking and any error value 372 | _error = err; 373 | return true; 374 | } 375 | 376 | char *cp = skipWhiteSpace(buffer); 377 | //if (isCommentChar(*cp)) 378 | //return (done ? errorSectionNotFound : 0); 379 | if (isCommentChar(*cp)) { 380 | // return (err == errorEndOfFile ? errorSectionNotFound : errorNoError); 381 | if (err == errorEndOfFile) { 382 | _error = errorSectionNotFound; 383 | return true; 384 | } 385 | else 386 | return false; // Continue searching 387 | } 388 | 389 | if (*cp == '[') { 390 | // Start of section 391 | ++cp; 392 | cp = skipWhiteSpace(cp); 393 | char *ep = strchr(cp, ']'); 394 | if (ep != NULL) { 395 | *ep = '\0'; // make ] be end of string 396 | removeTrailingWhiteSpace(cp); 397 | if (_caseSensitive) { 398 | if (strcmp(cp, section) == 0) { 399 | _error = errorNoError; 400 | return true; 401 | } 402 | } 403 | else { 404 | if (strcasecmp(cp, section) == 0) { 405 | _error = errorNoError; 406 | return true; 407 | } 408 | } 409 | } 410 | } 411 | 412 | // Not a valid section line 413 | //return (done ? errorSectionNotFound : 0); 414 | if (err == errorEndOfFile) { 415 | _error = errorSectionNotFound; 416 | return true; 417 | } 418 | 419 | return false; 420 | } 421 | 422 | // From the current file location look for the matching key. If 423 | // section is non-NULL don't look in the next section 424 | bool IniFile::findKey(const char* section, const char* key, 425 | char* buffer, size_t len, char** keyptr, 426 | IniFileState &state) const 427 | { 428 | if (key == NULL || *key == '\0') { 429 | _error = errorKeyNotFound; 430 | return true; 431 | } 432 | 433 | error_t err = IniFile::readLine(_file, buffer, len, state.readLinePosition); 434 | if (err != errorNoError && err != errorEndOfFile) { 435 | _error = err; 436 | return true; 437 | } 438 | 439 | char *cp = skipWhiteSpace(buffer); 440 | // if (isCommentChar(*cp)) 441 | // return (done ? errorKeyNotFound : 0); 442 | if (isCommentChar(*cp)) { 443 | if (err == errorEndOfFile) { 444 | _error = errorKeyNotFound; 445 | return true; 446 | } 447 | else 448 | return false; // Continue searching 449 | } 450 | 451 | if (section && *cp == '[') { 452 | // Start of a new section 453 | _error = errorKeyNotFound; 454 | return true; 455 | } 456 | 457 | // Find '=' 458 | char *ep = strchr(cp, '='); 459 | if (ep != NULL) { 460 | *ep = '\0'; // make = be the end of string 461 | removeTrailingWhiteSpace(cp); 462 | if (_caseSensitive) { 463 | if (strcmp(cp, key) == 0) { 464 | *keyptr = ep + 1; 465 | _error = errorNoError; 466 | return true; 467 | } 468 | } 469 | else { 470 | if (strcasecmp(cp, key) == 0) { 471 | *keyptr = ep + 1; 472 | _error = errorNoError; 473 | return true; 474 | } 475 | } 476 | } 477 | 478 | // Not the valid key line 479 | if (err == errorEndOfFile) { 480 | _error = errorKeyNotFound; 481 | return true; 482 | } 483 | return false; 484 | } 485 | 486 | bool IniFile::getCaseSensitive(void) const 487 | { 488 | return _caseSensitive; 489 | } 490 | 491 | void IniFile::setCaseSensitive(bool cs) 492 | { 493 | _caseSensitive = cs; 494 | } 495 | 496 | IniFileState::IniFileState() 497 | { 498 | readLinePosition = 0; 499 | getValueState = funcUnset; 500 | } 501 | -------------------------------------------------------------------------------- /libraries/IniFileLite/LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | (This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.) 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | {description} 474 | Copyright (C) {year} {fullname} 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | {signature of Ty Coon}, 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | GNU GENERAL PUBLIC LICENSE 3 | Version 3, 29 June 2007 4 | 5 | Copyright (C) 2007 Free Software Foundation, Inc. 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The GNU General Public License is a free, copyleft license for 12 | software and other kinds of works. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | the GNU General Public License is intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. We, the Free Software Foundation, use the 19 | GNU General Public License for most of our software; it applies also to 20 | any other work released this way by its authors. You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | them if you wish), that you receive source code or can get it if you 27 | want it, that you can change the software or use pieces of it in new 28 | free programs, and that you know you can do these things. 29 | 30 | To protect your rights, we need to prevent others from denying you 31 | these rights or asking you to surrender the rights. Therefore, you have 32 | certain responsibilities if you distribute copies of the software, or if 33 | you modify it: responsibilities to respect the freedom of others. 34 | 35 | For example, if you distribute copies of such a program, whether 36 | gratis or for a fee, you must pass on to the recipients the same 37 | freedoms that you received. You must make sure that they, too, receive 38 | or can get the source code. And you must show them these terms so they 39 | know their rights. 40 | 41 | Developers that use the GNU GPL protect your rights with two steps: 42 | (1) assert copyright on the software, and (2) offer you this License 43 | giving you legal permission to copy, distribute and/or modify it. 44 | 45 | For the developers' and authors' protection, the GPL clearly explains 46 | that there is no warranty for this free software. For both users' and 47 | authors' sake, the GPL requires that modified versions be marked as 48 | changed, so that their problems will not be attributed erroneously to 49 | authors of previous versions. 50 | 51 | Some devices are designed to deny users access to install or run 52 | modified versions of the software inside them, although the manufacturer 53 | can do so. This is fundamentally incompatible with the aim of 54 | protecting users' freedom to change the software. The systematic 55 | pattern of such abuse occurs in the area of products for individuals to 56 | use, which is precisely where it is most unacceptable. Therefore, we 57 | have designed this version of the GPL to prohibit the practice for those 58 | products. If such problems arise substantially in other domains, we 59 | stand ready to extend this provision to those domains in future versions 60 | of the GPL, as needed to protect the freedom of users. 61 | 62 | Finally, every program is threatened constantly by software patents. 63 | States should not allow patents to restrict development and use of 64 | software on general-purpose computers, but in those that do, we wish to 65 | avoid the special danger that patents applied to a free program could 66 | make it effectively proprietary. To prevent this, the GPL assures that 67 | patents cannot be used to render the program non-free. 68 | 69 | The precise terms and conditions for copying, distribution and 70 | modification follow. 71 | 72 | TERMS AND CONDITIONS 73 | 74 | 0. Definitions. 75 | 76 | "This License" refers to version 3 of the GNU General Public License. 77 | 78 | "Copyright" also means copyright-like laws that apply to other kinds of 79 | works, such as semiconductor masks. 80 | 81 | "The Program" refers to any copyrightable work licensed under this 82 | License. Each licensee is addressed as "you". "Licensees" and 83 | "recipients" may be individuals or organizations. 84 | 85 | To "modify" a work means to copy from or adapt all or part of the work 86 | in a fashion requiring copyright permission, other than the making of an 87 | exact copy. The resulting work is called a "modified version" of the 88 | earlier work or a work "based on" the earlier work. 89 | 90 | A "covered work" means either the unmodified Program or a work based 91 | on the Program. 92 | 93 | To "propagate" a work means to do anything with it that, without 94 | permission, would make you directly or secondarily liable for 95 | infringement under applicable copyright law, except executing it on a 96 | computer or modifying a private copy. Propagation includes copying, 97 | distribution (with or without modification), making available to the 98 | public, and in some countries other activities as well. 99 | 100 | To "convey" a work means any kind of propagation that enables other 101 | parties to make or receive copies. Mere interaction with a user through 102 | a computer network, with no transfer of a copy, is not conveying. 103 | 104 | An interactive user interface displays "Appropriate Legal Notices" 105 | to the extent that it includes a convenient and prominently visible 106 | feature that (1) displays an appropriate copyright notice, and (2) 107 | tells the user that there is no warranty for the work (except to the 108 | extent that warranties are provided), that licensees may convey the 109 | work under this License, and how to view a copy of this License. If 110 | the interface presents a list of user commands or options, such as a 111 | menu, a prominent item in the list meets this criterion. 112 | 113 | 1. Source Code. 114 | 115 | The "source code" for a work means the preferred form of the work 116 | for making modifications to it. "Object code" means any non-source 117 | form of a work. 118 | 119 | A "Standard Interface" means an interface that either is an official 120 | standard defined by a recognized standards body, or, in the case of 121 | interfaces specified for a particular programming language, one that 122 | is widely used among developers working in that language. 123 | 124 | The "System Libraries" of an executable work include anything, other 125 | than the work as a whole, that (a) is included in the normal form of 126 | packaging a Major Component, but which is not part of that Major 127 | Component, and (b) serves only to enable use of the work with that 128 | Major Component, or to implement a Standard Interface for which an 129 | implementation is available to the public in source code form. A 130 | "Major Component", in this context, means a major essential component 131 | (kernel, window system, and so on) of the specific operating system 132 | (if any) on which the executable work runs, or a compiler used to 133 | produce the work, or an object code interpreter used to run it. 134 | 135 | The "Corresponding Source" for a work in object code form means all 136 | the source code needed to generate, install, and (for an executable 137 | work) run the object code and to modify the work, including scripts to 138 | control those activities. However, it does not include the work's 139 | System Libraries, or general-purpose tools or generally available free 140 | programs which are used unmodified in performing those activities but 141 | which are not part of the work. For example, Corresponding Source 142 | includes interface definition files associated with source files for 143 | the work, and the source code for shared libraries and dynamically 144 | linked subprograms that the work is specifically designed to require, 145 | such as by intimate data communication or control flow between those 146 | subprograms and other parts of the work. 147 | 148 | The Corresponding Source need not include anything that users 149 | can regenerate automatically from other parts of the Corresponding 150 | Source. 151 | 152 | The Corresponding Source for a work in source code form is that 153 | same work. 154 | 155 | 2. Basic Permissions. 156 | 157 | All rights granted under this License are granted for the term of 158 | copyright on the Program, and are irrevocable provided the stated 159 | conditions are met. This License explicitly affirms your unlimited 160 | permission to run the unmodified Program. The output from running a 161 | covered work is covered by this License only if the output, given its 162 | content, constitutes a covered work. This License acknowledges your 163 | rights of fair use or other equivalent, as provided by copyright law. 164 | 165 | You may make, run and propagate covered works that you do not 166 | convey, without conditions so long as your license otherwise remains 167 | in force. You may convey covered works to others for the sole purpose 168 | of having them make modifications exclusively for you, or provide you 169 | with facilities for running those works, provided that you comply with 170 | the terms of this License in conveying all material for which you do 171 | not control copyright. Those thus making or running the covered works 172 | for you must do so exclusively on your behalf, under your direction 173 | and control, on terms that prohibit them from making any copies of 174 | your copyrighted material outside their relationship with you. 175 | 176 | Conveying under any other circumstances is permitted solely under 177 | the conditions stated below. Sublicensing is not allowed; section 10 178 | makes it unnecessary. 179 | 180 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 181 | 182 | No covered work shall be deemed part of an effective technological 183 | measure under any applicable law fulfilling obligations under article 184 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 185 | similar laws prohibiting or restricting circumvention of such 186 | measures. 187 | 188 | When you convey a covered work, you waive any legal power to forbid 189 | circumvention of technological measures to the extent such circumvention 190 | is effected by exercising rights under this License with respect to 191 | the covered work, and you disclaim any intention to limit operation or 192 | modification of the work as a means of enforcing, against the work's 193 | users, your or third parties' legal rights to forbid circumvention of 194 | technological measures. 195 | 196 | 4. Conveying Verbatim Copies. 197 | 198 | You may convey verbatim copies of the Program's source code as you 199 | receive it, in any medium, provided that you conspicuously and 200 | appropriately publish on each copy an appropriate copyright notice; 201 | keep intact all notices stating that this License and any 202 | non-permissive terms added in accord with section 7 apply to the code; 203 | keep intact all notices of the absence of any warranty; and give all 204 | recipients a copy of this License along with the Program. 205 | 206 | You may charge any price or no price for each copy that you convey, 207 | and you may offer support or warranty protection for a fee. 208 | 209 | 5. Conveying Modified Source Versions. 210 | 211 | You may convey a work based on the Program, or the modifications to 212 | produce it from the Program, in the form of source code under the 213 | terms of section 4, provided that you also meet all of these conditions: 214 | 215 | a) The work must carry prominent notices stating that you modified 216 | it, and giving a relevant date. 217 | 218 | b) The work must carry prominent notices stating that it is 219 | released under this License and any conditions added under section 220 | 7. This requirement modifies the requirement in section 4 to 221 | "keep intact all notices". 222 | 223 | c) You must license the entire work, as a whole, under this 224 | License to anyone who comes into possession of a copy. This 225 | License will therefore apply, along with any applicable section 7 226 | additional terms, to the whole of the work, and all its parts, 227 | regardless of how they are packaged. This License gives no 228 | permission to license the work in any other way, but it does not 229 | invalidate such permission if you have separately received it. 230 | 231 | d) If the work has interactive user interfaces, each must display 232 | Appropriate Legal Notices; however, if the Program has interactive 233 | interfaces that do not display Appropriate Legal Notices, your 234 | work need not make them do so. 235 | 236 | A compilation of a covered work with other separate and independent 237 | works, which are not by their nature extensions of the covered work, 238 | and which are not combined with it such as to form a larger program, 239 | in or on a volume of a storage or distribution medium, is called an 240 | "aggregate" if the compilation and its resulting copyright are not 241 | used to limit the access or legal rights of the compilation's users 242 | beyond what the individual works permit. Inclusion of a covered work 243 | in an aggregate does not cause this License to apply to the other 244 | parts of the aggregate. 245 | 246 | 6. Conveying Non-Source Forms. 247 | 248 | You may convey a covered work in object code form under the terms 249 | of sections 4 and 5, provided that you also convey the 250 | machine-readable Corresponding Source under the terms of this License, 251 | in one of these ways: 252 | 253 | a) Convey the object code in, or embodied in, a physical product 254 | (including a physical distribution medium), accompanied by the 255 | Corresponding Source fixed on a durable physical medium 256 | customarily used for software interchange. 257 | 258 | b) Convey the object code in, or embodied in, a physical product 259 | (including a physical distribution medium), accompanied by a 260 | written offer, valid for at least three years and valid for as 261 | long as you offer spare parts or customer support for that product 262 | model, to give anyone who possesses the object code either (1) a 263 | copy of the Corresponding Source for all the software in the 264 | product that is covered by this License, on a durable physical 265 | medium customarily used for software interchange, for a price no 266 | more than your reasonable cost of physically performing this 267 | conveying of source, or (2) access to copy the 268 | Corresponding Source from a network server at no charge. 269 | 270 | c) Convey individual copies of the object code with a copy of the 271 | written offer to provide the Corresponding Source. This 272 | alternative is allowed only occasionally and noncommercially, and 273 | only if you received the object code with such an offer, in accord 274 | with subsection 6b. 275 | 276 | d) Convey the object code by offering access from a designated 277 | place (gratis or for a charge), and offer equivalent access to the 278 | Corresponding Source in the same way through the same place at no 279 | further charge. You need not require recipients to copy the 280 | Corresponding Source along with the object code. If the place to 281 | copy the object code is a network server, the Corresponding Source 282 | may be on a different server (operated by you or a third party) 283 | that supports equivalent copying facilities, provided you maintain 284 | clear directions next to the object code saying where to find the 285 | Corresponding Source. Regardless of what server hosts the 286 | Corresponding Source, you remain obligated to ensure that it is 287 | available for as long as needed to satisfy these requirements. 288 | 289 | e) Convey the object code using peer-to-peer transmission, provided 290 | you inform other peers where the object code and Corresponding 291 | Source of the work are being offered to the general public at no 292 | charge under subsection 6d. 293 | 294 | A separable portion of the object code, whose source code is excluded 295 | from the Corresponding Source as a System Library, need not be 296 | included in conveying the object code work. 297 | 298 | A "User Product" is either (1) a "consumer product", which means any 299 | tangible personal property which is normally used for personal, family, 300 | or household purposes, or (2) anything designed or sold for incorporation 301 | into a dwelling. In determining whether a product is a consumer product, 302 | doubtful cases shall be resolved in favor of coverage. For a particular 303 | product received by a particular user, "normally used" refers to a 304 | typical or common use of that class of product, regardless of the status 305 | of the particular user or of the way in which the particular user 306 | actually uses, or expects or is expected to use, the product. A product 307 | is a consumer product regardless of whether the product has substantial 308 | commercial, industrial or non-consumer uses, unless such uses represent 309 | the only significant mode of use of the product. 310 | 311 | "Installation Information" for a User Product means any methods, 312 | procedures, authorization keys, or other information required to install 313 | and execute modified versions of a covered work in that User Product from 314 | a modified version of its Corresponding Source. The information must 315 | suffice to ensure that the continued functioning of the modified object 316 | code is in no case prevented or interfered with solely because 317 | modification has been made. 318 | 319 | If you convey an object code work under this section in, or with, or 320 | specifically for use in, a User Product, and the conveying occurs as 321 | part of a transaction in which the right of possession and use of the 322 | User Product is transferred to the recipient in perpetuity or for a 323 | fixed term (regardless of how the transaction is characterized), the 324 | Corresponding Source conveyed under this section must be accompanied 325 | by the Installation Information. But this requirement does not apply 326 | if neither you nor any third party retains the ability to install 327 | modified object code on the User Product (for example, the work has 328 | been installed in ROM). 329 | 330 | The requirement to provide Installation Information does not include a 331 | requirement to continue to provide support service, warranty, or updates 332 | for a work that has been modified or installed by the recipient, or for 333 | the User Product in which it has been modified or installed. Access to a 334 | network may be denied when the modification itself materially and 335 | adversely affects the operation of the network or violates the rules and 336 | protocols for communication across the network. 337 | 338 | Corresponding Source conveyed, and Installation Information provided, 339 | in accord with this section must be in a format that is publicly 340 | documented (and with an implementation available to the public in 341 | source code form), and must require no special password or key for 342 | unpacking, reading or copying. 343 | 344 | 7. Additional Terms. 345 | 346 | "Additional permissions" are terms that supplement the terms of this 347 | License by making exceptions from one or more of its conditions. 348 | Additional permissions that are applicable to the entire Program shall 349 | be treated as though they were included in this License, to the extent 350 | that they are valid under applicable law. If additional permissions 351 | apply only to part of the Program, that part may be used separately 352 | under those permissions, but the entire Program remains governed by 353 | this License without regard to the additional permissions. 354 | 355 | When you convey a copy of a covered work, you may at your option 356 | remove any additional permissions from that copy, or from any part of 357 | it. (Additional permissions may be written to require their own 358 | removal in certain cases when you modify the work.) You may place 359 | additional permissions on material, added by you to a covered work, 360 | for which you have or can give appropriate copyright permission. 361 | 362 | Notwithstanding any other provision of this License, for material you 363 | add to a covered work, you may (if authorized by the copyright holders of 364 | that material) supplement the terms of this License with terms: 365 | 366 | a) Disclaiming warranty or limiting liability differently from the 367 | terms of sections 15 and 16 of this License; or 368 | 369 | b) Requiring preservation of specified reasonable legal notices or 370 | author attributions in that material or in the Appropriate Legal 371 | Notices displayed by works containing it; or 372 | 373 | c) Prohibiting misrepresentation of the origin of that material, or 374 | requiring that modified versions of such material be marked in 375 | reasonable ways as different from the original version; or 376 | 377 | d) Limiting the use for publicity purposes of names of licensors or 378 | authors of the material; or 379 | 380 | e) Declining to grant rights under trademark law for use of some 381 | trade names, trademarks, or service marks; or 382 | 383 | f) Requiring indemnification of licensors and authors of that 384 | material by anyone who conveys the material (or modified versions of 385 | it) with contractual assumptions of liability to the recipient, for 386 | any liability that these contractual assumptions directly impose on 387 | those licensors and authors. 388 | 389 | All other non-permissive additional terms are considered "further 390 | restrictions" within the meaning of section 10. If the Program as you 391 | received it, or any part of it, contains a notice stating that it is 392 | governed by this License along with a term that is a further 393 | restriction, you may remove that term. If a license document contains 394 | a further restriction but permits relicensing or conveying under this 395 | License, you may add to a covered work material governed by the terms 396 | of that license document, provided that the further restriction does 397 | not survive such relicensing or conveying. 398 | 399 | If you add terms to a covered work in accord with this section, you 400 | must place, in the relevant source files, a statement of the 401 | additional terms that apply to those files, or a notice indicating 402 | where to find the applicable terms. 403 | 404 | Additional terms, permissive or non-permissive, may be stated in the 405 | form of a separately written license, or stated as exceptions; 406 | the above requirements apply either way. 407 | 408 | 8. Termination. 409 | 410 | You may not propagate or modify a covered work except as expressly 411 | provided under this License. Any attempt otherwise to propagate or 412 | modify it is void, and will automatically terminate your rights under 413 | this License (including any patent licenses granted under the third 414 | paragraph of section 11). 415 | 416 | However, if you cease all violation of this License, then your 417 | license from a particular copyright holder is reinstated (a) 418 | provisionally, unless and until the copyright holder explicitly and 419 | finally terminates your license, and (b) permanently, if the copyright 420 | holder fails to notify you of the violation by some reasonable means 421 | prior to 60 days after the cessation. 422 | 423 | Moreover, your license from a particular copyright holder is 424 | reinstated permanently if the copyright holder notifies you of the 425 | violation by some reasonable means, this is the first time you have 426 | received notice of violation of this License (for any work) from that 427 | copyright holder, and you cure the violation prior to 30 days after 428 | your receipt of the notice. 429 | 430 | Termination of your rights under this section does not terminate the 431 | licenses of parties who have received copies or rights from you under 432 | this License. If your rights have been terminated and not permanently 433 | reinstated, you do not qualify to receive new licenses for the same 434 | material under section 10. 435 | 436 | 9. Acceptance Not Required for Having Copies. 437 | 438 | You are not required to accept this License in order to receive or 439 | run a copy of the Program. Ancillary propagation of a covered work 440 | occurring solely as a consequence of using peer-to-peer transmission 441 | to receive a copy likewise does not require acceptance. However, 442 | nothing other than this License grants you permission to propagate or 443 | modify any covered work. These actions infringe copyright if you do 444 | not accept this License. Therefore, by modifying or propagating a 445 | covered work, you indicate your acceptance of this License to do so. 446 | 447 | 10. Automatic Licensing of Downstream Recipients. 448 | 449 | Each time you convey a covered work, the recipient automatically 450 | receives a license from the original licensors, to run, modify and 451 | propagate that work, subject to this License. You are not responsible 452 | for enforcing compliance by third parties with this License. 453 | 454 | An "entity transaction" is a transaction transferring control of an 455 | organization, or substantially all assets of one, or subdividing an 456 | organization, or merging organizations. If propagation of a covered 457 | work results from an entity transaction, each party to that 458 | transaction who receives a copy of the work also receives whatever 459 | licenses to the work the party's predecessor in interest had or could 460 | give under the previous paragraph, plus a right to possession of the 461 | Corresponding Source of the work from the predecessor in interest, if 462 | the predecessor has it or can get it with reasonable efforts. 463 | 464 | You may not impose any further restrictions on the exercise of the 465 | rights granted or affirmed under this License. For example, you may 466 | not impose a license fee, royalty, or other charge for exercise of 467 | rights granted under this License, and you may not initiate litigation 468 | (including a cross-claim or counterclaim in a lawsuit) alleging that 469 | any patent claim is infringed by making, using, selling, offering for 470 | sale, or importing the Program or any portion of it. 471 | 472 | 11. Patents. 473 | 474 | A "contributor" is a copyright holder who authorizes use under this 475 | License of the Program or a work on which the Program is based. The 476 | work thus licensed is called the contributor's "contributor version". 477 | 478 | A contributor's "essential patent claims" are all patent claims 479 | owned or controlled by the contributor, whether already acquired or 480 | hereafter acquired, that would be infringed by some manner, permitted 481 | by this License, of making, using, or selling its contributor version, 482 | but do not include claims that would be infringed only as a 483 | consequence of further modification of the contributor version. For 484 | purposes of this definition, "control" includes the right to grant 485 | patent sublicenses in a manner consistent with the requirements of 486 | this License. 487 | 488 | Each contributor grants you a non-exclusive, worldwide, royalty-free 489 | patent license under the contributor's essential patent claims, to 490 | make, use, sell, offer for sale, import and otherwise run, modify and 491 | propagate the contents of its contributor version. 492 | 493 | In the following three paragraphs, a "patent license" is any express 494 | agreement or commitment, however denominated, not to enforce a patent 495 | (such as an express permission to practice a patent or covenant not to 496 | sue for patent infringement). To "grant" such a patent license to a 497 | party means to make such an agreement or commitment not to enforce a 498 | patent against the party. 499 | 500 | If you convey a covered work, knowingly relying on a patent license, 501 | and the Corresponding Source of the work is not available for anyone 502 | to copy, free of charge and under the terms of this License, through a 503 | publicly available network server or other readily accessible means, 504 | then you must either (1) cause the Corresponding Source to be so 505 | available, or (2) arrange to deprive yourself of the benefit of the 506 | patent license for this particular work, or (3) arrange, in a manner 507 | consistent with the requirements of this License, to extend the patent 508 | license to downstream recipients. "Knowingly relying" means you have 509 | actual knowledge that, but for the patent license, your conveying the 510 | covered work in a country, or your recipient's use of the covered work 511 | in a country, would infringe one or more identifiable patents in that 512 | country that you have reason to believe are valid. 513 | 514 | If, pursuant to or in connection with a single transaction or 515 | arrangement, you convey, or propagate by procuring conveyance of, a 516 | covered work, and grant a patent license to some of the parties 517 | receiving the covered work authorizing them to use, propagate, modify 518 | or convey a specific copy of the covered work, then the patent license 519 | you grant is automatically extended to all recipients of the covered 520 | work and works based on it. 521 | 522 | A patent license is "discriminatory" if it does not include within 523 | the scope of its coverage, prohibits the exercise of, or is 524 | conditioned on the non-exercise of one or more of the rights that are 525 | specifically granted under this License. You may not convey a covered 526 | work if you are a party to an arrangement with a third party that is 527 | in the business of distributing software, under which you make payment 528 | to the third party based on the extent of your activity of conveying 529 | the work, and under which the third party grants, to any of the 530 | parties who would receive the covered work from you, a discriminatory 531 | patent license (a) in connection with copies of the covered work 532 | conveyed by you (or copies made from those copies), or (b) primarily 533 | for and in connection with specific products or compilations that 534 | contain the covered work, unless you entered into that arrangement, 535 | or that patent license was granted, prior to 28 March 2007. 536 | 537 | Nothing in this License shall be construed as excluding or limiting 538 | any implied license or other defenses to infringement that may 539 | otherwise be available to you under applicable patent law. 540 | 541 | 12. No Surrender of Others' Freedom. 542 | 543 | If conditions are imposed on you (whether by court order, agreement or 544 | otherwise) that contradict the conditions of this License, they do not 545 | excuse you from the conditions of this License. If you cannot convey a 546 | covered work so as to satisfy simultaneously your obligations under this 547 | License and any other pertinent obligations, then as a consequence you may 548 | not convey it at all. For example, if you agree to terms that obligate you 549 | to collect a royalty for further conveying from those to whom you convey 550 | the Program, the only way you could satisfy both those terms and this 551 | License would be to refrain entirely from conveying the Program. 552 | 553 | 13. Use with the GNU Affero General Public License. 554 | 555 | Notwithstanding any other provision of this License, you have 556 | permission to link or combine any covered work with a work licensed 557 | under version 3 of the GNU Affero General Public License into a single 558 | combined work, and to convey the resulting work. The terms of this 559 | License will continue to apply to the part which is the covered work, 560 | but the special requirements of the GNU Affero General Public License, 561 | section 13, concerning interaction through a network will apply to the 562 | combination as such. 563 | 564 | 14. Revised Versions of this License. 565 | 566 | The Free Software Foundation may publish revised and/or new versions of 567 | the GNU General Public License from time to time. Such new versions will 568 | be similar in spirit to the present version, but may differ in detail to 569 | address new problems or concerns. 570 | 571 | Each version is given a distinguishing version number. If the 572 | Program specifies that a certain numbered version of the GNU General 573 | Public License "or any later version" applies to it, you have the 574 | option of following the terms and conditions either of that numbered 575 | version or of any later version published by the Free Software 576 | Foundation. If the Program does not specify a version number of the 577 | GNU General Public License, you may choose any version ever published 578 | by the Free Software Foundation. 579 | 580 | If the Program specifies that a proxy can decide which future 581 | versions of the GNU General Public License can be used, that proxy's 582 | public statement of acceptance of a version permanently authorizes you 583 | to choose that version for the Program. 584 | 585 | Later license versions may give you additional or different 586 | permissions. However, no additional obligations are imposed on any 587 | author or copyright holder as a result of your choosing to follow a 588 | later version. 589 | 590 | 15. Disclaimer of Warranty. 591 | 592 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 593 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 594 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 595 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 596 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 597 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 598 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 599 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 600 | 601 | 16. Limitation of Liability. 602 | 603 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 604 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 605 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 606 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 607 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 608 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 609 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 610 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 611 | SUCH DAMAGES. 612 | 613 | 17. Interpretation of Sections 15 and 16. 614 | 615 | If the disclaimer of warranty and limitation of liability provided 616 | above cannot be given local legal effect according to their terms, 617 | reviewing courts shall apply local law that most closely approximates 618 | an absolute waiver of all civil liability in connection with the 619 | Program, unless a warranty or assumption of liability accompanies a 620 | copy of the Program in return for a fee. 621 | 622 | END OF TERMS AND CONDITIONS 623 | 624 | 625 | 626 | LGPL ADDENDUM: 627 | 628 | 629 | 630 | GNU LESSER GENERAL PUBLIC LICENSE 631 | Version 3, 29 June 2007 632 | 633 | Copyright (C) 2007 Free Software Foundation, Inc. 634 | Everyone is permitted to copy and distribute verbatim copies 635 | of this license document, but changing it is not allowed. 636 | 637 | 638 | This version of the GNU Lesser General Public License incorporates 639 | the terms and conditions of version 3 of the GNU General Public 640 | License, supplemented by the additional permissions listed below. 641 | 642 | 0. Additional Definitions. 643 | 644 | As used herein, "this License" refers to version 3 of the GNU Lesser 645 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 646 | General Public License. 647 | 648 | "The Library" refers to a covered work governed by this License, 649 | other than an Application or a Combined Work as defined below. 650 | 651 | An "Application" is any work that makes use of an interface provided 652 | by the Library, but which is not otherwise based on the Library. 653 | Defining a subclass of a class defined by the Library is deemed a mode 654 | of using an interface provided by the Library. 655 | 656 | A "Combined Work" is a work produced by combining or linking an 657 | Application with the Library. The particular version of the Library 658 | with which the Combined Work was made is also called the "Linked 659 | Version". 660 | 661 | The "Minimal Corresponding Source" for a Combined Work means the 662 | Corresponding Source for the Combined Work, excluding any source code 663 | for portions of the Combined Work that, considered in isolation, are 664 | based on the Application, and not on the Linked Version. 665 | 666 | The "Corresponding Application Code" for a Combined Work means the 667 | object code and/or source code for the Application, including any data 668 | and utility programs needed for reproducing the Combined Work from the 669 | Application, but excluding the System Libraries of the Combined Work. 670 | 671 | 1. Exception to Section 3 of the GNU GPL. 672 | 673 | You may convey a covered work under sections 3 and 4 of this License 674 | without being bound by section 3 of the GNU GPL. 675 | 676 | 2. Conveying Modified Versions. 677 | 678 | If you modify a copy of the Library, and, in your modifications, a 679 | facility refers to a function or data to be supplied by an Application 680 | that uses the facility (other than as an argument passed when the 681 | facility is invoked), then you may convey a copy of the modified 682 | version: 683 | 684 | a) under this License, provided that you make a good faith effort to 685 | ensure that, in the event an Application does not supply the 686 | function or data, the facility still operates, and performs 687 | whatever part of its purpose remains meaningful, or 688 | 689 | b) under the GNU GPL, with none of the additional permissions of 690 | this License applicable to that copy. 691 | 692 | 3. Object Code Incorporating Material from Library Header Files. 693 | 694 | The object code form of an Application may incorporate material from 695 | a header file that is part of the Library. You may convey such object 696 | code under terms of your choice, provided that, if the incorporated 697 | material is not limited to numerical parameters, data structure 698 | layouts and accessors, or small macros, inline functions and templates 699 | (ten or fewer lines in length), you do both of the following: 700 | 701 | a) Give prominent notice with each copy of the object code that the 702 | Library is used in it and that the Library and its use are 703 | covered by this License. 704 | 705 | b) Accompany the object code with a copy of the GNU GPL and this license 706 | document. 707 | 708 | 4. Combined Works. 709 | 710 | You may convey a Combined Work under terms of your choice that, 711 | taken together, effectively do not restrict modification of the 712 | portions of the Library contained in the Combined Work and reverse 713 | engineering for debugging such modifications, if you also do each of 714 | the following: 715 | 716 | a) Give prominent notice with each copy of the Combined Work that 717 | the Library is used in it and that the Library and its use are 718 | covered by this License. 719 | 720 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 721 | document. 722 | 723 | c) For a Combined Work that displays copyright notices during 724 | execution, include the copyright notice for the Library among 725 | these notices, as well as a reference directing the user to the 726 | copies of the GNU GPL and this license document. 727 | 728 | d) Do one of the following: 729 | 730 | 0) Convey the Minimal Corresponding Source under the terms of this 731 | License, and the Corresponding Application Code in a form 732 | suitable for, and under terms that permit, the user to 733 | recombine or relink the Application with a modified version of 734 | the Linked Version to produce a modified Combined Work, in the 735 | manner specified by section 6 of the GNU GPL for conveying 736 | Corresponding Source. 737 | 738 | 1) Use a suitable shared library mechanism for linking with the 739 | Library. A suitable mechanism is one that (a) uses at run time 740 | a copy of the Library already present on the user's computer 741 | system, and (b) will operate properly with a modified version 742 | of the Library that is interface-compatible with the Linked 743 | Version. 744 | 745 | e) Provide Installation Information, but only if you would otherwise 746 | be required to provide such information under section 6 of the 747 | GNU GPL, and only to the extent that such information is 748 | necessary to install and execute a modified version of the 749 | Combined Work produced by recombining or relinking the 750 | Application with a modified version of the Linked Version. (If 751 | you use option 4d0, the Installation Information must accompany 752 | the Minimal Corresponding Source and Corresponding Application 753 | Code. If you use option 4d1, you must provide the Installation 754 | Information in the manner specified by section 6 of the GNU GPL 755 | for conveying Corresponding Source.) 756 | 757 | 5. Combined Libraries. 758 | 759 | You may place library facilities that are a work based on the 760 | Library side by side in a single library together with other library 761 | facilities that are not Applications and are not covered by this 762 | License, and convey such a combined library under terms of your 763 | choice, if you do both of the following: 764 | 765 | a) Accompany the combined library with a copy of the same work based 766 | on the Library, uncombined with any other library facilities, 767 | conveyed under the terms of this License. 768 | 769 | b) Give prominent notice with the combined library that part of it 770 | is a work based on the Library, and explaining where to find the 771 | accompanying uncombined form of the same work. 772 | 773 | 6. Revised Versions of the GNU Lesser General Public License. 774 | 775 | The Free Software Foundation may publish revised and/or new versions 776 | of the GNU Lesser General Public License from time to time. Such new 777 | versions will be similar in spirit to the present version, but may 778 | differ in detail to address new problems or concerns. 779 | 780 | Each version is given a distinguishing version number. If the 781 | Library as you received it specifies that a certain numbered version 782 | of the GNU Lesser General Public License "or any later version" 783 | applies to it, you have the option of following the terms and 784 | conditions either of that published version or of any later version 785 | published by the Free Software Foundation. If the Library as you 786 | received it does not specify a version number of the GNU Lesser 787 | General Public License, you may choose any version of the GNU Lesser 788 | General Public License ever published by the Free Software Foundation. 789 | 790 | If the Library as you received it specifies that a proxy can decide 791 | whether future versions of the GNU Lesser General Public License shall 792 | apply, that proxy's public statement of acceptance of any version is 793 | permanent authorization for you to choose that version for the 794 | Library. 795 | -------------------------------------------------------------------------------- /gameFrame_Game/gameFrame_Game.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /*************************************************** 9 | BMP parsing code based on example sketch for the Adafruit 10 | 1.8" SPI display library by Adafruit. 11 | http://www.adafruit.com/products/358 12 | 13 | "Probably Random" number generator from: 14 | https://gist.github.com/endolith/2568571 15 | ****************************************************/ 16 | 17 | #define SD_CS 9 // Chip select line for SD card 18 | SdFat sd; // set filesystem 19 | SdFile myFile; // set filesystem 20 | 21 | #define BUFFPIXEL 1 22 | 23 | // In the SD card, place 24 bit color BMP files (be sure they are 24-bit!) 24 | // There are examples included 25 | 26 | // Parameter 1 = number of pixels in strip 27 | // Parameter 2 = pin number (most are valid) 28 | // Parameter 3 = pixel type flags, add together as needed: 29 | // NEO_RGB Pixels are wired for RGB bitstream 30 | // NEO_GRB Pixels are wired for GRB bitstream 31 | // NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels) 32 | // NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip) 33 | Adafruit_NeoPixel strip = Adafruit_NeoPixel(256, 6, NEO_GRB + NEO_KHZ800); 34 | 35 | //Random Number Generator 36 | byte sample = 0; 37 | boolean sample_waiting = false; 38 | byte current_bit = 0; 39 | byte randomResult = 0; 40 | 41 | //Button setup 42 | const uint8_t buttonNextPin = 4; // "Next" button 43 | const uint8_t buttonSetupPin = 5; // "Setup" button 44 | 45 | #define STATUS_LED 3 46 | 47 | //Enable prints? 48 | //Due to memory contraints Breakout is disabled in debugMode 49 | const boolean debugMode = false; 50 | 51 | //System Setup 52 | boolean 53 | folderLoop = true, // animation looping 54 | moveLoop = false, // translation/pan looping 55 | buttonPressed = false, // control button check 56 | buttonEnabled = true, // debounce guard 57 | setupActive = false, // set brightness, playback mode, etc. 58 | panoff = true, // movement scrolls off screen 59 | singleGraphic = false, // single BMP file 60 | abortImage = false, // image is corrupt; abort, retry, fail? 61 | verboseOutput = false, // output extra info to LEDs 62 | statusLedState = false, // flicker tech 63 | breakout = false, // breakout playing? 64 | ballMoving = false, 65 | gameInitialized = false; 66 | byte 67 | playMode = 0, // 0 = sequential, 1 = random, 2 = pause animations 68 | gameMode = 1, // breakout, ??? 69 | brightness = 4, // LED brightness 70 | brightnessMultiplier = 10, // DO NOT CHANGE THIS 71 | cycleTimeSetting = 2, // time before next animation: 1=10 secs, 2=30 secs, 3=1 min... 8=infinity 72 | fpShield = 0, // button false positive shield 73 | setupMode = 0, // 0 = brightmess, 1 = play mode, 2 = cycle time 74 | lowestMem = 250, // storage for lowest number of available bytes 75 | logoPlayed = 0, // hack for playing logo correctly reardless of playMode 76 | paddleIndex = 230, 77 | ballX = 112, 78 | ballY = 208, 79 | ballIndex = 216, 80 | currentSecond = 255; // current second 81 | int 82 | secondCounter = 0, // counts up every second 83 | cycleTime = 30, // seconds to wait before progressing to next folder 84 | numFolders = 0, // number of folders on sd 85 | folderIndex = 0, // current folder 86 | chainIndex = -1, // for chaining multiple folders 87 | fileIndex = 0, // current frame 88 | offsetBufferX = 0, // for storing offset when entering menu 89 | offsetBufferY = 0, // for storing offset when entering menu 90 | offsetSpeedX = 0, // number of pixels to translate each frame 91 | offsetSpeedY = 0, // number of pixels to translate each frame 92 | offsetX = 0, // for translating images x pixels 93 | offsetY = 0, // for translating images y pixels 94 | imageWidth = 0, 95 | imageHeight = 0, 96 | ballAngle; 97 | unsigned long 98 | lastTime = 0, // yep 99 | drawTime = 0, // debugging time to read from sd 100 | holdTime = 200, // millisecods to hold each .bmp frame 101 | swapTime = 0, // system time to advance to next frame 102 | baseTime = 0, // system time logged at start of each new image sequence 103 | buttonTime = 0, // time the last button was pressed (debounce code) 104 | setupEndTime = 0, // pause animation while in setup mode 105 | setupEnterTime = 0; // time we enter setup 106 | char 107 | chainRootFolder[9], // chain game 108 | nextFolder[18] = "00system/logo"; // dictated next animation 109 | 110 | RTC_DS1307 rtc; 111 | DateTime now; 112 | 113 | void setup(void) { 114 | // debug LED setup 115 | pinMode(STATUS_LED, OUTPUT); 116 | analogWrite(STATUS_LED, 100); 117 | 118 | wdtSetup(); 119 | 120 | pinMode(buttonNextPin, INPUT); // button as input 121 | pinMode(buttonSetupPin, INPUT); // button as input 122 | digitalWrite(buttonNextPin, HIGH); // turns on pull-up resistor after input 123 | digitalWrite(buttonSetupPin, HIGH); // turns on pull-up resistor after input 124 | 125 | if (debugMode == true) 126 | { 127 | Serial.begin(57600); 128 | printFreeRAM(); 129 | } 130 | 131 | // init clock and begin counting seconds 132 | rtc.begin(); 133 | rtc.adjust(DateTime(2014, 1, 1, 0, 0, 0)); 134 | 135 | byte output = 0; 136 | 137 | // load last settings 138 | // read brightness setting from EEPROM 139 | output = EEPROM.read(0); 140 | if (output >= 1 && output <= 7) brightness = output; 141 | 142 | // read playMode setting from EEPROM 143 | output = EEPROM.read(1); 144 | if (output >= 0 && output <= 2) playMode = output; 145 | 146 | // read cycleTimeSetting setting from EEPROM 147 | output = EEPROM.read(2); 148 | if (output >= 1 && output <= 8) cycleTimeSetting = output; 149 | setCycleTime(); 150 | 151 | strip.begin(); 152 | strip.show(); // Initialize all pixels to 'off' 153 | strip.setBrightness(brightness * brightnessMultiplier); 154 | 155 | // run burn in test if both buttons held on boot 156 | if ((digitalRead(buttonNextPin) == LOW) && (digitalRead(buttonSetupPin) == LOW)) 157 | { 158 | // max brightness 159 | strip.setBrightness(7 * brightnessMultiplier); 160 | while (true) 161 | { 162 | testScreen(); 163 | } 164 | } 165 | 166 | // revert to these values if setup button held on boot 167 | if (digitalRead(buttonSetupPin) == LOW) 168 | { 169 | brightness = 1; 170 | strip.setBrightness(brightness * brightnessMultiplier); 171 | playMode = 0; 172 | cycleTimeSetting = 2; 173 | setCycleTime(); 174 | } 175 | 176 | // show test screens and folder count if next button held on boot 177 | if (digitalRead(buttonNextPin) == LOW) 178 | { 179 | verboseOutput = true; 180 | testScreen(); 181 | } 182 | 183 | Serial.print(F("Init SD: ")); 184 | if (!sd.begin(SD_CS, SPI_FULL_SPEED)) { 185 | Serial.println(F("fail")); 186 | // SD error message 187 | sdErrorMessage(); 188 | return; 189 | } 190 | Serial.println(F("OK!")); 191 | 192 | char folder[9]; 193 | 194 | // file indexes appear to loop after 2048 195 | for (int fileIndex=0; fileIndex<2048; fileIndex++) 196 | { 197 | myFile.open(sd.vwd(), fileIndex, O_READ); 198 | if (myFile.isDir()) { 199 | Serial.println(F("---")); 200 | if (verboseOutput == true) 201 | { 202 | strip.setPixelColor(numFolders, strip.Color(128, 255, 0)); 203 | strip.show(); 204 | } 205 | numFolders++; 206 | Serial.print(F("File Index: ")); 207 | Serial.println(fileIndex); 208 | myFile.getFilename(folder); 209 | Serial.print(F("Folder: ")); 210 | Serial.println(folder); 211 | myFile.close(); 212 | } 213 | else myFile.close(); 214 | } 215 | Serial.print(numFolders); 216 | Serial.println(F(" folders found.")); 217 | if (verboseOutput == true) 218 | { 219 | delay(5000); 220 | } 221 | nextImage(); 222 | drawFrame(); 223 | } 224 | 225 | void testScreen() 226 | { 227 | // white 228 | for (int i=0; i<256; i++) 229 | { 230 | strip.setPixelColor(i, strip.Color(255, 255, 255)); 231 | } 232 | strip.show(); 233 | delay(2000); 234 | 235 | // red 236 | for (int i=0; i<256; i++) 237 | { 238 | strip.setPixelColor(i, strip.Color(255, 0, 0)); 239 | } 240 | strip.show(); 241 | delay(2000); 242 | 243 | // green 244 | for (int i=0; i<256; i++) 245 | { 246 | strip.setPixelColor(i, strip.Color(0, 255, 0)); 247 | } 248 | strip.show(); 249 | delay(2000); 250 | 251 | // blue 252 | for (int i=0; i<256; i++) 253 | { 254 | strip.setPixelColor(i, strip.Color(0, 0, 255)); 255 | } 256 | strip.show(); 257 | delay(2000); 258 | } 259 | 260 | void sdErrorMessage() 261 | { 262 | // red bars 263 | for (int index=64; index<80; index++) 264 | { 265 | strip.setPixelColor(index, strip.Color(255, 0, 0)); 266 | } 267 | for (int index=80; index<192; index++) 268 | { 269 | strip.setPixelColor(index, strip.Color(0, 0, 0)); 270 | } 271 | for (int index=192; index<208; index++) 272 | { 273 | strip.setPixelColor(index, strip.Color(255, 0, 0)); 274 | } 275 | // S 276 | yellowDot(7, 6); 277 | yellowDot(6, 6); 278 | yellowDot(5, 6); 279 | yellowDot(4, 7); 280 | yellowDot(5, 8); 281 | yellowDot(6, 8); 282 | yellowDot(7, 9); 283 | yellowDot(6, 10); 284 | yellowDot(5, 10); 285 | yellowDot(4, 10); 286 | 287 | // D 288 | yellowDot(9, 6); 289 | yellowDot(10, 6); 290 | yellowDot(11, 7); 291 | yellowDot(11, 8); 292 | yellowDot(11, 9); 293 | yellowDot(10, 10); 294 | yellowDot(9, 10); 295 | yellowDot(9, 7); 296 | yellowDot(9, 8); 297 | yellowDot(9, 9); 298 | 299 | strip.setBrightness(brightness * brightnessMultiplier); 300 | strip.show(); 301 | 302 | while (true) 303 | { 304 | for (int i=255; i>=0; i--) 305 | { 306 | analogWrite(STATUS_LED, i); 307 | delay(1); 308 | } 309 | for (int i=0; i<=254; i++) 310 | { 311 | analogWrite(STATUS_LED, i); 312 | delay(1); 313 | } 314 | } 315 | } 316 | 317 | void yellowDot(byte x, byte y) 318 | { 319 | strip.setPixelColor(getIndex(x, y), strip.Color(255, 255, 0)); 320 | } 321 | 322 | void setCycleTime() 323 | { 324 | if (cycleTimeSetting == 2) 325 | { 326 | cycleTime = 30; 327 | } 328 | else if (cycleTimeSetting == 3) 329 | { 330 | cycleTime = 60; 331 | } 332 | else if (cycleTimeSetting == 4) 333 | { 334 | cycleTime = 300; 335 | } 336 | else if (cycleTimeSetting == 5) 337 | { 338 | cycleTime = 900; 339 | } 340 | else if (cycleTimeSetting == 6) 341 | { 342 | cycleTime = 1800; 343 | } 344 | else if (cycleTimeSetting == 7) 345 | { 346 | cycleTime = 3600; 347 | } 348 | else if (cycleTimeSetting == 8) 349 | { 350 | cycleTime = -1; 351 | } 352 | else 353 | { 354 | cycleTime = 10; 355 | } 356 | } 357 | 358 | void statusLedFlicker() 359 | { 360 | if (statusLedState == false) 361 | { 362 | statusLedState = true; 363 | analogWrite(STATUS_LED, 254); 364 | } 365 | else 366 | { 367 | statusLedState = false; 368 | analogWrite(STATUS_LED, 255); 369 | } 370 | } 371 | 372 | void loop() { 373 | 374 | if (breakout == false) 375 | { 376 | mainLoop(); 377 | } 378 | 379 | else 380 | { 381 | if (!debugMode) breakoutLoop(); 382 | if (breakout == false) 383 | { 384 | nextImage(); 385 | drawFrame(); 386 | } 387 | } 388 | } 389 | 390 | void mainLoop() 391 | { 392 | buttonDebounce(); 393 | now = rtc.now(); 394 | 395 | // next button 396 | if (digitalRead(buttonNextPin) == LOW && buttonPressed == false && buttonEnabled == true) 397 | { 398 | buttonPressed = true; 399 | if (setupActive == false) 400 | { 401 | // exit chaining if necessary 402 | if (chainIndex > -1) 403 | { 404 | 405 | chainIndex = -1; 406 | chainRootFolder[0] = '\0'; 407 | sd.chdir("/"); 408 | } 409 | nextImage(); 410 | drawFrame(); 411 | } 412 | else 413 | { 414 | setupEndTime = millis() + 3000; 415 | 416 | // adjust brightness 417 | if (setupMode == 0) 418 | { 419 | brightness += 1; 420 | if (brightness > 7) brightness = 1; 421 | char brightChar[2]; 422 | char brightFile[23]; 423 | strcpy_P(brightFile, PSTR("/00system/bright_")); 424 | itoa(brightness, brightChar, 10); 425 | strcat(brightFile, brightChar); 426 | strcat(brightFile, ".bmp"); 427 | strip.setBrightness(brightness * brightnessMultiplier); 428 | bmpDraw(brightFile, 0, 0); 429 | } 430 | 431 | // adjust play mode 432 | else if (setupMode == 1) 433 | { 434 | playMode++; 435 | if (playMode > 2) playMode = 0; 436 | char playChar[2]; 437 | char playFile[21]; 438 | strcpy_P(playFile, PSTR("/00system/play_")); 439 | itoa(playMode, playChar, 10); 440 | strcat(playFile, playChar); 441 | strcat(playFile, ".bmp"); 442 | bmpDraw(playFile, 0, 0); 443 | } 444 | 445 | // adjust cycle time 446 | else if (setupMode == 2) 447 | { 448 | cycleTimeSetting++; 449 | if (cycleTimeSetting > 8) cycleTimeSetting = 1; 450 | setCycleTime(); 451 | char timeChar[2]; 452 | char timeFile[21]; 453 | strcpy_P(timeFile, PSTR("/00system/time_")); 454 | itoa(cycleTimeSetting, timeChar, 10); 455 | strcat(timeFile, timeChar); 456 | strcat(timeFile, ".bmp"); 457 | bmpDraw(timeFile, 0, 0); 458 | } 459 | 460 | // breakout time 461 | else if (setupMode == 3) 462 | { 463 | setupActive = false; 464 | if (EEPROM.read(0) != brightness) 465 | { 466 | EEPROM.write(0, brightness); 467 | } 468 | if (EEPROM.read(1) != playMode) 469 | { 470 | EEPROM.write(1, playMode); 471 | } 472 | if (EEPROM.read(2) != cycleTimeSetting) 473 | { 474 | EEPROM.write(2, cycleTimeSetting); 475 | } 476 | 477 | buttonTime = millis(); 478 | breakout = true; 479 | gameInitialized = false; 480 | buttonEnabled = false; 481 | 482 | char tmp[23]; 483 | strcpy_P(tmp, PSTR("/00system/breakout.bmp")); 484 | bmpDraw(tmp, 0, 0); 485 | 486 | paddleIndex = 230, 487 | ballX = 112, 488 | ballY = 208, 489 | ballIndex = 216; 490 | holdTime = 0; 491 | fileIndex = 0; 492 | strip.setPixelColor(ballIndex, strip.Color(175, 255, 15)); 493 | strip.setPixelColor(paddleIndex, strip.Color(200, 200, 200)); 494 | strip.setPixelColor(paddleIndex + 1, strip.Color(200, 200, 200)); 495 | strip.setPixelColor(paddleIndex + 2, strip.Color(200, 200, 200)); 496 | strip.show(); 497 | } 498 | } 499 | } 500 | 501 | // setup button 502 | else if (digitalRead(buttonSetupPin) == LOW && buttonPressed == false && buttonEnabled == true) 503 | { 504 | buttonPressed = true; 505 | setupEndTime = millis() + 3000; 506 | 507 | if (setupActive == false) 508 | { 509 | setupActive = true; 510 | setupEnterTime = millis(); 511 | offsetBufferX = offsetX; 512 | offsetBufferY = offsetY; 513 | offsetX = 0; 514 | offsetY = 0; 515 | if (myFile.isOpen()) myFile.close(); 516 | } 517 | else 518 | { 519 | setupMode++; 520 | if (setupMode > 3) setupMode = 0; 521 | } 522 | if (setupMode == 0) 523 | { 524 | char brightChar[2]; 525 | char brightFile[23]; 526 | strcpy_P(brightFile, PSTR("/00system/bright_")); 527 | itoa(brightness, brightChar, 10); 528 | strcat(brightFile, brightChar); 529 | strcat(brightFile, ".bmp"); 530 | bmpDraw(brightFile, 0, 0); 531 | } 532 | else if (setupMode == 1) 533 | { 534 | char playChar[2]; 535 | char playFile[21]; 536 | strcpy_P(playFile, PSTR("/00system/play_")); 537 | itoa(playMode, playChar, 10); 538 | strcat(playFile, playChar); 539 | strcat(playFile, ".bmp"); 540 | bmpDraw(playFile, 0, 0); 541 | } 542 | else if (setupMode == 2) 543 | { 544 | char timeChar[2]; 545 | char timeFile[21]; 546 | strcpy_P(timeFile, PSTR("/00system/time_")); 547 | itoa(cycleTimeSetting, timeChar, 10); 548 | strcat(timeFile, timeChar); 549 | strcat(timeFile, ".bmp"); 550 | bmpDraw(timeFile, 0, 0); 551 | } 552 | else if (setupMode == 3) 553 | { 554 | char gameFile[21]; 555 | strcpy_P(gameFile, PSTR("/00system/game.bmp")); 556 | bmpDraw(gameFile, 0, 0); 557 | } 558 | } 559 | 560 | if (((digitalRead(buttonSetupPin) == HIGH) && digitalRead(buttonNextPin) == HIGH) && buttonPressed == true) 561 | { 562 | buttonPressed = false; 563 | buttonEnabled = false; 564 | buttonTime = millis(); 565 | } 566 | 567 | // time to exit setup mode? 568 | if (setupActive == true) 569 | { 570 | if (millis() > setupEndTime) 571 | { 572 | setupActive = false; 573 | 574 | // save any new settings to EEPROM 575 | if (EEPROM.read(0) != brightness) 576 | { 577 | EEPROM.write(0, brightness); 578 | } 579 | if (EEPROM.read(1) != playMode) 580 | { 581 | EEPROM.write(1, playMode); 582 | } 583 | if (EEPROM.read(2) != cycleTimeSetting) 584 | { 585 | EEPROM.write(2, cycleTimeSetting); 586 | } 587 | 588 | // return to brightness setup next time 589 | setupMode = 0; 590 | 591 | offsetX = offsetBufferX; 592 | offsetY = offsetBufferY; 593 | if (playMode == 2) 594 | { 595 | offsetX = imageWidth / -2 + 8; 596 | offsetY = imageHeight / 2 - 8; 597 | } 598 | swapTime = swapTime + (millis() - setupEnterTime); 599 | baseTime = baseTime + (millis() - setupEnterTime); 600 | if ((holdTime != -1 || playMode != 2) && abortImage == false) 601 | { 602 | drawFrame(); 603 | } 604 | } 605 | } 606 | 607 | // currently playing images? 608 | if (setupActive == false && breakout == false) 609 | { 610 | // advance counter 611 | if (now.second() != currentSecond) 612 | { 613 | currentSecond = now.second(); 614 | secondCounter++; 615 | } 616 | // did image load fail? 617 | if (abortImage == true) 618 | { 619 | abortImage = false; 620 | nextImage(); 621 | drawFrame(); 622 | } 623 | // progress if cycleTime is up 624 | // check for infinite mode 625 | if (cycleTimeSetting != 8) 626 | { 627 | if (secondCounter >= cycleTime) 628 | { 629 | nextImage(); 630 | drawFrame(); 631 | } 632 | } 633 | 634 | // animate if not a single-frame & animations are on 635 | if (holdTime != -1 && playMode != 2 || logoPlayed < 2) 636 | { 637 | if (millis() >= swapTime) 638 | { 639 | statusLedFlicker(); 640 | swapTime = millis() + holdTime; 641 | fileIndex++; 642 | drawFrame(); 643 | } 644 | } 645 | } 646 | } 647 | 648 | void nextImage() 649 | { 650 | Serial.println(F("---")); 651 | Serial.println(F("Next Folder...")); 652 | if (myFile.isOpen()) myFile.close(); 653 | boolean foundNewFolder = false; 654 | secondCounter = 0; 655 | baseTime = millis(); 656 | holdTime = 0; 657 | char folder[9]; 658 | sd.chdir("/"); 659 | fileIndex = 0; 660 | offsetX = 0; 661 | offsetY = 0; 662 | singleGraphic = false; 663 | if (logoPlayed < 2) logoPlayed++; 664 | 665 | // are we chaining folders? 666 | if (chainIndex > -1) 667 | { 668 | char chainChar[3]; 669 | char chainDir[23]; 670 | strcpy_P(chainDir, PSTR("/")); 671 | strcat(chainDir, chainRootFolder); 672 | strcat(chainDir, "/"); 673 | itoa(chainIndex, chainChar, 10); 674 | strcat(chainDir, chainChar); 675 | if (sd.exists(chainDir)) 676 | { 677 | Serial.print(F("Chaining: ")); 678 | Serial.println(chainDir); 679 | sd.chdir(chainDir); 680 | chainIndex++; 681 | } 682 | else 683 | { 684 | // chaining concluded 685 | chainIndex = -1; 686 | chainRootFolder[0] = '\0'; 687 | sd.chdir("/"); 688 | } 689 | } 690 | 691 | // has the next animation has been dictated by the previous .INI file? 692 | if (nextFolder[0] != '\0' && chainIndex == -1) 693 | { 694 | Serial.print(F("Forcing next: ")); 695 | Serial.println(nextFolder); 696 | if (sd.exists(nextFolder)) 697 | { 698 | sd.chdir(nextFolder); 699 | } 700 | else 701 | { 702 | nextFolder[0] = '\0'; 703 | Serial.println(F("Not exists!")); 704 | } 705 | } 706 | 707 | // next folder not assigned by .INI 708 | if (nextFolder[0] == '\0' && chainIndex == -1) 709 | { 710 | // Getting next folder 711 | // shuffle playback using "probably_random" code 712 | // https://gist.github.com/endolith/2568571 713 | if (playMode != 0) // check we're not in a sequential play mode 714 | { 715 | if (sample_waiting == true) 716 | { 717 | randomResult = rotl(randomResult, 1); // Spread randomness around 718 | randomResult ^= sample; // XOR preserves randomness 719 | 720 | current_bit++; 721 | if (current_bit > 7) 722 | { 723 | current_bit = 0; 724 | } 725 | 726 | while (randomResult > numFolders) 727 | { 728 | randomResult = randomResult - numFolders; 729 | } 730 | } 731 | 732 | int targetFolder = randomResult; 733 | 734 | // don't repeat the same image, please. 735 | if (targetFolder <= 0 or targetFolder == numFolders or targetFolder == numFolders - 1) 736 | { 737 | // Repeat image detected! Incrementing targetFolder. 738 | targetFolder = targetFolder + 2; 739 | } 740 | 741 | Serial.print(F("Randomly advancing ")); 742 | Serial.print(targetFolder); 743 | Serial.println(F(" folder(s).")); 744 | int i = 1; 745 | while (i < targetFolder) 746 | { 747 | foundNewFolder = false; 748 | while (foundNewFolder == false) 749 | { 750 | myFile.open(sd.vwd(), folderIndex, O_READ); 751 | if (myFile.isDir()) { 752 | foundNewFolder = true; 753 | i++; 754 | } 755 | myFile.close(); 756 | folderIndex++; 757 | } 758 | } 759 | } 760 | 761 | foundNewFolder = false; 762 | 763 | while (foundNewFolder == false) 764 | { 765 | myFile.open(sd.vwd(), folderIndex, O_READ); 766 | myFile.getFilename(folder); 767 | 768 | // ignore system folders that start with "00" 769 | if (myFile.isDir() && folder[0] != 48 && folder[1] != 48) { 770 | foundNewFolder = true; 771 | Serial.print(F("Folder Index: ")); 772 | Serial.println(folderIndex); 773 | Serial.print(F("Opening Folder: ")); 774 | Serial.println(folder); 775 | 776 | sd.chdir(folder); 777 | myFile.close(); 778 | } 779 | else myFile.close(); 780 | folderIndex++; 781 | } 782 | } 783 | 784 | // is this the start of a folder chain? 785 | char chainDir[2]; 786 | strcpy_P(chainDir, PSTR("0")); 787 | if (sd.exists(chainDir)) 788 | { 789 | Serial.print(F("Chaining detected: ")); 790 | Serial.println(folder); 791 | memcpy(chainRootFolder, folder, 8); 792 | sd.chdir(chainDir); 793 | chainIndex = 1; 794 | } 795 | 796 | char firstImage[6]; 797 | strcpy_P(firstImage, PSTR("0.bmp")); 798 | if (sd.exists(firstImage)) 799 | { 800 | Serial.print(F("Opening File: ")); 801 | Serial.print(folder); 802 | Serial.println(F("/config.ini")); 803 | readIniFile(); 804 | 805 | char tmp[6]; 806 | strcpy_P(tmp, PSTR("0.bmp")); 807 | refreshImageDimensions(tmp); 808 | 809 | Serial.print(F("Hold (in ms): ")); 810 | Serial.println(holdTime); 811 | swapTime = millis() + holdTime; 812 | 813 | // setup image for x/y translation as needed if animations aren't paused 814 | if (playMode != 2) 815 | { 816 | if (offsetSpeedX > 0) 817 | { 818 | if (panoff == true) offsetX = (imageWidth * -1); 819 | else offsetX = (imageWidth * -1 + 16); 820 | } 821 | else if (offsetSpeedX < 0) 822 | { 823 | if (panoff == true) offsetX = 16; 824 | else offsetX = 0; 825 | } 826 | if (offsetSpeedY > 0) 827 | { 828 | if (panoff == true) offsetY = -16; 829 | else offsetY = 0; 830 | } 831 | else if (offsetSpeedY < 0) 832 | { 833 | if (panoff == true) offsetY = imageHeight; 834 | else offsetY = imageHeight - 16; 835 | } 836 | } 837 | // center image if animations are paused 838 | else 839 | { 840 | offsetX = imageWidth / -2 + 8; 841 | offsetY = imageHeight / 2 - 8; 842 | } 843 | 844 | // test for single frame 845 | 846 | char tmp_0[6]; 847 | char tmp_1[6]; 848 | strcpy_P(tmp_0, PSTR("0.bmp")); 849 | strcpy_P(tmp_1, PSTR("1.bmp")); 850 | if (sd.exists(tmp_0) && (!sd.exists(tmp_1))) 851 | { 852 | singleGraphic = true; 853 | // check for pan settings 854 | if (offsetSpeedX == 0 && offsetSpeedY == 0) 855 | { 856 | // single frame still 857 | holdTime = -1; 858 | } 859 | } 860 | } 861 | 862 | // empty folder 863 | else 864 | { 865 | Serial.println(F("Empty folder!")); 866 | nextImage(); 867 | } 868 | } 869 | 870 | void drawFrame() 871 | { 872 | if (panoff == true) 873 | { 874 | if (offsetX > 16 || offsetX < (imageWidth * -1) || offsetY > imageHeight || offsetY < -16) 875 | { 876 | if (moveLoop == false) 877 | { 878 | fileIndex = 0; 879 | nextImage(); 880 | } 881 | else 882 | { 883 | if (offsetSpeedX > 0 && offsetX >= 16) 884 | { 885 | offsetX = (imageWidth * -1); 886 | } 887 | else if (offsetSpeedX < 0 && offsetX <= imageWidth * -1) 888 | { 889 | offsetX = 16; 890 | } 891 | if (offsetSpeedY > 0 && offsetY >= imageHeight) 892 | { 893 | offsetY = -16; 894 | } 895 | else if (offsetSpeedY < 0 && offsetY <= -16) 896 | { 897 | offsetY = imageHeight; 898 | } 899 | } 900 | } 901 | } 902 | else 903 | { 904 | if (offsetX > 0 || offsetX < (imageWidth * -1 + 16) || offsetY > imageHeight - 16 || offsetY < 0) 905 | { 906 | if (moveLoop == false) 907 | { 908 | fileIndex = 0; 909 | nextImage(); 910 | } 911 | else 912 | { 913 | if (offsetSpeedX > 0 && offsetX >= 0) 914 | { 915 | offsetX = (imageWidth * -1 + 16); 916 | } 917 | else if (offsetSpeedX < 0 && offsetX <= imageWidth - 16) 918 | { 919 | offsetX = 0; 920 | } 921 | if (offsetSpeedY > 0 && offsetY >= imageHeight - 16) 922 | { 923 | offsetY = 0; 924 | } 925 | else if (offsetSpeedY < 0 && offsetY <= 0) 926 | { 927 | offsetY = imageHeight - 16; 928 | } 929 | } 930 | } 931 | } 932 | if (singleGraphic == false) 933 | { 934 | char bmpFile[8]; // 3-digit number + .bmp + null byte 935 | itoa(fileIndex, bmpFile, 10); 936 | strcat(bmpFile, ".bmp"); 937 | if (!sd.exists(bmpFile)) 938 | { 939 | fileIndex = 0; 940 | itoa(fileIndex, bmpFile, 10); 941 | strcat(bmpFile, ".bmp"); 942 | if (folderLoop == false) 943 | { 944 | nextImage(); 945 | } 946 | } 947 | bmpDraw(bmpFile, 0, 0); 948 | } 949 | else bmpDraw("0.bmp", 0, 0); 950 | 951 | if (debugMode == true) 952 | { 953 | // print draw time in milliseconds 954 | drawTime = millis() - lastTime; 955 | lastTime = millis(); 956 | Serial.print(F("ttd: ")); 957 | Serial.println(drawTime); 958 | } 959 | if (offsetSpeedX != 0) offsetX += offsetSpeedX; 960 | if (offsetSpeedY != 0) offsetY += offsetSpeedY; 961 | } 962 | 963 | void refreshImageDimensions(char *filename) { 964 | 965 | const uint8_t gridWidth = 16; 966 | const uint8_t gridHeight = 16; 967 | 968 | if((0 >= gridWidth) || (0 >= gridHeight)) { 969 | Serial.print(F("Abort.")); 970 | return; 971 | } 972 | 973 | // storing dimentions for image 974 | 975 | // Open requested file on SD card 976 | if (!myFile.open(filename, O_READ)) { 977 | Serial.println(F("File open failed")); 978 | sdErrorMessage(); 979 | return; 980 | } 981 | 982 | // Parse BMP header 983 | if(read16(myFile) == 0x4D42) { // BMP signature 984 | (void)read32(myFile); // Read & ignore file size 985 | (void)read32(myFile); // Read & ignore creator bytes 986 | (void)read32(myFile); // skip data 987 | // Read DIB header 988 | (void)read32(myFile); // Read & ignore Header size 989 | imageWidth = read32(myFile); 990 | imageHeight = read32(myFile); 991 | Serial.print(F("Image resolution: ")); 992 | Serial.print(imageWidth); 993 | Serial.print(F("x")); 994 | Serial.println(imageHeight); 995 | } 996 | Serial.println(F("Closing Image...")); 997 | myFile.close(); 998 | } 999 | 1000 | // This function opens a Windows Bitmap (BMP) file and 1001 | // displays it at the given coordinates. It's sped up 1002 | // by reading many pixels worth of data at a time 1003 | // (rather than pixel by pixel). Increasing the buffer 1004 | // size takes more of the Arduino's precious RAM but 1005 | // makes loading a little faster. 20 pixels seems a 1006 | // good balance. 1007 | 1008 | void bmpDraw(char *filename, uint8_t x, uint8_t y) { 1009 | 1010 | int bmpWidth, bmpHeight; // W+H in pixels 1011 | uint8_t bmpDepth; // Bit depth (currently must be 24) 1012 | uint32_t bmpImageoffset; // Start of image data in file 1013 | uint32_t rowSize; // Not always = bmpWidth; may have padding 1014 | uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) 1015 | uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer 1016 | boolean goodBmp = false; // Set to true on valid header parse 1017 | boolean flip = true; // BMP is stored bottom-to-top 1018 | int w, h, row, col; 1019 | uint8_t r, g, b; 1020 | uint32_t pos = 0; 1021 | const uint8_t gridWidth = 16; 1022 | const uint8_t gridHeight = 16; 1023 | 1024 | if((x >= gridWidth) || (y >= gridHeight)) { 1025 | Serial.print(F("Abort.")); 1026 | return; 1027 | } 1028 | 1029 | Serial.println(); 1030 | 1031 | if (!myFile.isOpen()) 1032 | { 1033 | Serial.print(F("Loading image '")); 1034 | Serial.print(filename); 1035 | Serial.println('\''); 1036 | // Open requested file on SD card 1037 | if (!myFile.open(filename, O_READ)) { 1038 | Serial.println(F("File open failed")); 1039 | sdErrorMessage(); 1040 | return; 1041 | } 1042 | } 1043 | else myFile.rewind(); 1044 | 1045 | if (debugMode == true) 1046 | { 1047 | printFreeRAM(); 1048 | } 1049 | 1050 | // Parse BMP header 1051 | if(read16(myFile) == 0x4D42) { // BMP signature 1052 | Serial.print(F("File size: ")); Serial.println(read32(myFile)); 1053 | (void)read32(myFile); // Read & ignore creator bytes 1054 | bmpImageoffset = read32(myFile); // Start of image data 1055 | Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC); 1056 | // Read DIB header 1057 | Serial.print(F("Header size: ")); Serial.println(read32(myFile)); 1058 | bmpWidth = read32(myFile); 1059 | bmpHeight = read32(myFile); 1060 | if(read16(myFile) == 1) { // # planes -- must be '1' 1061 | bmpDepth = read16(myFile); // bits per pixel 1062 | Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth); 1063 | if((bmpDepth == 24) && (read32(myFile) == 0)) { // 0 = uncompressed 1064 | 1065 | goodBmp = true; // Supported BMP format -- proceed! 1066 | Serial.print(F("Image size: ")); 1067 | Serial.print(bmpWidth); 1068 | Serial.print('x'); 1069 | Serial.println(bmpHeight); 1070 | 1071 | Serial.print(F("Image offset: ")); 1072 | Serial.print(offsetX); 1073 | Serial.print(F(", ")); 1074 | Serial.println(offsetY); 1075 | 1076 | // image smaller than 16x16? 1077 | if ((bmpWidth < 16 && bmpWidth > -16) || (bmpHeight < 16 && bmpHeight > -16)) 1078 | { 1079 | clearStripBuffer(); 1080 | } 1081 | 1082 | // BMP rows are padded (if needed) to 4-byte boundary 1083 | rowSize = (bmpWidth * 3 + 3) & ~3; 1084 | Serial.print(F("Row size: ")); 1085 | Serial.println(rowSize); 1086 | 1087 | // If bmpHeight is negative, image is in top-down order. 1088 | // This is not canon but has been observed in the wild. 1089 | if(bmpHeight < 0) { 1090 | bmpHeight = -bmpHeight; 1091 | flip = false; 1092 | } 1093 | 1094 | // initialize our pixel index 1095 | byte index = 0; // a byte is perfect for a 16x16 grid 1096 | 1097 | // Crop area to be loaded 1098 | w = bmpWidth; 1099 | h = bmpHeight; 1100 | if((x+w-1) >= gridWidth) w = gridWidth - x; 1101 | if((y+h-1) >= gridHeight) h = gridHeight - y; 1102 | 1103 | for (row=0; row= sizeof(sdbuffer)) { // Indeed 1124 | myFile.read(sdbuffer, sizeof(sdbuffer)); 1125 | buffidx = 0; // Set index to beginning 1126 | } 1127 | 1128 | // push to LED buffer 1129 | b = sdbuffer[buffidx++]; 1130 | g = sdbuffer[buffidx++]; 1131 | r = sdbuffer[buffidx++]; 1132 | 1133 | // offsetY is beyond bmpHeight 1134 | if (row >= bmpHeight - offsetY) 1135 | { 1136 | // black pixel 1137 | strip.setPixelColor(getIndex(col, row), strip.Color(0, 0, 0)); 1138 | } 1139 | // offsetY is negative 1140 | else if (row < offsetY * -1) 1141 | { 1142 | // black pixel 1143 | strip.setPixelColor(getIndex(col, row), strip.Color(0, 0, 0)); 1144 | } 1145 | // offserX is beyond bmpWidth 1146 | else if (col >= bmpWidth + offsetX) 1147 | { 1148 | // black pixel 1149 | strip.setPixelColor(getIndex(col, row), strip.Color(0, 0, 0)); 1150 | } 1151 | // offsetX is positive 1152 | else if (col < offsetX) 1153 | { 1154 | // black pixel 1155 | strip.setPixelColor(getIndex(col, row), strip.Color(0, 0, 0)); 1156 | } 1157 | // all good 1158 | else strip.setPixelColor(getIndex(col+x, row), strip.Color(r, g, b)); 1159 | // paint pixel color 1160 | } // end pixel 1161 | } // end scanline 1162 | } // end goodBmp 1163 | } 1164 | } 1165 | strip.show(); 1166 | // NOTE: strip.show() halts all interrupts, including the system clock. 1167 | // Each call results in about 6825 microseconds lost to the void. 1168 | if (singleGraphic == false || setupActive == true) 1169 | { 1170 | Serial.println(F("Closing Image...")); 1171 | myFile.close(); 1172 | } 1173 | if(!goodBmp) Serial.println(F("Format unrecognized.")); 1174 | } 1175 | 1176 | byte getIndex(byte x, byte y) 1177 | { 1178 | byte index; 1179 | if (y == 0) 1180 | { 1181 | index = 15 - x; 1182 | } 1183 | else if (y % 2 != 0) 1184 | { 1185 | index = y * 16 + x; 1186 | } 1187 | else 1188 | { 1189 | index = (y * 16 + 15) - x; 1190 | } 1191 | return index; 1192 | } 1193 | 1194 | void clearStripBuffer() 1195 | { 1196 | for (int i=0; i<256; i++) 1197 | { 1198 | strip.setPixelColor(i, strip.Color(0, 0, 0)); 1199 | } 1200 | } 1201 | 1202 | void buttonDebounce() 1203 | { 1204 | // button debounce -- no false positives 1205 | if (((digitalRead(buttonSetupPin) == HIGH) && digitalRead(buttonNextPin) == HIGH) && buttonPressed == true) 1206 | { 1207 | buttonPressed = false; 1208 | buttonEnabled = false; 1209 | buttonTime = millis(); 1210 | } 1211 | if ((buttonEnabled == false) && buttonPressed == false) 1212 | { 1213 | if (millis() > buttonTime + 50) buttonEnabled = true; 1214 | } 1215 | } 1216 | 1217 | // .INI file support 1218 | 1219 | void printErrorMessage(uint8_t e, bool eol = true) 1220 | { 1221 | switch (e) { 1222 | case IniFile::errorNoError: 1223 | Serial.print(F("no error")); 1224 | break; 1225 | case IniFile::errorFileNotFound: 1226 | Serial.print(F("fnf")); 1227 | break; 1228 | case IniFile::errorFileNotOpen: 1229 | Serial.print(F("fno")); 1230 | break; 1231 | case IniFile::errorBufferTooSmall: 1232 | Serial.print(F("bts")); 1233 | break; 1234 | case IniFile::errorSeekError: 1235 | Serial.print(F("se")); 1236 | break; 1237 | case IniFile::errorSectionNotFound: 1238 | Serial.print(F("snf")); 1239 | break; 1240 | case IniFile::errorKeyNotFound: 1241 | Serial.print(F("knf")); 1242 | break; 1243 | case IniFile::errorEndOfFile: 1244 | Serial.print(F("eof")); 1245 | break; 1246 | case IniFile::errorUnknownError: 1247 | Serial.print(F("unknown")); 1248 | break; 1249 | default: 1250 | Serial.print(F("unknown error value")); 1251 | break; 1252 | } 1253 | if (eol) 1254 | Serial.println(); 1255 | } 1256 | 1257 | void readIniFile() 1258 | { 1259 | const size_t bufferLen = 50; 1260 | char buffer[bufferLen]; 1261 | char configFile[11]; 1262 | strcpy_P(configFile, PSTR("config.ini")); 1263 | const char *filename = configFile; 1264 | IniFile ini(filename); 1265 | if (!ini.open()) { 1266 | Serial.print(filename); 1267 | Serial.println(F(" does not exist")); 1268 | // Cannot do anything else 1269 | } 1270 | else 1271 | { 1272 | Serial.println(F("Ini file exists")); 1273 | } 1274 | 1275 | // Check the file is valid. This can be used to warn if any lines 1276 | // are longer than the buffer. 1277 | if (!ini.validate(buffer, bufferLen)) { 1278 | Serial.print(F("ini file ")); 1279 | Serial.print(ini.getFilename()); 1280 | Serial.print(F(" not valid: ")); 1281 | printErrorMessage(ini.getError()); 1282 | // Cannot do anything else 1283 | } 1284 | char section[10]; 1285 | strcpy_P(section, PSTR("animation")); 1286 | char entry[11]; 1287 | strcpy_P(entry, PSTR("hold")); 1288 | 1289 | // Fetch a value from a key which is present 1290 | if (ini.getValue(section, entry, buffer, bufferLen)) { 1291 | Serial.print(F("hold value: ")); 1292 | Serial.println(buffer); 1293 | holdTime = atol(buffer); 1294 | } 1295 | else { 1296 | printErrorMessage(ini.getError()); 1297 | holdTime = 200; 1298 | } 1299 | 1300 | strcpy_P(entry, PSTR("loop")); 1301 | 1302 | // Fetch a boolean value 1303 | bool loopCheck; 1304 | bool found = ini.getValue(section, entry, buffer, bufferLen, loopCheck); 1305 | if (found) { 1306 | Serial.print(F("animation loop value: ")); 1307 | // Print value, converting boolean to a string 1308 | Serial.println(loopCheck ? F("TRUE") : F("FALSE")); 1309 | folderLoop = loopCheck; 1310 | } 1311 | else { 1312 | printErrorMessage(ini.getError()); 1313 | folderLoop = true; 1314 | } 1315 | 1316 | strcpy_P(section, PSTR("translate")); 1317 | strcpy_P(entry, PSTR("moveX")); 1318 | 1319 | // Fetch a value from a key which is present 1320 | if (ini.getValue(section, entry, buffer, bufferLen)) { 1321 | Serial.print(F("moveX value: ")); 1322 | Serial.println(buffer); 1323 | offsetSpeedX = atoi(buffer); 1324 | } 1325 | else { 1326 | printErrorMessage(ini.getError()); 1327 | offsetSpeedX = 0; 1328 | } 1329 | 1330 | strcpy_P(entry, PSTR("moveY")); 1331 | 1332 | // Fetch a value from a key which is present 1333 | if (ini.getValue(section, entry, buffer, bufferLen)) { 1334 | Serial.print(F("moveY value: ")); 1335 | Serial.println(buffer); 1336 | offsetSpeedY = atoi(buffer); 1337 | } 1338 | else { 1339 | printErrorMessage(ini.getError()); 1340 | offsetSpeedY = 0; 1341 | } 1342 | 1343 | strcpy_P(entry, PSTR("loop")); 1344 | 1345 | // Fetch a boolean value 1346 | bool loopCheck2; 1347 | bool found2 = ini.getValue(section, entry, buffer, bufferLen, loopCheck2); 1348 | if (found2) { 1349 | Serial.print(F("translate loop value: ")); 1350 | // Print value, converting boolean to a string 1351 | Serial.println(loopCheck2 ? F("TRUE") : F("FALSE")); 1352 | moveLoop = loopCheck2; 1353 | } 1354 | else { 1355 | printErrorMessage(ini.getError()); 1356 | moveLoop = false; 1357 | } 1358 | 1359 | strcpy_P(entry, PSTR("panoff")); 1360 | 1361 | // Fetch a boolean value 1362 | bool loopCheck3; 1363 | bool found3 = ini.getValue(section, entry, buffer, bufferLen, loopCheck3); 1364 | if (found3) { 1365 | Serial.print(F("panoff value: ")); 1366 | // Print value, converting boolean to a string 1367 | Serial.println(loopCheck3 ? F("TRUE") : F("FALSE")); 1368 | panoff = loopCheck3; 1369 | } 1370 | else { 1371 | printErrorMessage(ini.getError()); 1372 | panoff = true; 1373 | } 1374 | 1375 | strcpy_P(entry, PSTR("nextFolder")); 1376 | 1377 | // Fetch a value from a key which is present 1378 | if (ini.getValue(section, entry, buffer, bufferLen)) { 1379 | Serial.print(F("nextFolder value: ")); 1380 | Serial.println(buffer); 1381 | memcpy(nextFolder, buffer, 8); 1382 | } 1383 | else { 1384 | printErrorMessage(ini.getError()); 1385 | nextFolder[0] = '\0'; 1386 | } 1387 | 1388 | if (ini.isOpen()) ini.close(); 1389 | } 1390 | 1391 | // breakout code 1392 | void drawPaddle() 1393 | { 1394 | strip.setPixelColor(paddleIndex, strip.Color(200, 200, 200)); 1395 | strip.setPixelColor(paddleIndex+1, strip.Color(200, 200, 200)); 1396 | strip.setPixelColor(paddleIndex+2, strip.Color(200, 200, 200)); 1397 | strip.show(); 1398 | } 1399 | 1400 | void breakoutLoop() 1401 | { 1402 | if (holdTime > 0) holdTime--; 1403 | if (fileIndex > 0) fileIndex--; 1404 | 1405 | if (buttonEnabled == false) 1406 | { 1407 | if (millis() > buttonTime + 50) buttonEnabled = true; 1408 | } 1409 | 1410 | // setup button 1411 | if (digitalRead(buttonSetupPin) == LOW && holdTime == 0 && paddleIndex < 237 && gameInitialized == true && buttonEnabled == true) 1412 | { 1413 | paddleIndex++; 1414 | strip.setPixelColor(paddleIndex-1, strip.Color(0, 0, 0)); 1415 | drawPaddle(); 1416 | holdTime = 3000; 1417 | if (ballMoving == false) 1418 | { 1419 | ballMoving = true; 1420 | swapTime = 5000; 1421 | ballAngle = random(190, 225); 1422 | } 1423 | } 1424 | 1425 | // next button 1426 | else if (digitalRead(buttonNextPin) == LOW && holdTime == 0 && paddleIndex > 224 && buttonEnabled == true) 1427 | { 1428 | paddleIndex--; 1429 | strip.setPixelColor(paddleIndex+3, strip.Color(0, 0, 0)); 1430 | drawPaddle(); 1431 | holdTime = 3000; 1432 | if (ballMoving == false) 1433 | { 1434 | ballMoving = true; 1435 | swapTime = 5000; 1436 | ballAngle = random(135,170); 1437 | } 1438 | } 1439 | 1440 | else if (digitalRead(buttonNextPin) == HIGH && gameInitialized == false) gameInitialized = true; 1441 | 1442 | // ball logic 1443 | if (ballMoving == true && fileIndex == 0) 1444 | { 1445 | fileIndex = swapTime; 1446 | strip.setPixelColor(ballIndex, strip.Color(0, 0, 0)); 1447 | 1448 | // did the player lose? 1449 | if (ballIndex >= 239) 1450 | { 1451 | ballMoving = false; 1452 | breakout = false; 1453 | Serial.print(F("Lose!!!")); 1454 | for (int c=250; c>=0; c=c-15) 1455 | { 1456 | for (int i=0; i<256; i++) 1457 | { 1458 | byte r = 0; 1459 | byte g = 0; 1460 | byte b = 0; 1461 | if (random(0, 2)) 1462 | { 1463 | r = c; 1464 | } 1465 | if (random(0, 2)) 1466 | { 1467 | g = c; 1468 | } 1469 | if (random(0, 2)) 1470 | { 1471 | b = c; 1472 | } 1473 | strip.setPixelColor(i, strip.Color(r, g, b)); 1474 | } 1475 | strip.show(); 1476 | } 1477 | } 1478 | 1479 | // ball still in play 1480 | else 1481 | { 1482 | if (ballAngle < 180) 1483 | { 1484 | if ((ballX + sin(degToRad(ballAngle)) * 16) +.5 > 256) swapXdirection(); 1485 | } 1486 | else 1487 | { 1488 | if ((ballX + sin(degToRad(ballAngle)) * 16) +.5 < 0) swapXdirection(); 1489 | } 1490 | ballX = ballX + sin(degToRad(ballAngle)) * 16 +.5; 1491 | 1492 | if (ballAngle > 90 && ballAngle < 270) 1493 | { 1494 | if ((ballY + cos(degToRad(ballAngle)) * 16) +.5 < 0) swapYdirection(); 1495 | } 1496 | else 1497 | { 1498 | if ((ballY + cos(degToRad(ballAngle)) * 16) +.5 > 256) swapYdirection(); 1499 | } 1500 | ballY = ballY + cos(degToRad(ballAngle)) * 16 +.5; 1501 | ballIndex = getScreenIndex(ballX, ballY); 1502 | 1503 | // paddle hit? 1504 | if (ballIndex == paddleIndex or ballIndex == paddleIndex+1 or ballIndex == paddleIndex+2) 1505 | { 1506 | // move the ball back in time one step 1507 | ballX = ballX + ((sin(degToRad(ballAngle)) * 16 +.5) *-1); 1508 | ballY = ballY + ((cos(degToRad(ballAngle)) * 16 +.5) *-1); 1509 | swapYdirection(); 1510 | if (ballIndex == paddleIndex) 1511 | { 1512 | ballAngle = random(115,170); 1513 | } 1514 | else if (ballIndex == paddleIndex+2) 1515 | { 1516 | ballAngle = random(190, 245); 1517 | } 1518 | ballIndex = getScreenIndex(ballX, ballY); 1519 | strip.setPixelColor(paddleIndex, strip.Color(200, 200, 200)); 1520 | strip.setPixelColor(paddleIndex+1, strip.Color(200, 200, 200)); 1521 | strip.setPixelColor(paddleIndex+2, strip.Color(200, 200, 200)); 1522 | } 1523 | 1524 | // brick hit? 1525 | if (strip.getPixelColor(ballIndex) > 0) 1526 | { 1527 | // speed up and change direction 1528 | swapTime = swapTime - 30; 1529 | swapYdirection(); 1530 | if (winCheck()) 1531 | { 1532 | Serial.print(F("Win!!!")); 1533 | ballMoving = false; 1534 | breakout = false; 1535 | chdirFirework(); 1536 | char bmpFile[7]; // 2-digit number + .bmp + null byte 1537 | for (byte fileIndex=0; fileIndex<83; fileIndex++) 1538 | { 1539 | itoa(fileIndex, bmpFile, 10); 1540 | strcat(bmpFile, ".bmp"); 1541 | bmpDraw(bmpFile, 0, 0); 1542 | } 1543 | } 1544 | } 1545 | 1546 | // check for preceeding win 1547 | if (breakout == true) 1548 | { 1549 | strip.setPixelColor(ballIndex, strip.Color(175, 255, 15)); 1550 | strip.show(); 1551 | } 1552 | } 1553 | } 1554 | } 1555 | 1556 | void chdirFirework() 1557 | { 1558 | char tmp[20]; 1559 | strcpy_P(tmp, PSTR("/00system/firework")); 1560 | sd.chdir(tmp); 1561 | } 1562 | 1563 | boolean winCheck() 1564 | { 1565 | byte numberOfLitPixels = 0; 1566 | for (byte i=0; i<255; i++) 1567 | { 1568 | if (strip.getPixelColor(i) > 0) 1569 | { 1570 | numberOfLitPixels++; 1571 | } 1572 | } 1573 | if (numberOfLitPixels <= 4) 1574 | { 1575 | return true; 1576 | } 1577 | } 1578 | 1579 | byte getScreenIndex(byte x, byte y) 1580 | { 1581 | byte screenX = x / 16; 1582 | byte screenY = y / 16; 1583 | byte index; 1584 | index = screenY * 16; 1585 | if (screenY == 0) 1586 | { 1587 | index = 15 - screenX; 1588 | } 1589 | else if (screenY % 2 != 0) 1590 | { 1591 | index = (screenY * 16) + screenX; 1592 | } 1593 | else 1594 | { 1595 | index = (screenY * 16 + 15) - screenX; 1596 | } 1597 | return index; 1598 | } 1599 | 1600 | void swapYdirection() 1601 | { 1602 | if (ballAngle > 90 && ballAngle < 270) 1603 | { 1604 | if (ballAngle > 180) 1605 | { 1606 | ballAngle = 360 - (ballAngle - 180); 1607 | } 1608 | else 1609 | { 1610 | ballAngle = 90 - (ballAngle - 90); 1611 | } 1612 | } 1613 | else 1614 | { 1615 | if (ballAngle < 90) 1616 | { 1617 | ballAngle = 90 + (90 - ballAngle); 1618 | } 1619 | else 1620 | { 1621 | ballAngle = 180 + (360 - ballAngle); 1622 | } 1623 | } 1624 | } 1625 | 1626 | void swapXdirection() 1627 | { 1628 | if (ballAngle < 180) 1629 | { 1630 | if (ballAngle < 90) 1631 | { 1632 | ballAngle = 270 + (90 - ballAngle); 1633 | } 1634 | else ballAngle = 270 - (ballAngle - 90); 1635 | } 1636 | else 1637 | { 1638 | if (ballAngle > 270) 1639 | { 1640 | ballAngle = 360 - ballAngle; 1641 | } 1642 | else ballAngle = 180 - (ballAngle - 180); 1643 | } 1644 | } 1645 | 1646 | float degToRad(float deg) 1647 | { 1648 | float result; 1649 | result = deg * PI / 180; 1650 | return result; 1651 | } 1652 | 1653 | // These read 16- and 32-bit types from the SD card file. 1654 | // BMP data is stored little-endian, Arduino is little-endian too. 1655 | // May need to reverse subscript order if porting elsewhere. 1656 | 1657 | uint16_t read16(SdFile& f) { 1658 | uint16_t result; 1659 | ((uint8_t *)&result)[0] = f.read(); // LSB 1660 | ((uint8_t *)&result)[1] = f.read(); // MSB 1661 | return result; 1662 | } 1663 | 1664 | uint32_t read32(SdFile& f) { 1665 | uint32_t result; 1666 | ((uint8_t *)&result)[0] = f.read(); // LSB 1667 | ((uint8_t *)&result)[1] = f.read(); 1668 | ((uint8_t *)&result)[2] = f.read(); 1669 | ((uint8_t *)&result)[3] = f.read(); // MSB 1670 | return result; 1671 | } 1672 | 1673 | // available RAM checker 1674 | void printFreeRAM() 1675 | { 1676 | Serial.print(F("FreeRam: ")); 1677 | Serial.println(freeRam()); 1678 | if (freeRam() < lowestMem) lowestMem = freeRam(); 1679 | Serial.print(F("Lowest FreeRam: ")); 1680 | Serial.println(lowestMem); 1681 | } 1682 | 1683 | int freeRam () { 1684 | extern int __heap_start, *__brkval; 1685 | int v; 1686 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 1687 | } 1688 | 1689 | // Random Number Generation ("probably_random") 1690 | // https://gist.github.com/endolith/2568571 1691 | // Rotate bits to the left 1692 | // https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts 1693 | byte rotl(const byte value, int shift) { 1694 | if ((shift &= sizeof(value)*8 - 1) == 0) 1695 | return value; 1696 | return (value << shift) | (value >> (sizeof(value)*8 - shift)); 1697 | } 1698 | 1699 | // Setup of the watchdog timer. 1700 | void wdtSetup() { 1701 | cli(); 1702 | MCUSR = 0; 1703 | 1704 | /* Start timed sequence */ 1705 | WDTCSR |= _BV(WDCE) | _BV(WDE); 1706 | 1707 | /* Put WDT into interrupt mode */ 1708 | /* Set shortest prescaler(time-out) value = 2048 cycles (~16 ms) */ 1709 | WDTCSR = _BV(WDIE); 1710 | 1711 | sei(); 1712 | } 1713 | 1714 | // Watchdog Timer Interrupt Service Routine 1715 | ISR(WDT_vect) 1716 | { 1717 | sample = TCNT1L; // Ignore higher bits 1718 | sample_waiting = true; 1719 | } 1720 | --------------------------------------------------------------------------------