* Project Real-time Bus Arrival Alarm * Parts - WIZwiki-W7500 Platform - Seeed Grove OLED display - Seeed Grove 4-digit display - Seeed Grove Buzzer * Detailed description Real Time Bus Information will show you when your bus is due to arrive at your bus stop. * Target Bus Information System - GyeongGi Bus Information, Korea (www.gbis.go.kr)
Dependencies: WIZnetInterface mbed DigitDisplay HTTPClient NTPClient SeeedGrayOLED
main.cpp
- Committer:
- hkjung
- Date:
- 2015-08-26
- Revision:
- 0:879add9a219d
File content as of revision 0:879add9a219d:
#include "mbed.h" #include "EthernetInterface.h" #include "HTTPClient.h" // HTTP Client library #include "NTPClient.h" // NTP Client library (Network Time Protocol) #include "DigitDisplay.h" // Seeed Grove: 4-digit Display #include "SeeedGrayOLED.h" // Seeed Grove: OLED Display 0.96" 96x96 Serial pc(USBTX, USBRX); PwmOut Buzzer(D6); DigitDisplay display(D0, D1); // 4-Digit Display connected to UART Grove connector SeeedGrayOLED SeeedGrayOled(D14, D15); DigitalOut myled(LED1); Ticker tick; //////////////////////////////////////////////////////////////// // Defines //////////////////////////////////////////////////////////////// /* User adjustable defines */ //////////////////////////////////////////////////////////////// /* Debug Message Enable */ #define _DEBUG_BUS_ARRIVAL_ALARM_ 0 /* Number of Displayed Bus Info */ #define MAX_BUS_INFO 3 // The maximum bus information request can be up to Three (3) /* Display mode */ #define DISPLAY_MODE_CHANGE_CNT_SEC 10 // The OLED display holding time(sec) for each bus information displayed #define BUS_NUM_BLINK_ENABLE 1 // blink the 4-digit display when displayed bus numbers /* Alarm Sound Enabled and Time */ #define ALARM_SOUND_ENABLE 1 #define SOUND_START_HOUR 6 #define SOUND_START_MIN 15 #define SOUND_END_HOUR 07 #define SOUND_END_MIN 00 /* HTTP client */ //#define MAX_HTTPC_RETRY_CNT 2 // not used //////////////////////////////////////////////////////////////// /* Buzzer */ #define VOLUME 0.2 // 0.02 #define BPM 100.0 /* Display mode define */ #define DISPLAY_TIME_MODE 0 // do not change! /* Bus and Station (Busstop) info for GBIS openAPI */ #define DEFAULT_STATION_NUM 38270 //(Gwangju -> Seoul) #define DEFAULT_STATION_ID 234000302 // for test //#define DEFAULT_STATION_NUM 38269 //(Seoul -> Gwangju) //#define DEFAULT_STATION_ID 234000294 typedef struct { uint8_t * busNum; // Bus number, This value should be input at initialize stage uint16_t stationNum; // Station number, notused, This value should be input at initialize stage uint32_t routeId; // Bus route id for openAPI querying (openapi.gbis.go.kr) // This value should be input at initialize stage uint32_t stationId; // Bus station id for openAPI querying (openapi.gbis.go.kr) // This value should be input at initialize stage uint8_t resultCode; // 0; success, 4; bus info none uint8_t predictTime1; // 1st bus arrival predict time ('1' means the bus gone) uint8_t predictTime2; // 2st bus arrival predict time ('1' means the none of next bus info) uint8_t remainSeatCnt1; // 1st bus remain seat count uint8_t remainSeatCnt2; // 2st bus remain seat count }BUSINFO; //////////////////////////////////////////////////////////////// // Function declaration //////////////////////////////////////////////////////////////// void BuzzerSound(void); // Buzzer void Display_BusNumber(uint8_t * busnum); // 4-digit display uint8_t get_businfo(BUSINFO * bus); // Get Bus information (HTTP client) // OLED display void Draw_OLED_init(void); void Draw_OLED_default(void); void Draw_OLED_busInfo(uint8_t * busnum, uint8_t seats); void Draw_OLED_arrivalMin(uint8_t min); void Draw_OLED_nextMin(uint8_t nextmin); void Draw_OLED_busList(void); // for ticker void beat(); //////////////////////////////////////////////////////////////// // Global variable declaration //////////////////////////////////////////////////////////////// BUSINFO businfo[MAX_BUS_INFO]; uint8_t flag_display_mode[MAX_BUS_INFO+1] = {0, }; uint8_t display_mode = 0; uint8_t buzzer_sound_enable = 0; time_t beat_cTime; struct tm *beat_localtime; uint8_t mac[6] = {0x00,0x08,0xDC,0x01,0x02,0x03}; // MAC address, It must be modified as users MAC address int main() { pc.baud(115200); EthernetInterface ethernet; uint8_t i; //////////////////////////////////////////////////////////////// // Realtime Bus Information: Initialization //////////////////////////////////////////////////////////////// /* Bus number and route ID */ uint8_t busnum_1117[4] = {1, 1, 1, 7}; uint32_t busnum_1117_routeId = 234000069; uint8_t busnum_1113[4] = {1, 1, 1, 3}; uint32_t busnum_1113_routeId = 234000042; uint8_t busnum_1005[4] = {1, 0, 0, 5}; uint32_t busnum_1005_routeId = 234000065; // Bus info structure initialize businfo[0].busNum = busnum_1117; businfo[0].stationNum = DEFAULT_STATION_NUM; businfo[0].routeId = busnum_1117_routeId; businfo[0].stationId = DEFAULT_STATION_ID; businfo[1].busNum = busnum_1113; businfo[1].stationNum = DEFAULT_STATION_NUM; businfo[1].routeId = busnum_1113_routeId; businfo[1].stationId = DEFAULT_STATION_ID; businfo[2].busNum = busnum_1005; businfo[2].stationNum = DEFAULT_STATION_NUM; businfo[2].routeId = busnum_1005_routeId; businfo[2].stationId = DEFAULT_STATION_ID; // OLED display initialize SeeedGrayOled.init(); // Initialize SEEED OLED display SeeedGrayOled.clearDisplay(); // Clear Display SeeedGrayOled.setNormalDisplay(); // Set Normal Display Mode // OLED display initial draw Draw_OLED_default(); //Draw_OLED_init(); printf("\r\n==========================================\r\n"); printf(" Real-time Bus Arrival Alarm\r\n"); printf("==========================================\r\n"); printf(" Buzzer Sound START Time: %d:%.2d\r\n", SOUND_START_HOUR, SOUND_START_MIN); printf(" Buzzer Sound END Time : %d:%.2d\r\n", SOUND_END_HOUR, SOUND_END_MIN); printf("==========================================\r\n"); // Ethernet initialize int ret = ethernet.init(mac); printf("\r\nWIZwiki-W7500 Networking Started\r\n"); wait(1); // 1 second for stable state if (!ret) { printf("Initialized, MAC: %s\r\n", ethernet.getMACAddress()); ret = ethernet.connect(); if (!ret) { printf("IP: %s, MASK: %s, GW: %s\r\n", ethernet.getIPAddress(), ethernet.getNetworkMask(), ethernet.getGateway()); } else { printf("Error ethernet.connect() - ret = %d\r\n", ret); exit(0); } } else { printf("Error ethernet.init() - ret = %d\r\n", ret); exit(0); } // NTP initialize NTPClient ntp; printf("\r\nTrying to update time...\r\n"); if (ntp.setTime("211.233.40.78") == 0) { printf("Set time successfully\r\n"); time_t ctTime; ctTime = time(NULL); ctTime += 32400; // GMT+9/Seoul printf("Time is set to (GMT+9): %s\r\n", ctime(&ctTime)); } else { printf("Error\r\n"); } // 4-Digit display initialize display.write(0, 0); display.write(1, 0); display.write(2, 0); display.write(3, 0); display.setColon(true); tick.attach(&beat, 0.5); // Initial flag setting for get the bus info flag_display_mode[DISPLAY_TIME_MODE] = 1; printf(">> Initialize Done\r\n"); // Main routine while(1) { if(display_mode == DISPLAY_TIME_MODE) // Display: Time mode { if(flag_display_mode[display_mode]) { Draw_OLED_default(); flag_display_mode[display_mode] = 0; // Get the buses info: Bus arrival time preparation (beforehand) for(i = 0; i < MAX_BUS_INFO; i++) { get_businfo(&businfo[i]); #if (_DEBUG_BUS_ARRIVAL_ALARM_) //Debug message printf("Businfo #%d\r\n", i); printf("bus.resultCode = %c\r\n", businfo[i].resultCode); printf("1st Bus arrive after %d min\r\n", businfo[i].predictTime1); printf("1st Bus remain seats %d\r\n", businfo[i].remainSeatCnt1); printf("2nd Bus arrive after %d min\r\n", businfo[i].predictTime2); printf("2nd Bus remain seats %d\r\n\r\n", businfo[i].remainSeatCnt2); #endif } } } else // Display: Bus info mode { i = display_mode - 1; if(flag_display_mode[display_mode]) { Draw_OLED_busInfo(businfo[i].busNum, businfo[i].remainSeatCnt1); Draw_OLED_arrivalMin(businfo[i].predictTime1); if(businfo[i].predictTime2 == 1) { Draw_OLED_nextMin(0); } else { Draw_OLED_nextMin(businfo[i].predictTime2); } // Buzzer sound! // Each case means the displayed time(Remaining time until the bus arrival, minute) to ringing the buzzer switch(businfo[i].predictTime1) { case 5: case 6: case 7: case 8: case 9: case 10: BuzzerSound(); break; default: break; } flag_display_mode[display_mode] = 0; } } } } //////////////////////////////////////////////////////////////// // Member function of Ticker interface (attaching to a ticker) //////////////////////////////////////////////////////////////// void beat() { static uint8_t colon = 0; static uint8_t myled_blink = 1; static uint8_t display_mode_change_cnt = 0; // initial count value; 5 sec reduced // Get current local time info beat_cTime = time(NULL); beat_cTime += 32400; // GMT+9/Seoul beat_localtime = localtime(&beat_cTime); // Display Mode change handler (Time / Bus mode) display_mode_change_cnt++; // ++ every 0.5sec if((display_mode_change_cnt/2) >= DISPLAY_MODE_CHANGE_CNT_SEC) { display_mode++; if(display_mode > MAX_BUS_INFO) { display_mode = DISPLAY_TIME_MODE; // 0 } // Skip: (resultCode == 4) means 'Bus arrival info does not appear' while((display_mode != DISPLAY_TIME_MODE) && (businfo[display_mode-1].resultCode == 4)) { display_mode++; if(display_mode > MAX_BUS_INFO) { display_mode = DISPLAY_TIME_MODE; // 0 } } flag_display_mode[display_mode] = 1; display_mode_change_cnt = 0; } // 4-Digit Display handler if(display_mode == DISPLAY_TIME_MODE) // Time mode { display.on(); display.setColon(colon); if (colon) { display.write(0, beat_localtime->tm_hour / 10); display.write(1, beat_localtime->tm_hour % 10); display.write(2, beat_localtime->tm_min / 10); display.write(3, beat_localtime->tm_min % 10); } //colon = 1 - colon; // moved below } else // Bus info mode { #if (BUS_NUM_BLINK_ENABLE) if(colon) { Display_BusNumber(businfo[display_mode-1].busNum); } else { Display_BusNumber(NULL); } #else Display_BusNumber(businfo[display_mode-1].busNum); #endif } // Buzzer sound enable handler buzzer_sound_enable = 0; #if (ALARM_SOUND_ENABLE) if(((beat_localtime->tm_hour == SOUND_START_HOUR) && (beat_localtime->tm_min >= SOUND_START_MIN)) || (beat_localtime->tm_hour > SOUND_START_HOUR)) { if((beat_localtime->tm_hour < SOUND_END_HOUR) || ((beat_localtime->tm_hour == SOUND_END_HOUR) && (beat_localtime->tm_min < SOUND_END_MIN))) { buzzer_sound_enable = 1; } } #endif // LED blink; Device working indicator myled_blink ^= 1; myled = myled_blink ; // Invert every 0.5sec colon = 1 - colon; } //////////////////////////////////////////////////////////////// // Get Bus Information (HTTP client) Functions //////////////////////////////////////////////////////////////// uint8_t get_businfo(BUSINFO * bus) { uint8_t ret = 0; char str[2048] = {0, }; char get_req[512] = {0, }; char predictTime1[3], predictTime2[3]; char remainSeatCnt1[3], remainSeatCnt2[3]; char *CurrentAddr = 0; //uint8_t retry_cnt = 0; // Unimplemented, MAX_HTTPC_RETRY_CNT HTTPClient httpc; sprintf(get_req, "http://openapi.gbis.go.kr/ws/rest/busarrivalservice?serviceKey=test&routeId=%ld&stationId=%ld", bus->routeId, bus->stationId); httpc.get(get_req, str, sizeof(str), 1000); CurrentAddr = strstr(str,"<resultCode>"); bus->resultCode = *(CurrentAddr+12); if(bus->resultCode == '0') { CurrentAddr = strstr(str,"<predictTime1>"); if((*(CurrentAddr+15)) == '<') { predictTime1[0] = *(CurrentAddr+14); predictTime1[1] = 0; predictTime1[2] = 0; } else { predictTime1[0] = *(CurrentAddr+14); predictTime1[1] = *(CurrentAddr+15); predictTime1[2] = 0; } bus->predictTime1 = (uint8_t)atoi(predictTime1); CurrentAddr = strstr(str,"<predictTime2>"); if((*(CurrentAddr+15)) == '<') { predictTime2[0] = *(CurrentAddr+14); predictTime2[1] = 0; predictTime2[2] = 0; } else { predictTime2[0] = *(CurrentAddr+14); predictTime2[1] = *(CurrentAddr+15); predictTime2[2] = 0; } bus->predictTime2 = (uint8_t)atoi(predictTime2); CurrentAddr = strstr(str,"<remainSeatCnt1>"); if((*(CurrentAddr+17)) == '<') { remainSeatCnt1[0] = *(CurrentAddr+16); remainSeatCnt1[1] = 0; remainSeatCnt1[2] = 0; } else { remainSeatCnt1[0] = *(CurrentAddr+16); remainSeatCnt1[1] = *(CurrentAddr+17); remainSeatCnt1[2] = 0; } bus->remainSeatCnt1 = (uint8_t)atoi(remainSeatCnt1); if(bus->predictTime2 > 1) // (predictTime2 == 1) => The next bus information is not confirmed. { CurrentAddr = strstr(str,"<remainSeatCnt2>"); if((*(CurrentAddr+17)) == '<') { remainSeatCnt2[0] = *(CurrentAddr+16); remainSeatCnt2[1] = 0; remainSeatCnt2[2] = 0; } else { remainSeatCnt2[0] = *(CurrentAddr+16); remainSeatCnt2[1] = *(CurrentAddr+17); remainSeatCnt2[2] = 0; } bus->remainSeatCnt2 = (uint8_t)atoi(remainSeatCnt2); } ret = 1; } return ret; } //////////////////////////////////////////////////////////////// // Piezo Buzzer Functions //////////////////////////////////////////////////////////////// void playNote(float frequency, float duration, float volume) { Buzzer.period(1.0/(double)frequency); Buzzer = ((double)volume/2.0); wait(duration); Buzzer = 0.0; } void BuzzerSound(void) { // Calculate duration of a quarter note from bpm float beat_duration = 60.0 / BPM; if(buzzer_sound_enable) { //playNote(329.628, (0.75 * (double)beat_duration), VOLUME); //playNote(261.626, (0.75 * (double)beat_duration), VOLUME); playNote(529.628, (0.50 * (double)beat_duration), VOLUME); playNote(301.626, (0.50 * (double)beat_duration), VOLUME); } } //////////////////////////////////////////////////////////////// // 4-Digit Display Functions //////////////////////////////////////////////////////////////// void Display_BusNumber(uint8_t * busnum) { display.setColon(false); if(busnum != NULL) { display.on(); display.write(0, busnum[0]); display.write(1, busnum[1]); display.write(2, busnum[2]); display.write(3, busnum[3]); } else { display.off(); } } //////////////////////////////////////////////////////////////// // OLED Display Functions //////////////////////////////////////////////////////////////// void Draw_OLED_init(void) { uint8_t empty_busnum[4] = {0, 0, 0, 0}; Draw_OLED_busInfo(empty_busnum, 0); Draw_OLED_nextMin(0); } void Draw_OLED_default(void) { SeeedGrayOled.setTextXY(0, 1); SeeedGrayOled.putString("Bus NearBy "); SeeedGrayOled.setTextXY(1, 1); SeeedGrayOled.putString("========== "); Draw_OLED_arrivalMin('b'); SeeedGrayOled.setTextXY(11, 0); SeeedGrayOled.putString("WIZnet::Eric"); } void Draw_OLED_busList(void) { uint8_t i; char buf[15] = {0, }; SeeedGrayOled.setTextXY(0, 1); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(1, 1); SeeedGrayOled.putString("Bus List:"); Draw_OLED_arrivalMin('t'); for(i = 0; i < MAX_BUS_INFO; i++) { SeeedGrayOled.setTextXY(3+i, 2); sprintf(buf, "- %.1d%.1d%.1d%.1d", businfo[i].busNum[0], businfo[i].busNum[1], businfo[i].busNum[2], businfo[i].busNum[3]); SeeedGrayOled.putString(buf); } SeeedGrayOled.setTextXY(11, 1); SeeedGrayOled.putString(" "); } void Draw_OLED_busInfo(uint8_t * busnum, uint8_t seats) { char buf[15] = {0, }; sprintf(buf, "Bus %.1d%.1d%.1d%.1d ", busnum[0], busnum[1], busnum[2], busnum[3]); SeeedGrayOled.setTextXY(0, 1); SeeedGrayOled.putString(buf); sprintf(buf, "Seats %.2d ", seats); SeeedGrayOled.setTextXY(1, 1); SeeedGrayOled.putString(buf); } void Draw_OLED_nextMin(uint8_t nextmin) { char buf[15] = {0, }; if(nextmin == 0) { sprintf(buf, "Next: -- min"); } else { sprintf(buf, "Next: %.2d min", nextmin); } SeeedGrayOled.setTextXY(11, 0); SeeedGrayOled.putString(buf); } void Draw_OLED_arrivalMin(uint8_t min) { switch(min) { case 't': SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" "); break; case 'b': SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~~~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~~~~~~~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~ ~~ "); break; case 0: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~ ~ ~ ~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ ~~~~ "); break; case 1: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" Gone! "); break; case 2: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ "); break; case 3: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ "); break; case 4: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~ "); break; case 5: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ "); break; case 6: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ "); break; case 7: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~ "); break; case 8: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ "); break; case 9: SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ "); break; case 10: case 11: // 10 SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~ ~~~~ "); break; case 12: case 13: case 14: // 12 SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~ ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~ ~~~~ "); break; case 15: case 16: // 15 SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~ ~~~~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~ ~~~~ "); break; case 17: case 18: // 17 case 19: // 17 SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~ ~ "); break; case 20: // 20 SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ ~ ~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ ~~~~ "); break; default: // 20 SeeedGrayOled.setTextXY(3, 0); SeeedGrayOled.putString(" ~~~~ ~~~~ "); SeeedGrayOled.setTextXY(4, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(5, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(6, 0); SeeedGrayOled.putString(" ~~~~ ~ ~ "); SeeedGrayOled.setTextXY(7, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(8, 0); SeeedGrayOled.putString(" ~ ~ ~ "); SeeedGrayOled.setTextXY(9, 0); SeeedGrayOled.putString(" ~~~~ ~~~~ ~"); break; } }