Pico-Arduino
PicoHardwareI2C.h
1 #pragma once
2 #include "HardwareI2C.h"
3 #include "hardware/i2c.h"
4 #include "hardware/gpio.h"
5 #include "PicoLogger.h"
6 #include "pins_arduino.h"
7 #include <algorithm> // std::max
8 
9 namespace pico_arduino {
10 
22 class PicoHardwareI2C : public HardwareI2C {
23  public:
25  PicoHardwareI2C(i2c_inst_t *i2c, int maxBufferSize, int sdaPin, int sclPin){
26  this->i2c = i2c;
27  this->maxBufferSize = maxBufferSize;
28  sda_pin = sdaPin;
29  scl_pin = sclPin;
30  }
31 
34  end();
35  }
36 
38  virtual void begin() {
39  begin(-1, -1);
40  }
41 
43  virtual void begin(uint8_t address) {
44  begin(address, -1, -1);
45  }
46 
48  virtual void begin(int sdaPin, int sclPin) {
49  Logger.info("begin");
50  setupPins(sdaPin, sclPin);
51  i2c_init(i2c, 100000);
52  i2c_set_slave_mode(i2c, false, 0);
53  is_slave_mode = false;
54  setupWriteBuffer();
55  }
56 
58  virtual void begin(uint8_t address, int sdaPin, int sclPin) {
59  Logger.printf(PicoLogger::Info, "begin %d\n", address);
60  setupPins(sdaPin,sclPin);
61  transmission_address = address;
62  i2c_init(i2c, 100000);
63  i2c_set_slave_mode(i2c, true, address);
64  is_slave_mode = true;
65  setupWriteBuffer();
66  }
67 
69  virtual void end() {
70  Logger.info("end");
71  i2c_deinit(i2c);
72  if (read_buffer !=nullptr){
73  delete[]read_buffer;
74  read_buffer = nullptr;
75  }
76  if (write_buffer !=nullptr){
77  delete[]write_buffer;
78  write_buffer = nullptr;
79  }
80  }
81 
83  virtual void setClock(uint32_t baudrate) {
84  Logger.info("setClock");
85  i2c_set_baudrate(i2c, baudrate);
86  }
87 
89  virtual void beginTransmission(uint8_t address) {
90  Logger.printf(PicoLogger::Info, "beginTransmission %d\n", address);
91  transmission_address=address;
92  }
93 
95  virtual uint8_t endTransmission(bool stopBit) {
96  Logger.info("endTransmission", stopBit ? "stop" : "no-stop" );
97  uint8_t result = flush(stopBit);
98  transmission_address = -1;
99  return result;
100  }
101 
103  virtual uint8_t endTransmission(void) {
104  return endTransmission(true);
105  }
106 
108  virtual size_t write(uint8_t c) {
109  Logger.debug("write");
110  size_t result = 0;
111  if (write_pos>=maxBufferSize){
112  flush(false);
113  }
114  // we just write to a buffer
115  if (write_pos<maxBufferSize){
116  result = 1;
117  write_buffer[write_pos]=c;
118  write_pos++;
119  }
120  return result;
121  }
122 
124  size_t write(const char *buffer, size_t size) {
125  Logger.debug("write[]");
126  // if we have any data in the buffer flush this first
127  flush();
128  // and now write out the requested data
129  return i2c_write_blocking(i2c, transmission_address,(const uint8_t * ) buffer, size, true);
130  }
131 
133  virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) {
134  Logger.printf(PicoLogger::Info,"requestFrom (%d, %ld, %s)\n", address,len, stopBit?"stop":"no-stop");
135  flush();
136  setupReadBuffer(len);
137  read_address = address;
138 
139  // call requestHandler
140  if (this->requestHandler!=nullptr){
141  Logger.info("requestHandler");
142  (*this->requestHandler)();
143  }
144 
145  // read the data into the read_buffer
146  read_len = i2c_read_blocking(i2c, read_address, read_buffer, len, !stopBit);
147  read_pos = 0;
148  if (read_len==PICO_ERROR_GENERIC){
149  Logger.warning("requestFrom->","PICO_ERROR_GENERIC");
150  read_len = 0;
151  }
152  Logger.printf(PicoLogger::Debug, "requestFrom -> %ld\n",read_len);
153 
154  // call recieveHandler
155  if (read_len>0 && this->recieveHandler!=nullptr){
156  Logger.info("recieveHandler");
157  (*this->recieveHandler)(read_len);
158  }
159 
160  return read_len;
161  }
162 
164  virtual size_t requestFrom(uint8_t address, size_t len) {
165  return requestFrom(address, len, false);
166  }
167 
169  virtual int read() {
170  // trigger flush of write buffer
171  int result = (read_pos<read_len) ? read_buffer[read_pos++] : -1;
172  return result;
173  }
174 
176  virtual int peek() {
177  Logger.debug("peek");
178  return (read_pos<read_len) ? read_buffer[read_pos] : -1;
179  }
180 
182  virtual int available() {
183  int buffer_available = read_len - read_pos;
184  if (buffer_available < 0){
185  buffer_available = 0;
186  Logger.error("buffer_available is negative - corrected to 0");
187  }
188  Logger.printf(PicoLogger::Debug, "available: %d\n", buffer_available);
189  return buffer_available;
190  }
191 
193  virtual void onReceive(void(*recieveHandler)(int)) {
194  this->recieveHandler = recieveHandler;
195  Logger.info("onReceive");
196  }
197 
199  virtual void onRequest(void(*requestHandler)(void)) {
200  this->requestHandler = requestHandler;
201  Logger.info("onRequest");
202  };
203 
204  protected:
205  bool is_slave_mode;
206  i2c_inst_t *i2c;
207  int maxBufferSize;
208  // write
209  uint8_t transmission_address;
210  int write_pos;
211  uint8_t *write_buffer;
212 
213  // read
214  size_t read_len;
215  size_t read_pos;
216  bool read_stop_bit;
217  uint8_t read_address;
218  uint8_t *read_buffer;
219 
220  // handler
221  void(*recieveHandler)(int);
222  void(*requestHandler)(void);
223 
224  // pins
225  int sda_pin;
226  int scl_pin;
227  bool pin_is_setup = false;
228 
229  void setupPins(int sda, int scl){
230  if (!pin_is_setup) {
231  if (sda>=0){
232  sda_pin = sda;
233  }
234  if (scl>=0){
235  scl_pin = scl;
236  }
237  gpio_set_function(sda_pin, GPIO_FUNC_I2C);
238  gpio_set_function(scl_pin, GPIO_FUNC_I2C);
239  gpio_pull_up(sda_pin);
240  gpio_pull_up(scl_pin);
241 
242  }
243  }
244 
245 
246  int flush(bool stop=false) {
247  bool result = 0; // 4:other error
248  if (write_pos>0) {
249  Logger.printf(PicoLogger::Debug, "flush address:%d, len:%d, end:%s\n",transmission_address, write_pos, stop ? "stop": "no-stop" );
250  int result = i2c_write_blocking(i2c, transmission_address, write_buffer, write_pos, !stop);
251  if (result == write_pos){
252  result = 0; // OK
253  } else if (result < write_pos){
254  result = 1; // 1:data too long to fit in transmit buffer
255  } else {
256  result = 4; // 4:other error
257  }
258  write_pos = 0;
259  Logger.printf(PicoLogger::Debug, "flush->%d\n", result);
260 
261  }
262 
263  return result;
264  }
265 
266  void setupWriteBuffer(){
267  // setup buffer only if needed
268  if (write_buffer==nullptr){
269  Logger.info("setupWriteBuffer");
270  write_buffer = new uint8_t(maxBufferSize);
271  }
272  }
273 
274  void setupReadBuffer(int len){
275  if (read_buffer==nullptr){
276  // setup buffer only if needed
277  maxBufferSize = std::max(len, maxBufferSize);
278  read_buffer = new uint8_t(maxBufferSize);
279  } else {
280  if (len>maxBufferSize){
281  // grow the read buffer to the requested size
282  maxBufferSize = len;
283  delete[] read_buffer;
284  read_buffer = new uint8_t(maxBufferSize);
285  }
286  }
287  }
288 
289 };
290 
291 }
292 
293 
Definition: HardwareI2C.h:27
Arduino I2C implementation using the Pico functionality. In Arduino we can read and write individal c...
Definition: PicoHardwareI2C.h:22
PicoHardwareI2C(i2c_inst_t *i2c, int maxBufferSize, int sdaPin, int sclPin)
Standard Constructor for PicoHardwareI2C class.
Definition: PicoHardwareI2C.h:25
virtual void onRequest(void(*requestHandler)(void))
Register a function to be called when a master requests data from this slave device.
Definition: PicoHardwareI2C.h:199
virtual int read()
Reads a byte that was transmitted from a slave device to a master after a call to requestFrom() or wa...
Definition: PicoHardwareI2C.h:169
virtual void setClock(uint32_t baudrate)
This function modifies the clock frequency for I2C communication. I2C slave devices have no minimum w...
Definition: PicoHardwareI2C.h:83
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit)
Used by the master to request bytes from a slave device. The bytes may then be retrieved with the ava...
Definition: PicoHardwareI2C.h:133
virtual void beginTransmission(uint8_t address)
Begin a transmission to the I2C slave device with the given address. Subsequently,...
Definition: PicoHardwareI2C.h:89
size_t write(const char *buffer, size_t size)
Writes data from a slave device in response to a request from a master, or queues bytes for transmiss...
Definition: PicoHardwareI2C.h:124
virtual int peek()
Peeks current unread byte that was transmitted from a slave device to a master after a call to reques...
Definition: PicoHardwareI2C.h:176
virtual void begin(uint8_t address, int sdaPin, int sclPin)
Initiate the Wire library and join the I2C bus as a slave. This should normally be called only once.
Definition: PicoHardwareI2C.h:58
virtual void begin(int sdaPin, int sclPin)
Initiate the Wire library and join the I2C bus as a master. This should normally be called only once.
Definition: PicoHardwareI2C.h:48
virtual int available()
Returns the number of bytes available for retrieval with read(). This should be called on a master de...
Definition: PicoHardwareI2C.h:182
virtual size_t requestFrom(uint8_t address, size_t len)
Used by the master to request bytes from a slave device. The bytes may then be retrieved with the ava...
Definition: PicoHardwareI2C.h:164
virtual size_t write(uint8_t c)
Writes data from a slave device in response to a request from a master, or queues bytes for transmiss...
Definition: PicoHardwareI2C.h:108
virtual uint8_t endTransmission(bool stopBit)
Ends a transmission to a slave device that was begun by beginTransmission() and transmits the bytes t...
Definition: PicoHardwareI2C.h:95
~PicoHardwareI2C()
Destructor for PicoHardwareI2C class.
Definition: PicoHardwareI2C.h:33
virtual void begin()
Initiate the Wire library and join the I2C bus as a master. This should normally be called only once.
Definition: PicoHardwareI2C.h:38
virtual void end()
Closes the Wire Library.
Definition: PicoHardwareI2C.h:69
virtual void begin(uint8_t address)
Initiate the Wire library and join the I2C bus as a slave. This should normally be called only once.
Definition: PicoHardwareI2C.h:43
virtual void onReceive(void(*recieveHandler)(int))
Registers a function to be called when a slave device receives a transmission from a master.
Definition: PicoHardwareI2C.h:193
virtual uint8_t endTransmission(void)
Ends a transmission to a slave device that was begun by beginTransmission() and transmits the bytes t...
Definition: PicoHardwareI2C.h:103
virtual int printf(LogLevel current_level, const char *fmt,...)
printf support
Definition: PicoLogger.h:65
virtual void error(const char *str, const char *str1=nullptr, const char *str2=nullptr)
logs an error
Definition: PicoLogger.h:45
virtual void info(const char *str, const char *str1=nullptr, const char *str2=nullptr)
logs an info message
Definition: PicoLogger.h:50
virtual void warning(const char *str, const char *str1=nullptr, const char *str2=nullptr)
logs an warning
Definition: PicoLogger.h:55
virtual void debug(const char *str, const char *str1=nullptr, const char *str2=nullptr)
writes an debug message
Definition: PicoLogger.h:60
Pico Arduino Framework.
Definition: Arduino.cpp:26