RFID Cat Door Project

Dependencies:   EthernetNetIf TextLCD mbed HTTPServer ID12RFID

main.cpp

Committer:
sbobyr
Date:
2011-08-30
Revision:
2:9cc95c486c7b
Parent:
1:25a4acc15210

File content as of revision 2:9cc95c486c7b:

// RFID Cat Door Project
// The code runs on mbed and implements RFID Cat Door system. System comprises 3 sensors (RFID Reader, Proximity sensor, Reed sensor)
// and 1 actuator (Solenoid door lock). System operates either in offline or online mode (if IP address is acquired). In online mode
// a web page is created describing system's state. A lockdown override is available in online mode locking down the system.
// The system is controlled by a state machine and provides RFID-based entry control. Exit is allowed without authorization.

//#define NO_HW // uncomment if there's no HW attached to mbed

#include "mbed.h"                   // mbed library
#include "ID12RFID.h"               // ID12 RFID Reader library
#include "TextLCD.h"                // OrangeBoard LCD library
#include "EthernetNetIf.h"          // Ethernet library
#include "HTTPServer.h"             // HTTP Server library
#include "HTTPRequestHandler.h"     // HTTP Request Handler library
#include <string>

EthernetNetIf eth;
HTTPServer svr;
class CatDoorHandler;

// State Machine Events
enum Event { DoorOpenEvent, DoorClosedEvent, ProximityEvent, AuthTagReadEvent, DoorUnlockedTimeoutEvent, None };
string eventNames[] = { "DoorOpen", "DoorClosed", "Proximity", "AuthTagRead", "DoorUnlockedTimeout", "None" };
Event event = None;

// State Machine States
enum State { DoorLockedClosed, DoorUnlockedClosed, DoorUnlockedOpen };
string stateNames[] = { "Door Locked & Closed", "Door Unlocked & Closed", "Door Unlocked & Open" };
State state = DoorLockedClosed;

bool bLockdown = false; // variable indicating a lockdown from the web page

// Cat's possible locations
enum Location { Inside, Outside, Unknown };
string locationNames[] = { "Inside", "Outside", "Unknown" };

// Each cat has tag, name, and location
struct cat { int tag; string name; Location location; };
// List of authorized cats
cat cats[] = {
    5454121, "Yellow", Unknown,
    //9733970, "Blue", Unknown,
    //463733, "Red", Unknown
};
int catsN = sizeof(cats)/sizeof(cat);
int catId = 0; // current cat ID

TextLCD lcd(p24, p26, p27, p28, p29, p30);  // OrangeBoard LCD
ID12RFID rfid(p14);                         // uart rx for ID12 RFID reader
DigitalIn _door_open(p17);                  // reed sensor, 0 indicates door open
DigitalIn _proximity(p16);                  // proximity sensor, 0 indicates an object within 10 cm
DigitalOut unlock_door(p21);                // solenoid, 1 will unlock the door

DigitalOut door_unlocked_led(LED1);         // ON when door is unlocked
DigitalOut door_open_led(LED2);             // ON when door is open
DigitalOut proximity_led(LED3);             // ON when proximity sensor is triggered
PwmOut rfid_read_led(LED4);                 // DIM = unauthorized tag read; BRIGHT = authorized tag read

const float LED_DIM = 0.05;
const float LED_BRIGHT = 1;

// Authorized RFID Tag Read Event
Timer tagReadTimer;
bool IsAuthTagReadEvent() {
    if(rfid.readable()) {
        int tag = rfid.read();  // read the tag
        tagReadTimer.reset();
        tagReadTimer.start();   // start 5 sec timer
        
        lcd.cls(); lcd.locate(0, 0); lcd.printf("Tag: %08d", tag);
        for (int i = 0; i < catsN; ++i) { // find if tag is authorized
            if (cats[i].tag == tag) {
                catId = i;
                lcd.locate(0, 1); lcd.printf("Cat: %s", cats[i].name.c_str());
                rfid_read_led = LED_BRIGHT;
                return true;
            }
        }
        
        lcd.locate(0, 1); lcd.printf("Cat: Unknown"); // unknown tag
        rfid_read_led = LED_DIM;
    }
    if (tagReadTimer.read() > 5.0) { // each tag is shown for 5 sec
        tagReadTimer.stop();
        tagReadTimer.reset();
        rfid_read_led = 0;
        lcd.cls();
    }
    return false;
}

