Implementation of 1-Wire with added Alarm Search Functionality
Dependents: Max32630_One_Wire_Interface
OneWire_Masters/DS2465/DS2465.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-05-09
- Revision:
- 71:562f5c702094
- Parent:
- 69:f915c4c59a69
- Child:
- 72:6892702709ee
File content as of revision 71:562f5c702094:
#include "DS2465.hpp" #include "RomId.hpp" #include "mbed.h" #define I2C_WRITE 0 #define I2C_READ 1 // DS2465 commands #define CMD_1WMR 0xF0 #define CMD_WCFG 0xD2 #define CMD_CHSL 0xC3 #define CMD_SRP 0xE1 #define CMD_1WRS 0xB4 #define CMD_1WWB 0xA5 #define CMD_1WRB 0x96 #define CMD_1WSB 0x87 #define CMD_1WT 0x78 #define CMD_1WTB 0x69 #define CMD_1WRF 0xE1 #define CMD_CPS 0x5A #define CMD_CSS 0x4B #define CMD_CSAM 0x3C #define CMD_CSWM 0x2D #define CMD_CNMS 0x1E #define CMD_SPR 0x0F // DS2465 status bits #define STATUS_1WB 0x01 #define STATUS_PPD 0x02 #define STATUS_SD 0x04 #define STATUS_LL 0x08 #define STATUS_RST 0x10 #define STATUS_SBR 0x20 #define STATUS_TSB 0x40 #define STATUS_DIR 0x80 static const int I2C_WRITE_OK = 0; std::uint8_t DS2465::Config::readByte() const { std::uint8_t config = 0; if (get1WS()) config |= 0x08; if (getSPU()) config |= 0x04; if (getPDN()) config |= 0x02; if (getAPU()) config |= 0x01; return config; } std::uint8_t DS2465::Config::writeByte() const { std::uint8_t config = readByte(); return ((~config << 4) | config); } void DS2465::Config::reset() { set1WS(false); setSPU(false); setPDN(false); setAPU(true); } DS2465::DS2465(I2C & I2C_interface, std::uint8_t I2C_address) : m_I2C_interface(I2C_interface), m_I2C_address(I2C_address) { } OneWireMaster::CmdResult DS2465::OWInitMaster() { OneWireMaster::CmdResult result; // reset DS2465 result = reset(); if (result != OneWireMaster::Success) return result; // write the default configuration setup Config defaultConfig; result = writeConfig(defaultConfig, true); return result; } OneWireMaster::CmdResult DS2465::computeNextMasterSecret(bool swap, unsigned int pageNum, PageRegion region) { std::uint8_t command[2] = { CMD_CNMS, (std::uint8_t)(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) }; return writeMemory(ADDR_CMD_REG, command, 2); } OneWireMaster::CmdResult DS2465::computeWriteMac(bool regwrite, bool swap, unsigned int pageNum, unsigned int segmentNum) const { std::uint8_t command[2] = { CMD_CSWM, (std::uint8_t)((regwrite << 7) | (swap << 6) | (pageNum << 4) | segmentNum) }; return cWriteMemory(ADDR_CMD_REG, command, 2); } OneWireMaster::CmdResult DS2465::computeAuthMac(bool swap, unsigned int pageNum, PageRegion region) const { std::uint8_t command[2] = { CMD_CSAM, (std::uint8_t)(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) }; return cWriteMemory(ADDR_CMD_REG, command, 2); } OneWireMaster::CmdResult DS2465::computeSlaveSecret(bool swap, unsigned int pageNum, PageRegion region) { std::uint8_t command[2] = { CMD_CSS, (std::uint8_t)(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) }; return writeMemory(ADDR_CMD_REG, command, 2); } ISha256MacCoprocessor::CmdResult DS2465::setMasterSecret(const Secret & masterSecret) { OneWireMaster::CmdResult result; result = writeMemory(ADDR_SPAD, masterSecret, masterSecret.length); if (result == OneWireMaster::Success) result = copyScratchpadToSecret(); if (result == OneWireMaster::Success) wait_ms(eepromPageWriteDelayMs); return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } ISha256MacCoprocessor::CmdResult DS2465::computeWriteMac(const WriteMacData & writeMacData, Mac & mac) const { OneWireMaster::CmdResult result; // Write input data to scratchpad result = writeScratchpad(writeMacData, writeMacData.length); // Compute MAC if (result == OneWireMaster::Success) result = computeWriteMac(false); if (result == OneWireMaster::Success) { wait_ms(shaComputationDelayMs); // Read MAC from register result = readMemory(ADDR_MAC_READ, mac, mac.length, true); } return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } ISha256MacCoprocessor::CmdResult DS2465::computeAuthMac(const DevicePage & devicePage, const DeviceScratchpad & challenge, const AuthMacData & authMacData, Mac & mac) const { OneWireMaster::CmdResult result; int addr = ADDR_SPAD; // Write input data to scratchpad result = cWriteMemory(addr, devicePage, devicePage.length); if (result == OneWireMaster::Success) { addr += devicePage.length; result = cWriteMemory(addr, challenge, challenge.length); } if (result == OneWireMaster::Success) { addr += challenge.length; result = cWriteMemory(addr, authMacData, authMacData.length); } // Compute MAC if (result == OneWireMaster::Success) result = computeAuthMac(); if (result == OneWireMaster::Success) { wait_ms(shaComputationDelayMs * 2); // Read MAC from register result = readMemory(ADDR_MAC_READ, mac, mac.length, true); } return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } ISha256MacCoprocessor::CmdResult DS2465::computeSlaveSecret(const DevicePage & devicePage, const DeviceScratchpad & deviceScratchpad, const SlaveSecretData & slaveSecretData) { OneWireMaster::CmdResult result; int addr = ADDR_SPAD; // Write input data to scratchpad result = writeMemory(addr, devicePage, devicePage.length); if (result == OneWireMaster::Success) { addr += devicePage.length; result = writeMemory(addr, deviceScratchpad, deviceScratchpad.length); } if (result == OneWireMaster::Success) { addr += deviceScratchpad.length; result = writeMemory(addr, slaveSecretData, slaveSecretData.length); } // Compute secret if (result == OneWireMaster::Success) result = computeSlaveSecret(); if (result == OneWireMaster::Success) wait_ms(shaComputationDelayMs * 2); return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } OneWireMaster::CmdResult DS2465::copyScratchpad(bool destSecret, unsigned int pageNum, bool notFull, unsigned int segmentNum) { std::uint8_t command[2] = { CMD_CPS, (std::uint8_t)(destSecret ? 0 : (0x80 | (pageNum << 4) | (notFull << 3) | segmentNum)) }; return writeMemory(ADDR_CMD_REG, command, 2); } OneWireMaster::CmdResult DS2465::configureLevel(OWLevel level) { OneWireMaster::CmdResult result; if (m_curConfig.getSPU() != (level == LEVEL_STRONG)) { Config newConfig = m_curConfig; newConfig.setSPU(level == LEVEL_STRONG); result = writeConfig(newConfig, true); } else { result = OneWireMaster::Success; } return result; } OneWireMaster::CmdResult DS2465::OWSetLevel(OWLevel new_level) { if (new_level == LEVEL_STRONG) return OneWireMaster::OperationFailure; return configureLevel(new_level); } OneWireMaster::CmdResult DS2465::OWSetSpeed(OWSpeed new_speed) { // Requested speed is already set if (m_curConfig.get1WS() == (new_speed == SPEED_OVERDRIVE)) return OneWireMaster::Success; // set the speed Config newConfig = m_curConfig; newConfig.set1WS(new_speed == SPEED_OVERDRIVE); // write the new config return writeConfig(newConfig, true); } OneWireMaster::CmdResult DS2465::OWTriplet(SearchDirection & search_direction, std::uint8_t & sbr, std::uint8_t & tsb) { // 1-Wire Triplet (Case B) // S AD,0 [A] 1WT [A] SS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ // Repeat until 1WB bit has changed to 0 // [] indicates from slave // SS indicates byte containing search direction bit value in msbit OneWireMaster::CmdResult result; std::uint8_t command[2] = { CMD_1WT, (std::uint8_t)((search_direction == DIRECTION_WRITE_ONE) ? 0x80 : 0x00) }; result = writeMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) { std::uint8_t status; result = pollBusy(&status); if (result == OneWireMaster::Success) { // check bit results in status byte sbr = ((status & STATUS_SBR) == STATUS_SBR); tsb = ((status & STATUS_TSB) == STATUS_TSB); search_direction = ((status & STATUS_DIR) == STATUS_DIR) ? DIRECTION_WRITE_ONE : DIRECTION_WRITE_ZERO; } } return result; } OneWireMaster::CmdResult DS2465::OWReadBlock(std::uint8_t *rx_buf, std::uint8_t rx_len) { // 1-Wire Receive Block (Case A) // S AD,0 [A] ADDR_CMD_REG [A] 1WRF [A] PR [A] P // [] indicates from slave // PR indicates byte containing parameter OneWireMaster::CmdResult result; std::uint8_t command[2] = { CMD_1WRF, rx_len }; result = writeMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = pollBusy(); if (result == OneWireMaster::Success) result = readMemory(ADDR_SPAD, rx_buf, rx_len, false); return result; } OneWireMaster::CmdResult DS2465::OWWriteBlock(const std::uint8_t *tran_buf, std::uint8_t tran_len) { return OWWriteBlock(false, tran_buf, tran_len); } OneWireMaster::CmdResult DS2465::OWWriteBlockMac() { return OWWriteBlock(true, NULL, 0); } OneWireMaster::CmdResult DS2465::OWWriteBlock(bool tx_mac, const std::uint8_t *tran_buf, std::uint8_t tran_len) { OneWireMaster::CmdResult result; std::uint8_t command[2] = { CMD_1WTB, (std::uint8_t)(tx_mac ? 0xFF : tran_len) }; if (!tx_mac) { // prefill scratchpad with required data result = writeMemory(ADDR_SPAD, tran_buf, tran_len); if (result != OneWireMaster::Success) return result; } // 1-Wire Transmit Block (Case A) // S AD,0 [A] ADDR_CMD_REG [A] 1WTB [A] PR [A] P // [] indicates from slave // PR indicates byte containing parameter result = writeMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = pollBusy(); return result; } OneWireMaster::CmdResult DS2465::OWReadByte(std::uint8_t & recvbyte, OWLevel after_level) { // 1-Wire Read Bytes (Case C) // S AD,0 [A] ADDR_CMD_REG [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A // \--------/ // Repeat until 1WB bit has changed to 0 // Sr AD,0 [A] SRP [A] E1 [A] Sr AD,1 [A] DD A\ P // // [] indicates from slave // DD data read OneWireMaster::CmdResult result; std::uint8_t buf; result = configureLevel(after_level); if (result != OneWireMaster::Success) return result; buf = CMD_1WRB; result = writeMemory(ADDR_CMD_REG, &buf, 1); if (result == OneWireMaster::Success) result = pollBusy(); if (result == OneWireMaster::Success) result = readMemory(ADDR_DATA_REG, &buf, 1); if (result == OneWireMaster::Success) recvbyte = buf; return result; } OneWireMaster::CmdResult DS2465::OWWriteByte(std::uint8_t sendbyte, OWLevel after_level) { // 1-Wire Write Byte (Case B) // S AD,0 [A] ADDR_CMD_REG [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ // Repeat until 1WB bit has changed to 0 // [] indicates from slave // DD data to write OneWireMaster::CmdResult result; result = configureLevel(after_level); if (result != OneWireMaster::Success) return result; std::uint8_t command[2] = { CMD_1WWB, sendbyte }; result = writeMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = pollBusy(); return result; } OneWireMaster::CmdResult DS2465::OWTouchBit(std::uint8_t & sendrecvbit, OWLevel after_level) { // 1-Wire bit (Case B) // S AD,0 [A] ADDR_CMD_REG [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ // Repeat until 1WB bit has changed to 0 // [] indicates from slave // BB indicates byte containing bit value in msbit OneWireMaster::CmdResult result; result = configureLevel(after_level); if (result != OneWireMaster::Success) return result; std::uint8_t command[2] = { CMD_1WSB, (std::uint8_t)(sendrecvbit ? 0x80 : 0x00) }; std::uint8_t status; result = writeMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = pollBusy(&status); if (result == OneWireMaster::Success) sendrecvbit = (status & STATUS_SBR); return result; } OneWireMaster::CmdResult DS2465::cWriteMemory(std::uint8_t addr, const std::uint8_t * buf, std::size_t bufLen) const { int i; // Write SRAM (Case A) // S AD,0 [A] VSA [A] DD [A] P // \-----/ // Repeat for each data byte // [] indicates from slave // VSA valid SRAM memory address // DD memory data to write m_I2C_interface.start(); if (m_I2C_interface.write((m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } if (m_I2C_interface.write(addr) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } // loop to write each byte for (i = 0; i < bufLen; i++) { if (m_I2C_interface.write(buf[i]) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } } m_I2C_interface.stop(); return OneWireMaster::Success; } OneWireMaster::CmdResult DS2465::readMemory(std::uint8_t addr, std::uint8_t * buf, std::size_t bufLen, bool skipSetPointer) const { int i; // Read (Case A) // S AD,0 [A] MA [A] Sr AD,1 [A] [DD] A [DD] A\ P // \-----/ // Repeat for each data byte, NAK last byte // [] indicates from slave // MA memory address // DD memory data read m_I2C_interface.start(); if (!skipSetPointer) { if (m_I2C_interface.write((m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } if (m_I2C_interface.write(addr) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } m_I2C_interface.start(); } if (m_I2C_interface.write((m_I2C_address | I2C_READ)) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } // loop to read each byte, NAK last byte for (i = 0; i < bufLen; i++) { buf[i] = m_I2C_interface.read((i == (bufLen - 1)) ? I2C::NoACK : I2C::ACK); } m_I2C_interface.stop(); return OneWireMaster::Success; } OneWireMaster::CmdResult DS2465::writeConfig(const Config & config, bool verify) { std::uint8_t configBuf; OneWireMaster::CmdResult result; configBuf = config.writeByte(); result = writeMemory(ADDR_WCFG_REG, &configBuf, 1); if (verify) { if (result == OneWireMaster::Success) { result = readMemory(ADDR_WCFG_REG, &configBuf, 1); } if (result == OneWireMaster::Success) { if (configBuf != config.readByte()) result = OneWireMaster::OperationFailure; } } if (result == OneWireMaster::Success) m_curConfig = config; return result; } OneWireMaster::CmdResult DS2465::pollBusy(std::uint8_t * pStatus) { const unsigned int pollLimit = 200; OneWireMaster::CmdResult result; std::uint8_t status; unsigned int pollCount = 0; do { result = readMemory(ADDR_STATUS_REG, &status, 1, true); if (result != OneWireMaster::Success) return result; if (pStatus != NULL) *pStatus = status; if (pollCount++ >= pollLimit) return OneWireMaster::TimeoutError; } while (status & STATUS_1WB); return OneWireMaster::Success; } OneWireMaster::CmdResult DS2465::OWReset(void) { // 1-Wire reset (Case B) // S AD,0 [A] ADDR_CMD_REG [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ // Repeat until 1WB bit has changed to 0 // [] indicates from slave OneWireMaster::CmdResult result; std::uint8_t buf; buf = CMD_1WRS; result = writeMemory(ADDR_CMD_REG, &buf, 1); if (result == OneWireMaster::Success) result = pollBusy(&buf); if (result == OneWireMaster::Success) { // check for presence detect if ((buf & STATUS_PPD) != STATUS_PPD) result = OneWireMaster::OperationFailure; } return result; } OneWireMaster::CmdResult DS2465::reset(void) { // Device Reset // S AD,0 [A] ADDR_CMD_REG [A] 1WMR [A] Sr AD,1 [A] [SS] A\ P // [] indicates from slave // SS status byte to read to verify state OneWireMaster::CmdResult result; std::uint8_t buf; buf = CMD_1WMR; result = writeMemory(ADDR_CMD_REG, &buf, 1); if (result == OneWireMaster::Success) result = readMemory(ADDR_STATUS_REG, &buf, 1, true); if (result == OneWireMaster::Success) { if ((buf & 0xF7) != 0x10) result = OneWireMaster::OperationFailure; } if (result == OneWireMaster::Success) OWReset(); // do a command to get 1-Wire master reset out of holding state return result; }