osd-contiki/examples/osd/arduino-dallaseprom/DallasEPROM.cpp
2017-02-01 11:26:50 +01:00

383 lines
8.3 KiB
C++

// Maxim/Dallas 1-Wire EPROM & EEPROM library for Arduino
// Copyright (C) 2011-2014 Eric Hokanson
// https://github.com/pceric
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
#include "DallasEPROM.h"
/** Supported chips. */
model_type _chip_model_list[] = {
// EPROMs
{ 0x09, "DS2502", 4, true },
{ 0x0B, "DS2505", 64, true },
// EEPROMs
{ 0x14, "DS2430", 1, false },
{ 0x2D, "DS2431", 4, false },
{ 0x23, "DS2433", 16, false },
{ 0, 0, 0, 0 }
};
DallasEPROM::DallasEPROM(OneWire* rWire) {
_wire = rWire;
_progPin = -1;
}
DallasEPROM::DallasEPROM(OneWire* rWire, int progPin) {
_wire = rWire;
_progPin = progPin;
pinMode(progPin, OUTPUT);
digitalWrite(progPin, LOW);
}
/*******************
* Static methods
*******************/
bool DallasEPROM::validAddress(uint8_t* deviceAddress) {
return (OneWire::crc8(deviceAddress, 7) == deviceAddress[7]);
}
bool DallasEPROM::isSupported(uint8_t* deviceAddress) {
int i = 0;
while (_chip_model_list[i].id) {
if (deviceAddress[0] == _chip_model_list[i].id)
return true;
++i;
}
return false;
}
/*******************
* Public methods
*******************/
bool DallasEPROM::search() {
int i;
_curModelIndex = -1;
if (!_wire->reset())
return false;
_wire->reset_search();
while (_wire->search(_addr)) {
i = 0;
while (_chip_model_list[i].id) {
if (_addr[0] == _chip_model_list[i].id) {
_curModelIndex = i;
return true;
}
++i;
}
}
return false;
}
uint8_t* DallasEPROM::getAddress() {
return _addr;
}
void DallasEPROM::setAddress(uint8_t* pAddress) {
int i = 0;
_curModelIndex = -1;
memcpy(_addr, pAddress, 8);
while (_chip_model_list[i].id) {
if (_addr[0] == _chip_model_list[i].id) {
_curModelIndex = i;
return;
}
++i;
}
}
const char* DallasEPROM::getDeviceName() {
if (_curModelIndex >= 0)
return _chip_model_list[_curModelIndex].name;
else
return NULL;
}
bool DallasEPROM::isConnected() {
uint8_t tmpAddress[8];
if (!_wire->reset())
return false;
_wire->reset_search();
while (_wire->search(tmpAddress)) {
if (memcmp(_addr, tmpAddress, 8)==0)
return true;
}
return false;
}
int DallasEPROM::readPage(uint8_t* data, int page) {
unsigned int address = page * 32;
if (!isPageValid(page))
return INVALID_PAGE;
if (!isConnected())
return DEVICE_DISCONNECTED;
// check for page redirection
if (isEPROMDevice()) {
byte command[] = { READSTATUS, (byte)(page+1), 0x00 };
byte new_addr;
_wire->reset();
_wire->select(_addr);
_wire->write(command[0]);
_wire->write(command[1]);
_wire->write(command[2]);
if (OneWire::crc8(command, 3) != _wire->read())
return CRC_MISMATCH;
if ((new_addr = _wire->read()) != 0xFF)
address = new_addr;
}
byte command[] = { READMEMORY, (byte) address, (byte)(address >> 8) };
// send the command and starting address
_wire->reset();
_wire->select(_addr);
_wire->write(command[0]);
_wire->write(command[1]);
_wire->write(command[2]);
// Check CRC on EPROM devices
if (isEPROMDevice() && OneWire::crc8(command, 3) != _wire->read())
return CRC_MISMATCH;
// Read the entire page
for (int i = 0; i < 32; i++) {
data[i] = _wire->read();
}
// TODO: On EPROM device you can check the CRC post read
return 0;
}
int DallasEPROM::writePage(uint8_t* data, int page) {
unsigned int address = page * 32;
if (!isPageValid(page))
return INVALID_PAGE;
if (!isConnected())
return DEVICE_DISCONNECTED;
// EEPROMS have a difference write method than EPROMS
if (!isEPROMDevice()) {
int status;
// a page is 4 8-byte scratch writes
for (int i = 0; i < 32; i += 8) {
if ((status = scratchWrite(&data[i], 8, address + i)))
return status;
}
return 0;
}
byte command[] = { WRITEMEMORY, (byte) address, (byte)(address >> 8),
data[0] };
// send the command, address, and the first byte
_wire->reset();
_wire->select(_addr);
_wire->write(command[0]);
_wire->write(command[1]);
_wire->write(command[2]);
_wire->write(command[3]);
// Check CRC
if (OneWire::crc8(command, 4) != _wire->read())
return CRC_MISMATCH;
// Issue programming pulse for the first byte
if (_progPin >= 0) {
digitalWrite(_progPin, HIGH);
delayMicroseconds(500);
digitalWrite(_progPin, LOW);
}
delayMicroseconds(500);
// Check the first byte for proper burn
if (command[3] != _wire->read())
return COPY_FAILURE;
// write out the rest of the page
for (int i = 1; i < 32; i++) {
// Write byte
_wire->write(data[i]);
// Check CRC
_wire->read(); // FIXME: The EPROM calculates a CRC based on 9 bits, we can't do that with OneWire
//byte crc[] = { (byte)((address+i) & 0x01), data[i] };
//if (OneWire::crc8(crc, 2) != _wire->read())
// return CRC_MISMATCH;
// Issue programming pulse
if (_progPin >= 0) {
digitalWrite(_progPin, HIGH);
delayMicroseconds(500);
digitalWrite(_progPin, LOW);
}
delayMicroseconds(500);
// Check for proper burn
if (data[i] != _wire->read())
return COPY_FAILURE;
}
return 0;
}
int DallasEPROM::lockPage(int page) {
if (!isPageValid(page))
return INVALID_PAGE;
if (!isConnected())
return DEVICE_DISCONNECTED;
_wire->reset();
_wire->select(_addr);
if (isEPROMDevice()) {
byte command[] = { WRITESTATUS, 0x00, 0x00, (1 << page) };
_wire->write(command[0]);
_wire->write(command[1]);
_wire->write(command[2]);
_wire->write(command[3]);
// Check CRC
if (OneWire::crc8(command, 4) != _wire->read())
return CRC_MISMATCH;
// Issue programming pulse
if (_progPin >= 0) {
digitalWrite(_progPin, HIGH);
delayMicroseconds(500);
digitalWrite(_progPin, LOW);
}
delayMicroseconds(500);
// TODO: Verify data
} else {
unsigned int start;
byte data[] = { 0x55 }; // write protect
start = _chip_model_list[_curModelIndex].pages * 32 + page;
scratchWrite(data, 1, start);
}
return 0;
}
bool DallasEPROM::isPageLocked(int page) {
byte status;
if (!isPageValid(page))
return INVALID_PAGE;
if (!isConnected())
return DEVICE_DISCONNECTED;
_wire->reset();
_wire->select(_addr);
if (isEPROMDevice()) {
byte command[] = { READSTATUS, 0x00, 0x00 };
_wire->write(command[0]);
_wire->write(command[1]);
_wire->write(command[2]);
// Check CRC on EPROM devices
if (OneWire::crc8(command, 3) != _wire->read())
return CRC_MISMATCH;
status = _wire->read();
_wire->reset();
return 1 & (status >> page);
} else {
unsigned int start;
start = _chip_model_list[_curModelIndex].pages * 32 + page;
_wire->write(READMEMORY);
_wire->write((byte)start);
_wire->write((byte)(start >> 8));
if (_wire->read() == 0x55)
return true;
else
return false;
}
}
/*******************
* Private methods
*******************/
int DallasEPROM::scratchWrite(uint8_t* data, int length, unsigned int address) {
byte auth[3];
// send the command and address
_wire->reset();
_wire->select(_addr);
_wire->write(WRITEMEMORY);
_wire->write((byte) address);
_wire->write((byte)(address >> 8));
// write "length" bytes to the scratchpad
for (int i = 0; i < length; i++)
_wire->write(data[i]);
// Read the auth code from the scratchpad and verify integrity
_wire->reset();
_wire->select(_addr);
_wire->write(READSTATUS);
_wire->read_bytes(auth, 3);
for (int i = 0; i < length; i++) {
if (_wire->read() != data[i])
return BAD_INTEGRITY;
}
// Issue copy scratchpad with auth bytes
_wire->reset();
_wire->select(_addr);
_wire->write(WRITESTATUS);
_wire->write(auth[0]);
_wire->write(auth[1]);
_wire->write(auth[2], 1);
// Need 10ms prog delay
delay(10);
_wire->depower();
// Check for success
if (_wire->read() != 0xAA)
return COPY_FAILURE;
return 0;
}
bool DallasEPROM::isPageValid(int page) {
if (_curModelIndex >= 0 && page < _chip_model_list[_curModelIndex].pages)
return true;
return false;
}
bool DallasEPROM::isEPROMDevice() {
if (_curModelIndex >= 0 && _chip_model_list[_curModelIndex].isEPROM == true)
return true;
return false;
}
/** @file */