![](/media/cache/profiles/251bd0442dfcc53b5a761e050f8022b8.50x50_q85.jpg)
Bible eBook Prototype More details at: http://mbed.org/users/davervw/notebook/ebible-abstract/
Dependencies: SDHCFileSystem TextLCD mbed BibleIO
Revision 0:b9d9145827e2, committed 2011-02-27
- Comitter:
- davervw
- Date:
- Sun Feb 27 18:54:37 2011 +0000
- Commit message:
- NXP mbed Design Challenge Entry
Changed in this revision
diff -r 000000000000 -r b9d9145827e2 BibleIO.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BibleIO.lib Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/davervw/code/BibleIO/#1f3d069211cd
diff -r 000000000000 -r b9d9145827e2 BibleUI.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BibleUI.cpp Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,621 @@ +/* Bible UI Class Implementation - KJV Bible eBook Browser + * + * Copyright (c) 2011 David R. Van Wagner davervw@yahoo.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "BibleUI.h" + +//extern Serial console; + +BibleUI::BibleUI(BibleIO &bible, TextLCD &textlcd, DigitalIn& left, DigitalIn& right) + :HolyBible(bible), lcd(textlcd), lb(left), rb(right), led1(LED1), led2(LED2), led3(LED3), led4(LED4) +{ + //console.printf("\n\n" "Bible LCD\n\n"); + lcd.cls(); + lcd.printf("BibleLCD"); + + wait(0.5); + + show_title(); + + book = 0; + chapter = 0; + verse = 0; + offset = 0; + disp_len = 0; +} + +void BibleUI::start() +{ + main(); +} + +void BibleUI::display_nav() +{ + lcd.cls(); + char* book_name = HolyBible.title_book(book); + if (strlen(book_name) >= lcd.columns()) + book_name[lcd.columns()] = 0; + lcd.printf("%s%s%d:%d", book_name, strlen(book_name)==lcd.columns()?"":"\n", chapter+1, verse+1); + //console.printf("%s %d:%d", abbrev, chapter+1, verse+1); + delete [] book_name; +} + +bool BibleUI::append_next_verse(char*& text, short len, short book, short chapter, short verse) +{ + int size = 0; + do + { + // get next verse + char* next_verse = HolyBible.text_verse(book, chapter, ++verse); + if (next_verse == 0) + return size>0; // stop at end of chapter, return true if text has lengthened at all + size += strlen(next_verse); + + // combine + char* new_verse = new char[strlen(text)+strlen(next_verse)+2]; // add room for space delimiter and nul + strcpy(new_verse, text); + strcat(new_verse, " "); + strcat(new_verse, next_verse); + delete [] text; + delete [] next_verse; + text = new_verse; + } while (size < len); // repeat until enough characters added + + return size>0; +} + +void BibleUI::display_verse() +{ + // fix positioning, check ranges + char* text = 0; + if (offset < 0) + { + if (offset > -lcd.rows()*lcd.columns()) + offset = 0; // be sure to show beginning of verse + else + { + if (verse > 0) // previous verse + --verse; + else + { + if (chapter > 0) // last verse in previous chapter + { + --chapter; + verse = HolyBible.get_num_verses(book, chapter)-1; + } + else if (book > 0) // last verse in previous book + { + --book; + chapter = HolyBible.get_num_chapters(book)-1; + verse = HolyBible.get_num_verses(book, chapter)-1; + } + else //end of bible + { + book = HolyBible.get_num_books() - 1; + chapter = HolyBible.get_num_chapters(book)-1; + verse = HolyBible.get_num_verses(book, chapter)-1; + } + display_nav(); + wait(0.5); + } + } + text = HolyBible.text_verse(book, chapter, verse); + if (offset < 0) + { + int len = strlen(text); + if (len > lcd.rows()*lcd.columns()) + offset = len-lcd.rows()*lcd.columns(); + else + offset = 0; + } + } + else + text = HolyBible.text_verse(book, chapter, verse); + if (offset == 0) + { + char* text_start = strchr(text, ' '); + //console.printf("%s\n", text_start); + } + if (offset >= strlen(text)) + { + offset = 0; + delete [] text; + text = HolyBible.text_verse(book, chapter, ++verse); // next verse + if (text == 0) + { + text = HolyBible.text_verse(book, ++chapter, verse=0); // next chapter + if (text == 0) + text = HolyBible.text_verse(++book, chapter=0, verse=0); // next book + if (text == 0) + text = HolyBible.text_verse(book=0, chapter=0, verse=0); // end + display_nav(); + wait(0.5); + } + } + + // append enough text to fill screen and then some + append_next_verse(text, lcd.rows()*(lcd.columns()+1), book, chapter, verse); + + // find current position within verse(s) + char* verse_text = text + offset; + + // make a copy starting at offset so it can be modified + char* copy = new char[strlen(verse_text)+1]; + strcpy(copy, verse_text); + delete [] text; // note: text was allocated, verse_text was just pointed into it + text = 0; + verse_text = 0; + + // word wrap + disp_len = word_wrap(copy); + /* + if (strlen(copy) > lcd.rows()*lcd.columns()) + copy[lcd.rows()*lcd.columns()] = 0; + disp_len = strlen(copy); + */ + + // display + lcd.locate(0, 0); + lcd.printf("%s", copy); + + // pad with spaces (avoids cls which can cause some flashing) + int max_len = lcd.rows()*lcd.columns(); + for (int i=strlen(copy); i<max_len; ++i) + lcd.printf(" "); + + // free up storage + delete [] copy; + copy = 0; +} + +static bool alphanumeric(char c) +{ + return c >= '0' && c <= '9' + || c >= 'A' && c <= 'Z' + || c >= 'a' && c <= 'z'; +} + +static bool punc_or_space(char c) +{ + return !alphanumeric(c); +} + +int BibleUI::word_wrap(char* &text) +{ + // make copy of original text for later comparison + char* orig = new char[strlen(text)+1]; + strcpy(orig, text); + + // remove unwanted strings + remove_string(text, "# "); + remove_string(text, "["); + remove_string(text, "]"); + + // scan each line + for (int row=0; row<lcd.rows(); ++row) + { + int start = row * lcd.columns(); + int end = start + lcd.columns(); + + // remove spaces at start of line + while (start < strlen(text) && text[start]==' ') + { + // delete one character + int left = start; + int right = strlen(text+left+1); + char* new_text = new char[left+right+1]; + memcpy(new_text, text, left); + new_text[left] = 0; + strcat(new_text, text+left+1); + delete [] text; + text = new_text; + } + + // insert spaces to wrap words + if (strlen(text) > end && !punc_or_space(text[end])) + { + int left; + for (left=end-1; left>=start && !punc_or_space(text[left]); --left) + ; + if (left > start && left < end) + { + ++left; + int right=strlen(text+left); + int spaces=end-left; + //printf("row=%d total=%d left=%d spaces=%d right=%d\n", row, strlen(text), left, spaces, right); + char* new_text = new char[left+spaces+right+1]; + memcpy(new_text, text, left); + new_text[left] = 0; + for (int i=0; i<spaces; ++i) + strcat(new_text, " "); + strcat(new_text, text+left); + delete [] text; + text = new_text; + } + } + } + + // truncate to screen size + int max_len = lcd.rows()*lcd.columns(); + if (strlen(text)>=max_len) + text[max_len] = 0; + + // make copy with non-spaces + char* nospaces = new char[strlen(text)+1]; + int len = 0; + for (int i=0; i<strlen(text); ++i) + if (text[i] != ' ') + nospaces[len++] = text[i]; + nospaces[len] = 0; + + // calculate the number of characters displayed + int src=0; + for (int dest=0; dest<len; ++dest) + { + // non-space character must be there, advance in original until find it + while (orig[src++] != nospaces[dest]) + ; + } + + // free up storage + delete [] nospaces; + nospaces = 0; + delete [] orig; + orig = 0; + + // return length of source string that matches wrapped text, so know how to advance to next portion of verse + return src; +} + +void BibleUI::remove_string(char* &text, char* find) +{ + while (true) + { + char* p = strstr(text, find); + if (p == 0) + return; + int left = p-text; + int right = strlen(p+strlen(find)); + char* new_text = new char[left+right+1]; + memcpy(new_text, text, left); + new_text[left] = 0; + strcat(new_text, p+strlen(find)); + delete [] text; + text = new_text; + } +} + +void BibleUI::show_title() +{ + lcd.cls(); + char* title = HolyBible.title(); + lcd.printf("%s", title); + //console.printf("%s\n", title); + delete [] title; + title = 0; +} + +void BibleUI::main() +{ + enum emode { MODE_OFFSET=0, MODE_VERSE=1, MODE_CHAPTER=2, MODE_BOOK=3, MODE_4xBOOK=4, MODE_BOOKMARK=5 }; + + emode mode = MODE_OFFSET; + + display_nav(); + wait(0.5); + display_verse(); + + // debug: display all text + /* + int last_book = book; + int pages = -1; + while (book >= last_book) + { + ++pages; + last_book = book; + + display_verse(); + + char* book_name = HolyBible.title_book(book); + console.printf("%s %hd:%hd \r", book_name, chapter+1, verse+1); + delete [] book_name; + + //wait(0.025); + offset += disp_len; + } + lcd.cls(); + lcd.printf("%d", pages); + return; + */ + + Timer timer; + int old_buttons = 0; // start assuming nothing pressed + while (true) + { + // wait for something to happen + int new_buttons = rb + 2*lb; + if (new_buttons != old_buttons) + { + // simple debounce logic, wait for 25ms of steady state else start over + bool debounce = false; + int buttons = new_buttons; + timer.reset(); + timer.start(); + + led1 = lb; + led2 = rb; + + while (timer.read_ms() < 25) + { + int new_buttons = rb + 2*lb; + if (new_buttons != buttons) + { + debounce = false; + break; + } + else + debounce = true; + } + //console.printf("debounce: %d\n", new_buttons); + + if (debounce && new_buttons == 0) + { + while (true) + { + int new_buttons = rb + 2*lb; + led1 = lb; + led2 = rb; + + if (new_buttons != 0) + break; + if (timer.read_ms() > 2000) + { + mode = MODE_OFFSET; + display_verse(); + break; + } + } + buttons = new_buttons = 0; // pretend we didn't see a change yet + } + else if (debounce && new_buttons != 0) + { + timer.reset(); + timer.start(); + + emode next_mode = mode; + + int start_ms = 0; + while(true) + { + int new_buttons = rb + 2*lb; + led1 = lb; + led2 = rb; + + if (buttons != new_buttons) + { + mode = next_mode; + if (mode == MODE_OFFSET || mode == MODE_VERSE) + display_verse(); + break; + } + + { + int elapsed = timer.read_ms(); + int inc_elapsed = elapsed - start_ms; + if (elapsed >= 4000 && inc_elapsed >= 250 || mode == MODE_4xBOOK && inc_elapsed >= 25 && (start_ms == 0 || inc_elapsed >= 500) ) + { + //console.printf("4xBOOK elapsed=%d inc_elapsed=%d\n", elapsed, inc_elapsed); + if (buttons == 3) + { + } + if (buttons == 2) + { + book-=4; + if (book < 0) + book = 0; + } + if (buttons == 1) + { + book+=4; + if (book >= HolyBible.get_num_books()) + book = HolyBible.get_num_books()-1; + } + if (buttons != 3) + { + chapter = 0; + verse = 0; + offset = 0; + display_nav(); + next_mode = MODE_4xBOOK; + } + start_ms += inc_elapsed; + } + else if (elapsed >= 3000 && inc_elapsed >= 250 || mode == MODE_BOOK && inc_elapsed >= 25 && (start_ms == 0 || inc_elapsed >= 500) ) + { + //console.printf("BOOK elapsed=%d inc_elapsed=%d\n", elapsed, inc_elapsed); + if (buttons == 3) + { + } + if (buttons == 2) + { + if (chapter == 0 && --book < 0) + book = 0; + chapter = 0; + verse = 0; + offset = 0; + } + if (buttons == 1) + { + if (++book >= HolyBible.get_num_books()) + { + book = HolyBible.get_num_books()-1; + chapter = HolyBible.get_num_chapters(book)-1; + verse = HolyBible.get_num_verses(book, chapter)-1; + offset = 0; + } + else + { + chapter = 0; + verse = 0; + offset = 0; + } + } + if (buttons != 3) + { + display_nav(); + next_mode = MODE_BOOK; + } + start_ms += inc_elapsed; + } + else if (elapsed >= 2000 && inc_elapsed >= 250 || mode == MODE_CHAPTER && inc_elapsed >= 25 && (start_ms == 0 || inc_elapsed >= 500) ) + { + //console.printf("CHAPTER elapsed=%d inc_elapsed=%d\n", elapsed, inc_elapsed); + if (buttons == 3) + { + } + if (buttons == 2) + { + if (verse == 0 && --chapter < 0) + { + if (--book < 0) + { + book = 0; + chapter = 0; + } + else + chapter = HolyBible.get_num_chapters(book)-1; + } + } + if (buttons == 1) + { + if (++chapter >= HolyBible.get_num_chapters(book)) + { + if (++book >= HolyBible.get_num_books()) + { + book = HolyBible.get_num_books()-1; + chapter = HolyBible.get_num_chapters(book)-1; + } + else + chapter = 0; + } + } + if (buttons != 3) + { + verse = 0; + offset = 0; + display_nav(); + next_mode = MODE_CHAPTER; + } + start_ms += inc_elapsed; + } + else if (elapsed >= 1000 && inc_elapsed >= 250 || mode == MODE_VERSE && inc_elapsed >= 25 && (start_ms == 0 || inc_elapsed >= 500) ) + { + //console.printf("VERSE elapsed=%d inc_elapsed=%d\n", elapsed, inc_elapsed); + if (buttons == 3 && next_mode == MODE_BOOKMARK) + { + if (!HolyBible.bookmark_add(book, chapter, verse)) + HolyBible.bookmark_del(book, chapter, verse); + for (int i=0; i<3; ++i) + { + led4 = 1; + wait(0.2); + led4 = 0; + wait(0.2); + } + + next_mode = MODE_OFFSET; + } + if (buttons == 2) + { + if (offset > 0) + offset = 0; + else if (--verse < 0) + { + verse = 0; + offset = -lcd.rows()*lcd.columns(); + } + else + offset = 0; + } + if (buttons == 1) + { + char* text = HolyBible.text_verse(book, chapter, verse); + offset = strlen(text); + delete [] text; + } + display_verse(); + next_mode = MODE_VERSE; + start_ms += inc_elapsed; + } + else if (mode == MODE_OFFSET && elapsed >= 25 && elapsed < 1000 && (start_ms == 0 || inc_elapsed >= 500)) + { + //console.printf("OFFSET elapsed=%d inc_elapsed=%d\n", elapsed, inc_elapsed); + if (buttons == 3) + next_mode = MODE_BOOKMARK; + if (buttons == 2) + offset -= lcd.rows()*lcd.columns(); + if (buttons == 1) + offset += disp_len; + if (buttons != 3) + { + display_verse(); + next_mode = MODE_OFFSET; + } + start_ms += inc_elapsed; + } + else if (mode == MODE_BOOKMARK && elapsed >= 25 && (start_ms == 0 || inc_elapsed >= 500)) + { + if (buttons == 2) + { + if (HolyBible.bookmark_prev(book, chapter, verse)) + { + offset = 0; + display_nav(); + } + } + if (buttons == 1) + { + if (HolyBible.bookmark_next(book, chapter, verse)) + { + offset = 0; + display_nav(); + } + } + start_ms += inc_elapsed; + } + } + } + } + old_buttons = new_buttons; + } + } +} + +void BibleUI::indexing(int progress, void* context) +{ + //console.printf("Indexing %d%%\n", progress); + TextLCD& lcd = *(TextLCD*)context; + lcd.cls(); + lcd.printf("Indexing"); + lcd.locate(0,1); + lcd.printf("%d%%", progress); +}
diff -r 000000000000 -r b9d9145827e2 BibleUI.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BibleUI.h Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,58 @@ +/* Bible UI Class Definition - KJV Bible eBook Browser + * + * Copyright (c) 2011 David R. Van Wagner davervw@yahoo.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <mbed.h> +#include "BibleIO.h" +#include "TextLCD.h" + +class BibleUI +{ +private: + short book; + short chapter; + short verse; + short offset; + short disp_len; + BibleIO &HolyBible; + TextLCD &lcd; + DigitalIn& lb; + DigitalIn& rb; + DigitalOut led1; + DigitalOut led2; + DigitalOut led3; + DigitalOut led4; + +public: + BibleUI(BibleIO &bible, TextLCD &textlcd, DigitalIn& left, DigitalIn& right); + void start(); + static void indexing(int progress, void* context); + +private: + void display_nav(); + void display_verse(); + void show_title(); + void main(); + bool append_next_verse(char*& text, short len, short book, short chapter, short verse); + void remove_string(char* &text, char* find); + int word_wrap(char* &text); +};
diff -r 000000000000 -r b9d9145827e2 FATFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_unsupported/code/fatfilesystem/ \ No newline at end of file
diff -r 000000000000 -r b9d9145827e2 SDHCFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDHCFileSystem.lib Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/davervw/code/SDHCFileSystem/#248d03543f5f
diff -r 000000000000 -r b9d9145827e2 TextLCD.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextLCD.lib Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/davervw/code/TextLCD/#c5318c74f1a9
diff -r 000000000000 -r b9d9145827e2 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,51 @@ +/* KJV Bible eBook Browser + * + * Copyright (c) 2011 David R. Van Wagner davervw@yahoo.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <mbed.h> +#include "SDHCFileSystem.h" +#include "TextLCD.h" +#include "BibleIO.h" +#include "BibleUI.h" + +//Serial console(USBTX, USBRX); + +int main() +{ + //console.baud(921600); // mbed to pc usb serial supports: 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600 + //console.printf("Bible\n"); + + TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD8x2); // rs, e, d4, d5, d6, d7, LCD type + //lcd.printf("Bible\n"); + + SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs, mount point + BibleIO HolyBible("/sd/bible.txt", BibleUI::indexing, &lcd); + + DigitalIn left(p21); + DigitalIn right(p22); + left.mode(PullDown); + right.mode(PullDown); + + // go UI + BibleUI ui(HolyBible, lcd, left, right); // Bible, TextLCD, left button, right button + ui.start(); +}
diff -r 000000000000 -r b9d9145827e2 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sun Feb 27 18:54:37 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912