Fork to see if I can get working

Dependencies:   BufferedSerial OneWire WinbondSPIFlash libxDot-dev-mbed5-deprecated

Fork of xDotBridge_update_test20180823 by Matt Briggs

Revision:
44:ece6330e9b57
Parent:
41:9ef4c4d77711
Child:
47:a68747642a7a
--- a/xDotBridge/src/BaseboardIO.cpp	Tue Jan 31 21:02:56 2017 +0000
+++ b/xDotBridge/src/BaseboardIO.cpp	Wed Feb 01 15:20:45 2017 -0700
@@ -8,121 +8,363 @@
 #include "BaseboardIO.h"
 #include "MTSLog.h"
 
+const float coilOnTime = 0.030; // 30 ms
+
+// Port expander 0
+const uint8_t pEx0232En     = 0x01;
+const uint8_t pEx0232TxDis  = 0x02;
+const uint8_t pEx0Rot1B1    = 0x04;
+const uint8_t pEx0Rot1B2    = 0x08;
+const uint8_t pEx0Rot1B4    = 0x10;
+const uint8_t pEx0Rot1B8    = 0x20;
+const uint8_t pEx0Rot2B1    = 0x40;
+const uint8_t pEx0Rot2B2    = 0x80;
+
+// Port expander 1
+const uint8_t pEx1NoNcSel   = 0x01;
+const uint8_t pEx1RxTxSel   = 0x02;
+const uint8_t pEx1WanSel    = 0x04;
+const uint8_t pEx1SerialEn  = 0x08; // Labeled as reserved
+const uint8_t pEx1Rot2B8    = 0x10;
+const uint8_t pEx1Rot2B4    = 0x20;
+const uint8_t pEx1RlyB      = 0x40; // This is actually a coil
+const uint8_t pEx1RlyA      = 0x80; // This is actually a coil
+
+/**
+ * Note for interrupt within uC cannot use two pins with the same numeric suffix (e.g. cannot
+ * use both PA_0 and PB_0).  Note 1, 6, 7, 8, and 13 are used by LoRa radio.
+ */
+
 BaseboardIO::BaseboardIO()
+    : mOWMaster(I2C_SDA),
+      mCCIn(WAKE), // Interrupt pin PA_0
+      mTamper(GPIO1), // Interrupt pin PA_5
+      mPairBtn(UART_CTS), // Interrupt pin PA_11
+      mLed(SWDIO),
+      mSwitchedIOCtrl(I2C_SCL)
 {
-    mCCInIntCallback = NULL;
-    mTamperIntCallback = NULL;
-    mPairBtnIntCallback = NULL;
+//    mCCInIntCallback = NULL;
+//    mTamperIntCallback = NULL;
+//    mPairBtnIntCallback = NULL;
 
-    std::memset(portExpanderROM0, 0x00, 8);
-    std::memset(portExpanderROM1, 0x00, 8);
-    portExpanderVal0 = 0x00;
-    portExpanderVal1 = 0x00;
+    std::memset(mPortExpanderROM0, 0x00, 8);
+    std::memset(mPortExpanderROM1, 0x00, 8);
+    mPortExpanderVal0 = 0x00;
+    mPortExpanderVal1 = 0x00;
+
+    mPortEx0 = NULL;
+    mPortEx1 = NULL;
 }
 CmdResult BaseboardIO::init()
 {
     logError("Not implemented yet!!!");
+    // Setup port expanders
+    CmdResult result = readInfoFromNVM();
+    if (result == cmdSuccess) {
+        // Values stored just read them foo
+        logError("Not implemented yet!!!");
+    }
+    else { // EEPROM values not there or corrupt
+        result = identifyPortExpanders(); // Get ROM addresses
+        if (result != cmdSuccess) {
+            logError("Error identifying port expanders");
+            return cmdError;
+        }
+    }
+    mPortEx0 = new DS2408(&mOWMaster, mPortExpanderROM0);
+    mPortEx1 = new DS2408(&mOWMaster, mPortExpanderROM1);
+
+    // Put relay in known state
+
+    logInfo("Baseboard IO initialization successful");
+    return cmdSuccess;
 }
 
 // Registering for interrupts
