From a1b60e00ae3b38d01361cf56c21ab87c0f913f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Wed, 21 Nov 2018 22:00:04 +0100 Subject: [PATCH 1/5] added proposal for I2C peer-to-peer communication (master/slave) examples --- .../Wire/examples/i2c-P2P-master/crc16.h | 209 +++++++++++++ .../i2c-P2P-master/i2c-P2P-master.ino | 271 +++++++++++++++++ .../examples/i2c-P2P-master/i2c-scanner.h | 43 +++ libraries/Wire/examples/i2c-P2P-slave/crc16.h | 209 +++++++++++++ .../examples/i2c-P2P-slave/i2c-P2P-slave.ino | 281 ++++++++++++++++++ 5 files changed, 1013 insertions(+) create mode 100644 libraries/Wire/examples/i2c-P2P-master/crc16.h create mode 100644 libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino create mode 100644 libraries/Wire/examples/i2c-P2P-master/i2c-scanner.h create mode 100644 libraries/Wire/examples/i2c-P2P-slave/crc16.h create mode 100644 libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino diff --git a/libraries/Wire/examples/i2c-P2P-master/crc16.h b/libraries/Wire/examples/i2c-P2P-master/crc16.h new file mode 100644 index 0000000000..1f2d724acf --- /dev/null +++ b/libraries/Wire/examples/i2c-P2P-master/crc16.h @@ -0,0 +1,209 @@ +//------------------------------------------------------------------------------------- +// CRC16 support class +// Based on various examples found on the web +// Copyright (C) 2014 Vincenzo Mennella (see license.txt) +// History +// 0.1.0 31/05/2014: First public code release +// 0.1.1 17/12/2014: Minor revision and commented code +// +// License +// "MIT Open Source Software License": +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in the +// Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +// and to permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//------------------------------------------------------------------------------------- +#ifndef CRC16_H +#define CRC16_H +#define LIBRARY_VERSION_CRC16_H "0.1.1" + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#elif defined(ARDUINO) +#include "WProgram.h" +#else +#include +#endif + +class Crc16 { +private: + //Crc parameters + uint16_t _msbMask; + uint16_t _mask; + uint16_t _xorIn; + uint16_t _xorOut; + uint16_t _polynomial; + uint8_t _reflectIn; + uint8_t _reflectOut; + //Crc value + uint16_t _crc; + uint8_t reflect(uint8_t data, uint8_t bits = 32); + +public: + inline Crc16() + { + //Default to XModem parameters + _reflectIn = false; + _reflectOut = false; + _polynomial = 0x1021; + _xorIn = 0x0000; + _xorOut = 0x0000; + _msbMask = 0x8000; + _mask = 0xFFFF; + _crc = _xorIn; + } + inline Crc16(uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask) + { + _reflectIn = reflectIn; + _reflectOut = reflectOut; + _polynomial = polynomial; + _xorIn = xorIn; + _xorOut = xorOut; + _msbMask = msbMask; + _mask = mask; + _crc = _xorIn; + } + inline void clearCrc(); + inline void updateCrc(uint8_t data); + inline uint16_t getCrc(); + inline unsigned int fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask); + inline unsigned int XModemCrc(uint8_t data[], uint8_t start, uint16_t length) + { + // XModem parameters: poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 + return fastCrc(data, start, length, false, false, 0x1021, 0x0000, 0x0000, 0x8000, 0xffff); + } +}; + +//--------------------------------------------------- +// Initialize crc calculation +//--------------------------------------------------- +void Crc16::clearCrc() +{ + _crc = _xorIn; +} +//--------------------------------------------------- +// Update crc with new data +//--------------------------------------------------- +void Crc16::updateCrc(uint8_t data) +{ + if (_reflectIn != 0) + data = (uint8_t) reflect(data, 8); + + int j = 0x80; + + while (j > 0) + { + uint16_t bit = (uint16_t)(_crc & _msbMask); + + _crc <<= 1; + + if ((data & j) != 0) + { + bit = (uint16_t)(bit ^ _msbMask); + } + + if (bit != 0) + { + _crc ^= _polynomial; + } + + j >>= 1; + } +} + +//--------------------------------------------------- +// Get final crc value +//--------------------------------------------------- +uint16_t Crc16::getCrc() +{ + if (_reflectOut != 0) + _crc = (unsigned int)((reflect(_crc) ^ _xorOut) & _mask); + + return _crc; +} + +//--------------------------------------------------- +// Calculate generic crc code on data array +// Examples of crc 16: +// Kermit: width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 +// Modbus: width=16 poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37 +// XModem: width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3 +// CCITT-False: width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 +//--------------------------------------------------- +unsigned int Crc16::fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask) +{ + unsigned int crc = xorIn; + + int j; + uint8_t c; + unsigned int bit; + + if (length == 0) return crc; + + for (int i = start; i < (start + length); i++) + { + c = data[i]; + + if (reflectIn != 0) + c = (uint8_t) reflect(c, 8); + + j = 0x80; + + while (j > 0) + { + bit = (unsigned int)(crc & msbMask); + crc <<= 1; + + if ((c & j) != 0) + { + bit = (unsigned int)(bit ^ msbMask); + } + + if (bit != 0) + { + crc ^= polynomial; + } + + j >>= 1; + } + } + + if (reflectOut != 0) + crc = (unsigned int)((reflect(crc) ^ xorOut) & mask); + + return crc; +} + +//------------------------------------------------------- +// Reflects bit in a uint8_t +//------------------------------------------------------- +uint8_t Crc16::reflect(uint8_t data, uint8_t bits) +{ + unsigned long reflection = 0x00000000; + // Reflect the data about the center bit. + for (uint8_t bit = 0; bit < bits; bit++) + { + // If the LSB bit is set, set the reflection of it. + if ((data & 0x01) != 0) + { + reflection |= (unsigned long)(1 << ((bits - 1) - bit)); + } + + data = (uint8_t)(data >> 1); + } + + return reflection; +} +#endif diff --git a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino new file mode 100644 index 0000000000..51fd40cf7a --- /dev/null +++ b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino @@ -0,0 +1,271 @@ +/* + * ESP8266 I2C master-slave communication, requires Arduno Core with I2C Slave Support (2.5.0+) + * + * Expects two ESP8266 devices with three pins connected: GND, SDA and SCL. This is master. + * Will send "MESA" messages to predefined slave address and then expect "PONG" response, + * or request to retransfer if message was misunderstood (e.g. CRC check failed). + * Message can be up to 26 bytes long (plus wrapper). + * + * 21-11-2018: initial drop by Matej Sychra (github.com/suculent) + */ + +#include + +#include "i2c-scanner.h" + +#define WIRE_SDA D1 +#define WIRE_SCL D2 + +#include "crc16.h" + +#define LED_PIN D4 + +const int16_t I2C_MASTER = 0x42; +const int16_t I2C_SLAVE = 0x08; + +int16_t slave_address = I2C_SLAVE; // may be overridden using scan() + +// Keep this structure in sync with the i2c-P2P-slave example. Should be in shared header. +struct MESSAGE_DATA { + uint8_t sequence; + uint16_t crc16; + uint8_t data[26]; + uint8_t terminator; +}; + +MESSAGE_DATA msgdata; +Crc16 crc; +bool expect_pong = false; +byte sequence = 0; +unsigned long next_ping = millis() + 1000; + +// analytics +uint16_t error_count = 0; +uint16_t byte_count = 0; + +// forward declarations +uint16_t calculateCRC16(uint8_t *data, size_t length); +void sendMessage(int seq, String msg); +MESSAGE_DATA encodeMessage(String bytes); +void receiveEvent(int howMany); +MESSAGE_DATA validateMessage(char* bytes_message); + +// + +// should be in shared header +uint16_t calculateCRC16(uint8_t *data, size_t length) { + crc.clearCrc(); + uint16_t value = (uint16_t)crc.XModemCrc(data,0,length); + Serial.print("crc = 0x"); Serial.println(value, HEX); + return value; +} + +// should be in shared header +MESSAGE_DATA encodeMessage(String bytes) { + + msgdata.terminator = '.'; + + int datasize = sizeof(msgdata.data); + Serial.print("\nEncoding data of size: "); + Serial.println(datasize); + + // Generate new data set for the struct + for (size_t i = 0; i < datasize; i++) { + if (bytes.length() >= i) { + msgdata.data[i] = bytes[i]; + } else { + msgdata.data[i] = '\0'; + } + Serial.print(msgdata.data[i]); + Serial.print(" "); + } + Serial.print('\n'); + msgdata.crc16 = calculateCRC16((uint8_t*) &msgdata.data[0], datasize); + //Serial.print("ENCODED Message CRC16: "); Serial.println(msgdata.crc16, HEX); + return msgdata; +} + +// should be in shared header +MESSAGE_DATA validateMessage(char* bytes_message) { + + MESSAGE_DATA tmp; + memcpy(&tmp, bytes_message, sizeof(tmp)); + + // Validate PROTOCOL terminator + if (tmp.terminator != '.') { + Serial.print("[ERROR] Terminator invalid: '"); + Serial.print(tmp.terminator); + Serial.println("'"); + return tmp; // should be nullptr // TODO: return error + } + + int datasize = sizeof(tmp.data); + Serial.print("Data of size: "); Serial.println(datasize); + + uint16_t data_crc = calculateCRC16((uint8_t*) &tmp.data[0], datasize); + + // Validate incoming data CRC against remote CRC + if (tmp.crc16 == data_crc) { + Serial.println("[OK] Data CRC valid."); + char inmsg[datasize]; + memcpy(inmsg, &tmp.data, datasize); + Serial.print("MASTER Incoming message: "); Serial.println(String(inmsg)); + } else { + Serial.print("CRC-A = 0x"); + Serial.println(tmp.crc16, HEX); + Serial.print("Incoming message CRC-B = 0x"); + Serial.println(data_crc, HEX); + Serial.print("tmp CRC16: "); + Serial.println(tmp.crc16, HEX); + Serial.println("[ERROR] Request retransfer exception."); + return tmp; + } + + // Validate sequence number + uint8_t remote_sequence = tmp.sequence; + if (remote_sequence < sequence - 1) { + Serial.print("[WARNING] TODO: Unexpected sequence number: "); + Serial.print(remote_sequence); + Serial.print(" while local is "); + Serial.println(sequence); // TODO: return error + } + + msgdata = tmp; // tmp is valid, assign to result address + + return tmp; + +} + +void sendMessage(int seq, String msg) { + + Serial.print("[MASTER] Sending message: "); + Serial.print(msg); + + if (msg.indexOf("MESA") == 0) { + expect_pong = true; + } else { + expect_pong = false; + } + + Wire.beginTransmission(I2C_SLAVE); // transmit to device 0x08 + //Sending Side + MESSAGE_DATA struct_data = encodeMessage(msg); + struct_data.sequence = seq; + char buf[sizeof(struct_data)]; + Serial.print(" of size "); + Serial.println(sizeof(struct_data)); + Serial.print("Encoding struct of size: "); Serial.println(sizeof(struct_data)); + memcpy(buf, &struct_data, sizeof(struct_data)); + for (int i = 0; i < sizeof(struct_data); i++) { + Wire.write(buf[i]); + Serial.print(buf[i]);Serial.print(" "); + } + Wire.endTransmission(); // stop transmitting + Serial.println(""); +} + +void receiveEvent(int howMany) { + + byte_count = byte_count + howMany; + + char incoming[howMany]; + incoming[howMany - 1] = '\0'; + int index = 0; + + digitalWrite(LED_PIN, LOW); + + // message duration may not exceed 100 ms (100 bytes, 3x buffer retransferred) + unsigned long rtimeout = millis() + 100; + while (millis() < rtimeout) { + // this must be fast, keep free from logging to serial here if possible + while (0 < Wire.available()) { // loop through all but the last + int c = Wire.read(); // receive byte as a character + if (index < howMany) { + incoming[index] = (char)c; // save the character + } + index++; + } + } + + Serial.println(); Serial.print("[MASTER] Received "); Serial.print(index); Serial.println(" bytes from SLAVE."); + //Serial.print("[MASTER] Local Sequence: "); Serial.println((int)sequence); + + MESSAGE_DATA message = validateMessage(incoming); + + char inmsg[sizeof(message.data)]; + memcpy(inmsg, &message.data, sizeof(message.data)); + if (inmsg[0] == 'R') { + String retransfer_command = String(inmsg); + retransfer_command.replace("R", ""); + int retransfer_offset = retransfer_command.toInt(); + Serial.println(sequence); + Serial.print("[MASTER] Retransfer request: "); + // dumb retransfer, only changes sequence number when expecting PONG + if (expect_pong) { + sequence = retransfer_offset + 1; + } else { + // debug only, WARNING! may loose important messages in production + sequence = retransfer_offset + 1; + } + Serial.println(sequence); + } else { + // Serial.print("[MASTER] Incoming message from SLAVE: "); Serial.println(String(inmsg)); + } + + String instring = String(inmsg); + if (instring.indexOf("PONG")) { + // alles kitz... + expect_pong = false; + } + + // Do something with the message... + + digitalWrite(LED_PIN, HIGH); +} + +void setup() { + + delay(2000); + + Wire.pins(WIRE_SDA, WIRE_SCL); + Wire.begin(I2C_MASTER); // join i2c bus (address optional for master) + Wire.onReceive(receiveEvent); + + Serial.begin(230400); // keep serial fast as possible for debug logging + while (!Serial); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + + slave_address = scan(); // useful with master/slave devices only on the bus +} + +unsigned long second_timer = millis() + 1000; + +void loop() { + + if (millis() > second_timer) { + Serial.print("Errors/Bytes: "); + Serial.print(error_count); + Serial.print("/"); + Serial.print(byte_count); + Serial.println(" per second"); + error_count = 0; + byte_count = 0; + second_timer = millis() + 1000; + } + + if (millis() > next_ping) { + digitalWrite(LED_PIN, LOW); + next_ping = millis() + 200; + Serial.print("[MASTER] Sequence » "); + Serial.println(sequence); + digitalWrite(LED_PIN, HIGH); + sendMessage(sequence, "MESA"); + if (expect_pong) { + error_count++; + } + expect_pong = true; + sequence++; + } + +} diff --git a/libraries/Wire/examples/i2c-P2P-master/i2c-scanner.h b/libraries/Wire/examples/i2c-P2P-master/i2c-scanner.h new file mode 100644 index 0000000000..987e87b66e --- /dev/null +++ b/libraries/Wire/examples/i2c-P2P-master/i2c-scanner.h @@ -0,0 +1,43 @@ +/* ESP8266 I2C master-slave communication, requires i2c_slave by bjoham */ + +#include + +int scan(uint16_t) { + byte error, address; + int nDevices; + int aDevice = 0; + + Serial.println("Scanning..."); + + nDevices = 0; + for (address = 1; address < 127; address++) { + Wire.beginTransmission(address); + error = Wire.endTransmission(); + + if (error == 0) { + Serial.print("I2C device found at address 0x"); + if (address < 16) { + Serial.print("0"); + } + Serial.print(address, HEX); + Serial.println(" !"); + nDevices++; + aDevice = address; + + } else if (error == 4) { + Serial.print("Unknown error at address 0x"); + if (address < 16) { + Serial.print("0"); + } + Serial.println(address, HEX); + } + } + + if (nDevices == 0) { + Serial.println("No I2C devices found\n"); + } else { + Serial.println("Done.\n"); + } + + return aDevice; +} diff --git a/libraries/Wire/examples/i2c-P2P-slave/crc16.h b/libraries/Wire/examples/i2c-P2P-slave/crc16.h new file mode 100644 index 0000000000..1f2d724acf --- /dev/null +++ b/libraries/Wire/examples/i2c-P2P-slave/crc16.h @@ -0,0 +1,209 @@ +//------------------------------------------------------------------------------------- +// CRC16 support class +// Based on various examples found on the web +// Copyright (C) 2014 Vincenzo Mennella (see license.txt) +// History +// 0.1.0 31/05/2014: First public code release +// 0.1.1 17/12/2014: Minor revision and commented code +// +// License +// "MIT Open Source Software License": +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in the +// Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +// and to permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//------------------------------------------------------------------------------------- +#ifndef CRC16_H +#define CRC16_H +#define LIBRARY_VERSION_CRC16_H "0.1.1" + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#elif defined(ARDUINO) +#include "WProgram.h" +#else +#include +#endif + +class Crc16 { +private: + //Crc parameters + uint16_t _msbMask; + uint16_t _mask; + uint16_t _xorIn; + uint16_t _xorOut; + uint16_t _polynomial; + uint8_t _reflectIn; + uint8_t _reflectOut; + //Crc value + uint16_t _crc; + uint8_t reflect(uint8_t data, uint8_t bits = 32); + +public: + inline Crc16() + { + //Default to XModem parameters + _reflectIn = false; + _reflectOut = false; + _polynomial = 0x1021; + _xorIn = 0x0000; + _xorOut = 0x0000; + _msbMask = 0x8000; + _mask = 0xFFFF; + _crc = _xorIn; + } + inline Crc16(uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask) + { + _reflectIn = reflectIn; + _reflectOut = reflectOut; + _polynomial = polynomial; + _xorIn = xorIn; + _xorOut = xorOut; + _msbMask = msbMask; + _mask = mask; + _crc = _xorIn; + } + inline void clearCrc(); + inline void updateCrc(uint8_t data); + inline uint16_t getCrc(); + inline unsigned int fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask); + inline unsigned int XModemCrc(uint8_t data[], uint8_t start, uint16_t length) + { + // XModem parameters: poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 + return fastCrc(data, start, length, false, false, 0x1021, 0x0000, 0x0000, 0x8000, 0xffff); + } +}; + +//--------------------------------------------------- +// Initialize crc calculation +//--------------------------------------------------- +void Crc16::clearCrc() +{ + _crc = _xorIn; +} +//--------------------------------------------------- +// Update crc with new data +//--------------------------------------------------- +void Crc16::updateCrc(uint8_t data) +{ + if (_reflectIn != 0) + data = (uint8_t) reflect(data, 8); + + int j = 0x80; + + while (j > 0) + { + uint16_t bit = (uint16_t)(_crc & _msbMask); + + _crc <<= 1; + + if ((data & j) != 0) + { + bit = (uint16_t)(bit ^ _msbMask); + } + + if (bit != 0) + { + _crc ^= _polynomial; + } + + j >>= 1; + } +} + +//--------------------------------------------------- +// Get final crc value +//--------------------------------------------------- +uint16_t Crc16::getCrc() +{ + if (_reflectOut != 0) + _crc = (unsigned int)((reflect(_crc) ^ _xorOut) & _mask); + + return _crc; +} + +//--------------------------------------------------- +// Calculate generic crc code on data array +// Examples of crc 16: +// Kermit: width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 +// Modbus: width=16 poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37 +// XModem: width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3 +// CCITT-False: width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 +//--------------------------------------------------- +unsigned int Crc16::fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask) +{ + unsigned int crc = xorIn; + + int j; + uint8_t c; + unsigned int bit; + + if (length == 0) return crc; + + for (int i = start; i < (start + length); i++) + { + c = data[i]; + + if (reflectIn != 0) + c = (uint8_t) reflect(c, 8); + + j = 0x80; + + while (j > 0) + { + bit = (unsigned int)(crc & msbMask); + crc <<= 1; + + if ((c & j) != 0) + { + bit = (unsigned int)(bit ^ msbMask); + } + + if (bit != 0) + { + crc ^= polynomial; + } + + j >>= 1; + } + } + + if (reflectOut != 0) + crc = (unsigned int)((reflect(crc) ^ xorOut) & mask); + + return crc; +} + +//------------------------------------------------------- +// Reflects bit in a uint8_t +//------------------------------------------------------- +uint8_t Crc16::reflect(uint8_t data, uint8_t bits) +{ + unsigned long reflection = 0x00000000; + // Reflect the data about the center bit. + for (uint8_t bit = 0; bit < bits; bit++) + { + // If the LSB bit is set, set the reflection of it. + if ((data & 0x01) != 0) + { + reflection |= (unsigned long)(1 << ((bits - 1) - bit)); + } + + data = (uint8_t)(data >> 1); + } + + return reflection; +} +#endif diff --git a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino new file mode 100644 index 0000000000..c9fc879938 --- /dev/null +++ b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino @@ -0,0 +1,281 @@ +/* + * ESP8266 I2C master-slave communication, requires Arduno Core with I2C Slave Support (2.5.0+) + * + * Expects two ESP8266 devices with three pins connected: GND, SDA and SCL. This is slave. + * Will wait for "MESA" message and then respond with "PONG" message, + * or request retransfer if message was misunderstood (e.g. CRC check failed). + * Message can be up to 26 bytes long (plus wrapper). + * + * 21-11-2018: initial drop by Matej Sychra (github.com/suculent) + */ + +#include + +#include "crc16.h" + +#define SDA_PIN D1 +#define SCL_PIN D2 +#define LED_PIN D4 + +const uint16_t I2C_ADDRESS = 0x08; +const uint16_t I2C_MASTER = 0x42; +uint16_t local_address = I2C_ADDRESS; // slave + +// Keep this structure in sync with the i2c-P2P-master example. Should be in shared header. +struct MESSAGE_DATA { + uint8_t sequence; + uint16_t crc16; + uint8_t data[26]; + uint8_t terminator; +}; + +MESSAGE_DATA message; +MESSAGE_DATA msgdata; + +Crc16 crc; +byte seq = 0; + +// forward declarations +uint16_t calculateCRC16(uint8_t *data, size_t length); +void sendEvent(int a, String msg); +void sendMessage(int seq, String msg); +void receiveEvent(int howMany); +MESSAGE_DATA validateMessage(char* bytes_message); + +// + +// should be in shared header +uint16_t calculateCRC16(uint8_t *data, size_t length) { + crc.clearCrc(); + unsigned short value = crc.XModemCrc(data, 0, length); + Serial.print("crc = 0x"); Serial.println(value, HEX); + return (uint16_t)value; +} + +void setup() { + + // Enable internal pullup (there's always one from the master side) + //digitalWrite(SDA_PIN, HIGH); + //digitalWrite(SCL_PIN, HIGH); + + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + Wire.pins(SDA_PIN, SCL_PIN); + Wire.begin(I2C_ADDRESS); // address required for slave + + Serial.begin(230400); + //while (!Serial); if you want to wait for first messages + + delay(2000); + digitalWrite(LED_PIN, HIGH); + + Wire.onReceive(receiveEvent); + + Serial.print("I2C Slave started on address: 0x0"); + Serial.println(I2C_ADDRESS, HEX); +} + +// should be in shared header +MESSAGE_DATA encodeMessage(String bytes) { + + msgdata.terminator = '.'; + + int datasize = sizeof(msgdata.data); + Serial.print("Encoding data of size: "); + Serial.println(datasize); + + // Generate new data set for the struct + for (size_t i = 0; i < datasize; i++) { + if (bytes.length() >= i) { + msgdata.data[i] = bytes[i]; + } else { + msgdata.data[i] = '\0'; + } + Serial.print(msgdata.data[i]); + Serial.print(" "); + } + Serial.println(); + msgdata.crc16 = calculateCRC16((uint8_t*) &msgdata.data[0], datasize); + Serial.print("Outgoing Message CRC16: "); Serial.println(msgdata.crc16, HEX); + return msgdata; +} + +// should be in shared header +MESSAGE_DATA validateMessage(char* bytes_message) { + + MESSAGE_DATA tmp; + memcpy(&tmp, bytes_message, sizeof(tmp)); + + // Validate terminator + if (tmp.terminator == '.') { + Serial.println("[OK] Terminator valid."); + } else { + Serial.print("[ERROR] Terminator invalid: '"); + Serial.print(tmp.terminator); + Serial.println("'"); + return tmp; + } + + int datasize = sizeof(tmp.data); + if (datasize != 28) { + Serial.print("Data of size: "); Serial.println(datasize); + if (datasize > 28) { + datasize == 28; + } + } + + // Calculate data CRC + uint16_t data_crc = calculateCRC16((uint8_t*) &tmp.data[0], sizeof(datasize)); + + // should be only when CRC is good like commented below + char inmsg[datasize]; + memcpy(inmsg, &tmp.data, datasize); + + // Validate incoming data CRC against remote CRC + if (tmp.crc16 == data_crc) { + Serial.println("[OK] Data CRC valid."); + Serial.print("SLAVE Incoming message: "); Serial.println(String(inmsg)); + } else { + Serial.print("CRC-A = 0x"); + Serial.println(tmp.crc16, HEX); + Serial.print("CRC-B = 0x"); + Serial.println(data_crc, HEX); + Serial.print("tmp CRC16: "); + Serial.println(tmp.crc16, HEX); + Serial.print("SLAVE Incoming message: "); Serial.println(String(inmsg)); + Serial.println("[ERROR] TODO: Request retransfer exception."); + return tmp; + } + + // Validate sequence number ( should be already updated from byteParser ) + uint8_t remote_sequence = tmp.sequence; + if (remote_sequence != seq) { + Serial.println((char*)tmp.data); + } + + msgdata = tmp; // tmp is valid, assign to result address + + return msgdata; + +} + +void receiveEvent(int howMany) { + + Serial.print("Received "); Serial.print(howMany); Serial.println(" bytes..."); + char c; + char chars[howMany]; + chars[howMany - 1] = '\0'; + int index = 0; + + Serial.print("Local Sequence: "); Serial.println((int)seq); + digitalWrite(LED_PIN, LOW); + + bool requestRetransfer = false; + + unsigned long rtimeout = millis() + 200; // skip 100ms timeouts + while (millis() < rtimeout) { + while (0 < Wire.available()) { // loop through all but the last + //digitalWrite(LED_PIN, LOW); + c = Wire.read(); + chars[index] = c; + //Serial.print(index); Serial.print(" : "); Serial.println((int)c); + Serial.print((int)c); + Serial.print(" "); + + // Parses first byte for sequence number, contains recovery logic... + if (index == 0) { + + Serial.print("Remote Sequence: "); Serial.println((int)c); + + if ( c!= seq && ((c > seq - 4) || (c < seq + 4)) && c != seq + 1) { + Serial.print("[DIFF] Sequence offset [!]: "); + Serial.println(c - seq); + Serial.print("Re-assigning sequence number: "); + Serial.println(seq); + seq = c; + requestRetransfer = true; + + } else if (c != seq + 1) { + + Serial.print("[+DIFF] Local Sequence: "); + Serial.println(seq); + Serial.print("[+DIFF] Sequence offset [!]: "); + Serial.println(c - seq); + requestRetransfer = true; + } + + if (seq == 0) { + Serial.print("Assigning sequence 0: "); + Serial.println(seq); + seq = c; + + } else if (c != seq + 1) { + Serial.print("Re-assigning sequence number: "); + Serial.println(seq); + seq = c; + } + seq = c; + + } // if 0 + + digitalWrite(LED_PIN, HIGH); + index++; + } // while + } // while + + Serial.println(String(chars)); + + if (requestRetransfer) { + String event = String("R") + String(seq) + String('\0'); + sendMessage(seq, event); + } else { + + } + + int error = 0; + Serial.print("Decoding data of size: "); Serial.println(sizeof(chars)); + message = validateMessage(chars); // &error + + // TODO: Do something with the message. + char inmessage[5] = {0}; + memcpy(inmessage, (const char*)&message.data, 4); + String inmsg = String(inmessage); + if (inmsg.indexOf("MESA") == 0) { + String event = String("PONG"); + sendMessage(seq, event); + } + +} + +void sendMessage(int seq, String msg) { + Wire.beginTransmission(0x42); // transmit to device #8 + //Sending Side + MESSAGE_DATA struct_data = encodeMessage(msg); + struct_data.sequence = seq; + char b[sizeof(struct_data)]; + memcpy(b, &struct_data, sizeof(struct_data)); + Serial.print("Sending message of size "); Serial.print(sizeof(struct_data)); Serial.println(); + Serial.print("'"); + for (int i = 0; i < sizeof(struct_data); i++) { + Wire.write(b[i]); + Serial.print(b[i]); + } + Serial.println("' sent..."); + Wire.endTransmission(); // stop transmitting +} + +// wire_transmit +void sendEvent(int a, String msg) { + Serial.print("Sending "); + Serial.println(msg); + Wire.beginTransmission(0x42); // transmit to master + Wire.write(a); + Wire.write(";"); // sends five bytes + Wire.write(msg.c_str()); + Wire.endTransmission(); // stop transmitting +} + +void loop() { + // nothing here, slave receives data and sends reply in own callback +} From ace0b371973c4b2ec2ab0c2ea2f4dbc4e38d2d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Wed, 21 Nov 2018 22:45:50 +0100 Subject: [PATCH 2/5] fixes with regards to Travis CI help --- .../i2c-P2P-master/i2c-P2P-master.ino | 93 +++++++++---------- .../examples/i2c-P2P-slave/i2c-P2P-slave.ino | 46 +++++---- 2 files changed, 68 insertions(+), 71 deletions(-) diff --git a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino index 51fd40cf7a..1032feffaf 100644 --- a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino +++ b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino @@ -1,28 +1,25 @@ -/* - * ESP8266 I2C master-slave communication, requires Arduno Core with I2C Slave Support (2.5.0+) - * +/* + * ESP8266 I2C master-slave communication, requires Arduno Core with I2C Slave Support (2.5.0+) + * * Expects two ESP8266 devices with three pins connected: GND, SDA and SCL. This is master. * Will send "MESA" messages to predefined slave address and then expect "PONG" response, * or request to retransfer if message was misunderstood (e.g. CRC check failed). * Message can be up to 26 bytes long (plus wrapper). - * + * * 21-11-2018: initial drop by Matej Sychra (github.com/suculent) */ #include +#include "crc16.h" #include "i2c-scanner.h" -#define WIRE_SDA D1 -#define WIRE_SCL D2 - -#include "crc16.h" - -#define LED_PIN D4 +#define WIRE_SDA 4 // D1 +#define WIRE_SCL 5 // D2 +#define LED_PIN 12 // D4 const int16_t I2C_MASTER = 0x42; const int16_t I2C_SLAVE = 0x08; - int16_t slave_address = I2C_SLAVE; // may be overridden using scan() // Keep this structure in sync with the i2c-P2P-slave example. Should be in shared header. @@ -34,9 +31,11 @@ struct MESSAGE_DATA { }; MESSAGE_DATA msgdata; + Crc16 crc; -bool expect_pong = false; byte sequence = 0; + +bool expect_pong = false; unsigned long next_ping = millis() + 1000; // analytics @@ -54,35 +53,35 @@ MESSAGE_DATA validateMessage(char* bytes_message); // should be in shared header uint16_t calculateCRC16(uint8_t *data, size_t length) { - crc.clearCrc(); + crc.clearCrc(); uint16_t value = (uint16_t)crc.XModemCrc(data,0,length); - Serial.print("crc = 0x"); Serial.println(value, HEX); + Serial.print("crc = 0x"); Serial.println(value, HEX); return value; } // should be in shared header MESSAGE_DATA encodeMessage(String bytes) { - - msgdata.terminator = '.'; - + + msgdata.terminator = '.'; + int datasize = sizeof(msgdata.data); Serial.print("\nEncoding data of size: "); Serial.println(datasize); - + // Generate new data set for the struct for (size_t i = 0; i < datasize; i++) { if (bytes.length() >= i) { - msgdata.data[i] = bytes[i]; + msgdata.data[i] = bytes[i]; } else { msgdata.data[i] = '\0'; } Serial.print(msgdata.data[i]); Serial.print(" "); - } + } Serial.print('\n'); msgdata.crc16 = calculateCRC16((uint8_t*) &msgdata.data[0], datasize); //Serial.print("ENCODED Message CRC16: "); Serial.println(msgdata.crc16, HEX); - return msgdata; + return msgdata; } // should be in shared header @@ -92,7 +91,7 @@ MESSAGE_DATA validateMessage(char* bytes_message) { memcpy(&tmp, bytes_message, sizeof(tmp)); // Validate PROTOCOL terminator - if (tmp.terminator != '.') { + if (tmp.terminator != '.') { Serial.print("[ERROR] Terminator invalid: '"); Serial.print(tmp.terminator); Serial.println("'"); @@ -100,16 +99,16 @@ MESSAGE_DATA validateMessage(char* bytes_message) { } int datasize = sizeof(tmp.data); - Serial.print("Data of size: "); Serial.println(datasize); + Serial.print("Data of size: "); Serial.println(datasize); uint16_t data_crc = calculateCRC16((uint8_t*) &tmp.data[0], datasize); // Validate incoming data CRC against remote CRC - if (tmp.crc16 == data_crc) { + if (tmp.crc16 == data_crc) { Serial.println("[OK] Data CRC valid."); char inmsg[datasize]; memcpy(inmsg, &tmp.data, datasize); - Serial.print("MASTER Incoming message: "); Serial.println(String(inmsg)); + Serial.print("MASTER Incoming message: "); Serial.println(String(inmsg)); } else { Serial.print("CRC-A = 0x"); Serial.println(tmp.crc16, HEX); @@ -120,7 +119,7 @@ MESSAGE_DATA validateMessage(char* bytes_message) { Serial.println("[ERROR] Request retransfer exception."); return tmp; } - + // Validate sequence number uint8_t remote_sequence = tmp.sequence; if (remote_sequence < sequence - 1) { @@ -137,16 +136,16 @@ MESSAGE_DATA validateMessage(char* bytes_message) { } void sendMessage(int seq, String msg) { - + Serial.print("[MASTER] Sending message: "); - Serial.print(msg); + Serial.print(msg); if (msg.indexOf("MESA") == 0) { expect_pong = true; } else { expect_pong = false; } - + Wire.beginTransmission(I2C_SLAVE); // transmit to device 0x08 //Sending Side MESSAGE_DATA struct_data = encodeMessage(msg); @@ -155,11 +154,11 @@ void sendMessage(int seq, String msg) { Serial.print(" of size "); Serial.println(sizeof(struct_data)); Serial.print("Encoding struct of size: "); Serial.println(sizeof(struct_data)); - memcpy(buf, &struct_data, sizeof(struct_data)); + memcpy(buf, &struct_data, sizeof(struct_data)); for (int i = 0; i < sizeof(struct_data); i++) { Wire.write(buf[i]); Serial.print(buf[i]);Serial.print(" "); - } + } Wire.endTransmission(); // stop transmitting Serial.println(""); } @@ -167,15 +166,15 @@ void sendMessage(int seq, String msg) { void receiveEvent(int howMany) { byte_count = byte_count + howMany; - + char incoming[howMany]; - incoming[howMany - 1] = '\0'; + incoming[howMany - 1] = '\0'; int index = 0; digitalWrite(LED_PIN, LOW); // message duration may not exceed 100 ms (100 bytes, 3x buffer retransferred) - unsigned long rtimeout = millis() + 100; + unsigned long rtimeout = millis() + 100; while (millis() < rtimeout) { // this must be fast, keep free from logging to serial here if possible while (0 < Wire.available()) { // loop through all but the last @@ -186,15 +185,15 @@ void receiveEvent(int howMany) { index++; } } - + Serial.println(); Serial.print("[MASTER] Received "); Serial.print(index); Serial.println(" bytes from SLAVE."); //Serial.print("[MASTER] Local Sequence: "); Serial.println((int)sequence); MESSAGE_DATA message = validateMessage(incoming); - + char inmsg[sizeof(message.data)]; memcpy(inmsg, &message.data, sizeof(message.data)); - if (inmsg[0] == 'R') { + if (inmsg[0] == 'R') { String retransfer_command = String(inmsg); retransfer_command.replace("R", ""); int retransfer_offset = retransfer_command.toInt(); @@ -207,8 +206,8 @@ void receiveEvent(int howMany) { // debug only, WARNING! may loose important messages in production sequence = retransfer_offset + 1; } - Serial.println(sequence); - } else { + Serial.println(sequence); + } else { // Serial.print("[MASTER] Incoming message from SLAVE: "); Serial.println(String(inmsg)); } @@ -231,10 +230,10 @@ void setup() { Wire.begin(I2C_MASTER); // join i2c bus (address optional for master) Wire.onReceive(receiveEvent); - Serial.begin(230400); // keep serial fast as possible for debug logging + Serial.begin(230400); // keep serial fast as possible for debug logging while (!Serial); pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, HIGH); + digitalWrite(LED_PIN, HIGH); slave_address = scan(); // useful with master/slave devices only on the bus } @@ -250,22 +249,22 @@ void loop() { Serial.print(byte_count); Serial.println(" per second"); error_count = 0; - byte_count = 0; + byte_count = 0; second_timer = millis() + 1000; } - + if (millis() > next_ping) { digitalWrite(LED_PIN, LOW); - next_ping = millis() + 200; + next_ping = millis() + 200; Serial.print("[MASTER] Sequence » "); Serial.println(sequence); digitalWrite(LED_PIN, HIGH); - sendMessage(sequence, "MESA"); + sendMessage(sequence, "MESA"); if (expect_pong) { error_count++; } expect_pong = true; - sequence++; + sequence++; } - + } diff --git a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino index c9fc879938..6c1d185a51 100644 --- a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino +++ b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino @@ -1,21 +1,20 @@ -/* - * ESP8266 I2C master-slave communication, requires Arduno Core with I2C Slave Support (2.5.0+) - * +/* + * ESP8266 I2C master-slave communication, requires Arduno Core with I2C Slave Support (2.5.0+) + * * Expects two ESP8266 devices with three pins connected: GND, SDA and SCL. This is slave. - * Will wait for "MESA" message and then respond with "PONG" message, + * Will wait for "MESA" message and then respond with "PONG" message, * or request retransfer if message was misunderstood (e.g. CRC check failed). * Message can be up to 26 bytes long (plus wrapper). - * + * * 21-11-2018: initial drop by Matej Sychra (github.com/suculent) */ #include - #include "crc16.h" -#define SDA_PIN D1 -#define SCL_PIN D2 -#define LED_PIN D4 +#define SDA_PIN 4 // D1 +#define SCL_PIN 5 // D2 +#define LED_PIN 12 // D4 const uint16_t I2C_ADDRESS = 0x08; const uint16_t I2C_MASTER = 0x42; @@ -48,7 +47,7 @@ MESSAGE_DATA validateMessage(char* bytes_message); uint16_t calculateCRC16(uint8_t *data, size_t length) { crc.clearCrc(); unsigned short value = crc.XModemCrc(data, 0, length); - Serial.print("crc = 0x"); Serial.println(value, HEX); + Serial.print("crc = 0x"); Serial.println(value, HEX); return (uint16_t)value; } @@ -57,19 +56,19 @@ void setup() { // Enable internal pullup (there's always one from the master side) //digitalWrite(SDA_PIN, HIGH); //digitalWrite(SCL_PIN, HIGH); - + pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); Wire.pins(SDA_PIN, SCL_PIN); Wire.begin(I2C_ADDRESS); // address required for slave - + Serial.begin(230400); //while (!Serial); if you want to wait for first messages - + delay(2000); digitalWrite(LED_PIN, HIGH); - + Wire.onReceive(receiveEvent); Serial.print("I2C Slave started on address: 0x0"); @@ -78,13 +77,13 @@ void setup() { // should be in shared header MESSAGE_DATA encodeMessage(String bytes) { - + msgdata.terminator = '.'; - int datasize = sizeof(msgdata.data); + unsigned int datasize = sizeof(msgdata.data); Serial.print("Encoding data of size: "); Serial.println(datasize); - + // Generate new data set for the struct for (size_t i = 0; i < datasize; i++) { if (bytes.length() >= i) { @@ -94,7 +93,7 @@ MESSAGE_DATA encodeMessage(String bytes) { } Serial.print(msgdata.data[i]); Serial.print(" "); - } + } Serial.println(); msgdata.crc16 = calculateCRC16((uint8_t*) &msgdata.data[0], datasize); Serial.print("Outgoing Message CRC16: "); Serial.println(msgdata.crc16, HEX); @@ -121,7 +120,7 @@ MESSAGE_DATA validateMessage(char* bytes_message) { if (datasize != 28) { Serial.print("Data of size: "); Serial.println(datasize); if (datasize > 28) { - datasize == 28; + datasize = 28; } } @@ -129,12 +128,12 @@ MESSAGE_DATA validateMessage(char* bytes_message) { uint16_t data_crc = calculateCRC16((uint8_t*) &tmp.data[0], sizeof(datasize)); // should be only when CRC is good like commented below - char inmsg[datasize]; + char inmsg[datasize]; memcpy(inmsg, &tmp.data, datasize); - + // Validate incoming data CRC against remote CRC if (tmp.crc16 == data_crc) { - Serial.println("[OK] Data CRC valid."); + Serial.println("[OK] Data CRC valid."); Serial.print("SLAVE Incoming message: "); Serial.println(String(inmsg)); } else { Serial.print("CRC-A = 0x"); @@ -233,7 +232,6 @@ void receiveEvent(int howMany) { } - int error = 0; Serial.print("Decoding data of size: "); Serial.println(sizeof(chars)); message = validateMessage(chars); // &error @@ -257,7 +255,7 @@ void sendMessage(int seq, String msg) { memcpy(b, &struct_data, sizeof(struct_data)); Serial.print("Sending message of size "); Serial.print(sizeof(struct_data)); Serial.println(); Serial.print("'"); - for (int i = 0; i < sizeof(struct_data); i++) { + for (unsigned int i = 0; i < sizeof(struct_data); i++) { Wire.write(b[i]); Serial.print(b[i]); } From 474ba24ce86f12d560db02a5dfd27977cde83209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Wed, 21 Nov 2018 22:59:05 +0100 Subject: [PATCH 3/5] i2c_clock_stretching_fix --- cores/esp8266/core_esp8266_si2c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index bb7b66ed0c..545b97c665 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -267,6 +267,7 @@ unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned i SCL_LOW(); twi_delay(twi_dcount); SCL_HIGH(); + unsigned int t=0; while(SCL_READ()==0 && (t++) Date: Wed, 21 Nov 2018 23:26:35 +0100 Subject: [PATCH 4/5] oh, the warnings. now the goes to default but address needs to be set anyway --- libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino | 2 +- libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino index 1032feffaf..d935f58966 100644 --- a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino +++ b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino @@ -226,7 +226,7 @@ void setup() { delay(2000); - Wire.pins(WIRE_SDA, WIRE_SCL); + // Wire.pins(WIRE_SDA, WIRE_SCL); // should set pins before address init Wire.begin(I2C_MASTER); // join i2c bus (address optional for master) Wire.onReceive(receiveEvent); diff --git a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino index 6c1d185a51..4d6ae64990 100644 --- a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino +++ b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino @@ -60,7 +60,7 @@ void setup() { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); - Wire.pins(SDA_PIN, SCL_PIN); + // Wire.pins(WIRE_SDA, WIRE_SCL); // should set pins before address init Wire.begin(I2C_ADDRESS); // address required for slave Serial.begin(230400); From 716f3a0b3d448c772a486a5a235007fc8bfcab56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Wed, 21 Nov 2018 23:30:32 +0100 Subject: [PATCH 5/5] proposing new init method with pins and address, because pins() is deprecated and two begins are ambiguous --- libraries/Wire/Wire.cpp | 20 ++++++++++++++----- libraries/Wire/Wire.h | 4 ++-- .../i2c-P2P-master/i2c-P2P-master.ino | 3 +-- .../examples/i2c-P2P-slave/i2c-P2P-slave.ino | 3 +-- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index 7e86894991..f7e35d7f3b 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -69,6 +69,16 @@ void TwoWire::begin(int sda, int scl){ flush(); } +void TwoWire::begin(int sda, int scl, uint8_t address){ + default_sda_pin = sda; + default_scl_pin = scl; + twi_setAddress(address); + twi_init(sda, scl); + twi_attachSlaveTxEvent(onRequestService); + twi_attachSlaveRxEvent(onReceiveService); + flush(); +} + void TwoWire::pins(int sda, int scl){ default_sda_pin = sda; default_scl_pin = scl; @@ -224,17 +234,17 @@ void TwoWire::onReceiveService(uint8_t* inBytes, size_t numBytes) // if(rxBufferIndex < rxBufferLength){ // return; // } - + // copy twi rx buffer into local read buffer // this enables new reads to happen in parallel for (uint8_t i = 0; i < numBytes; ++i) { rxBuffer[i] = inBytes[i]; } - + // set rx iterator vars rxBufferIndex = 0; rxBufferLength = numBytes; - + // alert user program user_onReceive(numBytes); } @@ -245,12 +255,12 @@ void TwoWire::onRequestService(void) if (!user_onRequest) { return; } - + // reset tx buffer iterator vars // !!! this will kill any pending pre-master sendTo() activity txBufferIndex = 0; txBufferLength = 0; - + // alert user program user_onRequest(); } diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h index e697bcca07..a797a95960 100644 --- a/libraries/Wire/Wire.h +++ b/libraries/Wire/Wire.h @@ -51,6 +51,7 @@ class TwoWire : public Stream public: TwoWire(); void begin(int sda, int scl); + void begin(int sda, int scl, uint8_t address); void pins(int sda, int scl) __attribute__((deprecated)); // use begin(sda, scl) in new code void begin(); void begin(uint8_t); @@ -68,7 +69,7 @@ class TwoWire : public Stream uint8_t requestFrom(uint8_t, uint8_t, uint8_t); uint8_t requestFrom(int, int); uint8_t requestFrom(int, int, int); - + virtual size_t write(uint8_t); virtual size_t write(const uint8_t *, size_t); virtual int available(void); @@ -90,4 +91,3 @@ extern TwoWire Wire; #endif #endif - diff --git a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino index d935f58966..5abfd6e5bb 100644 --- a/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino +++ b/libraries/Wire/examples/i2c-P2P-master/i2c-P2P-master.ino @@ -226,8 +226,7 @@ void setup() { delay(2000); - // Wire.pins(WIRE_SDA, WIRE_SCL); // should set pins before address init - Wire.begin(I2C_MASTER); // join i2c bus (address optional for master) + Wire.begin(WIRE_SDA, WIRE_SCL, I2C_MASTER); // join i2c bus (address optional for master) Wire.onReceive(receiveEvent); Serial.begin(230400); // keep serial fast as possible for debug logging diff --git a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino index 4d6ae64990..7657d785f3 100644 --- a/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino +++ b/libraries/Wire/examples/i2c-P2P-slave/i2c-P2P-slave.ino @@ -60,8 +60,7 @@ void setup() { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); - // Wire.pins(WIRE_SDA, WIRE_SCL); // should set pins before address init - Wire.begin(I2C_ADDRESS); // address required for slave + Wire.begin(SDA_PIN, SCL_PIN, I2C_ADDRESS); // address required for slave Serial.begin(230400); //while (!Serial); if you want to wait for first messages