working version of song control with initialization from sd card

Dependencies:   MFRC522 NRF2401P SDFileSystem SPI_TFT_ILI9341 TFT_fonts mbed

Fork of Song_Control by Malcolm McCulloch

Files at this revision

API Documentation at this revision

Comitter:
dxyang
Date:
Sun Feb 21 00:04:16 2016 +0000
Parent:
2:d1eae91343a9
Child:
5:88c516cf34e6
Commit message:
integration of main hub progress (battery pick up and drop off, RFIDs and display, reading and saving users to SD card, logging all actions to SD cards)

Changed in this revision

MFRC522.lib Show annotated file Show diff for this revision Revisions of this file
SPI_TFT_ILI9341.lib Show annotated file Show diff for this revision Revisions of this file
TFT_fonts.lib Show annotated file Show diff for this revision Revisions of this file
hub.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MFRC522.lib	Sun Feb 21 00:04:16 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/AtomX/code/MFRC522/#63d729186747
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPI_TFT_ILI9341.lib	Sun Feb 21 00:04:16 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/dreschpe/code/SPI_TFT_ILI9341/#b2b3e5430f81
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TFT_fonts.lib	Sun Feb 21 00:04:16 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/dreschpe/code/TFT_fonts/#76774250fcec
--- a/hub.cpp	Thu Jan 28 14:38:45 2016 +0000
+++ b/hub.cpp	Sun Feb 21 00:04:16 2016 +0000
@@ -5,31 +5,183 @@
 #include "mbed.h"
 #include "utils.h"
 #include "NRF2401P.h"
+
+#include "MFRC522.h"
+#include "SPI_TFT_ILI9341.h"
+#include "Arial24x23.h"
+#include "SDFileSystem.h"
+
 #define debug 
 
-// Flags
-unsigned char flag1sH = 0;
-
-// Variables
-Ticker tick1sHub;
-float currentMaxH = 1.5; // Maximum current that each cube can consume.
-
+/*************************************************************************************************/
+/* Global variables */
+/*************************************************************************************************/
 // tx nRF2401
 extern char txBuff[];
 extern NRF2401P nrf1;
 extern int channel;
 long long addrLcker=0xBBBBBBBBBB;
