From c0a183c76988962c33f9aab63a0ba3b8fbcae638 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Mon, 27 Apr 2015 21:53:31 +0200 Subject: [PATCH] finished implementation of most important 1-wire functionalities --- LowLevel.h | 2 +- OneWireIO.ino | 42 +++++++++++++-- OneWireSlave.cpp | 134 ++++++++++++++++++++++++++++++++--------------- OneWireSlave.h | 26 +++++---- 4 files changed, 147 insertions(+), 57 deletions(-) diff --git a/LowLevel.h b/LowLevel.h index 3e695af..35ed948 100644 --- a/LowLevel.h +++ b/LowLevel.h @@ -71,8 +71,8 @@ class Pin { private: - IO_REG_TYPE mask_; volatile IO_REG_TYPE *reg_; + IO_REG_TYPE mask_; byte interruptNumber_; public: diff --git a/OneWireIO.ino b/OneWireIO.ino index aa70a0b..b3a9b16 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -12,11 +12,21 @@ Pin led(LEDPin); byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; +byte buffer1[8]; +byte buffer2[8]; +volatile byte* backBuffer = buffer1; +volatile byte bufferPos = 0; + +byte sendBuffer[8]; + +void owReceive(OneWireSlave::ReceiveEvent evt, byte data); + void setup() { led.outputMode(); led.writeLow(); + OneWire.setReceiveCallback(&owReceive); OneWire.begin(owROM, OWPin); Serial.begin(9600); @@ -34,15 +44,39 @@ void loop() cli();//disable interrupts SerialChannel::swap(); + byte* frontBuffer = (byte*)backBuffer; + byte frontBufferSize = bufferPos; + backBuffer = backBuffer == buffer1 ? buffer2 : buffer1; + bufferPos = 0; sei();//enable interrupts SerialChannel::flush(); - byte b; - if (OneWire.read(b)) + for (int i = 0; i < frontBufferSize; ++i) { - char msg[32]; - sprintf(msg, "Received byte : %d", (int)b); + char msg[16]; + sprintf(msg, "Received byte: %d", (int)frontBuffer[i]); debug.write(msg); + + if (frontBuffer[i] == 0x42) + { + sendBuffer[0] = 0xBA; + sendBuffer[1] = 0xAD; + sendBuffer[2] = 0xF0; + sendBuffer[3] = 0x0D; + OneWire.write(sendBuffer, 4, 0); + } + } +} + +void owReceive(OneWireSlave::ReceiveEvent evt, byte data) +{ + switch (evt) + { + case OneWireSlave::RE_Byte: + backBuffer[bufferPos++] = data; + break; + default: + ; } } diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index 965d349..ec1c55d 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -1,11 +1,20 @@ #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 @@ -37,18 +46,21 @@ 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::receivingBitPos_; -byte OneWireSlave::receiveTarget_; byte OneWireSlave::searchRomBytePos_; byte OneWireSlave::searchRomBitPos_; bool OneWireSlave::searchRomInverse_; -byte* OneWireSlave::receiveBytesBuffer_; -short OneWireSlave::receiveBytesLength_; +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 { @@ -101,19 +113,11 @@ void OneWireSlave::end() sei(); } -bool OneWireSlave::read(byte& b) -{ - return false; -} - -void OneWireSlave::setReceiveCallback(void(*callback)()) -{ - -} - 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) @@ -151,18 +155,25 @@ void OneWireSlave::disableTimer_() 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 - debug.append(message); + if (message == 0) + debug.append("unspecified error"); + else + debug.append(message); #endif beginWaitReset_(); } @@ -312,7 +323,7 @@ void OneWireSlave::waitReset_() { if (resetDuration > ResetMaxDuration) { - error_("Reset too long"); + ERROR("Reset too long"); onLeaveInterrupt_(); return; } @@ -320,6 +331,8 @@ void OneWireSlave::waitReset_() lastReset_ = now; pin_.detachInterrupt(); setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresence_); + if (clientReceiveCallback_ != 0) + clientReceiveCallback_(RE_Reset, 0); } } else @@ -353,14 +366,14 @@ void OneWireSlave::endPresence_() void OneWireSlave::beginWaitCommand_() { - receiveTarget_ = ReceiveCommand; + bufferPos_ = ReceiveCommand; beginReceive_(); } void OneWireSlave::beginReceive_() { receivingByte_ = 0; - receivingBitPos_ = 0; + bufferBitPos_ = 0; beginReceiveBit_(&OneWireSlave::onBitReceived_); } @@ -368,23 +381,23 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) { if (error) { - error_("Invalid bit"); - if (receiveTarget_ >= 0) + ERROR("Invalid bit"); + if (bufferPos_ >= 0) receiveBytesCallback_(true); return; } - receivingByte_ |= ((bit ? 1 : 0) << receivingBitPos_); - ++receivingBitPos_; + receivingByte_ |= ((bit ? 1 : 0) << bufferBitPos_); + ++bufferBitPos_; - if (receivingBitPos_ == 8) + if (bufferBitPos_ == 8) { #ifdef DEBUG_LOG debug.SC_APPEND_STR_INT("received byte", (long)receivingByte_); #endif - if (receiveTarget_ == ReceiveCommand) + if (bufferPos_ == ReceiveCommand) { - receiveTarget_ = 0; + bufferPos_ = 0; switch (receivingByte_) { case 0xF0: // SEARCH ROM @@ -402,16 +415,16 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) matchRomBytesReceived_(false); return; default: - error_("Unknown command"); + ERROR("Unknown command"); return; } } else { - receiveBytesBuffer_[receiveTarget_++] = receivingByte_; + buffer_[bufferPos_++] = receivingByte_; receivingByte_ = 0; - receivingBitPos_ = 0; - if (receiveTarget_ == receiveBytesLength_) + bufferBitPos_ = 0; + if (bufferPos_ == bufferLength_) { beginWaitReset_(); receiveBytesCallback_(false); @@ -445,7 +458,7 @@ void OneWireSlave::continueSearchRom_(bool error) { if (error) { - error_("Failed to send bit"); + ERROR("Failed to send bit"); return; } @@ -464,7 +477,7 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) { if (error) { - error_("Bit read error during ROM search"); + ERROR("Bit read error during ROM search"); return; } @@ -503,15 +516,48 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) void OneWireSlave::beginWriteBytes_(byte* data, short numBytes, void(*complete)(bool error)) { - // TODO - beginWaitReset_(); + 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)) { - receiveBytesBuffer_ = buffer; - receiveBytesLength_ = numBytes; - receiveTarget_ = 0; + buffer_ = buffer; + bufferLength_ = numBytes; + bufferPos_ = 0; receiveBytesCallback_ = complete; beginReceive_(); } @@ -519,14 +565,14 @@ void OneWireSlave::beginReceiveBytes_(byte* buffer, short numBytes, void(*comple void OneWireSlave::noOpCallback_(bool error) { if (error) - error_("error during an internal 1-wire operation"); + ERROR("error during an internal 1-wire operation"); } void OneWireSlave::matchRomBytesReceived_(bool error) { if (error) { - error_("error receiving match rom bytes"); + ERROR("error receiving match rom bytes"); return; } @@ -550,11 +596,13 @@ void OneWireSlave::notifyClientByteReceived_(bool error) { if (error) { - error_("error receiving device specific bytes"); + if (clientReceiveCallback_ != 0) + clientReceiveCallback_(RE_Error, 0); + ERROR("error receiving custom bytes"); return; } - beginWaitReset_(); - - // TODO + beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_); + if (clientReceiveCallback_ != 0) + clientReceiveCallback_(RE_Byte, scratchpad_[0]); } diff --git a/OneWireSlave.h b/OneWireSlave.h index a310c33..b1dbc94 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -7,17 +7,21 @@ class OneWireSlave { public: + enum ReceiveEvent + { + RE_Reset, //!< The master has sent a general reset + RE_Byte, //!< The master just sent a byte of data + RE_Error //!< A communication error happened (such as a timeout) ; the library will stop all 1-wire activities until the next reset + }; + //! Starts listening for the 1-wire master, on the specified pin, as a virtual slave device identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Reset, Presence, SearchRom and MatchRom are handled automatically. The library will use the external interrupt on the specified pin (note that this is usually not possible with all pins, depending on the board), as well as one hardware timer. Blocking interrupts (either by disabling them explicitely with sei/cli, or by spending time in another interrupt) can lead to malfunction of the library, due to tight timing for some 1-wire operations. void begin(byte* rom, byte pinNumber); //! Stops all 1-wire activities, which frees hardware resources for other purposes. void end(); - //! Pops one byte from the receive buffer, or returns false if no byte has been received. - bool read(byte& b); - - //! Sets (or replaces) a function to be called when at least one byte has been received. Callbacks are executed from interrupts and should be as short as possible. - void setReceiveCallback(void(*callback)()); + //! Sets (or replaces) a function to be called when something is received. The callback is executed from interrupts and should be as short as possible. Failure to return quickly can prevent the library from correctly reading the next byte. + void setReceiveCallback(void(*callback)(ReceiveEvent evt, byte data)) { clientReceiveCallback_ = callback; } //! Enqueues the specified bytes in the send buffer. They will be sent in the background. The optional callback is used to notify when the bytes are sent, or if an error occured. Callbacks are executed from interrupts and should be as short as possible. void write(byte* bytes, short numBytes, void(*complete)(bool error)); @@ -58,6 +62,7 @@ private: static void noOpCallback_(bool error); static void matchRomBytesReceived_(bool error); static void notifyClientByteReceived_(bool error); + static void bitSent_(bool error); // interrupt handlers static void waitReset_(); @@ -83,16 +88,19 @@ private: static void(*bitSentCallback_)(bool error); static byte receivingByte_; - static byte receivingBitPos_; - static byte receiveTarget_; static byte searchRomBytePos_; static byte searchRomBitPos_; static bool searchRomInverse_; - static byte* receiveBytesBuffer_; - static short receiveBytesLength_; + static byte* buffer_; + static short bufferLength_; + static short bufferPos_; + static byte bufferBitPos_; static void(*receiveBytesCallback_)(bool error); + static void(*sendBytesCallback_)(bool error); + + static void(*clientReceiveCallback_)(ReceiveEvent evt, byte data); }; extern OneWireSlave OneWire;