1-Wire® library for mbed. Complete 1-Wire library that supports our silicon masters along with a bit-bang master on the MAX32600MBED platform with one common interface for mbed. Slave support has also been included and more slaves will be added as time permits.
Dependents: MAXREFDES131_Qt_Demo MAX32630FTHR_iButton_uSD_Logger MAX32630FTHR_DS18B20_uSD_Logger MAXREFDES130_131_Demo ... more
Superseded by MaximInterface.
Diff: OneWire_Masters/DS2465/DS2465.cpp
- Revision:
- 21:00c94aeb533e
- Child:
- 22:686273e55cdc
diff -r ba60c076e92b -r 00c94aeb533e OneWire_Masters/DS2465/DS2465.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWire_Masters/DS2465/DS2465.cpp Mon Mar 21 14:12:28 2016 -0500 @@ -0,0 +1,1769 @@ +#include "DS2465.hpp" + +#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 config bits +#define CONFIG_APU 0x01 +#define CONFIG_PDN 0x02 +#define CONFIG_SPU 0x04 +#define CONFIG_1WS 0x08 + +// 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 + +// delays (if not polling for complete) +#define EEPROM_WRITE_DELAY 30 +#define LOAD_SECRET_DELAY 90 +#define SHA_COMPUTATION_DELAY 5 + +static const int I2C_WRITE_OK = 0; + +DS2465::DS2465(I2C & I2C_interface, unsigned char I2C_address) + : m_I2C_interface(I2C_interface), m_I2C_address(I2C_address) +{ + +} + + + + +OneWireMaster::CmdResult DS2465::OWInitMaster() +{ + return Detect(); +} + + +//-------------------------------------------------------------------------- +// Compute Next Master Secret DS2465 +// +// 'swap' - 1 if swapping a page into the computation +// 'page' - page number to swap in +// 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page +// +// Returns: true write successful +// false failure to complete read +// +OneWireMaster::CmdResult DS2465::Compute_NextMasterSecret(bool swap, unsigned int pageNum, PageRegion region) +{ + uint8_t par; + + // create parameter byte + if (!swap) + par = 0xBF; + else + par = (0xC8 | (pageNum << 4) | region); + + return Write_Command_Reg(CMD_CNMS, par, false); +} + +//-------------------------------------------------------------------------- +// Compute Write MAC DS2465 +// +// 'regwrite' - true if writing to a register, false if regular memory +// 'swap' - true if swapping a page into the computation +// 'page' - page number to swap in +// 'segment' - segment number if swaping +// +// Returns: true write successful +// false failure to complete read +// +OneWireMaster::CmdResult DS2465::Compute_WriteMAC(bool regwrite, bool swap, unsigned int pageNum, unsigned int segmentNum) const +{ + uint8_t par; + + // create parameter byte + par = ((regwrite << 7) | (swap << 6) | (pageNum << 4) | segmentNum); + + return Write_Command_Reg(CMD_CSWM, par, false); +} + +//-------------------------------------------------------------------------- +// Compute Slave Authentication MAC DS2465 +// +// 'swap' - true if swapping a page into the computation +// 'page' - page number to swap in +// 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page +// +// Returns: true write successful +// false failure to complete read +// +OneWireMaster::CmdResult DS2465::Compute_AuthMAC(bool swap, unsigned int pageNum, PageRegion region) const +{ + uint8_t par; + + // create parameter byte + if (!swap) + par = 0xBF; + else + par = (0xC8 | (pageNum << 4) | region); + + return Write_Command_Reg(CMD_CSAM, par, false); +} + +//-------------------------------------------------------------------------- +// Compute S-Secret on DS2465 +// +// 'swap' - true if swapping a page into the computation +// 'page' - page number to swap in +// 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page +// +// Returns: true write successful +// false failure to complete read +// +OneWireMaster::CmdResult DS2465::Compute_SSecret(bool swap, unsigned int pageNum, PageRegion region) +{ + uint8_t par; + + // create parameter byte + if (!swap) + par = 0xBF; + else + par = (0xC8 | (pageNum << 4) | region); + + return Write_Command_Reg(CMD_CSS, par, false); +} + + + + +ISha256MacCoprocessor::CmdResult DS2465::setMasterSecret(const std::uint8_t (&secret)[secret_len]) +{ + OneWireMaster::CmdResult result; + result = WriteScratchpad(ADDR_SPAD, secret, secret_len); + if (result == OneWireMaster::Success) + result = CopyScratchpad(1, 0, 1, 0); + if (result == OneWireMaster::Success) + wait_ms(8 * EEPROM_WRITE_DELAY); + return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); +} + +ISha256MacCoprocessor::CmdResult DS2465::ComputeAndRead_WriteMAC(const std::uint8_t (&WriteMAC_data)[WriteMAC_data_len], std::uint8_t (&mac)[mac_len]) const +{ + OneWireMaster::CmdResult result; + // Write input data to scratchpad + result = WriteScratchpad(ADDR_SPAD, WriteMAC_data, WriteMAC_data_len); + // Compute MAC + if (result == OneWireMaster::Success) + result = Compute_WriteMAC(false, false, 0, 0); + if (result == OneWireMaster::Success) + { + wait_ms(SHA_COMPUTATION_DELAY); + // Read MAC from register + result = ReadMemory(ADDR_MAC_READ, mac, mac_len, true); + } + return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); +} + +ISha256MacCoprocessor::CmdResult DS2465::ComputeAndRead_AuthMAC(const std::uint8_t (&devicePage)[devicePage_len], const std::uint8_t (&challenge)[deviceScratchpad_len], + const std::uint8_t (&AuthMAC_data)[AuthMAC_data_len], std::uint8_t (&mac)[mac_len]) const +{ + OneWireMaster::CmdResult result; + int addr = ADDR_SPAD; + // Write input data to scratchpad + result = WriteScratchpad(addr, devicePage, devicePage_len); + if (result == OneWireMaster::Success) + { + addr += devicePage_len; + result = WriteScratchpad(addr, challenge, deviceScratchpad_len); + } + if (result == OneWireMaster::Success) + { + addr += deviceScratchpad_len; + result = WriteScratchpad(addr, AuthMAC_data, AuthMAC_data_len); + } + // Compute MAC + if (result == OneWireMaster::Success) + result = Compute_AuthMAC(false, 0, REGION_FULL_PAGE); + if (result == OneWireMaster::Success) + { + wait_ms(SHA_COMPUTATION_DELAY * 2); + // Read MAC from register + result = ReadMemory(ADDR_MAC_READ, mac, mac_len, true); + } + return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); +} + +ISha256MacCoprocessor::CmdResult DS2465::Compute_SSecret(const unsigned char (&devicePage)[devicePage_len], const unsigned char (&deviceScratchpad)[deviceScratchpad_len], + const unsigned char (&SSecret_data)[SSecret_data_len]) +{ + OneWireMaster::CmdResult result; + int addr = ADDR_SPAD; + // Write input data to scratchpad + result = WriteScratchpad(addr, devicePage, devicePage_len); + if (result == OneWireMaster::Success) + { + addr += devicePage_len; + result = WriteScratchpad(addr, deviceScratchpad, deviceScratchpad_len); + } + if (result == OneWireMaster::Success) + { + addr += deviceScratchpad_len; + result = WriteScratchpad(addr, SSecret_data, SSecret_data_len); + } + // Compute secret + if (result == OneWireMaster::Success) + result = Compute_SSecret(false, 0, REGION_FULL_PAGE); + if (result == OneWireMaster::Success) + wait_ms(SHA_COMPUTATION_DELAY * 2); + return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); +} + +//-------------------------------------------------------------------------- +// Copy Scratchpad on DS2465 to either secret or memory page +// +// 'dest_secret' - 1 if destination is secret, 0 if memory page +// 'page' - page number if dest_secret=0 +// 'notfull' - 0 if only 4 byte segment, 1 if writing to full page, +// 'seg' - Segment number if full=0. +// +// Returns: true write successful +// false failure to complete read +// +OneWireMaster::CmdResult DS2465::CopyScratchpad(bool dest_secret, unsigned int pageNum, bool notFull, unsigned int segmentNum) +{ + uint8_t par; + + // create parameter byte + if (dest_secret) + par = 0; + else + par = (0x80 | (pageNum << 4) | (notFull << 3) | segmentNum); + + return Write_Command_Reg(CMD_CPS, par, false); +} + +//-------------------------------------------------------------------------- +// APU enable or disable +// +// 'readflag' - 1 if reading current configuration +// 'apu_enable' - 1 to enable +// +// Returns: true if write successful, or return configuration value if reading +// +OneWireMaster::CmdResult DS2465::ConfigureAPU(bool apu_enable) +{ + // clear power down bit in the global config state + cAPU = apu_enable ? CONFIG_APU : 0; + + // write the new config + return Write_Config(c1WS | cSPU | cPDN | cAPU); +} + +//-------------------------------------------------------------------------- +// Power up 1-Wire using extended function +// +// Returns: true successful +// false failure during communication +// +OneWireMaster::CmdResult DS2465::OWPowerUp(void) +{ + OneWireMaster::CmdResult rt; + + // clear power down bit in the global config state + cPDN = 0; + + // write the new config + rt = Write_Config(c1WS | cSPU | cPDN | cAPU); + + // delay 2ms to allow units to power up + wait_ms(2); + + return rt; +} + +//-------------------------------------------------------------------------- +// Power down 1-Wire using extended function +// +// Returns: true successful +// false program voltage not available +// +OneWireMaster::CmdResult DS2465::OWPowerDown(void) +{ + // set power down bit in the global config state + cPDN = CONFIG_PDN; + + // write the new config + return Write_Config(c1WS | cSPU | cPDN | cAPU); +} + +//-------------------------------------------------------------------------- +// Send 1 bit of communication to the 1-Wire Net and verify that the +// response matches the 'applyPowerResponse' bit and apply power delivery +// to the 1-Wire net. Note that some implementations may apply the power +// first and then turn it off if the response is incorrect. +// +// 'applyPowerResponse' - 1 bit response to check, if correct then start +// power delivery +// +// Returns: true: bit written and response correct, strong pullup now on +// false: response incorrect +// +OneWireMaster::CmdResult DS2465::OWReadBitPower(uint8_t applyPowerResponse) +{ + OneWireMaster::CmdResult result; + uint8_t rdbit; + + // set strong pull-up enable + cSPU = CONFIG_SPU; + + // write the new config + result = Write_Config(c1WS | cSPU | cPDN | cAPU); + if (result != OneWireMaster::Success) + return result; + + // perform read bit + result = OWReadBit(rdbit); + if (result != OneWireMaster::Success) + return result; + + // check if response was correct, if not then turn off strong pull-up + if (rdbit != applyPowerResponse) + { + OWLevel(LEVEL_NORMAL); + return OneWireMaster::OperationFailure; + } + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// Read 8 bits of communication from the 1-Wire Net. After the +// 8 bits are read then change the level of the 1-Wire net. +// +// Returns: 8 bits read from 1-Wire Net +// +OneWireMaster::CmdResult DS2465::OWReadBytePower(uint8_t & recvbyte) +{ + OneWireMaster::CmdResult result; + + // set strong pull-up enable + cSPU = CONFIG_SPU; + + // write the new config + result = Write_Config(c1WS | cSPU | cPDN | cAPU); + if (result != OneWireMaster::Success) + return result; + + // do the read byte + result = OWReadByte(recvbyte); + return result; +} + +//-------------------------------------------------------------------------- +// Send 8 bits of communication to the 1-Wire Net and verify that the +// 8 bits read from the 1-Wire Net is the same (write operation). +// The parameter 'sendbyte' least significant 8 bits are used. After the +// 8 bits are sent change the level of the 1-Wire net. +// +// 'sendbyte' - 8 bits to send (least significant bit) +// +OneWireMaster::CmdResult DS2465::OWWriteBytePower(uint8_t sendbyte) +{ + OneWireMaster::CmdResult result; + + // set strong pull-up enable + cSPU = CONFIG_SPU; + + // write the new config + result = Write_Config(c1WS | cSPU | cPDN | cAPU); + if (result != OneWireMaster::Success) + return result; + + // perform write byte + return OWWriteByte(sendbyte); +} + +//-------------------------------------------------------------------------- +// Set the 1-Wire Net line level pull-up to normal. The DS2465 does only +// allows enabling strong pull-up on a bit or byte event. Consequently this +// function only allows the MODE_STANDARD argument. To enable strong pull-up +// use OWWriteBytePower or OWReadBitPower. +// +// 'new_level' - new level defined as +// MODE_STANDARD 0x00 +// +// Returns: current 1-Wire Net level +// +OneWireMaster::CmdResult DS2465::OWLevel(OW_LEVEL new_level) +{ + // function only will turn back to non-strong pull-up + if (new_level != LEVEL_NORMAL) + return OneWireMaster::OperationFailure; + + // clear the strong pull-up bit in the global config state + cSPU = 0; + + // write the new config + return Write_Config(c1WS | cSPU | cPDN | cAPU); +} + +//-------------------------------------------------------------------------- +// The 'OWOverdriveMatchROM' function does an overdrive Match-ROM using the +// global ROM_NO device +// +// Returns: true (1) : OWReset successful and match rom sent. +// false (0): OWReset did not have presence +// +OneWireMaster::CmdResult DS2465::OWOverdriveMatchROM(const RomId & romId) +{ + OneWireMaster::CmdResult result; + // use overdrive MatchROM + OWSpeed(SPEED_STANDARD); + result = OWReset(); + if (result == OneWireMaster::Success) + { + result = OWWriteByte(0x69); + if (result == OneWireMaster::Success) + { + OWSpeed(SPEED_OVERDRIVE); + // send ROM + result = OWWriteBlock(false, romId, RomId::byteLen); + } + } + return result; +} + +//-------------------------------------------------------------------------- +// The 'OWMatchROM' function does a Match-ROM using the global ROM_NO device +// +// Returns: true (1) : OWReset successful and match rom sent. +// false (0): OWReset did not have presence +// +OneWireMaster::CmdResult DS2465::OWMatchROM(const RomId & romId) +{ + OneWireMaster::CmdResult result; + uint8_t buf[1 + RomId::byteLen]; + + // use MatchROM + result = OWReset(); + if (result == OneWireMaster::Success) + { + buf[0] = 0x55; + std::memcpy(&buf[1], romId, RomId::byteLen); + // send command and rom + result = OWWriteBlock(false, buf, 1 + RomId::byteLen); + } + + return result; +} + +//-------------------------------------------------------------------------- +// Setup the search to skip the current device type on the next call +// to OWNext(). +// +void DS2465::OWFamilySkipSetup(void) +{ + // set the Last discrepancy to last family discrepancy + m_lastDiscrepancy = m_lastFamilyDiscrepancy; + + // clear the last family discrpepancy + m_lastFamilyDiscrepancy = 0; + + // check for end of list + if (m_lastDiscrepancy == 0) + m_lastDeviceFlag = true; +} + +//-------------------------------------------------------------------------- +// Setup the search to find the device type 'family_code' on the next call +// to OWNext() if it is present. +// +void DS2465::OWTargetSetup(RomId & romId) +{ + // set the search state to find SearchFamily type devices + for (int i = 1; i < 8; i++) + romId[i] = 0; + m_lastDiscrepancy = 64; + m_lastFamilyDiscrepancy = 0; + m_lastDeviceFlag = false; +} + +//-------------------------------------------------------------------------- +// Verify the device with the ROM number in ROM_NO buffer is present. +// Return true : device verified present +// false : device not present +// +OneWireMaster::CmdResult DS2465::OWVerify(const RomId & romId) +{ + OneWireMaster::CmdResult result; + RomId romIdCopy(romId); + int ld_backup, ldf_backup, lfd_backup; + + // keep a backup copy of the current state + ld_backup = m_lastDiscrepancy; + ldf_backup = m_lastDeviceFlag; + lfd_backup = m_lastFamilyDiscrepancy; + + // set search to find the same device + m_lastDiscrepancy = 64; + m_lastDeviceFlag = false; + + result = OWSearch(romIdCopy); + if (result == OneWireMaster::Success) + { + // check if same device found + if (romId != romIdCopy) + { + result = OneWireMaster::OperationFailure; + } + } + + // restore the search state + m_lastDiscrepancy = ld_backup; + m_lastDeviceFlag = ldf_backup; + m_lastFamilyDiscrepancy = lfd_backup; + + // return the result of the verify + return result; +} + +//-------------------------------------------------------------------------- +// Find the 'next' devices on the 1-Wire network +// Return true : device found, ROM number in ROM_NO buffer +// false : device not found, end of search +// +OneWireMaster::CmdResult DS2465::OWNext(RomId & romId) +{ + // leave the search state alone + return OWSearch(romId); +} + +//-------------------------------------------------------------------------- +// Set the 1-Wire Net communication speed. +// +// 'new_speed' - new speed defined as +// MODE_STANDARD 0x00 +// MODE_OVERDRIVE 0x01 +// +// Returns: current 1-Wire Net speed +// +OneWireMaster::CmdResult DS2465::OWSpeed(OW_SPEED new_speed) +{ + // set the speed + if (new_speed == SPEED_OVERDRIVE) + c1WS = CONFIG_1WS; + else + c1WS = 0; + + // write the new config + return Write_Config(c1WS | cSPU | cPDN | cAPU); +} + +//-------------------------------------------------------------------------- +// The 'OWOverdriveSkipROM' function does an Overdrive skip-ROM. Ignores +// result from standard speed OWReset(). +// +// Returns: true (1) : OWReset and skip rom sent. +// false (0): Could not change to overdrive +// +OneWireMaster::CmdResult DS2465::OWOverdriveSkipROM(void) +{ + OneWireMaster::CmdResult result = OWSpeed(SPEED_STANDARD); + if (result == OneWireMaster::Success) + result = OWReset(); + if (result == OneWireMaster::Success) + result = OWWriteByte(0x3C); + if (result == OneWireMaster::Success) + result = OWSpeed(SPEED_OVERDRIVE); + return result; +} + +//-------------------------------------------------------------------------- +// The 'OWResume' function does a Resume command 0xA5. +// +// Returns: true (1) : OWReset successful and RESUME sent. +// false (0): OWReset did not have presence +// +OneWireMaster::CmdResult DS2465::OWResume(void) +{ + OneWireMaster::CmdResult result; + result = OWReset(); + if (result == OneWireMaster::Success) + { + result = OWWriteByte(0xA5); + } + return result; +} + +//-------------------------------------------------------------------------- +// The 'OWSkipROM' function does a skip-ROM. This function +// uses the Skip-ROM function CCh. +// +// Returns: true (1) : OWReset successful and skip rom sent. +// false (0): OWReset did not have presence +// +OneWireMaster::CmdResult DS2465::OWSkipROM(void) +{ + OneWireMaster::CmdResult result; + result = OWReset(); + if (result == OneWireMaster::Success) + { + result = OWWriteByte(0xCC); + } + return result; +} + +//-------------------------------------------------------------------------- +// The 'OWReadROM' function does a Read-ROM. This function +// uses the read-ROM function 33h to read a ROM number and verify CRC8. +// +// Returns: true (1) : OWReset successful and Serial Number placed +// in the global ROM, CRC8 valid +// false (0): OWReset did not have presence or CRC8 invalid +// +OneWireMaster::CmdResult DS2465::OWReadROM(RomId & romId) +{ + OneWireMaster::CmdResult result; + uint8_t buf[2 + RomId::byteLen]; + + result = OWReset(); + if (result == OneWireMaster::Success) + result = OWWriteByte(0x33); // READ ROM + + // read the ROM + if (result == OneWireMaster::Success) + result = OWReadBlock(buf, RomId::byteLen); + + // verify CRC8 + if ((result == OneWireMaster::Success) && (RomId::calculateCRC8(buf, RomId::byteLen) == 0) && (buf[1] != 0)) + romId = RomId(reinterpret_cast<std::uint8_t (&)[RomId::byteLen]>(buf[0])); + + return result; +} + +//-------------------------------------------------------------------------- +// Use the DS2465 help command '1-Wire triplet' to perform one bit of a 1-Wire +// search. This command does two read bits and one write bit. The write bit +// is either the default direction (all device have same bit) or in case of +// a discripancy, the 'search_direction' parameter is used. +// +// Returns The DS2465 status byte result from the triplet command +// +OneWireMaster::CmdResult DS2465::Triplet(Direction search_direction, uint8_t & status) +{ + int poll_count = 0; + + // 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 + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WT) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write((unsigned char)((search_direction == DIRECTION_WRITE_ONE) ? 0x80 : 0x00)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + status = STATUS_1WB; + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + status = m_I2C_interface.read(status & STATUS_1WB); + } + + // one last read with NACK + m_I2C_interface.read(m_I2C_interface.NoACK); + + m_I2C_interface.stop(); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + Reset(); + return OneWireMaster::TimeoutError; + } + + // return status byte + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// The 'OWSearch' function does a general search. This function +// continues from the previos search state. The search state +// can be reset by using the 'OWFirst' function. +// This function contains one parameter 'alarm_only'. +// When 'alarm_only' is true (1) the find alarm command +// 0xEC is sent instead of the normal search command 0xF0. +// Using the find alarm command 0xEC will limit the search to only +// 1-Wire devices that are in an 'alarm' state. +// +// Returns: true (1) : when a 1-Wire device was found and it's +// Serial Number placed in the global ROM +// false (0): when no new device was found. Either the +// last search was the last device or there +// are no devices on the 1-Wire Net. +// +OneWireMaster::CmdResult DS2465::OWSearch(RomId & romId) +{ + int id_bit_number; + int last_zero, rom_byte_number; + int id_bit, cmp_id_bit; + unsigned char rom_byte_mask, status; + bool search_result; + unsigned char crc8 = 0; + Direction search_direction; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = false; + + // if the last call was not the last one + if (!m_lastDeviceFlag) + { + // 1-Wire reset + OneWireMaster::CmdResult result = OWReset(); + if (result != OneWireMaster::Success) + { + // reset the search + m_lastDiscrepancy = 0; + m_lastDeviceFlag = false; + m_lastFamilyDiscrepancy = 0; + return result; + } + + // issue the search command + OWWriteByte(0xF0); + + // loop to do the search + do + { + // if this discrepancy if before the Last Discrepancy + // on a previous next then pick the same as last time + if (id_bit_number < m_lastDiscrepancy) + { + if ((romId[rom_byte_number] & rom_byte_mask) > 0) + search_direction = DIRECTION_WRITE_ONE; + else + search_direction = DIRECTION_WRITE_ZERO; + } + else + { + // if equal to last pick 1, if not then pick 0 + if (id_bit_number == m_lastDiscrepancy) + search_direction = DIRECTION_WRITE_ONE; + else + search_direction = DIRECTION_WRITE_ZERO; + } + + // Peform a triple operation on the DS2465 which will perform 2 read bits and 1 write bit + Triplet(search_direction, status); + + // check bit results in status byte + id_bit = ((status & STATUS_SBR) == STATUS_SBR); + cmp_id_bit = ((status & STATUS_TSB) == STATUS_TSB); + search_direction = ((status & STATUS_DIR) == STATUS_DIR) ? DIRECTION_WRITE_ONE : DIRECTION_WRITE_ZERO; + + // check for no devices on 1-wire + if ((id_bit) && (cmp_id_bit)) + break; + else + { + if ((!id_bit) && (!cmp_id_bit) && (search_direction == DIRECTION_WRITE_ZERO)) + { + last_zero = id_bit_number; + + // check for Last discrepancy in family + if (last_zero < 9) + m_lastFamilyDiscrepancy = last_zero; + } + + // set or clear the bit in the ROM byte rom_byte_number + // with mask rom_byte_mask + if (search_direction == DIRECTION_WRITE_ONE) + romId[rom_byte_number] |= rom_byte_mask; + else + romId[rom_byte_number] &= (unsigned char)~rom_byte_mask; + + // increment the byte counter id_bit_number + // and shift the mask rom_byte_mask + id_bit_number++; + rom_byte_mask <<= 1; + + // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask + if (rom_byte_mask == 0) + { + crc8 = RomId::calculateCRC8(crc8, romId[rom_byte_number]); // accumulate the CRC + rom_byte_number++; + rom_byte_mask = 1; + } + } + } + while(rom_byte_number < RomId::byteLen); // loop until through all ROM bytes 0-7 + + // if the search was successful then + if (!((id_bit_number <= (RomId::byteLen * 8)) || (crc8 != 0))) + { + // search successful so set m_lastDiscrepancy,m_lastDeviceFlag,search_result + m_lastDiscrepancy = last_zero; + + // check for last device + if (m_lastDiscrepancy == 0) + m_lastDeviceFlag = true; + + search_result = true; + } + } + + // if no device found then reset counters so next 'search' will be like a first + if (!search_result || (romId.familyCode() == 0)) + { + m_lastDiscrepancy = 0; + m_lastDeviceFlag = false; + m_lastFamilyDiscrepancy = 0; + search_result = false; + } + + return search_result ? OneWireMaster::Success : OneWireMaster::OperationFailure; +} + +//-------------------------------------------------------------------------- +// Find the 'first' devices on the 1-Wire network +// Return true : device found, ROM number in ROM_NO buffer +// false : no device present +// +OneWireMaster::CmdResult DS2465::OWFirst(RomId & romId) +{ + // reset the search state + m_lastDiscrepancy = 0; + m_lastDeviceFlag = false; + m_lastFamilyDiscrepancy = 0; + + return OWSearch(romId); +} + +//-------------------------------------------------------------------------- +// The 'OWReadBlock' receives a block of data from the +// 1-Wire Net. The destination is the mac buffer (rx_mac=1) or +// the scratchpad (rx_mac=0). The result is buffer is returned. +// +// 'rx_buf' - pointer to a block to receive bytes +// of length 'rx_len' from 1-Wire Net +// 'rx_len' - length in bytes to read. Only valid numbers are 8,16,20,32; +// +OneWireMaster::CmdResult DS2465::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len) +{ + uint8_t status; + int poll_count = 0; + OneWireMaster::CmdResult result; + + // 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 + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WRF) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write((unsigned char)rx_len) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.stop(); + status = STATUS_1WB; + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + result = ReadMemory(ADDR_STATUS_REG, &status, 1, false); + if (result != OneWireMaster::Success) + return result; + } + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + result = ReadMemory(ADDR_SPAD, rx_buf, rx_len, false); + + // read out the data + return result; +} + + + + +OneWireMaster::CmdResult DS2465::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len) +{ + return OWWriteBlock(false, tran_buf, tran_len); +} + +//-------------------------------------------------------------------------- +// The 'OWWriteBlock' transfers a block of data to the +// 1-Wire Net. The mac buffer can be sent (tx_mac=1) or a +// portion of the scratchpad can be sent. +// +// 'tx_mac' - flag to indicate if the MAC buffer is to be sent (1) or +// the data provided in teh tran_buf is to be sent (0) +// 'tran_buf' - pointer to a block of bytes +// of length 'tran_len' that will be sent +// to the 1-Wire Net +// 'tran_len' - length in bytes to transfer. Only valid numbers are 8,16,20,32; +// +OneWireMaster::CmdResult DS2465::OWWriteBlock(bool tx_mac, const uint8_t *tran_buf, uint8_t tran_len) +{ + OneWireMaster::CmdResult result; + uint8_t par, status; + int poll_count = 0; + + // create parameter byte + if (tx_mac) + par = 0xFF; + else + { + // scratchpad is source + par = tran_len; + + // prefill scratchpad with required data + result = WriteScratchpad(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 + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WTB) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(par) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.stop(); + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + status = STATUS_1WB; + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + result = ReadMemory(ADDR_STATUS_REG, &status, 1, false); + if (result != OneWireMaster::Success) + return result; + } + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// The 'OWBlock' transfers a block of data to and from the +// 1-Wire Net. The result is returned in the same buffer. +// +// 'tran_buf' - pointer to a block of unsigned +// chars of length 'tran_len' that will be sent +// to the 1-Wire Net +// 'tran_len' - length in bytes to transfer +// +OneWireMaster::CmdResult DS2465::OWBlock(uint8_t *tran_buf, uint8_t tran_len) +{ + OneWireMaster::CmdResult result; + for (uint8_t i = 0; i < tran_len; i++) + { + result = OWTouchByte(tran_buf[i]); + if (result != OneWireMaster::Success) + break; + } + return result; +} + +//-------------------------------------------------------------------------- +// Send 8 bits of communication to the 1-Wire Net and return the +// result 8 bits read from the 1-Wire Net. The parameter 'sendbyte' +// least significant 8 bits are used and the least significant 8 bits +// of the result is the return byte. +// +// 'sendbyte' - 8 bits to send (least significant byte) +// +// Returns: 8 bits read from sendbyte +// +OneWireMaster::CmdResult DS2465::OWTouchByte(uint8_t & sendrecvbyte) +{ + OneWireMaster::CmdResult result = OWWriteByte(sendrecvbyte); + if (result == OneWireMaster::Success) + OWReadByte(sendrecvbyte); + return result; +} + +//-------------------------------------------------------------------------- +// Send 8 bits of read communication to the 1-Wire Net and return the +// result 8 bits read from the 1-Wire Net. +// +// Returns: 8 bits read from 1-Wire Net +// +OneWireMaster::CmdResult DS2465::OWReadByte(uint8_t & recvbyte) +{ + uint8_t status; + int poll_count = 0; + + // 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 + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WRB) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + return OneWireMaster::CommunicationWriteError; + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + status = STATUS_1WB; + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + status = m_I2C_interface.read(m_I2C_interface.ACK); + } + + // one last read with NACK + m_I2C_interface.read(m_I2C_interface.NoACK); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_DATA_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + recvbyte = m_I2C_interface.read(m_I2C_interface.NoACK); + + m_I2C_interface.stop(); + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// Send 8 bits of communication to the 1-Wire Net and verify that the +// 8 bits read from the 1-Wire Net is the same (write operation). +// The parameter 'sendbyte' least significant 8 bits are used. +// +// 'sendbyte' - 8 bits to send (least significant byte) +// +// Returns: true: bytes written and echo was the same +// false: echo was not the same +// +OneWireMaster::CmdResult DS2465::OWWriteByte(uint8_t sendbyte) +{ + uint8_t status; + int poll_count = 0; + + // 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 + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WWB) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(sendbyte) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + status = STATUS_1WB; + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + status = m_I2C_interface.read(m_I2C_interface.ACK); + } + + // one last read with NACK + m_I2C_interface.read(m_I2C_interface.NoACK); + + m_I2C_interface.stop(); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// Send 1 bit of communication to the 1-Wire Net and return the +// result 1 bit read from the 1-Wire Net. The parameter 'sendbit' +// least significant bit is used and the least significant bit +// of the result is the return bit. +// +// 'sendbit' - the least significant bit is the bit to send +// +// Returns: 0: 0 bit read from sendbit +// 1: 1 bit read from sendbit +// +OneWireMaster::CmdResult DS2465::OWTouchBit(uint8_t & sendrecvbit) +{ + unsigned char status; + int poll_count = 0; + + // 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 + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WSB) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(sendrecvbit ? 0x80 : 0x00) != 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 checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + status = STATUS_1WB; + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + status = m_I2C_interface.read(status & STATUS_1WB); + } + + // one last read with NACK + m_I2C_interface.read(m_I2C_interface.NoACK); + + m_I2C_interface.stop(); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + // check bit state + sendrecvbit = (status & STATUS_SBR); + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// Reads 1 bit of communication from the 1-Wire Net and returns the +// result +// +// Returns: 1 bit read from 1-Wire Net +// +OneWireMaster::CmdResult DS2465::OWReadBit(uint8_t & recvbit) +{ + recvbit = 0x01; + return OWTouchBit(recvbit); +} + +//-------------------------------------------------------------------------- +// Send 1 bit of communication to the 1-Wire Net. +// The parameter 'sendbit' least significant bit is used. +// +// 'sendbit' - 1 bit to send (least significant byte) +// +OneWireMaster::CmdResult DS2465::OWWriteBit(uint8_t sendbit) +{ + return OWTouchBit(sendbit); +} + +//-------------------------------------------------------------------------- +// +// +// +// +// +// +// +// Returns: +// +// +OneWireMaster::CmdResult DS2465::Write_Command_Reg(unsigned char cmd, unsigned char par, bool poll) const +{ + int poll_count = 0, status; + + // Generic command + // S AD,0 [A] ADDR_CMD_REG [A] CMD [A] PP [A] P + // [] indicates from slave + // CMD command + // PP parameter + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(cmd) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(par) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + m_I2C_interface.stop(); + + poll_count = 0; + if (poll) + { + // Poll for completion by checking for NAK on address + do + { + m_I2C_interface.start(); + status = m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)); + m_I2C_interface.stop(); + } while ((status != I2C_WRITE_OK) && (poll_count++ < POLL_LIMIT)); + } + else + { + // delay instead of poll, longest operation (only for SHA compute) + wait_ms(SHA_COMPUTATION_DELAY * 2); + wait_ms(8); // Additional delay + } + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// Write to Scratchpad (SRAM) memory on the DS2465 +// +// 'addr' - address to start writing (must be in SRAM) +// 'buf' - buffer of data to write +// 'len' - length to write +// +// Returns: true write successful +// false failure to complete write +// +OneWireMaster::CmdResult DS2465::WriteScratchpad(std::uint8_t addr, const std::uint8_t * buf, 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((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write((unsigned char)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; +} + +//-------------------------------------------------------------------------- +// Read memory from the DS2465 +// +// 'addr' - address to start reading +// 'buf' - buffer to hold memory read +// 'len' - length to read +// 'skip_set_pointer' - flag to indicate to skip setting address pointer +// +// Returns: true read successful +// false failure to complete read +// +OneWireMaster::CmdResult DS2465::ReadMemory(std::uint8_t addr, std::uint8_t * buf, size_t bufLen, bool skip_set_pointer) 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 (!skip_set_pointer) + { + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write((unsigned char)addr) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.start(); + } + + if (m_I2C_interface.write((unsigned char)(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)) ? m_I2C_interface.NoACK : m_I2C_interface.ACK); + } + m_I2C_interface.stop(); + + return OneWireMaster::Success; +} + + + + + +OneWireMaster::CmdResult DS2465::ReadOneWireConfig(OWConfigAddr addr, std::uint8_t & config) const +{ + std::uint8_t buf; + OneWireMaster::CmdResult result = ReadMemory(addr, &buf, 1, false); + if (result == OneWireMaster::Success) + config = buf; + return result; +} + + + + + +OneWireMaster::CmdResult DS2465::WriteOneWireConfig(OWConfigAddr addr, unsigned int ovr, unsigned int std) +{ + std::uint8_t buf; + + // convert and write value + buf = (ovr << 4) | std; + return (WriteScratchpad(addr, &buf, 1)); +} + +//-------------------------------------------------------------------------- +// Write the configuration register in the DS2465. The configuration +// options are provided in the lower nibble of the provided config byte. +// The uppper nibble in bitwise inverted when written to the DS2465. +// +// Returns: true: config written and response correct +// false: response incorrect +// +OneWireMaster::CmdResult DS2465::Write_Config(uint8_t config) +{ + unsigned char read_config; + + // Write configuration byte + // S AD,0 [A] ADDR_WCFG_REG [A] CONIG [A] P + // [] indicates from slave + // CF configuration byte to write + + m_I2C_interface.start(); + + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_WCFG_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write((unsigned char)(config | (~config << 4))) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.stop(); + + // read it back to confirm + // S AD,0 [A] ADDR_WCFG_REG [A] Sr AD,1 [A] [CF] A\ + + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_WCFG_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + read_config = m_I2C_interface.read(m_I2C_interface.NoACK); + m_I2C_interface.stop(); + + + // check for failure due to incorrect read back + if (config != read_config) + { + // handle error + // ... + //Reset(); + + return OneWireMaster::TimeoutError; + } + + return OneWireMaster::Success; +} + +//-------------------------------------------------------------------------- +// Reset all of the devices on the 1-Wire Net and return the result. +// +// Returns: true(1): presense pulse(s) detected, device(s) reset +// false(0): no presense pulses detected +// +OneWireMaster::CmdResult DS2465::OWReset(void) +{ + unsigned char status; + int poll_count = 0; + + // 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 + + m_I2C_interface.start(); + + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + if (m_I2C_interface.write(CMD_1WRS) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + m_I2C_interface.start(); + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + status = STATUS_1WB; + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)) + { + status = m_I2C_interface.read(m_I2C_interface.ACK); + } + + // one last read with NACK + m_I2C_interface.read(m_I2C_interface.NoACK); + + m_I2C_interface.stop(); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + //Reset(); + return OneWireMaster::TimeoutError; + } + + // check for short condition + if (status & STATUS_SD) + short_detected = true; + else + short_detected = false; + + + // check for presence detect + if (status & STATUS_PPD) + return OneWireMaster::Success; + // else + return OneWireMaster::OperationFailure; +} + +OneWireMaster::CmdResult DS2465::Reset(void) +{ + uint8_t status; + + // 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 + + m_I2C_interface.start(); + + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + if (m_I2C_interface.write(CMD_1WMR) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + m_I2C_interface.start(); + + if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) + { + m_I2C_interface.stop(); + return OneWireMaster::CommunicationWriteError; + } + + status = m_I2C_interface.read(m_I2C_interface.NoACK); + + m_I2C_interface.stop(); + + // do a command to get 1-Wire master reset out of holding state + OWReset(); + + // check for failure due to incorrect read back of status + return ((status & 0xF7) == 0x10) ? OneWireMaster::Success : OneWireMaster::OperationFailure; +} + +OneWireMaster::CmdResult DS2465::Detect(void) +{ + OneWireMaster::CmdResult result; + + // reset DS2465 + result = Reset(); + if (result != OneWireMaster::Success) + return result; + + // default configuration + c1WS = 0; + cSPU = 0; + cPDN = 0; + cAPU = CONFIG_APU; + + // write the default configuration setup + result = Write_Config(c1WS | cSPU | cPDN | cAPU); + return result; +}