/* Ian Fleet 2018
All files , software , schematics and designs are provided as - is with no warranty .
All files , software , schematics and designs are for experimental / hobby use .
Under no circumstances should any part be used for critical systems where safety ,
life or property depends upon it . You are responsible for all use .
You are free to use , modify , derive or otherwise extend for your own purposes
*/
// This example emulates a DS2413 device on an Arduino UNO or ATTINY85
// note : physical DS2413 devices found in 2018 are often clones with
// a device code different to the Maxim datasheet
# include "Arduino.h"
# include "OneWireSlave.h"
# include "comptime.h"
// This is the pin that will be used for one-wire data
// On Arduino Uno, you can use pin 2 or pin 3
Pin oneWireData ( 2 ) ; // PB2 only attiny85 pin with rising/falling interrupts
//Pin led(0);
// This sample emulates a DS2413 device , so we start by defining the available commands
const byte DS2413_FAMILY_ID = 0x3A ; // Maxim DS2413 device code
const byte CLONE_FAMILY_ID = 0x85 ; // clone device code
const byte DS2413_ACCESS_READ = 0xF5 ;
const byte DS2413_ACCESS_WRITE = 0x5A ;
const byte DS2413_ACK_SUCCESS = 0xAA ;
// generate unique id
const byte owROM [ 7 ] = { DS2413_FAMILY_ID , SERIAL_NUMBER } ;
// will be calculated in begin:---------------^^^^
// or use fixed id - make sure it doesn't conflict with another device
//const byte owROM[7] = { 0x3A, 0x00, 0x55, 0xAA, 0x00, 0x11, 0x22 };
# define PIOA 3 // (pin 3)
# define PIOB 4 // (pin 4)
uint8_t latch = 0 ;
uint8_t statusbyte1 = 0 ;
uint8_t statusbyte2 = 0 ;
enum DeviceState
{
DS_WaitingReset ,
DS_WaitingCommand ,
DS_WaitingStatus1 ,
DS_WaitingStatus2 ,
} ;
volatile DeviceState state = DS_WaitingReset ;
// scratchpad
volatile byte scratchpad [ 2 ] ;
volatile byte response [ 2 ] ;
// This function will be called each time the OneWire library has an event to notify (reset, error, byte received)
void owReceive ( OneWireSlave : : ReceiveEvent evt , byte data ) ;
//////////////////////////////////////////
void setup ( )
{
// led.outputMode();
// led.writeLow();
// OSCCAL = 85;
// Setup the OneWire library
OWSlave . setReceiveCallback ( & owReceive ) ;
OWSlave . begin ( owROM , oneWireData . getPinNumber ( ) ) ;
}
//////////////////////////////////////////
void loop ( )
{
delay ( 10 ) ;
cli ( ) ; //disable interrupts
// Be sure to not block interrupts for too long, OneWire timing is very tight for some operations. 1 or 2 microseconds (yes, microseconds, not milliseconds) can be too much depending on your master controller, but then it's equally unlikely that you block exactly at the moment where it matters.
// This can be mitigated by using error checking and retry in your high-level communication protocol. A good thing to do anyway.
sei ( ) ; //enable interrupts
}
//////////////////////////////////////////
static uint8_t getstatus ( ) {
uint8_t c = 0 ;
if ( latch & 0x01 ) c | = 0x02 ;
if ( digitalRead ( PIOA ) ) c | = 0x01 ;
if ( latch & 0x02 ) c | = 0x08 ;
if ( digitalRead ( PIOB ) ) c | = 0x04 ;
uint8_t x = ( ~ c ) < < 4 ;
return x + c ;
}
//////////////////////////////////////////
static void port ( int PIO , bool stat ) {
if ( stat ) {
digitalWrite ( PIO , HIGH ) ;
pinMode ( PIO , INPUT ) ;
} else {
pinMode ( PIO , OUTPUT ) ;
digitalWrite ( PIO , LOW ) ;
}
}
//////////////////////////////////////////
static void set ( uint8_t val ) {
latch = val ;
port ( PIOA , latch & 1 ) ;
port ( PIOB , latch & 2 ) ;
//TODO copy latch to EEPROM
}
//////////////////////////////////////////
void owReceive ( OneWireSlave : : ReceiveEvent evt , byte data )
{
switch ( evt )
{
case OneWireSlave : : RE_Byte :
switch ( state )
{
case DS_WaitingCommand :
switch ( data )
{
case DS2413_ACCESS_WRITE :
state = DS_WaitingStatus1 ;
break ;
case DS2413_ACCESS_READ :
state = DS_WaitingReset ;
scratchpad [ 0 ] = getstatus ( ) ;
OWSlave . beginWrite ( ( const byte * ) scratchpad , 1 , 0 ) ;
break ;
//case :
// break;
}
break ;
case DS_WaitingStatus1 :
statusbyte1 = data ;
state = DS_WaitingStatus2 ;
break ;
case DS_WaitingStatus2 :
statusbyte2 = data ;
if ( statusbyte1 ! = ~ statusbyte2 ) {
set ( statusbyte1 ) ;
response [ 0 ] = DS2413_ACK_SUCCESS ;
} else {
response [ 0 ] = 0x11 ; // mark error - real DS2413 does not do this
}
response [ 1 ] = getstatus ( ) ;
OWSlave . beginWrite ( ( const byte * ) response , 2 , 0 ) ;
state = DS_WaitingCommand ;
break ;
}
break ;
case OneWireSlave : : RE_Reset :
state = DS_WaitingCommand ;
break ;
case OneWireSlave : : RE_Error :
state = DS_WaitingReset ;
break ;
}
}