Skip to content

Commit 29332d8

Browse files
committed
libraries/Wire: Add support for target mode.
Signed-off-by: iabdalkader <[email protected]>
1 parent 045ae9d commit 29332d8

File tree

2 files changed

+175
-58
lines changed

2 files changed

+175
-58
lines changed

libraries/Wire/Wire.cpp

Lines changed: 154 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,117 @@
55
*/
66

77
#include <Wire.h>
8+
#include <stddef.h>
89
#include <zephyr/sys/util_macro.h>
910

10-
arduino::ZephyrI2C::ZephyrI2C(const struct device *i2c) : i2c_dev(i2c)
11-
{
11+
// Helper function to get ZephyrI2C instance from config pointer.
12+
static arduino::ZephyrI2C* getInstance(struct i2c_target_config *config) {
13+
return reinterpret_cast<arduino::ZephyrI2C*>(
14+
reinterpret_cast<char*>(config) - offsetof(arduino::ZephyrI2C, i2c_cfg)
15+
);
16+
}
17+
18+
static int i2c_target_stop_cb(struct i2c_target_config *config) {
19+
arduino::ZephyrI2C *instance = getInstance(config);
20+
return instance->stopCallback(config);
21+
}
22+
23+
static int i2c_target_write_requested_cb(struct i2c_target_config *config) {
24+
arduino::ZephyrI2C *instance = getInstance(config);
25+
return instance->writeRequestedCallback(config);
26+
}
27+
28+
static int i2c_target_write_received_cb(struct i2c_target_config *config, uint8_t val) {
29+
arduino::ZephyrI2C *instance = getInstance(config);
30+
return instance->writeReceivedCallback(config, val);
31+
}
32+
33+
static int i2c_target_read_requested_cb(struct i2c_target_config *config, uint8_t *val) {
34+
arduino::ZephyrI2C *instance = getInstance(config);
35+
return instance->readRequestedCallback(config, val);
36+
}
37+
38+
static int i2c_target_read_processed_cb(struct i2c_target_config *config, uint8_t *val) {
39+
arduino::ZephyrI2C *instance = getInstance(config);
40+
return instance->readProcessedCallback(config, val);
41+
}
42+
43+
// I2C target callback structure.
44+
static struct i2c_target_callbacks target_callbacks = {
45+
.write_requested = i2c_target_write_requested_cb,
46+
.read_requested = i2c_target_read_requested_cb,
47+
.write_received = i2c_target_write_received_cb,
48+
.read_processed = i2c_target_read_processed_cb,
49+
.stop = i2c_target_stop_cb,
50+
};
51+
52+
arduino::ZephyrI2C::ZephyrI2C(const struct device *i2c) : i2c_dev(i2c), i2c_cfg({0}) {
53+
ring_buf_init(&txRingBuffer.rb, sizeof(txRingBuffer.buffer), txRingBuffer.buffer);
54+
ring_buf_init(&rxRingBuffer.rb, sizeof(rxRingBuffer.buffer), rxRingBuffer.buffer);
55+
1256
}
1357

1458
void arduino::ZephyrI2C::begin() {
15-
ring_buf_init(&rxRingBuffer.rb, sizeof(rxRingBuffer.buffer), rxRingBuffer.buffer);
59+
1660
}
1761

1862
void arduino::ZephyrI2C::begin(uint8_t slaveAddr) {
19-
63+
i2c_cfg.address = slaveAddr;
64+
i2c_cfg.callbacks = &target_callbacks;
65+
66+
// Register I2C target
67+
i2c_target_register(i2c_dev, &i2c_cfg);
2068
}
2169

22-
void arduino::ZephyrI2C::end() {}
70+
void arduino::ZephyrI2C::end() {
71+
// Unregister I2C target
72+
// TODO
73+
//i2c_target_unregister(i2c_dev, &i2c_cfg);
74+
}
2375

2476
void arduino::ZephyrI2C::setClock(uint32_t freq) {
25-
uint8_t speed = I2C_SPEED_STANDARD;
26-
if(freq > 0x06u ) {
27-
if(freq == 100000) {
28-
speed = I2C_SPEED_STANDARD;
29-
} else if(freq == 400000) {
30-
speed = I2C_SPEED_FAST;
31-
} else if(freq == 1000000) {
32-
speed = I2C_SPEED_FAST_PLUS;
33-
} else {
34-
speed = I2C_SPEED_STANDARD;
35-
}
36-
} else {
37-
speed = (uint8_t) freq;
38-
}
39-
uint32_t i2c_cfg = I2C_MODE_CONTROLLER |
40-
I2C_SPEED_SET(speed);
41-
42-
if (i2c_configure(i2c_dev, i2c_cfg)) {
43-
//Serial.println("Failed to configure i2c interface.");
44-
}
45-
}
46-
47-
void arduino::ZephyrI2C::beginTransmission(uint8_t address) { // TODO for ADS1115
77+
uint8_t speed;
78+
79+
if (freq == 100000) {
80+
speed = I2C_SPEED_STANDARD;
81+
} else if (freq == 400000) {
82+
speed = I2C_SPEED_FAST;
83+
} else if (freq == 1000000) {
84+
speed = I2C_SPEED_FAST_PLUS;
85+
} else {
86+
speed = I2C_SPEED_STANDARD;
87+
}
88+
89+
i2c_configure(i2c_dev, I2C_SPEED_SET(speed) | I2C_MODE_CONTROLLER);
90+
}
91+
92+
void arduino::ZephyrI2C::beginTransmission(uint8_t address) {
4893
_address = address;
49-
usedTxBuffer = 0;
94+
ring_buf_reset(&txRingBuffer.rb);
95+
ring_buf_reset(&rxRingBuffer.rb);
5096
}
5197

5298
uint8_t arduino::ZephyrI2C::endTransmission(bool stopBit) {
53-
int ret = i2c_write(i2c_dev, txBuffer, usedTxBuffer, _address);
54-
if (ret) {
55-
return 1; // fail
99+
int ret = 0;
100+
uint8_t *data = NULL;
101+
size_t max = ring_buf_capacity_get(&txRingBuffer.rb);
102+
size_t len = ring_buf_get_claim(&txRingBuffer.rb, &data, max);
103+
104+
if (len) {
105+
ret = i2c_write(i2c_dev, data, len, _address);
56106
}
57-
return 0;
107+
108+
// Must be called even if 0 bytes claimed.
109+
ring_buf_get_finish(&txRingBuffer.rb, len);
110+
111+
return ret ? 1 : 0;
58112
}
59113

60-
uint8_t arduino::ZephyrI2C::endTransmission(void) { // TODO for ADS1115
114+
uint8_t arduino::ZephyrI2C::endTransmission(void) {
61115
return endTransmission(true);
62116
}
63117

64-
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len,
65-
bool stopBit) {
118+
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len, bool stopBit) {
66119
uint8_t buf[len];
67120
int ret = i2c_read(i2c_dev, buf, len, address);
68121
if (ret != 0)
@@ -77,22 +130,16 @@ size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len,
77130
return len;
78131
}
79132

80-
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len) { // TODO for ADS1115
133+
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len) {
81134
return requestFrom(address, len, true);
82135
}
83136

84-
size_t arduino::ZephyrI2C::write(uint8_t data) { // TODO for ADS1115
85-
txBuffer[usedTxBuffer++] = data;
86-
return 1;
137+
size_t arduino::ZephyrI2C::write(uint8_t data) {
138+
return ring_buf_put(&txRingBuffer.rb, &data, 1);
87139
}
88140

89141
size_t arduino::ZephyrI2C::write(const uint8_t *buffer, size_t size) {
90-
if (usedTxBuffer + size > 256) {
91-
size = 256 - usedTxBuffer;
92-
}
93-
memcpy(txBuffer + usedTxBuffer, buffer, size);
94-
usedTxBuffer += size;
95-
return size;
142+
return ring_buf_put(&txRingBuffer.rb, buffer, size);
96143
}
97144

98145
int arduino::ZephyrI2C::read() {
@@ -115,15 +162,72 @@ int arduino::ZephyrI2C::peek() {
115162
uint8_t buf[1];
116163
int bytes_read = ring_buf_peek(&rxRingBuffer.rb, buf, 1);
117164
if (bytes_read == 0){
118-
return 0;
165+
return -1;
119166
}
120167
return (int)buf[0];
121168
}
122169

123-
void arduino::ZephyrI2C::flush() {}
170+
void arduino::ZephyrI2C::flush() {
124171

125-
void arduino::ZephyrI2C::onReceive(voidFuncPtrParamInt cb) {}
126-
void arduino::ZephyrI2C::onRequest(voidFuncPtr cb) {}
172+
}
173+
174+
void arduino::ZephyrI2C::onReceive(voidFuncPtrParamInt cb) {
175+
onReceiveCb = cb;
176+
}
177+
178+
void arduino::ZephyrI2C::onRequest(voidFuncPtr cb) {
179+
onRequestCb = cb;
180+
}
181+
182+
int arduino::ZephyrI2C::writeRequestedCallback(struct i2c_target_config *config) {
183+
// Reset the buffer on write requests.
184+
ring_buf_reset(&rxRingBuffer.rb);
185+
return 0;
186+
}
187+
188+
int arduino::ZephyrI2C::writeReceivedCallback(struct i2c_target_config *config, uint8_t val) {
189+
size_t len = ring_buf_size_get(&rxRingBuffer.rb);
190+
size_t max = ring_buf_capacity_get(&rxRingBuffer.rb);
191+
192+
// If the buffer is about to overflow, invoke the callback
193+
// with the current length.
194+
if (onReceiveCb && ((len + 1) > max)) {
195+
onReceiveCb(len);
196+
}
197+
198+
return ring_buf_put(&rxRingBuffer.rb, &val, 1) ? 0 : -1;
199+
}
200+
201+
int arduino::ZephyrI2C::readRequestedCallback(struct i2c_target_config *config, uint8_t *val) {
202+
// Reset the buffer on read requests.
203+
ring_buf_reset(&txRingBuffer.rb);
204+
205+
if (onRequestCb) {
206+
onRequestCb();
207+
}
208+
209+
return readProcessedCallback(config, val);
210+
}
211+
212+
int arduino::ZephyrI2C::readProcessedCallback(struct i2c_target_config *config, uint8_t *val) {
213+
*val = 0xFF;
214+
ring_buf_get(&txRingBuffer.rb, val, 1);
215+
// Returning a negative value here is not handled gracefully and
216+
// causes the target/board to stop responding (at least with ST).
217+
return 0;
218+
}
219+
220+
int arduino::ZephyrI2C::stopCallback(struct i2c_target_config *config) {
221+
// If the RX buffer is not empty invoke the callback with the
222+
// remaining data length.
223+
if (onReceiveCb) {
224+
size_t len = ring_buf_size_get(&rxRingBuffer.rb);
225+
if (len) {
226+
onReceiveCb(len);
227+
}
228+
}
229+
return 0;
230+
}
127231

128232
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), i2cs)
129233
#if (DT_PROP_LEN(DT_PATH(zephyr_user), i2cs) > 1)

libraries/Wire/Wire.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ typedef void (*voidFuncPtrParamInt)(int);
1515

1616
namespace arduino {
1717

18+
struct i2c_ring {
19+
struct ring_buf rb;
20+
uint8_t buffer[256];
21+
};
22+
1823
class ZephyrI2C : public HardwareI2C {
1924
public:
2025
ZephyrI2C(const struct device* i2c);
@@ -43,16 +48,24 @@ class ZephyrI2C : public HardwareI2C {
4348
virtual void flush();
4449
virtual int available();
4550

51+
// I2C target callbacks
52+
int writeRequestedCallback(struct i2c_target_config *config);
53+
int writeReceivedCallback(struct i2c_target_config *config, uint8_t val);
54+
int readRequestedCallback(struct i2c_target_config *config, uint8_t *val);
55+
int readProcessedCallback(struct i2c_target_config *config, uint8_t *val);
56+
int stopCallback(struct i2c_target_config *config);
57+
58+
struct i2c_target_config i2c_cfg;
59+
4660
private:
4761
int _address;
48-
uint8_t txBuffer[256];
49-
uint32_t usedTxBuffer;
50-
struct rx_ring_buf{
51-
struct ring_buf rb;
52-
uint8_t buffer[256];
53-
};
54-
struct rx_ring_buf rxRingBuffer;
55-
const struct device* i2c_dev;
62+
63+
struct i2c_ring txRingBuffer;
64+
struct i2c_ring rxRingBuffer;
65+
const struct device *i2c_dev;
66+
67+
voidFuncPtr onRequestCb = NULL;
68+
voidFuncPtrParamInt onReceiveCb = NULL;
5669
};
5770

5871
} // namespace arduino

0 commit comments

Comments
 (0)