-void BaseboardIO::regCCInInt(void (*callback) (void))
+void BaseboardIO::regCCInInt(Callback<void()> func)
 {
-    mCCInIntCallback = callback;
+    // Pulled high, switched low
+    mCCIn.fall(func);
 }
-void BaseboardIO::regTamperInt(void (*callback) (void))
+void BaseboardIO::regTamperInt(Callback<void()> func)
 {
-    mTamperIntCallback = callback;
+    // Pulled high, switched low
+    mTamper.fall(func);
 }
-void BaseboardIO::regPairBtnInt(void (*callback) (void))
+void BaseboardIO::regPairBtnInt(Callback<void()> func)
 {
-    logError("Not implemented yet!!!");
+    // Pulled low, switched high
+    mPairBtn.rise(func);
 }
 
 // Input
 CmdResult BaseboardIO::sampleUserSwitches()
 {
-    logError("Not implemented yet!!!");
-    return cmdError;
+    // Sample port expanders
+    if (mPortEx0->pioLogicRead(mPortExpanderVal0) != cmdSuccess) {
+        logError("Error reading port expander 0.");
+        return cmdError;
+    }
+    if (mPortEx1->pioLogicRead(mPortExpanderVal1) != cmdSuccess) {
+        logError("Error reading port expander 1.");
+        return cmdError;
+    }
+    return cmdSuccess;
 }
 bool BaseboardIO::isPairBtn()
 {
-    logError("Not implemented yet!!!");
-    return false;
+    // Depressed button is high
+    return mPairBtn.read() == 1;
 }
 bool BaseboardIO::isCCOutNO()
 {
-    logError("Not implemented yet!!!");
-    return false;
+    // When DIP switch is not closed (i.e. value reads high) assume NO
+    return (mPortExpanderVal1 & pEx1NoNcSel) != 0;
 }
 bool BaseboardIO::isRx()
 {
-    logError("Not implemented yet!!!");
-    return false;
+    // When DIP switch is not closed (i.e. value reads high) assume RX
+    return (mPortExpanderVal1 & pEx1RxTxSel) != 0;
 }
 bool BaseboardIO::isLoRaWANMode()
 {
-    logError("Not implemented yet!!!");
-    return false;
+    // When DIP switch is not closed (i.e. value reads high) assume P2P not WAN
+    return (mPortExpanderVal1 & pEx1WanSel) == 0;
 }
 uint8_t BaseboardIO::rotarySwitch1()
 {
-    logError("Not implemented yet!!!");
-    return 0;
+    // If a bit of a nibble is asserted then the port expander line is switched low.
+    uint8_t val = 0;
+    if ((mPortExpanderVal0 & pEx0Rot1B8) == 0)
+        val |= 0x08;
+    if ((mPortExpanderVal0 & pEx0Rot1B4) == 0)
+        val |= 0x04;
+    if ((mPortExpanderVal0 & pEx0Rot1B2) == 0)
+        val |= 0x02;
+    if ((mPortExpanderVal0 & pEx0Rot1B1) == 0)
+        val |= 0x01;
+    return val;
 }
 uint8_t BaseboardIO::rotarySwitch2()
 {
-    logError("Not implemented yet!!!");
-    return 0;
+    // If a bit of a nibble is asserted then the port expander line is switched low.
+    uint8_t val = 0;
+    if ((mPortExpanderVal1 & pEx1Rot2B8) == 0)
+        val |= 0x08;
+    if ((mPortExpanderVal1 & pEx1Rot2B4) == 0)
+        val |= 0x04;
+    if ((mPortExpanderVal0 & pEx0Rot2B2) == 0)
+        val |= 0x02;
+    if ((mPortExpanderVal0 & pEx0Rot2B1) == 0)
+        val |= 0x01;
+    return val;
 }
 
 // Output
 CmdResult BaseboardIO::ledOn()
 {
-    logError("Not implemented yet!!!");
-    return cmdError;
+    mLed = 1;
+    return cmdSuccess;
 }
 CmdResult BaseboardIO::ledOff()
 {
-    logError("Not implemented yet!!!");
-    return cmdError;
+    mLed = 0;
+    return cmdSuccess;
 }
 CmdResult BaseboardIO::relayAlert()
 {
-    logError("Not implemented yet!!!");
-    return cmdError;
+    if (isCCOutNO()) { // Normally Open
+        return closeRelay();
+    }
+    else { // Normally Close
+        return openRelay();
+    }
 }
 CmdResult BaseboardIO::relayNormal()
 {
-    logError("Not implemented yet!!!");
-    return cmdError;
+    if (isCCOutNO()) { // Normally Open
+        return openRelay();
+    }
+    else { // Normally Close
+        return closeRelay();
+    }
 }
 
 // Future
 CmdResult BaseboardIO::serialRx(bool enable)
 {
+    uint8_t val;
+    mPortEx0->pioLogicRead(val);
+
+    // Active low from port expander -> pmos -> 232 (active chip EN)
+    if (enable) {
+        val &= ~pEx0232En;
+    }
+    else {
+        val |= pEx0232En;
+    }
+
+    if (mPortEx1->pioLogicWrite(val) != cmdSuccess) {
+        logError("Error enabling 232");
+        return cmdError;
+    }
+    return cmdSuccess;
+}
+CmdResult BaseboardIO::serialTx(bool enable)
+{
+    uint8_t val;
+    mPortEx0->pioLogicRead(val);
+
+    // Active high tx disable therefore active low tx enable (note chip must also be enabled for TX)
+    if (enable) {
+        val &= ~pEx0232TxDis;
+    }
+    else {
+        val |= pEx0232TxDis;
+    }
+
+    if (mPortEx1->pioLogicWrite(val) != cmdSuccess) {
+        logError("Error enabling 232 TX");
+        return cmdError;
+    }
+    return cmdSuccess;
+}
+
+// private
+CmdResult BaseboardIO::readInfoFromNVM()
+{
     logError("Not implemented yet!!!");
     return cmdError;
 }
