# include "OneWireSlave.h"
# define DEBUG_LOG
# define ERROR_MESSAGES
# ifdef DEBUG_LOG
# include "SerialChannel.h"
extern SerialChannel debug ;
Pin dbgOutput ( 3 ) ;
# else
# undef ERROR_MESSAGES
# endif
# ifdef ERROR_MESSAGES
# define ERROR(msg) error_(msg)
# else
# define ERROR(msg) error_(0)
# endif
namespace
{
const unsigned long ResetMinDuration = 480 ;
const unsigned long ResetMaxDuration = 900 ;
const unsigned long PresenceWaitDuration = 30 ;
const unsigned long PresenceDuration = 300 ;
const unsigned long ReadBitSamplingTime = 25 ;
const unsigned long SendBitDuration = 35 ;
const byte ReceiveCommand = ( byte ) - 1 ;
void ( * timerEvent ) ( ) = 0 ;
}
OneWireSlave OneWire ;
byte OneWireSlave : : rom_ [ 8 ] ;
byte OneWireSlave : : scratchpad_ [ 8 ] ;
Pin OneWireSlave : : pin_ ;
byte OneWireSlave : : tccr1bEnable_ ;
unsigned long OneWireSlave : : resetStart_ ;
unsigned long OneWireSlave : : lastReset_ ;
void ( * OneWireSlave : : receiveBitCallback_ ) ( bool bit , bool error ) ;
void ( * OneWireSlave : : bitSentCallback_ ) ( bool error ) ;
void ( * OneWireSlave : : clientReceiveCallback_ ) ( ReceiveEvent evt , byte data ) ;
byte OneWireSlave : : receivingByte_ ;
byte OneWireSlave : : searchRomBytePos_ ;
byte OneWireSlave : : searchRomBitPos_ ;
bool OneWireSlave : : searchRomInverse_ ;
byte * OneWireSlave : : buffer_ ;
short OneWireSlave : : bufferLength_ ;
byte OneWireSlave : : bufferBitPos_ ;
short OneWireSlave : : bufferPos_ ;
void ( * OneWireSlave : : receiveBytesCallback_ ) ( bool error ) ;
void ( * OneWireSlave : : sendBytesCallback_ ) ( bool error ) ;
ISR ( TIMER1_COMPA_vect ) // timer1 interrupt
{
TCCR1B = 0 ; // disable clock
void ( * event ) ( ) = timerEvent ;
timerEvent = 0 ;
event ( ) ;
}
void OneWireSlave : : begin ( byte * rom , byte pinNumber )
{
pin_ = Pin ( pinNumber ) ;
resetStart_ = ( unsigned long ) - 1 ;
lastReset_ = 0 ;
memcpy ( rom_ , rom , 7 ) ;
rom_ [ 7 ] = crc8_ ( rom_ , 7 ) ;
# ifdef DEBUG_LOG
debug . append ( " Enabling 1-wire library " ) ;
dbgOutput . outputMode ( ) ;
dbgOutput . writeHigh ( ) ;
# endif
cli ( ) ; // disable interrupts
pin_ . inputMode ( ) ;
pin_ . writeLow ( ) ; // make sure the internal pull-up resistor is disabled
// prepare hardware timer
TCCR1A = 0 ;
TCCR1B = 0 ;
TIMSK1 | = ( 1 < < OCIE1A ) ; // enable timer compare interrupt
tccr1bEnable_ = ( 1 < < WGM12 ) | ( 1 < < CS11 ) | ( 1 < < CS10 ) ; // turn on CTC mode with 64 prescaler
// start 1-wire activity
beginWaitReset_ ( ) ;
sei ( ) ; // enable interrupts
}
void OneWireSlave : : end ( )
{
# ifdef DEBUG_LOG
debug . append ( " Disabling 1-wire library " ) ;
# endif
cli ( ) ;
disableTimer_ ( ) ;
pin_ . detachInterrupt ( ) ;
releaseBus_ ( ) ;
sei ( ) ;
}
void OneWireSlave : : write ( byte * bytes , short numBytes , void ( * complete ) ( bool error ) )
{
cli ( ) ;
beginWriteBytes_ ( bytes , numBytes , complete = = 0 ? noOpCallback_ : complete ) ;
sei ( ) ;
}
byte OneWireSlave : : crc8_ ( byte * data , short numBytes )
{
byte crc = 0 ;
while ( numBytes - - ) {
byte inbyte = * data + + ;
for ( byte i = 8 ; i ; i - - ) {
byte mix = ( crc ^ inbyte ) & 0x01 ;
crc > > = 1 ;
if ( mix ) crc ^ = 0x8C ;
inbyte > > = 1 ;
}
}
return crc ;
}
void OneWireSlave : : setTimerEvent_ ( short delayMicroSeconds , void ( * handler ) ( ) )
{
delayMicroSeconds - = 10 ; // remove overhead (tuned on Arduino Uno)
short skipTicks = ( delayMicroSeconds - 3 ) / 4 ; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.)
if ( skipTicks < 1 ) skipTicks = 1 ;
TCNT1 = 0 ;
OCR1A = skipTicks ;
timerEvent = handler ;
TCCR1B = tccr1bEnable_ ;
}
void OneWireSlave : : disableTimer_ ( )
{
TCCR1B = 0 ;
}
void OneWireSlave : : onEnterInterrupt_ ( )
{
# ifdef DEBUG_LOG
dbgOutput . writeLow ( ) ;
# endif
}
void OneWireSlave : : onLeaveInterrupt_ ( )
{
# ifdef DEBUG_LOG
dbgOutput . writeHigh ( ) ;
# endif
}
void OneWireSlave : : error_ ( const char * message )
{
# ifdef DEBUG_LOG
if ( message = = 0 )
debug . append ( " unspecified error " ) ;
else
debug . append ( message ) ;
# endif
beginWaitReset_ ( ) ;
}
void OneWireSlave : : pullLow_ ( )
{
pin_ . outputMode ( ) ;
pin_ . writeLow ( ) ;
# ifdef DEBUG_LOG
//dbgOutput.writeLow();
# endif
}
void OneWireSlave : : releaseBus_ ( )
{
pin_ . inputMode ( ) ;
# ifdef DEBUG_LOG
//dbgOutput.writeHigh();
# endif
}
void OneWireSlave : : beginResetDetection_ ( )
{
setTimerEvent_ ( ResetMinDuration - 50 , & OneWireSlave : : resetCheck_ ) ;
resetStart_ = micros ( ) - 50 ;
}
void OneWireSlave : : cancelResetDetection_ ( )
{
disableTimer_ ( ) ;
resetStart_ = ( unsigned long ) - 1 ;
}
void OneWireSlave : : resetCheck_ ( )
{
onEnterInterrupt_ ( ) ;
if ( ! pin_ . read ( ) )
{
pin_ . attachInterrupt ( & OneWireSlave : : waitReset_ , CHANGE ) ;
# ifdef DEBUG_LOG
debug . SC_APPEND_STR ( " Reset detected during another operation " ) ;
# endif
}
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : beginReceiveBit_ ( void ( * completeCallback ) ( bool bit , bool error ) )
{
receiveBitCallback_ = completeCallback ;
pin_ . attachInterrupt ( & OneWireSlave : : receive_ , FALLING ) ;
}
void OneWireSlave : : receive_ ( )
{
onEnterInterrupt_ ( ) ;
pin_ . detachInterrupt ( ) ;
setTimerEvent_ ( ReadBitSamplingTime , & OneWireSlave : : readBit_ ) ;
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : readBit_ ( )
{
onEnterInterrupt_ ( ) ;
bool bit = pin_ . read ( ) ;
if ( bit )
cancelResetDetection_ ( ) ;
else
beginResetDetection_ ( ) ;
receiveBitCallback_ ( bit , false ) ;
//dbgOutput.writeLow();
//dbgOutput.writeHigh();
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : beginSendBit_ ( bool bit , void ( * completeCallback ) ( bool error ) )
{
bitSentCallback_ = completeCallback ;
if ( bit )
{
pin_ . attachInterrupt ( & OneWireSlave : : sendBitOne_ , FALLING ) ;
}
else
{
pin_ . attachInterrupt ( & OneWireSlave : : sendBitZero_ , FALLING ) ;
}
}
void OneWireSlave : : sendBitOne_ ( )
{
onEnterInterrupt_ ( ) ;
beginResetDetection_ ( ) ;
bitSentCallback_ ( false ) ;
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : sendBitZero_ ( )
{
pullLow_ ( ) ; // this must be executed first because the timing is very tight with some master devices
onEnterInterrupt_ ( ) ;
pin_ . detachInterrupt ( ) ;
setTimerEvent_ ( SendBitDuration , & OneWireSlave : : endSendBitZero_ ) ;
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : endSendBitZero_ ( )
{
onEnterInterrupt_ ( ) ;
releaseBus_ ( ) ;
bitSentCallback_ ( false ) ;
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : beginWaitReset_ ( )
{
disableTimer_ ( ) ;
pin_ . attachInterrupt ( & OneWireSlave : : waitReset_ , CHANGE ) ;
resetStart_ = ( unsigned int ) - 1 ;
}
void OneWireSlave : : waitReset_ ( )
{
onEnterInterrupt_ ( ) ;
bool state = pin_ . read ( ) ;
unsigned long now = micros ( ) ;
if ( state )
{
if ( resetStart_ = = ( unsigned int ) - 1 )
{
onLeaveInterrupt_ ( ) ;
return ;
}
unsigned long resetDuration = now - resetStart_ ;
resetStart_ = ( unsigned int ) - 1 ;
if ( resetDuration > = ResetMinDuration )
{
if ( resetDuration > ResetMaxDuration )
{
ERROR ( " Reset too long " ) ;
onLeaveInterrupt_ ( ) ;
return ;
}
lastReset_ = now ;
pin_ . detachInterrupt ( ) ;
setTimerEvent_ ( PresenceWaitDuration - ( micros ( ) - now ) , & OneWireSlave : : beginPresence_ ) ;
if ( clientReceiveCallback_ ! = 0 )
clientReceiveCallback_ ( RE_Reset , 0 ) ;
}
}
else
{
resetStart_ = now ;
}
onLeaveInterrupt_ ( ) ;
}
void OneWireSlave : : beginPresence_ ( )
{
unsigned long now = micros ( ) ;
pullLow_ ( ) ;
setTimerEvent_ ( PresenceDuration , & OneWireSlave : : endPresence_ ) ;
# ifdef DEBUG_LOG
debug . SC_APPEND_STR_TIME ( " reset " , lastReset_ ) ;
debug . SC_APPEND_STR_TIME ( " beginPresence " , now ) ;
# endif
}
void OneWireSlave : : endPresence_ ( )
{
unsigned long now = micros ( ) ;
releaseBus_ ( ) ;
# ifdef DEBUG_LOG
debug . SC_APPEND_STR_TIME ( " endPresence " , now ) ;
# endif
beginWaitCommand_ ( ) ;
}
void OneWireSlave : : beginWaitCommand_ ( )
{
bufferPos_ = ReceiveCommand ;
beginReceive_ ( ) ;
}
void OneWireSlave : : beginReceive_ ( )
{
receivingByte_ = 0 ;
bufferBitPos_ = 0 ;
beginReceiveBit_ ( & OneWireSlave : : onBitReceived_ ) ;
}
void OneWireSlave : : onBitReceived_ ( bool bit , bool error )
{
if ( error )
{
ERROR ( " Invalid bit " ) ;
if ( bufferPos_ > = 0 )
receiveBytesCallback_ ( true ) ;
return ;
}
receivingByte_ | = ( ( bit ? 1 : 0 ) < < bufferBitPos_ ) ;
+ + bufferBitPos_ ;
if ( bufferBitPos_ = = 8 )
{
# ifdef DEBUG_LOG
debug . SC_APPEND_STR_INT ( " received byte " , ( long ) receivingByte_ ) ;
# endif
if ( bufferPos_ = = ReceiveCommand )
{
bufferPos_ = 0 ;
switch ( receivingByte_ )
{
case 0xF0 : // SEARCH ROM
beginSearchRom_ ( ) ;
return ;
case 0x33 : // READ ROM
beginWriteBytes_ ( rom_ , 8 , & OneWireSlave : : noOpCallback_ ) ;
return ;
case 0x55 : // MATCH ROM
beginReceiveBytes_ ( scratchpad_ , 8 , & OneWireSlave : : matchRomBytesReceived_ ) ;
return ;
case 0xCC : // SKIP ROM
// emulate a match rom operation
memcpy ( scratchpad_ , rom_ , 8 ) ;
matchRomBytesReceived_ ( false ) ;
return ;
default :
ERROR ( " Unknown command " ) ;
return ;
}
}
else
{
buffer_ [ bufferPos_ + + ] = receivingByte_ ;
receivingByte_ = 0 ;
bufferBitPos_ = 0 ;
if ( bufferPos_ = = bufferLength_ )
{
beginWaitReset_ ( ) ;
receiveBytesCallback_ ( false ) ;
return ;
}
}
}
beginReceiveBit_ ( & OneWireSlave : : onBitReceived_ ) ;
}
void OneWireSlave : : beginSearchRom_ ( )
{
searchRomBytePos_ = 0 ;
searchRomBitPos_ = 0 ;
searchRomInverse_ = false ;
beginSearchRomSendBit_ ( ) ;
}
void OneWireSlave : : beginSearchRomSendBit_ ( )
{
byte currentByte = rom_ [ searchRomBytePos_ ] ;
bool currentBit = bitRead ( currentByte , searchRomBitPos_ ) ;
bool bitToSend = searchRomInverse_ ? ! currentBit : currentBit ;
beginSendBit_ ( bitToSend , & OneWireSlave : : continueSearchRom_ ) ;
}
void OneWireSlave : : continueSearchRom_ ( bool error )
{
if ( error )
{
ERROR ( " Failed to send bit " ) ;
return ;
}
searchRomInverse_ = ! searchRomInverse_ ;
if ( searchRomInverse_ )
{
beginSearchRomSendBit_ ( ) ;
}
else
{
beginReceiveBit_ ( & OneWireSlave : : searchRomOnBitReceived_ ) ;
}
}
void OneWireSlave : : searchRomOnBitReceived_ ( bool bit , bool error )
{
if ( error )
{
ERROR ( " Bit read error during ROM search " ) ;
return ;
}
byte currentByte = rom_ [ searchRomBytePos_ ] ;
bool currentBit = bitRead ( currentByte , searchRomBitPos_ ) ;
if ( bit = = currentBit )
{
+ + searchRomBitPos_ ;
if ( searchRomBitPos_ = = 8 )
{
searchRomBitPos_ = 0 ;
+ + searchRomBytePos_ ;
}
if ( searchRomBytePos_ = = 8 )
{
# ifdef DEBUG_LOG
debug . SC_APPEND_STR ( " ROM sent entirely " ) ;
# endif
beginWaitReset_ ( ) ;
}
else
{
beginSearchRomSendBit_ ( ) ;
}
}
else
{
# ifdef DEBUG_LOG
debug . SC_APPEND_STR ( " Leaving ROM search " ) ;
# endif
beginWaitReset_ ( ) ;
}
}
void OneWireSlave : : beginWriteBytes_ ( byte * data , short numBytes , void ( * complete ) ( bool error ) )
{
buffer_ = data ;
bufferLength_ = numBytes ;
bufferPos_ = 0 ;
bufferBitPos_ = 0 ;
sendBytesCallback_ = complete ;
bool bit = bitRead ( buffer_ [ 0 ] , 0 ) ;
beginSendBit_ ( bit , & OneWireSlave : : bitSent_ ) ;
}
void OneWireSlave : : bitSent_ ( bool error )
{
if ( error )
{
ERROR ( " error sending a bit " ) ;
sendBytesCallback_ ( true ) ;
return ;
}
+ + bufferBitPos_ ;
if ( bufferBitPos_ = = 8 )
{
bufferBitPos_ = 0 ;
+ + bufferPos_ ;
}
if ( bufferPos_ = = bufferLength_ )
{
beginWaitReset_ ( ) ;
sendBytesCallback_ ( false ) ;
return ;
}
bool bit = bitRead ( buffer_ [ bufferPos_ ] , bufferBitPos_ ) ;
beginSendBit_ ( bit , & OneWireSlave : : bitSent_ ) ;
}
void OneWireSlave : : beginReceiveBytes_ ( byte * buffer , short numBytes , void ( * complete ) ( bool error ) )
{
buffer_ = buffer ;
bufferLength_ = numBytes ;
bufferPos_ = 0 ;
receiveBytesCallback_ = complete ;
beginReceive_ ( ) ;
}
void OneWireSlave : : noOpCallback_ ( bool error )
{
if ( error )
ERROR ( " error during an internal 1-wire operation " ) ;
}
void OneWireSlave : : matchRomBytesReceived_ ( bool error )
{
if ( error )
{
ERROR ( " error receiving match rom bytes " ) ;
return ;
}
if ( memcmp ( rom_ , scratchpad_ , 8 ) = = 0 )
{
# ifdef DEBUG_LOG
debug . SC_APPEND_STR ( " ROM matched " ) ;
# endif
beginReceiveBytes_ ( scratchpad_ , 1 , & OneWireSlave : : notifyClientByteReceived_ ) ;
}
else
{
# ifdef DEBUG_LOG
debug . SC_APPEND_STR ( " ROM not matched " ) ;
# endif
beginWaitReset_ ( ) ;
}
}
void OneWireSlave : : notifyClientByteReceived_ ( bool error )
{
if ( error )
{
if ( clientReceiveCallback_ ! = 0 )
clientReceiveCallback_ ( RE_Error , 0 ) ;
ERROR ( " error receiving custom bytes " ) ;
return ;
}
beginReceiveBytes_ ( scratchpad_ , 1 , & OneWireSlave : : notifyClientByteReceived_ ) ;
if ( clientReceiveCallback_ ! = 0 )
clientReceiveCallback_ ( RE_Byte , scratchpad_ [ 0 ] ) ;
}