// Proximity Event
bool IsProximityEvent() {
    bool result = false;
    static bool wasProximity = false;       // last state
    bool bProximity = !_proximity.read();   // 0 indicates an object within 10 cm
    proximity_led = bProximity;
    if (bProximity & !wasProximity)         // create event on transition only
        result = true;
    wasProximity = bProximity;
    return result;
}

// Door Open Event
bool IsDoorOpenEvent() {
    bool result = false;
    static bool wasOpen = false;            // last state
    bool bDoorOpen = !_door_open.read();    // 0 indicates door open
    door_open_led = bDoorOpen;
    if (bDoorOpen & !wasOpen)               // create event on transition only
        result = true;
    wasOpen = bDoorOpen;
    return result;
}

// Door Closed Event
Timer doorClosedTimer;
bool IsDoorClosedEvent() {
    bool result = false;
    static bool wasClosed = true;           // last state
    bool bDoorClosed = _door_open.read();
    if (bDoorClosed & !wasClosed) {         // start timer when door closes
        doorClosedTimer.reset();
        doorClosedTimer.start();
    }
    // event is only created if door has been closed for more than 1.2 sec
    if (bDoorClosed & doorClosedTimer.read() > 1.2) {
        doorClosedTimer.stop();
        doorClosedTimer.reset();
        result = true;
    }
    wasClosed = bDoorClosed;
    return result;
}

// Door locking/unlocking code
Timer doorUnlockedTimer;
void UnlockDoor(bool req) {
    unlock_door = (req) ? 1 : 0;
    door_unlocked_led = unlock_door;
    if (req) {
        doorUnlockedTimer.reset();
        doorUnlockedTimer.start();
    }
}

// Door Unlocked Timeout Event
bool IsDoorUnlockedTimeoutEvent() {
    if (doorUnlockedTimer.read() > 5.0) { // fires if door has been unlocked for more than 5 sec
        doorUnlockedTimer.stop();
        doorUnlockedTimer.reset();
        return true;
    }
    return false;
}

// State Machine Logic
void CatDoorStateMachine(Event event) {
    static Location destination = Outside; // destination variable helps determine location of a cat
    printf("State: %s\t Event: %s\n", stateNames[state].c_str(), eventNames[event].c_str());
    
    switch(state)
    {
        case DoorLockedClosed :
            if (bLockdown) break; // bLockdown doesn't let state machine exit DoorLockedClosed state
            switch(event)
            {
                case ProximityEvent :
                    UnlockDoor(true);                   // unlock door
                    state = DoorUnlockedClosed;
                    destination = Outside;              // cat's coming outside
                    break;
                case AuthTagReadEvent :
                    UnlockDoor(true);                   // unlock door
                    state = DoorUnlockedClosed;
                    destination = Inside;               // cat's coming inside
                    break;
                default :
                    break;
            }
            break;
        case DoorUnlockedClosed :
            switch(event)
            {
                case DoorUnlockedTimeoutEvent :         // lock door after 5 sec
                    UnlockDoor(false);                  // lock door
                    state = DoorLockedClosed;
                    break;
                case DoorOpenEvent :
                    state = DoorUnlockedOpen;
                    break;
                default :
                    break;
            }
            break;
        case DoorUnlockedOpen :
            switch(event)
            {
                case DoorClosedEvent :                  // door closed, can lock it now
                    UnlockDoor(false);                  // lock door
                    state = DoorLockedClosed;
                    cats[catId].location = destination; // cat's location determined
                    break;
                default :
                    break;
            }
            break;
        default :
            break;
    }
}