-CmdResult BaseboardIO::serialTx(bool enable)
+CmdResult BaseboardIO::writeInfoToNVM()
 {
     logError("Not implemented yet!!!");
     return cmdError;
 }
+CmdResult BaseboardIO::identifyPortExpanders()
+{
+    uint8_t addr[8];
+    uint8_t result;
 
-// private
+    // Search Bus
+    logInfo("Starting OneWire Search");
+    int i=0;
+    while (true) {
+        // TODO maybe change to family based search
+        result = mOWMaster.search(addr);
+        logInfo("ROM Addr: %02x:%02x:%02x:%02x:%02x:%02x:%02x%02x found.",
+                addr[7],addr[6],addr[5],addr[4],addr[3],addr[2],addr[1],addr[0]);
+        if (result != 1)
+            break;
+        if (i == 0) {
+            std::memcpy(mPortExpanderROM0, addr, sizeof(mPortExpanderROM0));
+        }
+        else if (i == 1) {
+            std::memcpy(mPortExpanderROM1, addr, sizeof(mPortExpanderROM1));
+        }
+        i++;
+    }
+
+    logInfo("Finished OneWire Search");
+    if (i != 2) {
+        logError("Incorrect Number (Got %d.  Expected 2) OneWire port expanders found.", i);
+        return cmdError;
+    }
+
+    // If switches are set in factory default mode then port expander 1 should read 0xFF and
+    // port expander 2 should read 0xF0.
 
-CmdResult readInfoFromEEPROM()
-{
-    logError("Not implemented yet!!!");
-    return cmdError;
+    mPortEx0 = new DS2408(&mOWMaster, mPortExpanderROM0);
+    mPortEx1 = new DS2408(&mOWMaster, mPortExpanderROM1);
+
+    if (mPortEx0->pioLogicRead(mPortExpanderVal0) != cmdSuccess) {
+        logError("Error during port expander ID.  Read failed.");
+        delete mPortEx0;
+        delete mPortEx1;
+        return cmdError;
+    }
+    if (mPortEx1->pioLogicRead(mPortExpanderVal1) != cmdSuccess) {
+        logError("Error during port expander ID.  Read failed.");
+        delete mPortEx0;
+        delete mPortEx1;
+        return cmdError;
+    }
+
+    if ((mPortExpanderVal0 == 0xFF) and (mPortExpanderVal1 == 0xF0)) { // Luckily got it right
+        logInfo("ROMS Swap Not Needed.");
+    }
+    else if ((mPortExpanderVal0 == 0xF0) and (mPortExpanderVal1 == 0xFF)) { // Just need to swap
+        std::memcpy(addr, mPortExpanderROM0, sizeof(addr)); // Store Orig ROM0 -> addr
+        std::memcpy(mPortExpanderROM0, mPortExpanderROM1, sizeof(mPortExpanderROM0)); // Store Orig ROM1 -> ROM0
+        std::memcpy(mPortExpanderROM1, addr, sizeof(mPortExpanderROM1)); // Store Orig ROM0 (addr) -> ROM1
+        logInfo("Swapped ROMS.");
+    }
+    else {
+        logError("Error during port expander ID.  Port expanders not in expected states.  Check user switches.");
+        delete mPortEx0;
+        delete mPortEx1;
+        return cmdError;
+    }
+
+    // Cleanup
+    delete mPortEx0;
+    delete mPortEx1;
+
+    return cmdSuccess;
 }
-CmdResult writeInfoToEEPROM()
-{
-    logError("Not implemented yet!!!");
-    return cmdError;
+CmdResult BaseboardIO::closeRelay() {
+    uint8_t val;
+    mPortEx1->pioLogicRead(val);
+
+    val |=  pEx1RlyA; // Turn on Relay A
+    val &= ~pEx1RlyB; // Make sure Relay B is off
+
+    if (mPortEx1->pioLogicWrite(val) != cmdSuccess) {
+        val &= ~pEx1RlyA; // Turn Relay A off
+        val &= ~pEx1RlyB; // Turn Relay B off
+        mPortEx1->pioLogicWrite(val); // Write a non assert value just to try to overcome an error
+        logError ("Error turning on coil.  Turning both coils off.");
+        return cmdError;
+    }
+
+    wait(coilOnTime);
+
+    val &= ~pEx1RlyA; // Turn Relay A off
+    val &= ~pEx1RlyB; // Turn Relay B off
+
+    if (mPortEx1->pioLogicWrite(val) != cmdSuccess) {
+        mPortEx1->pioLogicWrite(val);
+        logError ("Error turning off coils.  Trying again.");
+        return cmdError;
+    }
+
+    return cmdSuccess;
 }
-CmdResult identifyPortExpanders()
-{
-    logError("Not implemented yet!!!");
-    return cmdError;
+CmdResult BaseboardIO::openRelay() {
+    uint8_t val;
+    mPortEx1->pioLogicRead(val);
+
+    val &= ~pEx1RlyA; // Make sure Relay A is off
+    val |=  pEx1RlyB; // Turn on Relay B
+
+    if (mPortEx1->pioLogicWrite(val) != cmdSuccess) {
+        val &= ~pEx1RlyA; // Turn Relay A off
+        val &= ~pEx1RlyB; // Turn Relay B off
+        mPortEx1->pioLogicWrite(val); // Write a non assert value just to try to overcome an error
+        logError ("Error turning on coil.  Turning both coils off.");
+        return cmdError;
+    }
+
+    wait(coilOnTime);
+
+    val &= ~pEx1RlyA; // Turn Relay A off
+    val &= ~pEx1RlyB; // Turn Relay B off
+
+    if (mPortEx1->pioLogicWrite(val) != cmdSuccess) {
+        mPortEx1->pioLogicWrite(val);
+        logError ("Error turning off coils.  Trying again.");
+        return cmdError;
+    }
+
+    return cmdSuccess;
 }