#include "Bakalarka.h" #include "prescaler.h" #include #include #include //#include #include "rotary.h" Rotary encoder = Rotary(ENC_A, ENC_B); #include "DS1302/DS1302.h" DS1302 rtc(DS_RST, DS_IO, DS_SCK); #include "SPI/SPI.h" #include "MFRC522/MFRC522.h" MFRC522 mfrc522(RFID_SS, RFID_RST); #include "PCD8544/PCD8544.h" PCD8544 lcd(LCD_DC, LCD_RST, LCD_SS); #include #include // store error strings in flash to save RAM #define error(s) error_P(PSTR(s)) SdCard card; Fat16 file; #include "SerialCommand/SerialCommand.h" SerialCommand SCmd; volatile uint32_t lastDebounce; volatile int8_t currentMenuItem = 0; volatile boolean button = false, cursor = false, reading = false; uint16_t lastRefresh; static uint8_t storageIndex EEMEM; Menu storage = {"Storage", list, 0}; Menu add_storage = {"New file", addStorage, 0}; Menu date_time = {"Date/time", frontPage, 0}; Menu exit_menu = {"Exit", frontPage, 0}; //Menu s1 = {"s1", list, 0}; //Menu s2 = {"s2", list, 0}; //Menu s3 = {"s3", list, 0}; //Menu s4 = {"s4", list, 0}; Menu mainMenu = { "", NULL, 4, { &storage, &add_storage, &date_time, &exit_menu} }; // bitmaps const byte icon_usb[20] PROGMEM = { 0x08, 0x1C, 0x3E, 0x3E, 0x1C, 0x08, 0x0C, 0x0E, 0x0A, 0x1A, 0x3B, 0x6B, 0x4B, 0xE8, 0xE8, 0xE8, 0x08, 0x3E, 0x1C, 0x08 }; const byte icon_battery_100[21] PROGMEM = { 0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xFF, 0x3C, 0x3C }; const byte icon_battery_75[21] PROGMEM = { 0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C }; const byte icon_battery_50[21] PROGMEM = { 0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C }; const byte icon_battery_25[21] PROGMEM = { 0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C }; const byte icon_arrow[6] PROGMEM = { 0x00, 0xFE, 0x7C, 0x38, 0x10, 0x00 }; void setup(void) { // There is 16HMz crystal used, halve it to reliable 8MHz@3V3 setClockPrescaler(CLOCK_PRESCALER_2); // The fastest reliable baud rate is 38400 Serial.begin(38400); lcd.begin(); lcd.clear(); // Rotary interrupt pin change enable PCICR |= (1 << PCIE1); PCMSK1 |= (1 << PCINT8) | (1 << PCINT9); // RFID host interrupt request attachInterrupt(0, RFIDInterrupt, FALLING); // Encoder button interrupt handle attachInterrupt(1, debounceInterrupt, FALLING); // Encoder button pull-up pinMode(BTN, INPUT_PULLUP); SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card if (!card.init(0, SD_SS)) error("card.init failed!"); if (!Fat16::init(&card)) error("Fat16::init failed!"); pinMode(SPKR, OUTPUT); pinMode(VBAT_ADC_EN, OUTPUT); // wdt_enable(WDTO_8S); frontPage(); SCmd.addCommand("ls", ls); SCmd.addCommand("touch", touch); SCmd.addCommand("rm", rm); // SCmd.addCommand("HELLO", SayHello); // Echos the string argument back // SCmd.addCommand("P", process_command); // Converts two arguments to integers and echos them back SCmd.addDefaultHandler(unrecognized); // Handler for command that isn't matched (says "What?") sei(); } void loop(void) { // wdt_reset(); // tone(SPKR, 1000, 100); // topBar(); SCmd.readSerial(); if (millis() - lastRefresh > 1000) { frontPage(); lastRefresh = millis(); } if (button) { button = false; navigateMenu(&mainMenu); return; // uint8_t menuLenght = sizeof(menuItems) / sizeof(menuItems[0]); // if (currentMenuItem >= menuLenght) // currentMenuItem = 0; // else if (currentMenuItem < 0) // currentMenuItem = menuLenght - 1; // lcd.setCursor(0, 0); // uint8_t i = 0, offset = 0; // if (currentMenuItem >= PCD8544_LINES) // offset = currentMenuItem - PCD8544_LINES + 1; // for (i = offset; i < menuLenght && i < PCD8544_LINES + offset; i++) { // if (i == (uint8_t)currentMenuItem) // lcd.bitmap(icon_arrow, 1, 6); // else // lcd.print(' '); // lcd.print(menuItems[i]); // lcd.clearRestOfLine(); // } } // delay(1000); // lcd.clear(); // topBar(); // delay(1000); // if (Serial.available()) { // Fat16::ls(LS_DATE | LS_SIZE); // while(Serial.available()) // Serial.read(); // } if (reading && mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) { // // Look for new cards // if ( ! mfrc522.PICC_IsNewCardPresent()) // return; // // // // Select one of the cards // if ( ! mfrc522.PICC_ReadCardSerial()) // return; tone(SPKR, 5500, 70); delay(1500); reading = false; if (file.open(eeprom_read_byte(&storageIndex), O_APPEND | O_WRITE)) { Time t = rtc.time(); char buf[21]; snprintf(buf, sizeof buf, "%04d-%02d-%02d %02d:%02d:%02d;", t.yr, t.mon, t.day, t.hr, t.min, t.sec); file.print(buf); for (byte i = 0; i < mfrc522.uid.size; i++) { file.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : ""); file.print(mfrc522.uid.uidByte[i], HEX); } file.println(";"); file.close(); } // lcd.setCursor(0, 1); // for (byte i = 0; i < mfrc522.uid.size; i++) { // lcd.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : ""); // lcd.print(mfrc522.uid.uidByte[i], HEX); // } // lcd.clearRestOfLine(); //// Dump debug info about the card. PICC_HaltA() is automatically called. // mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); } delay(100); } ISR(PCINT1_vect) { cursor = encoder.process(); if (cursor == DIR_CW) currentMenuItem++; else if (cursor == DIR_CCW) currentMenuItem--; } void debounceInterrupt(void) { if ((long) (micros() - lastDebounce) >= (long)DEBOUNCE * 1000) { button = true; lastDebounce = micros(); } } void RFIDInterrupt(void) { if (!reading) reading = true; } void error_P(const char* str) { lcd.setCursor(1, 4); lcd.print(PSTR("ERROR")); PgmPrint("error: "); SerialPrintln_P(str); if (card.errorCode) { PgmPrint("SD error: "); Serial.println(card.errorCode, HEX); } while (1) ; } void navigateMenu(Menu *menu) { if (menu->numSubmenus == 0) { /* Execute the command */ lcd.clear(); menu->command(); return; } /* This is a menu, not a command, so show the menu and get the user's choice */ displayMenu(menu); if (button) { button = false; menu = menu->submenu[currentMenuItem]; } // menu = get_user_selection(menu); navigateMenu(menu); } void displayMenu(Menu *menu) { // uint8_t menuLenght = sizeof(menuItems) / sizeof(menuItems[0]); if (currentMenuItem >= menu->numSubmenus) currentMenuItem = 0; else if (currentMenuItem < 0) currentMenuItem = menu->numSubmenus - 1; lcd.setCursor(0, 0); uint8_t i = 0, offset = 0; if (currentMenuItem >= PCD8544_LINES) offset = currentMenuItem - PCD8544_LINES + 1; for (i = offset; i < PCD8544_LINES + offset; i++) { // clear rest of the menu screen if there are less items than LCD lines if (i >= menu->numSubmenus) { lcd.print(' '); lcd.clearRestOfLine(); continue; } if (i == (uint8_t)currentMenuItem) lcd.bitmap(icon_arrow, 1, 6); else lcd.print(' '); lcd.print(menu->submenu[i]->title); lcd.clearRestOfLine(); } } void list(void) { cursor = DIR_CW; while (!button) { if (cursor) { lcd.setCursor(0, 0); dir_t d; uint16_t i = 0; boolean found = false; uint8_t offset = 0; if (currentMenuItem >= PCD8544_LINES) offset = currentMenuItem - PCD8544_LINES + 1; for (i = offset; Fat16::readDir(&d, &i, DIR_ATT_VOLUME_ID); i++) { // if we are over the display, just seek the last file index if (i >= (uint16_t)(PCD8544_LINES + offset)) continue; if (i == (uint16_t) currentMenuItem) { lcd.bitmap(icon_arrow, 1, 6); found = true; } else lcd.print(' '); lcd.print(i); lcd.print(':'); printDirName(d); } Serial.print("a: "); if (!found) { Serial.print("NOTfound, "); if (cursor == DIR_CW) { currentMenuItem++; Serial.print("++"); } else if (cursor == DIR_CCW) { currentMenuItem--; Serial.print("--"); } } else // this means that the screen will be refreshed cursor = false; if (currentMenuItem < 0) { currentMenuItem = i - 1; cursor = DIR_CCW; Serial.print("i-1"); } if ((uint16_t) currentMenuItem > i - 1) { currentMenuItem = 0; Serial.print("0"); cursor = DIR_CW; } Serial.print("; cmi: "); Serial.print(currentMenuItem); Serial.print(", li: "); Serial.print(i); Serial.print(", cursor: "); Serial.print(cursor); Serial.print(", button: "); Serial.println(button); } } Serial.println("Saved"); // save index of a file to store into to the EEPROM memory eeprom_write_byte(&storageIndex, currentMenuItem); button = false; lcd.clear(); frontPage(); } void addStorage(void) { // file.writeError = false; char buf[14]; for (unsigned short int i = 1; ; i++) { snprintf(buf, sizeof buf, "file%d.csv", i); if (file.open(buf, O_CREAT | O_WRITE | O_EXCL)) break; } file.close(); frontPage(); // snprintf(buf, sizeof buf, "FILE%d.CSV", 1); } void frontPage(void) { // lcd.clear(); lcd.setCursor(0, 0); // tone(SPKR, 5000, 50); // USB plugged in if (analogRead(STAT) < 512) { lcd.bitmap(icon_usb, 1, 20); } // battery else { digitalWrite(VBAT_ADC_EN, LOW); uint8_t vbat = (analogRead(VBAT_ADC) - 523) / 5; if (vbat < 25) lcd.bitmap(icon_battery_25, 1, 21); else if (vbat < 50) lcd.bitmap(icon_battery_50, 1, 21); else if (vbat < 75) lcd.bitmap(icon_battery_75, 1, 21); else lcd.bitmap(icon_battery_100, 1, 21); digitalWrite(VBAT_ADC_EN, HIGH); } // Get the current time and date from the chip. Time t = rtc.time(); char buf[24]; lcd.setCursor(9, 0); snprintf(buf, sizeof(buf), "%02d:%02d", t.hr, t.min); lcd.print(buf); uint16_t i = eeprom_read_byte(&storageIndex); dir_t d; if (Fat16::readDir(&d, &i, DIR_ATT_VOLUME_ID)) { lcd.setCursor(0, 2); lcd.println("Saving to: "); printDirName(d); } } void printDirName(const dir_t& dir) { uint8_t w = 0; for (uint8_t i = 0; i < 11; i++) { if (dir.name[i] == ' ') continue; if (i == 8) { lcd.print('.'); w++; } lcd.print((char) dir.name[i]); w++; } lcd.clearRestOfLine(); } // //void SayHello() { // char *arg; // arg = SCmd.next(); // Get the next argument from the SerialCommand object buffer // if (arg != NULL) // As long as it existed, take it // { // Serial.print("Hello "); // Serial.println(arg); // } else { // Serial.println("Hello, whoever you are"); // } //} // //void process_command() { // int aNumber; // char *arg; // // Serial.println("We're in process_command"); // arg = SCmd.next(); // if (arg != NULL) { // aNumber = atoi(arg); // Converts a char string to an integer // Serial.print("First argument was: "); // Serial.println(aNumber); // } else { // Serial.println("No arguments"); // } // // arg = SCmd.next(); // if (arg != NULL) { // aNumber = atol(arg); // Serial.print("Second argument was: "); // Serial.println(aNumber); // } else { // Serial.println("No second argument"); // } // //} void ls() { Fat16::ls(); } void touch() { char *arg, fileName[14]; arg = SCmd.next(); snprintf(fileName, sizeof fileName, "%s.csv", arg); PgmPrint("File '"); Serial.print(fileName); if (!file.open(fileName, O_CREAT | O_WRITE)) PgmPrintln("' could not be created."); else PgmPrintln("' was created successfully"); } void rm() { char *arg, fileName[14]; arg = SCmd.next(); snprintf(fileName, sizeof fileName, "%s.csv", arg); PgmPrint("File '"); Serial.print(fileName); if (file.open(fileName, O_WRITE) && file.remove()) PgmPrintln("' was removed successfully"); else PgmPrintln("' could not be removed."); } void mv() { char *arg; } // This gets set as the default handler, and gets called when no other command matches. void unrecognized() { PgmPrintln("Unrecognized command. Possibilities are: "); PgmPrintln("ls\t\t\t- display files"); PgmPrintln("touch FILE\t\t- create file FILE.csv"); Serial.println(); }