int main() {
    bool bEthPresent = true; // online/offline mode variable
    lcd.cls(); lcd.locate(0, 0); lcd.printf("RFID Cat Door");
    lcd.locate(0, 1); lcd.printf("Setting up ^..^");
    printf("RFID Cat Door\n");
    printf("Setting up Ethernet ^..^\n");
    EthernetErr ethErr = eth.setup(); // Ethernet setup
    if (ethErr) {
        printf("Error %d in Ethernet setup\n", ethErr);
        printf("Operating in offline mode ^..^\n");
        lcd.cls(); lcd.printf("Offline mode");
        bEthPresent = false; // offline mode set
    }
    else {
        printf("Ethernet setup OK\n");
        printf("Operating in online mode ^..^\n");
        IpAddr ip = eth.getIp(); // IP address
        lcd.cls(); lcd.locate(0, 0); lcd.printf("Online mode, IP:");
        lcd.locate(0, 1); lcd.printf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
      
        svr.addHandler<CatDoorHandler>("/");    // our HTTP handler added
        svr.bind(80);                           // port 80 bound
    }

    while(1) {
        if (bEthPresent)
            Net::poll();                        // service HTTP requests

#ifndef NO_HW        
        if (IsAuthTagReadEvent()) {
            event = AuthTagReadEvent;           // Authorized Tag Read Event
            CatDoorStateMachine(event);
        }
#endif    
        if (IsProximityEvent()) {
            event = ProximityEvent;             // Proximity Event
            CatDoorStateMachine(event);
        }
        
        if (IsDoorOpenEvent()) {
            event = DoorOpenEvent;              // Door Open Event
            CatDoorStateMachine(event);
        }
        
        if (IsDoorClosedEvent()) {
            event = DoorClosedEvent;            // Door Closed Event
            CatDoorStateMachine(event);
        }
        
        if (IsDoorUnlockedTimeoutEvent()) {
            event = DoorUnlockedTimeoutEvent;   // Door Unlocked Timeout Event
            CatDoorStateMachine(event);
        }
    }
}

// Cat Door HTTP Handler will handle HTTP GET requests
class CatDoorHandler : public HTTPRequestHandler
{
public:
    CatDoorHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) :
        HTTPRequestHandler(rootPath, path, pTCPSocket){}

    virtual ~CatDoorHandler(){}

    static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTCPSocket)
    { return new CatDoorHandler(rootPath, path, pTCPSocket); }

    virtual void doGet() // handles HTTP GET requests
    {
        string _path = path(); // path will have "lockdown=yes" if lockdown checkbox was checked
        printf("doGet path: %s\n", _path.c_str());
        bLockdown = (_path.find("lockdown=yes") == string::npos) ? false : true;
        if (bLockdown) {
            lcd.cls(); lcd.printf("System Lockdown!");
        }
        else {
            lcd.cls();
        }
        
        // Create HTML page with status information, lockdown checkbox, and submit/refresh button
        string rs = "<html><head><title>RFID Cat Door</title></head><body><h3>RFID Cat Door</h3>";
        string ds = "Door Status: <i>" + stateNames[state] + "</i><br>";
        string cs = "Cat Status: <i>" + locationNames[cats[catId].location] + "</i><p>";
        string ld = (bLockdown) ? " checked" : ""; // lockdownn checkbox reflects system lockdown state
        string fr = "<form method='get' action=''>"
        "<input type='checkbox' name='lockdown' value='yes'" + ld + "> Lockdown System <p>"
        "<input type='submit' value='Submit/Refresh Data'></form></body></html>";
        rs += ds + cs + fr;
        setContentLen(rs.length());
        respHeaders()["Connection"] = "close";
        writeData(rs.c_str(), rs.length());
    }

    virtual void doPost() {}
    virtual void doHead() {}
    virtual void onReadable() {}
    virtual void onWriteable() {}
    virtual void onClose() {}
};