diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 5dab1f40e6..0866a08dd5 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -5285,8 +5285,8 @@ inline void gcode_M121() { endstops.enable_globally(false); } uint8_t bytes = code_seen('B') ? code_value_byte() : 1; - if (i2c.addr > 0 && bytes > 0 && bytes <= 32) { - i2c.reqbytes(bytes); + if (i2c.addr && bytes && bytes <= TWIBUS_BUFFER_SIZE) { + i2c.relay(bytes); } else { SERIAL_ERROR_START; diff --git a/Marlin/twibus.cpp b/Marlin/twibus.cpp index ab04fa368b..bf17db3c28 100644 --- a/Marlin/twibus.cpp +++ b/Marlin/twibus.cpp @@ -86,32 +86,72 @@ void TWIBus::send() { this->reset(); } -void TWIBus::echodata(uint8_t bytes, const char prefix[], uint8_t adr) { +// static +void TWIBus::echoprefix(uint8_t bytes, const char prefix[], uint8_t adr) { SERIAL_ECHO_START; serialprintPGM(prefix); SERIAL_ECHOPAIR(": from:", adr); SERIAL_ECHOPAIR(" bytes:", bytes); SERIAL_ECHOPGM (" data:"); +} + +// static +void TWIBus::echodata(uint8_t bytes, const char prefix[], uint8_t adr) { + echoprefix(bytes, prefix, adr); while (bytes-- && Wire.available()) SERIAL_CHAR(Wire.read()); SERIAL_EOL; } -void TWIBus::reqbytes(const uint8_t bytes) { - if (!this->addr) return; +void TWIBus::echobuffer(const char prefix[], uint8_t adr) { + echoprefix(this->buffer_s, prefix, adr); + for (uint8_t i = 0; i < this->buffer_s; i++) SERIAL_CHAR(this->buffer[i]); + SERIAL_EOL; +} + +bool TWIBus::request(const uint8_t bytes) { + if (!this->addr) return false; #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("reqbytes"), bytes); + debug(PSTR("request"), bytes); #endif // requestFrom() is a blocking function Wire.requestFrom(this->addr, bytes); - // Wait until all bytes arrive, or timeout + // Wait for all bytes to arrive millis_t t = millis() + this->timeout; - while (Wire.available() < bytes && PENDING(millis(), t)) { /*nada*/ } + while (Wire.available() < bytes) + if (ELAPSED(millis(), t)) { + #if ENABLED(DEBUG_TWIBUS) + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("i2c timeout"); + #endif + return false; + } + + return true; +} + +void TWIBus::relay(const uint8_t bytes) { + #if ENABLED(DEBUG_TWIBUS) + debug(PSTR("relay"), bytes); + #endif + + if (this->request(bytes)) + echodata(bytes, PSTR("i2c-reply"), this->addr); +} + +uint8_t TWIBus::capture(char *dst, const uint8_t bytes) { + this->reset(); + uint8_t count = 0; + while (count < bytes && Wire.available()) + dst[count++] = Wire.read(); + return count; +} - // Simply echo the data to the bus - this->echodata(bytes, PSTR("i2c-reply"), this->addr); +// static +void TWIBus::flush() { + while (Wire.available()) Wire.read(); } #if I2C_SLAVE_ADDRESS > 0 @@ -120,7 +160,7 @@ void TWIBus::reqbytes(const uint8_t bytes) { #if ENABLED(DEBUG_TWIBUS) debug(PSTR("receive"), bytes); #endif - this->echodata(bytes, PSTR("i2c-receive"), 0); + echodata(bytes, PSTR("i2c-receive"), 0); } void TWIBus::reply(char str[]/*=NULL*/) { @@ -142,6 +182,7 @@ void TWIBus::reqbytes(const uint8_t bytes) { #if ENABLED(DEBUG_TWIBUS) + // static void TWIBus::prefix(const char func[]) { SERIAL_ECHOPGM("TWIBus::"); serialprintPGM(func); diff --git a/Marlin/twibus.h b/Marlin/twibus.h index 32928a8e15..d578a6d1fb 100644 --- a/Marlin/twibus.h +++ b/Marlin/twibus.h @@ -33,6 +33,8 @@ typedef void (*twiReceiveFunc_t)(int bytes); typedef void (*twiRequestFunc_t)(); +#define TWIBUS_BUFFER_SIZE 32 + /** * TWIBUS class * @@ -70,7 +72,7 @@ class TWIBus { * @brief Internal buffer * @details A fixed buffer. TWI commands can be no longer than this. */ - char buffer[32]; + char buffer[TWIBUS_BUFFER_SIZE]; public: @@ -134,6 +136,14 @@ class TWIBus { */ void address(const uint8_t adr); + /** + * @brief Prefix for echo to serial + * @details Echo a label, length, address, and "data:" + * + * @param bytes the number of bytes to request + */ + static void echoprefix(uint8_t bytes, const char prefix[], uint8_t adr); + /** * @brief Echo data on the bus to serial * @details Echo some number of bytes from the bus @@ -144,14 +154,48 @@ class TWIBus { static void echodata(uint8_t bytes, const char prefix[], uint8_t adr); /** - * @brief Request data from the slave device + * @brief Echo data in the buffer to serial + * @details Echo the entire buffer to serial + * to serial in a parser-friendly format. + * + * @param bytes the number of bytes to request + */ + void echobuffer(const char prefix[], uint8_t adr); + + /** + * @brief Request data from the slave device and wait. * @details Request a number of bytes from a slave device. - * This implementation simply sends the data to serial - * in a parser-friendly format. + * Wait for the data to arrive until the timeout + * interval expires. Return true on success. + * + * @param bytes the number of bytes to request + * @return status of the request: true=success, false=timeout + */ + bool request(const uint8_t bytes); + + /** + * @brief Capture data from the bus into the buffer. + * @details Capture data after a request has succeeded. + * + * @param bytes the number of bytes to request + * @return the number of bytes captured to the buffer + */ + uint8_t capture(char *dst, const uint8_t bytes); + + /** + * @brief Flush the i2c bus. + * @details Get all bytes on the bus and throw them away. + */ + static void flush(); + + /** + * @brief Request data from the slave device, echo to serial. + * @details Request a number of bytes from a slave device and output + * the returned data to serial in a parser-friendly format. * * @param bytes the number of bytes to request */ - void reqbytes(const uint8_t bytes); + void relay(const uint8_t bytes); #if I2C_SLAVE_ADDRESS > 0 @@ -181,6 +225,7 @@ class TWIBus { /** * @brief Send a reply to the bus * @details Send the buffer and clear it. + * If a string is passed, write it into the buffer first. */ void reply(char str[]=NULL); inline void reply(const char str[]) { this->reply((char*)str); }