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

Revision:
3:86773d65ed58
Parent:
2:d1eae91343a9
Child:
5:88c516cf34e6
--- 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