-// -----------------------------------------------------------------------------
-// Interupt routines
-// -----------------------------------------------------------------------------
+
+// MFRC522 RfChip (SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS, MF_RESET); 
+MFRC522 BatteryRfChipH (PTD2, PTD3, PTD1, PTE25, PTB3);
+MFRC522 PoshoRfChipH (PTD2, PTD3, PTD1, PTB10, PTB11);
+MFRC522 IncubatorRfChipH (PTD2, PTD3, PTD1, PTC11, PTC10);
+
+// tickers and flags for checking rfid statuses
+Ticker tickBatteryRfidH;
+Ticker tickPoshoRfidH;
+Ticker tickIncubatorRfidH;
+char flagBatteryRfidH = 0;
+char flagPoshoRfidH = 0;
+char flagIncubatorRfidH = 0;
+
+//SPI_TFT_ILI9341(PinName mosi, PinName miso, PinName sclk, 
+//                PinName cs, PinName reset, PinName dc, const char* name ="TFT");
+SPI_TFT_ILI9341 TFT_H(PTD2, PTD3, PTD1, PTB2, PTB20, PTB18,"TFT");
+
+// button interrupt signals and respective flags
+InterruptIn buttonOneH(PTC3);
+InterruptIn buttonTwoH(PTC2);
+InterruptIn buttonThreeH(PTA2);
+InterruptIn buttonFourH(PTB23);
+char flagButtonOneH = 0;
+char flagButtonTwoH = 0;
+char flagButtonThreeH = 0;
+char flagButtonFourH = 0;
+
+// ticker that causes time to be displayed
+Ticker tickTimeCheckH;
+char flagTimeCheckH = 0; 
+
+// ticker that causes an interrupt to update the user table every 1/2 an hour
+Ticker tickerUpdateUserTableH;
+char flagUpdateUserTableH = 0; 
+
+// ticker that goes off every second
+unsigned char flag1sH = 0;
+Ticker tick1sHub;
+
+// Maximum current that each cube can consume.
+float currentMaxH = 1.5; 
+
+// A hubUser can be assigned any of four lockers, each with a unique locker address
+enum LockerAddressH {
+    lockerUnassigned,
+    lockerOne,
+    lockerTwo,
+    lockerThree,
+    lockerFour
+};
+
+// The hub display screen can involve multiple stages
+enum HubScreenStageH {
+    initialScanRfid,
+    waitForRfid,
+    batterySelectAction,
+    batterySelectNumberForPickup,
+    batterySelectNumberForDropoff
+};
+enum HubScreenStageH currentScreenH = initialScanRfid;
+
+// hubUser struct containing the users uid, rfid, number of batteries, current account credit,
+// an enum corresponding to a locker channel address, and pod ID within a locker
+struct hubUserH {
+    uint32_t uid;
+    uint32_t rfid;
+    int32_t accountCredit;
+    enum LockerAddressH lockerID;
+    int32_t podID;
+    int32_t batteriesOut;
+    int32_t batterySubscription;
+};
+
+// community ID should be defined somewhere and accessible globally
+uint32_t communityID_H = 1;
+
+// array to store all users and index of end of the current list
+hubUserH allUsersH[256];
+uint8_t userCountH = 0;
+uint8_t currentUserH;
+
+// Data is being logged and collected
+// these actions depend on a known user using the system
+enum HubActionForLoggingH {
+    hubAction_RfidScanned,
+    hubAction_Exit,
+    hubAction_OneBatteryDropped,
+    hubAction_TwoBatteryDropped,
+    hubAction_ThreeBatteryDropped,
+    hubAction_OneBatteryPicked,
+    hubAction_TwoBatteryPicked,
+    hubAction_ThreeBatteryPicked
+};
+
+/*************************************************************************************************/
+/* Set a flag when an interrupt is detected */
+/*************************************************************************************************/
+/**
+ *  Time check interrupt
+ */
+void interruptTimeCheckH()
+{ flagTimeCheckH = 1; }
+
+/**
+ *  Update user table interrupt
+ */
+void interruptUpdateUserTableH()
+{ flagUpdateUserTableH = 1; }
+
+/**
+ *  Battery RFID reader interrupt 
+ */
+void interruptBatteryRfidH()
+{ flagBatteryRfidH = 1; }
+
+/**
+ *  Posho RFID reader interrupt 
+ */
+void interruptPoshoRfidH()
+{ flagPoshoRfidH = 1; }
+
+/**
+ *  Incubator RFID reader interrupt 
+ */
+void interruptIncubatorRfidH()
+{ flagIncubatorRfidH = 1; }
+
+/**
+ *  buttone one interrupt 
+ */
+void interruptButtonOneH()
+{ flagButtonOneH = 1; }
+
+/**
+ *  buttone two interrupt 
+ */
+void interruptButtonTwoH()
+{ flagButtonTwoH = 1; }
+
+/**
+ *  buttone three interrupt 
+ */
+void interruptButtonThreeH()
+{ flagButtonThreeH = 1; }
+
+/**
+ *  buttone four interrupt 
+ */
+void interruptButtonFourH()
+{ flagButtonFourH = 1; }
+
 /**
 * Fast interrupt routine for every 1 second
 */
 void int1sH()
-{
-    flag1sH=1;
-    // add only fast code.
-}
+{ flag1sH=1; }
+
+/*************************************************************************************************/
+/* Transfer Info */
+/*************************************************************************************************/
 /**
 * Sends a time stamp
 */
