From 6a6d104f35b57f1dcdd966f354b2beca73310fe4 Mon Sep 17 00:00:00 2001 From: Dmitry Mikhirev Date: Thu, 23 Oct 2014 22:57:51 +0400 Subject: major code revision --- brainuino.ino | 194 +++++++++++++++++++++++++--------------------------------- font.h | 15 ++--- game.h | 24 +++++--- lcdprint.cpp | 67 +++++++++++++------- lcdprint.h | 7 ++- pinout.h | 39 ++++++------ utf8.cpp | 93 +++++++++++++++++++++++----- utf8.h | 9 ++- 8 files changed, 258 insertions(+), 190 deletions(-) diff --git a/brainuino.ino b/brainuino.ino index 6457be1..1e33602 100644 --- a/brainuino.ino +++ b/brainuino.ino @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2011-2013 Dmitry Mikhirev + Copyright (C) 2011-2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,7 +26,6 @@ LiquidCrystal lcd(LCD4, LCD6, LCD11, LCD12, LCD13, LCD14); - void setup() { lcd.begin(16, 2); @@ -41,7 +40,6 @@ void setup() preSignal = 0; } - void loop() { buttonPressed = 0; @@ -56,18 +54,17 @@ void loop() ask(); } - +// ask() - wait until start button is pressed, then run timer +// the question should be asked at this time void ask() { -// waiting while question is being asked - digitalWrite(GREENLAMP, LOW); digitalWrite(REDLAMP, LOW); #ifdef RUSSIAN - printState("Задаётся вопрос "); + printState(F("Задаётся вопрос ")); #else - printState("Asking question "); + printState(F("Asking question ")); #endif while (true) { @@ -80,16 +77,14 @@ void ask() } } - // if start button is pressed - if (digitalRead(CONTROL1) == LOW) { + if (digitalRead(CONTROL1) == LOW) { // start button is pressed if (discuss(timer1) == WRONG) { while (discuss(timer2) == WRONG) {} } return; } - // if stop button is pressed - if (digitalRead(CONTROL2) == LOW) { + if (digitalRead(CONTROL2) == LOW) { // stop button is pressed return; } @@ -97,17 +92,14 @@ void ask() } } - -char discuss(uint16_t timer) -{ +// discuss() - start timer and wait for button being pressed // here teams can discuss question or single players think themselves - - char reply = NOREPLY; +answer_t discuss(uint16_t timer) +{ + answer_t reply = NOREPLY; // is random delay needed here when playing with false starts? unsure... -// time = 0; - // reset timer or continue count if (timer > 0) { time = 0; @@ -126,9 +118,9 @@ char discuss(uint16_t timer) printGameType(); #ifdef RUSSIAN - printState("Отсчёт: "); + printState(F("Отсчёт: ")); #else - printState("Count: "); + printState(F("Count: ")); #endif while (!buttonPressed && time < (timer - preSignal) * 1000) { @@ -166,20 +158,19 @@ char discuss(uint16_t timer) return reply; } - -char answer(uint8_t num) { - -// waiting while answer is given - +// answer() - wait while the answer is given +// return answer correctness +answer_t answer(uint8_t num) +{ digitalWrite(REDLAMP, HIGH); // if (timer2 > 0) // timer = timer2; printPlayer(num); #ifdef RUSSIAN - printState("Ответ "); + printState(F("Ответ ")); #else - printState("Answer "); + printState(F("Answer ")); #endif printPreciseTime(); @@ -193,33 +184,29 @@ char answer(uint8_t num) { // if start button was pressed if (digitalRead(CONTROL1) == LOW) { -// digitalWrite(REDLAMP, LOW); buttonPressed = 0; return WRONG; } // if stop button was pressed if (digitalRead(CONTROL2) == LOW) { -// digitalWrite(REDLAMP, LOW); - buttonPressed = 0; - return CORRECT; + buttonPressed = 0; + return CORRECT; } delay(100); } } - -void falseStart(uint8_t num) { - -// if there is false start, show info about it during few time - +// falseStart() - display false start message +void falseStart(uint8_t num) +{ tone(SPEAKER, 1784, 1000); digitalWrite(REDLAMP, HIGH); #ifdef RUSSIAN - printState(" Фальстарт "); + printState(F(" Фальстарт ")); #else - printState(" False start "); + printState(F(" False start ")); #endif printPlayer(num); delay(3000); @@ -227,75 +214,66 @@ void falseStart(uint8_t num) { return; } - -void refresh() { - -// displaying current timer state - +// refresh() - display current timer state +void refresh() +{ time = millis() - startTime; printTime(); } - -void printState(char *state) { - -// displaying string in the beginning of LCD second row - +// printState() - display string in the beginning of LCD second row +void printState(const char *state) +{ lcd.setCursor(0, 1); uprint(state, &lcd); } +// printState() variant getting strings stored in flash +void printState(const __FlashStringHelper *state) +{ + lcd.setCursor(0, 1); + uprint(state, &lcd); +} -void printTime() { - -// displaying time passed after starting timer - - char timestr[33]; - char integer[10]; - char fractional[2]; +// printTime() - display time passed since timer was started +void printTime() +{ + char s[4]; - sprintf(integer, "%u", time/1000); - sprintf(fractional, "%u", time%1000/100); - sprintf(timestr, "%s.%s", integer, fractional); lcd.setCursor(8, 1); - uprint(timestr, &lcd); + itoa(time/1000, s, 10); + uprint(s, &lcd); + uprint(".", &lcd); + itoa(time%1000/100, s, 10); + uprint(s, &lcd); } - -void printPreciseTime() { - -// displaying time passed after starting timer +// printPreciseTime() - display time passed since timer was started // or that it was not started yet +void printPreciseTime() +{ + char s[5]; - char timestr[33]; - char integer[10]; - char fractional[4]; + lcd.setCursor(8, 1); - // if timer was started - if (startTime > 0) { + if (startTime > 0) { // timer was started time = millis()-startTime; - sprintf(integer, "%u", time/1000); - sprintf(fractional, "%03u", time%1000); - sprintf(timestr, "%s.%s", integer, fractional); - } - // if it was not - else - + itoa(time/1000, s, 10); + uprint(s, &lcd); + sprintf(s, ".%03u", time%1000); + uprint(s, &lcd); + } else { // timer was not started yet #ifdef RUSSIAN - sprintf(timestr, "досрочно"); + uprint(F("досрочно"), &lcd); #else - sprintf(timestr, "prematur"); + uprint(F("prematur"), &lcd); #endif - - lcd.setCursor(8, 1); - uprint(timestr, &lcd); + } } - -void readButton() { - -// scan buttons - +// readButton() - scan buttons +void readButton() +{ if (buttonPressed > 0) return; if (digitalRead(BUTTON1) == LOW) { @@ -316,11 +294,9 @@ void readButton() { } } - -void pinInit() { - -// Arduino I/O initialisation, needed on startup only - +// pinInit() - Arduino I/O initialization, needed on startup only +void pinInit() +{ digitalWrite(2, HIGH); digitalWrite(3, HIGH); digitalWrite(BUTTON1, HIGH); @@ -336,48 +312,44 @@ void pinInit() { attachInterrupt(0, readButton, FALLING); } - -void printGameType() { - -// displaying game title on LCD - +// printGameType() - display game title on LCD +void printGameType() +{ lcd.setCursor(0, 0); switch (gameType) { case BRAIN: #ifdef RUSSIAN - uprint(" Брейн-ринг ", &lcd); + uprint(F(" Брейн-ринг "), &lcd); #else - uprint(" Brain-ring ", &lcd); + uprint(F(" Brain-ring "), &lcd); #endif break; case SI: #ifdef RUSSIAN - uprint(" Своя игра ", &lcd); + uprint(F(" Своя игра "), &lcd); #else - uprint(" Jeopardy ", &lcd); + uprint(F(" Jeopardy "), &lcd); #endif break; case CHGK: #ifdef RUSSIAN - uprint("Что? Где? Когда?", &lcd); + uprint(F("Что? Где? Когда?"), &lcd); #else - uprint("What?Where?When?", &lcd); + uprint(F("What?Where?When?"), &lcd); #endif break; } } - -void printPlayer(uint8_t num) { - -// displaying number of player or team - +// printPlayer() - display number of player or team +void printPlayer(uint8_t num) +{ char printstring[65]; lcd.setCursor(0, 0); @@ -385,18 +357,18 @@ void printPlayer(uint8_t num) { case BRAIN: #ifdef RUSSIAN - sprintf(printstring, "Команда %u ", num); + sprintf(printstring, ("Команда %u "), num); #else - sprintf(printstring, "Team %u ", num); + sprintf(printstring, ("Team %u "), num); #endif break; case SI: #ifdef RUSSIAN - sprintf(printstring, "Игрок %u ", num); + sprintf(printstring, ("Игрок %u "), num); #else - sprintf(printstring, "Player %u ", num); + sprintf(printstring, ("Player %u "), num); #endif break; diff --git a/font.h b/font.h index 34271be..960424f 100644 --- a/font.h +++ b/font.h @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2012 Dmitry Mikhirev + Copyright (C) 2012, 2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,15 +23,17 @@ #include #include "pinout.h" +const char NOCHAR = 0xff; + struct charcode { - const int32_t uni; + const wchar_t uni; const char font; }; const charcode charmap[] PROGMEM = { +// NB: keep this array sorted by uni values -#ifdef RUSSIAN -// English + Russian font +#ifdef RUSSIAN // English + Russian font // tilde {0x007e, 0xe9}, @@ -75,7 +77,7 @@ const charcode charmap[] PROGMEM = { {0x03bf, 0x6f}, {0x03c0, 0xbe}, {0x03c1, 0x70}, -// cyryllic +// cyrillic {0x0401, 0xa2}, {0x0410, 0x41}, {0x0411, 0xa0}, @@ -161,8 +163,7 @@ const charcode charmap[] PROGMEM = { {0x2218, 0xef}, {0x22c5, 0xdf} -#else -// English + Japan (katakana) font +#else // English + Japan (katakana) font // latin-1 supplement {0x00a2, 0xec}, diff --git a/game.h b/game.h index 58ba479..5706461 100644 --- a/game.h +++ b/game.h @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2011 Dmitry Mikhirev + Copyright (C) 2011, 2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,17 +21,21 @@ #define game_h // game types -#define BRAIN 0 -#define SI 1 -#define CHGK 2 +enum game_t { + BRAIN , + SI, + CHGK, +}; //question status -#define CORRECT 1 -#define WRONG 0 -#define NOREPLY -1 - -uint8_t gameType; -uint8_t withFalseStart; +enum answer_t { + CORRECT = 1, + WRONG = 0, + NOREPLY = -1, +}; + +game_t gameType; +bool withFalseStart; uint8_t timer1; uint8_t timer2; //uint32_t timer; diff --git a/lcdprint.cpp b/lcdprint.cpp index af0eaeb..c53118a 100644 --- a/lcdprint.cpp +++ b/lcdprint.cpp @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2011-2012 Dmitry Mikhirev + Copyright (C) 2011, 2012, 2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,31 +21,54 @@ #include "lcdprint.h" #include "font.h" -size_t uprint(char* rawstr, LiquidCrystal *lcd) +size_t uprint(const char* rawstr, Print* out) { - int32_t ucode; - int i, j; - int numcodes = sizeof(charmap)/sizeof(charcode); utf8 str = utf8(rawstr); - char result[str.chars()]; - - for (i = 0; i < str.chars(); i++) { - ucode = str.get(); - if (ucode > 0x0000) { - if (ucode <= 0x007d) { - result[i] = ucode; - } else { - result[i] = 0xff; - for (j = 0; (j < numcodes) && (pgm_read_dword(&charmap[j].uni) <= ucode); j++) { - if (pgm_read_dword(&charmap[j].uni) == ucode) { - result[i] = pgm_read_byte(&charmap[j].font); - } - } - } + return utf8print(&str, out); +} + +size_t uprint(const __FlashStringHelper* rawstr, Print* out) +{ + utf8 str = utf8(rawstr); + return utf8print(&str, out); +} + +size_t utf8print(utf8* str, Print* out) +{ + char result[str->chars() + 1]; + wchar_t ucode; + int i; + + for (i = 0; i < (str->chars()); i++) { + ucode = str->get(); + if (ucode != 0x0000) { + result[i] = codeOf(ucode); } else { break; } } - result[i] = 0; - return lcd->print(result); + result[i] = '\0'; + return out->print(result); +} + +char codeOf(wchar_t ucode) +{ + if (ucode > 0x0000 && ucode <= 0x007d) // ASCII symbol + return char(ucode); + + int low, high, mid; + + low = 0; + high = sizeof(charmap)/sizeof(charcode) - 1; + while (low <= high) { + mid = (low + high) >> 1; + wchar_t u = pgm_read_word(&charmap[mid].uni); + if (wchar_t(u) > ucode) + high = mid - 1; + else if (u < ucode) + low = mid + 1; + else + return pgm_read_byte(&charmap[mid].font); + } + return NOCHAR; } diff --git a/lcdprint.h b/lcdprint.h index bcc95f6..63fc663 100644 --- a/lcdprint.h +++ b/lcdprint.h @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2011-2012 Dmitry Mikhirev + Copyright (C) 2011, 2012, 2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +22,9 @@ #include "utf8.h" -size_t uprint (char*, LiquidCrystal*); +size_t uprint (const char*, Print*); +size_t uprint(const __FlashStringHelper*, Print*); +size_t utf8print(utf8*, Print*); +char codeOf(wchar_t); #endif diff --git a/pinout.h b/pinout.h index 02f2398..670dba5 100644 --- a/pinout.h +++ b/pinout.h @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2011 Dmitry Mikhirev + Copyright (C) 2011, 2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,13 +28,15 @@ digital pins 2 and 3 must be used for interrupts */ // undefine the following if your LCD does not support Russian font #define RUSSIAN +enum { + // digital pins connected to LCD display -#define LCD4 7 -#define LCD6 8 -#define LCD11 9 -#define LCD12 10 -#define LCD13 11 -#define LCD14 12 + LCD4 = 7, + LCD6 = 8, + LCD11 = 9, + LCD12 = 10, + LCD13 = 11, + LCD14 = 12, /* pins 1 and 5 of LCD must be connected to GND, pin 2 - to +5V pin 3 - to 10K potentiometer @@ -43,29 +45,30 @@ and GND respectively pins 7-10 - no connection */ // digital pin connected to speaker -#define SPEAKER 5 + SPEAKER = 5, // digital pin connected to LED lamp -#define GREENLAMP 13 -#define REDLAMP 6 + GREENLAMP = 13, + REDLAMP = 6, // digital pins connected to players' buttons -#define BUTTON1 14 -#define BUTTON2 15 -#define BUTTON3 16 -#define BUTTON4 17 + BUTTON1 = 14, + BUTTON2 = 15, + BUTTON3 = 16, + BUTTON4 = 17, // digital pins connected to control buttons // start/OK button -#define CONTROL1 18 + CONTROL1 = 18, // break/cansel button -#define CONTROL2 19 + CONTROL2 = 19, // digital pin connected to encoder button -#define ENCPUSH 20 + ENCPUSH = 20, // digital pin connected to encoder 'B' output -#define ENCODERB 4 + ENCODERB = 4, // encoder 'A' output must be connected to Arduino D3 +}; #endif diff --git a/utf8.cpp b/utf8.cpp index d4e605e..e4a295e 100644 --- a/utf8.cpp +++ b/utf8.cpp @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2012, 2013 Dmitry Mikhirev + Copyright (C) 2012-2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,15 +15,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -*/ + */ #include "utf8.h" #include -utf8::utf8 (char* input) +utf8::utf8 (const char* input) { _bytes = strlen(input); _string = strdup(input); + _string_p = NULL; _chars = 0; for (_index = 0; _index < _bytes; _index++) { if ((_string[_index] & 0x80) == 0x00) { @@ -42,25 +43,83 @@ utf8::utf8 (char* input) _index = 0; } +utf8::utf8 (const __FlashStringHelper* input) +{ + _string_p = (char*) input; + _string = NULL; + _bytes = strlen_P(_string_p); + _chars = 0; + for (_index = 0; _index < _bytes; _index++) { + if ((pgm_read_byte(_string_p + _index) & 0x80) == 0x00) { + _chars++; + } else if ((pgm_read_byte(_string_p + _index) & 0x20) == 0x00) { + _chars++; + _index ++; + } else if ((pgm_read_byte(_string_p + _index) & 0x10) == 0x00) { + _chars++; + _index += 2; + } else if ((pgm_read_byte(_string_p + _index) & 0x08) == 0x00) { + _chars++; + _index += 3; + } + } + _index = 0; +} + utf8::~utf8 () { - free(_string); + if (_string != NULL) + free(_string); } -int32_t utf8::get() +wchar_t utf8::get() { - int32_t code; - if ((_string[_index] & 0x80) == 0) { - code = int32_t(_string[_index]); - _index++; - } else if ((_string[_index] & 0x20) == 0) { - code = int32_t(_string[_index] & 0x1f) << 6 | int32_t(_string[_index+1] & 0x3f); - _index += 2; - } else if ((_string[_index] & 0x10) == 0) { - code = int32_t(_string[_index] & 0xf) << 12 | int32_t(_string[_index+1] & 0x3f) << 6 | int32_t(_string[_index+2] & 0x3f); - _index += 3; - } else if ((_string[_index] & 0x8) == 0) { - code = int32_t(_string[_index] & 0x7) << 18 | int32_t(_string[_index+1] & 0x3f) << 12 | int32_t(_string[_index+2] & 0x3f) << 6 | int32_t(_string[_index+3] & 0x3f); + wchar_t code; + if (_string_p == NULL) { // string in RAM + if ((_string[_index] & 0x80) == 0) { + code = wchar_t(_string[_index]); + _index++; + } else if ((_string[_index] & 0x20) == 0) { + code = wchar_t(_string[_index] & 0x1f) << 6 | + wchar_t(_string[_index+1] & 0x3f); + _index += 2; + } else if ((_string[_index] & 0x10) == 0) { + code = wchar_t(_string[_index] & 0x0f) << 12 | + wchar_t(_string[_index+1] & 0x3f) << 6 | + wchar_t(_string[_index+2] & 0x3f); + _index += 3; + } else if (((_string[_index] & 0x8) == 0) && (sizeof(code) >= 3)) { + code = wchar_t(_string[_index] & 0x07) << 18 | + wchar_t(_string[_index+1] & 0x3f) << 12 | + wchar_t(_string[_index+2] & 0x3f) << 6 | + wchar_t(_string[_index+3] & 0x3f); + } else { + code = '?'; + _index++; + } + } else { // string in flash + byte first = pgm_read_byte(_string_p + _index); + if ((first & 0x80) == 0) { + code = wchar_t(first); + _index++; + } else if ((first & 0x20) == 0) { + code = wchar_t(first & 0x1f) << 6 | + wchar_t(pgm_read_byte(_string_p + _index + 1) & 0x3f); + _index += 2; + } else if ((first & 0x10) == 0) { + code = wchar_t(first & 0x0f) << 12 | + wchar_t(pgm_read_byte(_string_p + _index + 1) & 0x3f) << 6 | + wchar_t(pgm_read_byte(_string_p + _index + 2) & 0x3f); + _index += 3; + } else if (((first & 0x8) == 0) && (sizeof(code) >= 3)) { + code = wchar_t(first & 0x07) << 18 | + wchar_t(pgm_read_byte(_string_p + _index + 1) & 0x3f) << 12 | + wchar_t(pgm_read_byte(_string_p + _index + 2) & 0x3f) << 6 | + wchar_t(pgm_read_byte(_string_p + _index + 3) & 0x3f); + } else { + code = '?'; + _index++; + } } if (_index >= _bytes) _index = 0; return code; diff --git a/utf8.h b/utf8.h index 9bab45b..213042d 100644 --- a/utf8.h +++ b/utf8.h @@ -1,7 +1,7 @@ /* Brainuino Aleph - Copyright (C) 2012, 2013 Dmitry Mikhirev + Copyright (C) 2012-2014 Dmitry Mikhirev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,13 +20,15 @@ #ifndef utf8_h #define utf8_h +#include #include "Arduino.h" class utf8 { public: - utf8(char* string); + utf8(const char* string); + utf8 (const __FlashStringHelper* flashString); ~utf8(void); - int32_t get(); + wchar_t get(); uint16_t chars(); uint16_t bytes(); @@ -35,6 +37,7 @@ class utf8 { uint16_t _chars; uint16_t _bytes; char* _string; + char* _string_p; }; #endif -- cgit v1.2.1