The Bachelor's thesis - Design and implementation of a portable device for creating RFID tag lists
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

546 lines
12 KiB

#include "Bakalarka.h"
#include "prescaler.h"
#include <stdio.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
//#include <avr/wdt.h>
#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 <Fat16.h>
#include <Fat16util.h>
// 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();
}