@@ -66,6 +218,7 @@
 */
 void do1sH()
 {
+    flag1sH = 0;
 #ifdef debug
     printf("Hub 1s \n\r");
 #endif
@@ -83,17 +236,10 @@
 // Initializaton
 // -----------------------------------------------------------------------------
 /**
-* Sets up the interrupts for the hub
-*/
-void initInteruptsHub(){
-    tick1sHub.attach(&int1sH, 10.0);
-}
-/**
-* asks the user for the time
-*/
-
-void setRTCpc()
-{
+ * Initialize system on reset and set the time from the terminal
+ */
+void initializeTimeH()
+{ 
     // get the current time from the terminal
     struct tm t;
     printf("Enter current date :\n\r");
@@ -109,18 +255,639 @@
 
     // set the time
     set_time(mktime(&t));
+#ifdef debug
+    printf("Time initialized\n\r");
+#endif
+}
+
+/**
+ *  Initialize all the interrupts 
+ */
+void initializeInterruptsH() 
+{
+    tickTimeCheckH.attach(&interruptTimeCheckH, 5.0);
+    tickBatteryRfidH.attach(&interruptBatteryRfidH, 1.0);
+    tickPoshoRfidH.attach(&interruptPoshoRfidH, 1.0);
+    tickIncubatorRfidH.attach(&interruptIncubatorRfidH, 1.0);
+    tickerUpdateUserTableH.attach(&interruptUpdateUserTableH, 1800.0);
+    buttonOneH.rise(&interruptButtonOneH);
+    buttonTwoH.rise(&interruptButtonTwoH);
+    buttonThreeH.rise(&interruptButtonThreeH);
+    buttonFourH.rise(&interruptButtonFourH);
+    tick1sHub.attach(&int1sH, 10.0);
+
+#ifdef debug
+    printf("Interrupts initialized\n\r");
+#endif
+}
+
+/**
+ *  Initialize RFID readers 
+ */
+void initializeRfidReadersH() 
+{
+    BatteryRfChipH.PCD_Init();
+    PoshoRfChipH.PCD_Init();
+    IncubatorRfChipH.PCD_Init();
+
+#ifdef debug
+    uint8_t tempA = BatteryRfChipH.PCD_ReadRegister(MFRC522::VersionReg);
+    printf("Battery MFRC522 version: %d\n\r", tempA & 0x07);
+    printf("\n\r");
+    uint8_t tempB = PoshoRfChipH.PCD_ReadRegister(MFRC522::VersionReg);
+    printf("Posho MFRC522 version: %d\n\r", tempB & 0x07);
+    printf("\n\r");
+    uint8_t tempC = IncubatorRfChipH.PCD_ReadRegister(MFRC522::VersionReg);
+    printf("Incubator MFRC522 version: %d\n\r", tempC & 0x07);
+    printf("\n\r");
+#endif
+
+#ifdef debug
+    printf("RFID readers initialized\n\r");
+#endif
+}
+
+/**
+ *  Initialize LCD screen 
+ */
+void initializeLCD_H() 
+{
+    TFT_H.background(Black);    // set background to black
+    TFT_H.foreground(White);    // set chars to white
+    TFT_H.cls();                // clear the screen
+    TFT_H.set_font((unsigned char*) Arial24x23);
+    TFT_H.set_orientation(3);   //Portrait, wiring on left
+#ifdef debug
+    printf("LCD initialized\n\r");
+#endif
+}
+
+/**
+ * Creates a new user by defining user attributes.
+ * @param rfid - uint32_t corresponding to unique id of the RFID tag
+ * @param accountCredit - int32 for user account balance (can be negative)
+ * @param locker - int32_t for which locker (originaly 1-4) user is assigned
+ * @param batterySubscription - max batteries user can get (can be 0)
+ * @param batteriesOut - number of batteries user has out (usually 0 initially)
+ * @param podID - pod associated with the user (originally 0-15) *must be 0 indexed*
+ */
+void createNewUserH(uint32_t rfid, int32_t accountCredit, int32_t locker, 
+        int32_t batterySubscription, int32_t batteriesOut, int32_t podID)
+{
+    allUsersH[userCountH].rfid = rfid;
+    allUsersH[userCountH].accountCredit = accountCredit;
+    switch(locker) {
+        case 1:
+            allUsersH[userCountH].lockerID = lockerOne;
+            break;
+        case 2:
+            allUsersH[userCountH].lockerID = lockerTwo;
+            break;
+        case 3:
+            allUsersH[userCountH].lockerID = lockerThree;
+            break;
+        case 4:
+            allUsersH[userCountH].lockerID = lockerFour;
+            break;
+        default:
+            allUsersH[userCountH].lockerID = lockerUnassigned;
+            break;
+    }
+    allUsersH[userCountH].batterySubscription = batterySubscription;
+    allUsersH[userCountH].batteriesOut = batteriesOut;
+    allUsersH[userCountH].podID = podID;
+
+    // generate the user id, a 32 byte value
+    // [community byte 1][community byte 2][locker byte 3][podID (1/2 byte) | 0000 (1/2 byte)]
+    uint32_t actualUid = ((((uint32_t)communityID_H << 16) | ((uint32_t)locker << 8)) | 
+                           ((uint32_t)podID << 4));
+    allUsersH[userCountH].uid = actualUid;
+
+    userCountH++;
+
+#ifdef debug
+    printf("UserID (decimal):%u\n\r", actualUid);
+    printf("**************************\n\r");
+#endif
+}
+
+/**
+ * Initialize system with users from users.txt on SD card
+ */
+void initializeUsersFromSD_H() 
+{
+    spiSD();
+    FILE *fp = fopen("/sd/users.txt", "r");
+    
+    if (fp == NULL) {
+#ifdef debug
+        printf("User text file can't be opened");
+#endif
+        return;
+    }
+
+    // the first line of the user file has the headers for the following roles - get to the next line 
+    char line[180];
+    if (fgets(line, 180, fp) != NULL) {
+#ifdef debug
+        printf("Format of text file:\n\r%s\n\r", line);
+        printf("**************************\n\r");
+#endif
+    }
+
+    // read a set of six values at a time, corresponding to a line, from the user text file. Generate a user per line.
+    uint32_t rfid;
+    int32_t accountCredit;
+    int32_t locker;
+    int32_t batterySubscription;
+    int32_t batteriesOut;
+    int32_t podID;
+    while (fscanf(fp, "%u %d %d %d %d %d", &rfid, &accountCredit, &locker, &batterySubscription, &batteriesOut, &podID) != EOF) {
+#ifdef debug
+        printf("rfid: %u\n\r accountCredit: %d\n\r locker: %d\n\r batterySubscription: %d\n\r batteriesOut: %d\n\r podID: %d\n\r", 
+                   rfid, accountCredit, locker, batterySubscription, batteriesOut, podID);
+#endif
+       createNewUserH(rfid, accountCredit, locker, batterySubscription, batteriesOut, podID);
+    }
+#ifdef debug
+        printf("Users created\n\r");
+#endif
+}
+
+/*************************************************************************************************/
+/* Logging */
+/*************************************************************************************************/
+/**
+ * Log an action from a selection of predefined actions done by the current user
+ * Actions used with this method should require a known user to be using system
+ * @param action - enumerated HubActionForLogging that selects from predefined actions
+ */
+void logActionWithUserInfoH(enum HubActionForLoggingH action)
+{ 
+    // Append to a log text file
+    spiSD();
+    char * name = "/sd/HubLog.txt";
+    FILE *fp;
+    fp = fopen(name, "a");
+    
+    // get the time and append it to an output buffer
+    time_t seconds = time(NULL);
+    char logLine[180];
+    sprintf(logLine, "%x", seconds);
+
+    // append relevant information for action
+    switch (action) {
+        case hubAction_RfidScanned:
+            strcat(logLine, " R ");
+            break;
+        case hubAction_Exit:
+            strcat(logLine, " X ");
+            break;
+        case hubAction_OneBatteryDropped:
+            strcat(logLine, " D 1 ");
+            break;
+        case hubAction_TwoBatteryDropped:
+            strcat(logLine, " D 2 ");
+            break;
+        case hubAction_ThreeBatteryDropped:
+            strcat(logLine, " D 3 ");
+            break;
+        case hubAction_OneBatteryPicked:
+            strcat(logLine, " P 1 ");
+            break;
+        case hubAction_TwoBatteryPicked:
+            strcat(logLine, " P 2 ");
+            break;
+        case hubAction_ThreeBatteryPicked:
+            strcat(logLine, " P 3 ");
+            break;
+    }
+
+    // append general user information
+    char rfidBuffer[20];
+    char uidBuffer[20];
+    char acctBalanceBuffer[20];
+    sprintf(rfidBuffer, "%u ", allUsersH[currentUserH].rfid);                                                                                 
+    sprintf(uidBuffer, "%u ", allUsersH[currentUserH].uid);
+    sprintf(acctBalanceBuffer, "%d\n", allUsersH[currentUserH].accountCredit);
+    strcat(logLine, rfidBuffer);
+    strcat(logLine, uidBuffer);
+    strcat(logLine, acctBalanceBuffer);
+
+    // write the line to the log file and close the file
+    fputs(logLine, fp);
+    fclose(fp);
+
+#ifdef debug
+    printf("%s\n\r", logLine);
+#endif
+
+}
+
+/**
+ * Log an error - RFID not associated with a known user is scanned
+ * @param unknownRfid - uint32 for the unique ID of the unknown rfid tag
+ */
+void logErrorUnknownRfidScannedH(uint32_t unknownRfid)
+{ 
+    // Append to a log text file
+    char * name = "/sd/HubLog.txt";
+    spiSD();
+    FILE *fp;
+    fp = fopen(name, "a");
+    
+    // get the time and append it to an output buffer
+    time_t seconds = time(NULL);
+    char logLine[180];
+    sprintf(logLine, "%x", seconds);
+
+    // RFID action
+    strcat(logLine, " R X ");
+
+    // include just the RFID (indicates that no known user was found)
+    char rfidBuffer[20];
+    sprintf(rfidBuffer, "%u ", unknownRfid);                                                                                 
+    strcat(logLine, rfidBuffer);
+    strcat(logLine, "\n");
+
+    // write the line to the log file and close the file
+    fputs(logLine, fp);
+    fclose(fp);
+
+#ifdef debug
+    printf("%s\n\r", logLine);
+#endif
 
 }
 
+/*************************************************************************************************/
+/* Housekeeping - flag clearing before entering new sections of code */
+/*************************************************************************************************/
+/*
+ *  Reset all user initiated flags. Useful after sequences of events where flags may have 
+ *  piled up from misc inputs and you don't want the system to act seemingly sporadically.
+ */
+void clearAllUserInitiatedFlagsH() {
+    flagButtonOneH = 0;
+    flagButtonTwoH = 0;
+    flagButtonThreeH = 0;
+    flagButtonFourH = 0;
+    flagBatteryRfidH = 0;
+    flagPoshoRfidH = 0;
+    flagIncubatorRfidH = 0;
+}
 
+/*************************************************************************************************/
+/* Things to do after detecting an interrupt (from user input or system generated) */
+/*************************************************************************************************/
+/*
+ * User presses the button corresponding to an exit. Returns to home screen
+ * after logging the action.
+ */
+void cancelPressedH() {
+    clearAllUserInitiatedFlagsH();
+    currentScreenH = initialScanRfid;
+    logActionWithUserInfoH(hubAction_Exit);
+}
+
+/**
+ *  Do if time check flag is set 
+ *  reads the unix time, converts into human readable format, and displays on PC
+ */
+void doTimeCheckH()
+{
+    flagTimeCheckH = 0;
+    time_t seconds = time(NULL);
+    printf("%s\n\r", ctime(&seconds));
+}
+
+/**
+ *  Do if update user table flag is set 
+ */
+void doUpdateUserTableH()
+{
+    flagUpdateUserTableH = 0;
+    // Write to a users.txt file
+    spiSD();
+    char * name = "/sd/users.txt";
+    FILE *fp;
+    fp = fopen(name, "w");
+
+    // output the header for the users.txt file
+    fputs("rfid accountCredit locker batterySubscription batteriesOut podID\n", fp);
+    
+    // output buffer
+    char logLine[180];
+
+    for (int i = 0; i < userCountH; i++) {
+        // get all the needed information in strings
+        sprintf(logLine, "%u ", allUsersH[i].rfid);
+        char accountCreditBuffer[20];
+        char* lockerBuffer;
+        char batterySubscriptionBuffer[20];
+        char batteriesOutBuffer[20];
+        char podIdBuffer[20];
+
+        sprintf(accountCreditBuffer, "%d ", allUsersH[i].accountCredit);
+        switch (allUsersH[i].lockerID) {
+            case lockerOne:
+                lockerBuffer = "1 ";
+                break;
+            case lockerTwo:
+                lockerBuffer = "2 ";
+                break;
+            case lockerThree:
+                lockerBuffer = "3 ";
+                break;
+            case lockerFour:
+                lockerBuffer = "4 ";
+                break;
+            case lockerUnassigned:
+            default:
+                lockerBuffer = "0 ";
+                break;
+        }
+        sprintf(batterySubscriptionBuffer, "%d ", allUsersH[i].batterySubscription);
+        sprintf(batteriesOutBuffer, "%d ", allUsersH[i].batteriesOut);
+        sprintf(podIdBuffer, "%d\n", allUsersH[i].podID);
+
+        // concatenate all the strings
+        strcat(logLine, accountCreditBuffer);
+        strcat(logLine, lockerBuffer);
+        strcat(logLine, batterySubscriptionBuffer);
+        strcat(logLine, batteriesOutBuffer);
+        strcat(logLine, podIdBuffer);
+
+        // write the line to the log file
+        fputs(logLine, fp);
+
+#ifdef debug
+    printf("%s\n\r", logLine);
+#endif
+    }
+    fclose(fp);
+}
 
 /**
-* Initialise for a locker
+ *  Do if Battery RFID flag is set. Read RFID tag and check user status. 
+ *  If there's a valid battery subscription, display drop off and/or pick up. 
+ *  Otherwise, returns to initial screen.
+ */
+void doBatteryRfidH()
+{
+    flagBatteryRfidH = 0;
+
+    // is there a new readable card?
+    if (!BatteryRfChipH.PICC_IsNewCardPresent()) {
+        return;
+    }
+
+    if (!BatteryRfChipH.PICC_ReadCardSerial()) {
+#ifdef debug
+        printf("Card not readable\n\r");
+#endif
+        return;
+    }
+    
+    // get the id of the scanned tag 
+    uint8_t tempReadingRfid[4]; 
+    for(uint8_t i = 0; i < BatteryRfChipH.uid.size; i++) {
+        tempReadingRfid[i] = BatteryRfChipH.uid.uidByte[i];
+    }
+    
+    // concatenate the 4 bytes into a single integer via bit shifting
+    uint32_t actualRfid = ((((uint32_t)tempReadingRfid[0] << 24) | 
+                              ((uint32_t)tempReadingRfid[1] << 16)) | 
+                             (((uint32_t)tempReadingRfid[2] << 8) | 
+                              ((uint32_t)tempReadingRfid[3] << 0)));
+
+    // find the user info
+    char foundUserFlag = 0;
+    for (int i = 0; i < userCountH; i++) {
+        if (allUsersH[i].rfid == actualRfid) {
+            currentUserH = i;
+            foundUserFlag = 1;
+            break;
+        }
+    }
+
+    // if the user is found, set the global variable for current user interacting with the system
+    // if the user isn't found, log that an rfid without a user was used and display
+    if (!foundUserFlag) {
+#ifdef debug
+        printf("User not found\n\r");
+        printf("ID:%u\n\r", actualRfid);
+#endif
+        // log the error interaction
+        logErrorUnknownRfidScannedH(actualRfid);
+
+        // let user know tag wasn't found
+        TFT_H.cls();
+        TFT_H.locate(0,0);
+        TFT_H.printf("User not found\n\r");
+        TFT_H.printf("ID:%u\n\r", actualRfid);
+        wait(1);
+        currentScreenH = initialScanRfid;
+        return;
+    }
+    
+    // log user scan
+    logActionWithUserInfoH(hubAction_RfidScanned);
+
+    // Display info about the user 
+    char authorizationFlag = 0;
+    TFT_H.cls();
+    TFT_H.locate(0,0);
+    TFT_H.printf("UserID: %u\n\r", actualRfid);
+    TFT_H.printf("Balance:%d\n\r", allUsersH[currentUserH].accountCredit);
+    if (allUsersH[currentUserH].batterySubscription > 0) {
+        authorizationFlag = 1;
+    }
+    TFT_H.printf("Authorization:%s\n\r", (authorizationFlag)? "YES":"NO");
+
+#ifdef debug
+    printf("User:");
+    for(uint8_t i = 0; i < BatteryRfChipH.uid.size; i++)
+    {
+        uint8_t uidByte = BatteryRfChipH.uid.uidByte[i];
+        printf(" %d", uidByte);
+    }
+    printf("\n\rUserID: %u\n\r", actualRfid);
+#endif
+
+    // if not authorized for batteries, return to main screen
+    wait(1);
+    if (!authorizationFlag) {
+        currentScreenH = initialScanRfid;
+        return;
+    }
+
+    // otherwise, ask user if the user wants to pick up or drop off batteries?
+    TFT_H.locate(0,160);
+    TFT_H.printf("Battery Action?\n\r");
+    TFT_H.locate(0,200);
+
+    uint8_t maxBatteries = allUsersH[currentUserH].batterySubscription;
+    uint8_t outBatteries = allUsersH[currentUserH].batteriesOut;
+
+    if ((maxBatteries - outBatteries) == 0) {   // can only drop off
+        TFT_H.printf(" drop           exit");
+    } else if (outBatteries == 0) {             // can only pick up 
+        TFT_H.printf(" pick           exit");
+    } else {                                    // can pickup or dropoff                 
+        TFT_H.printf(" pick     drop  exit");
+    }
+
+    // go to action selecting screen and clear buttons beforehand
+    currentScreenH = batterySelectAction;
+    clearAllUserInitiatedFlagsH();
+    return;
+}
+
+/**
+ *  Do if user selects to pickup a battery. Determines how many batteries
+ *  a user can pickup based off user info and displays corresponding text
+ */
+void batteryPickUpH() {
+    TFT_H.cls();
+    TFT_H.locate(0,0);
+    TFT_H.printf("UserID: %u\n\r\n\r", allUsersH[currentUserH].rfid);
+
+    TFT_H.printf("Action: PICK UP\n\r");
+    TFT_H.locate(0,160);
+    TFT_H.printf("How many batteries?\n\r");
+    TFT_H.locate(0,200);
+    switch (allUsersH[currentUserH].batterySubscription - allUsersH[currentUserH].batteriesOut) {
+        case 1: {
+            TFT_H.printf("  1            exit");
+            break;
+        }
+        case 2: {
+            TFT_H.printf("  1    2       exit");
+            break;
+        }
+        case 3: {
+            TFT_H.printf("  1    2    3  exit");
+            break;
+        }
+    }
+
+    // go to wait for selection input and reset button flags
+    currentScreenH = batterySelectNumberForPickup;
+    clearAllUserInitiatedFlagsH();
+    return;
+}
+
+/**
+ *  Do if user selects to dropoff a battery. Determines how many batteries
+ *  a user can pickup based off user info and displays corresponding text
+ */
+void batteryDropOffH() {
+    TFT_H.cls();
+    TFT_H.locate(0,0);
+    TFT_H.printf("UserID: %u\n\r\n\r", allUsersH[currentUserH].rfid);
+
+    TFT_H.printf("Action: DROP OFF\n\r");
+    TFT_H.locate(0,160);
+    TFT_H.printf("How many batteries?\n\r");
+    TFT_H.locate(0,200);
+    switch (allUsersH[currentUserH].batteriesOut) {
+        case 1: {
+            TFT_H.printf("  1            exit");
+            break;
+        }
+        case 2: {
+            TFT_H.printf("  1    2       exit");
+            break;
+        }
+        case 3: {
+            TFT_H.printf("  1    2    3  exit");
+            break;
+        }
+    }
+    
+    // go to wait for selection input and reset button flags
+    currentScreenH = batterySelectNumberForDropoff;
+    clearAllUserInitiatedFlagsH();
+    return;
+}
+
+/**
+ *  Do after use selects number of batteries to drop off. 
+ *  Logs the action, changes user info, transmits instructions to other systems
+ *  @param numBatteries - int for number of batteries selected to drop off
+ */
+void batteryDropOffH(int numBatteries) {
+    switch(numBatteries) {
+        case 1:
+            logActionWithUserInfoH(hubAction_OneBatteryDropped);
+            allUsersH[currentUserH].batteriesOut--;
+            break;
+        case 2:
+            logActionWithUserInfoH(hubAction_TwoBatteryDropped);
+            allUsersH[currentUserH].batteriesOut -= 2;
+            break;
+        case 3:
+            logActionWithUserInfoH(hubAction_ThreeBatteryDropped);
+            allUsersH[currentUserH].batteriesOut -= 3;
+            break;
+    }
+
+    currentScreenH = initialScanRfid;
+    return;
+}
+
+/**
+ *  Do after use selects number of batteries to pick up. 
+ *  Logs the action, changes user info, transmits instructions to other systems
+ *  @param numBatteries - int for number of batteries selected to pick up
+ */
+void batteryPickUpH(int numBatteries) {
+    switch(numBatteries) {
+        case 1:
+            logActionWithUserInfoH(hubAction_OneBatteryPicked);
+            allUsersH[currentUserH].batteriesOut++;
+            break;
+        case 2:
+            logActionWithUserInfoH(hubAction_TwoBatteryPicked);
+            allUsersH[currentUserH].batteriesOut += 2;
+            break;
+        case 3:
+            logActionWithUserInfoH(hubAction_ThreeBatteryPicked);
+            allUsersH[currentUserH].batteriesOut += 3;
+            break;
+    }
+
+    currentScreenH = initialScanRfid;
+    return;
+}
+
+/**
+ *  Do if Posho RFID flag is set. Add posho functionality later.
+ */
+void doPoshoRfidH()
+{
+    flagPoshoRfidH = 0;
+}
+
+/**
+ *  Do if Incubator RFID flag is set. Add incubator functionality later.
+ */
+void doIncubatorRfidH()
+{
+    flagIncubatorRfidH = 0;
+}
+
+/*************************************************************************************************/
+/* Public Methods */
+/*************************************************************************************************/
+/**
+* Initialise for a hub
 * fp is the config file if additonal information is needed.
 */
 void initialiseHub(FILE *fp){
 #ifdef debug
-    printf("Initialise Hub\n\r");
+    printf("Initializing Hub\n\r");
 #endif
 
     // Read in hub address and channel
@@ -130,10 +897,8 @@
 #ifdef debug
     printf("  Channel:%x, Hub Address %llx \n\r",channel, addrLcker);
 #endif
-    setRTCpc();
 
     // Setup nrf
-
 #ifdef debug
     printf("Steup doNrf \n\r");
 #endif
@@ -145,20 +910,100 @@
     printf("Setup doNrf complete [nrf:%s]\n\r",nrf1.statusString());
 #endif
 
-    // Setup interupts
-    initInteruptsHub();
-
-
+    // Other initialization routines
+    initializeTimeH();
+    initializeInterruptsH();
+    initializeRfidReadersH();
+    initializeLCD_H();
+    initializeUsersFromSD_H();
 }
 
-// Interupt routines
+void loopHub(){
+    while (true) {
+        // put interrupts here that should supercede anything else
+        if (flag1sH) { do1sH(); }
 
-// Loop through slow routines
+        // put interrupts here that may be active depending on screen stage
+        switch(currentScreenH) {
+            case initialScanRfid: {
+                    TFT_H.cls();
+                    TFT_H.locate(0,0);
+                    TFT_H.printf("Please scan your ID");
+                    currentScreenH = waitForRfid;
+                    clearAllUserInitiatedFlagsH();
+            }
+            case waitForRfid: {
+                if (flagTimeCheckH) doTimeCheckH();
+                if (flagBatteryRfidH) doBatteryRfidH();
+                if (flagPoshoRfidH) doPoshoRfidH();
+                if (flagIncubatorRfidH) doIncubatorRfidH();
+                if (flagUpdateUserTableH) doUpdateUserTableH();
+                break;
+            }
+            case batterySelectAction: {
+                uint8_t maxBatteries = allUsersH[currentUserH].batterySubscription;
+                uint8_t outBatteries = allUsersH[currentUserH].batteriesOut;
+
+                if ((maxBatteries - outBatteries) == 0) {
+                    if (flagButtonOneH) batteryDropOffH();
+                    if (flagButtonFourH) cancelPressedH();
+                } else if (outBatteries == 0) { 
+                    if (flagButtonOneH) batteryPickUpH();
+                    if (flagButtonFourH) cancelPressedH();
+                } else {                                                     
+                    if (flagButtonOneH) batteryPickUpH();
+                    if (flagButtonThreeH) batteryDropOffH();
+                    if (flagButtonFourH) cancelPressedH();
+                }
 
-void loopHub(){
-
-    if (flag1sH){
-        do1sH();
-        flag1sH=0;
+                break;
+            }
+            case batterySelectNumberForDropoff: {
+                switch (allUsersH[currentUserH].batteriesOut) {
+                    case 1: {
+                        if (flagButtonOneH) batteryDropOffH(1);
+                        if (flagButtonFourH) cancelPressedH();
+                        break;
+                    }
+                    case 2: {
+                        if (flagButtonOneH) batteryDropOffH(1);
+                        if (flagButtonTwoH) batteryDropOffH(2);
+                        if (flagButtonFourH) cancelPressedH();
+                        break;
+                    }
+                    case 3: {
+                        if (flagButtonOneH) batteryDropOffH(1);
+                        if (flagButtonTwoH) batteryDropOffH(2);
+                        if (flagButtonThreeH) batteryDropOffH(3);
+                        if (flagButtonFourH) cancelPressedH();
+                        break;
+                    }
+                }
+                break;
+            }
+            case batterySelectNumberForPickup: {
+                switch (allUsersH[currentUserH].batterySubscription - allUsersH[currentUserH].batteriesOut) {
+                    case 1: {
+                        if (flagButtonOneH) batteryPickUpH(1);
+                        if (flagButtonFourH) cancelPressedH();
+                        break;
+                    }
+                    case 2: {
+                        if (flagButtonOneH) batteryPickUpH(1);
+                        if (flagButtonTwoH) batteryPickUpH(2);
+                        if (flagButtonFourH) cancelPressedH();
+                        break;
+                    }
+                    case 3: {
+                        if (flagButtonOneH) batteryPickUpH(1);
+                        if (flagButtonTwoH) batteryPickUpH(2);
+                        if (flagButtonThreeH) batteryPickUpH(3);
+                        if (flagButtonFourH) cancelPressedH();
+                        break;
+                    }
+                }
+                break;
+            }
+        }
     }
 }
\ No newline at end of file