Skip to content

Commit 1ed725c

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

File tree

2 files changed

+193
-78
lines changed

2 files changed

+193
-78
lines changed

libraries/Wire/Wire.cpp

Lines changed: 172 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,104 +5,150 @@
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);
1255
}
1356

1457
void arduino::ZephyrI2C::begin() {
15-
ring_buf_init(&rxRingBuffer.rb, sizeof(rxRingBuffer.buffer), rxRingBuffer.buffer);
58+
1659
}
1760

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

22-
void arduino::ZephyrI2C::end() {}
69+
void arduino::ZephyrI2C::end() {
70+
// Unregister I2C target
71+
if (i2c_cfg.address) {
72+
i2c_target_unregister(i2c_dev, &i2c_cfg);
73+
memset(&i2c_cfg, 0, sizeof(i2c_cfg));
74+
}
75+
}
2376

2477
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
78+
uint8_t speed;
79+
80+
if (freq == 100000) {
81+
speed = I2C_SPEED_STANDARD;
82+
} else if (freq == 400000) {
83+
speed = I2C_SPEED_FAST;
84+
} else if (freq == 1000000) {
85+
speed = I2C_SPEED_FAST_PLUS;
86+
} else {
87+
speed = I2C_SPEED_STANDARD;
88+
}
89+
90+
i2c_configure(i2c_dev, I2C_SPEED_SET(speed) | I2C_MODE_CONTROLLER);
91+
}
92+
93+
void arduino::ZephyrI2C::beginTransmission(uint8_t address) {
4894
_address = address;
49-
usedTxBuffer = 0;
95+
ring_buf_reset(&txRingBuffer.rb);
96+
ring_buf_reset(&rxRingBuffer.rb);
5097
}
5198

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

60-
uint8_t arduino::ZephyrI2C::endTransmission(void) { // TODO for ADS1115
115+
uint8_t arduino::ZephyrI2C::endTransmission(void) {
61116
return endTransmission(true);
62117
}
63118

64-
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len,
65-
bool stopBit) {
66-
uint8_t buf[len];
67-
int ret = i2c_read(i2c_dev, buf, len, address);
68-
if (ret != 0)
69-
{
70-
return 0;
71-
}
72-
ret = ring_buf_put(&rxRingBuffer.rb, buf, len);
73-
if (ret == 0)
74-
{
75-
return 0;
119+
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len, bool stopBit) {
120+
int ret = 0;
121+
uint8_t *buf = NULL;
122+
len = ring_buf_put_claim(&rxRingBuffer.rb, &buf, len);
123+
124+
if (len && buf) {
125+
ret = i2c_read(i2c_dev, buf, len, address);
76126
}
77-
return len;
127+
128+
// Must be called even if 0 bytes claimed.
129+
ring_buf_put_finish(&rxRingBuffer.rb, len);
130+
131+
return ret ? 1 : 0;
78132
}
79133

80-
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len) { // TODO for ADS1115
134+
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len) {
81135
return requestFrom(address, len, true);
82136
}
83137

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

89142
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;
143+
return ring_buf_put(&txRingBuffer.rb, buffer, size);
96144
}
97145

98146
int arduino::ZephyrI2C::read() {
99147
uint8_t buf[1];
100-
if (ring_buf_size_get(&rxRingBuffer.rb)) {
101-
int ret = ring_buf_get(&rxRingBuffer.rb, buf, 1);
102-
if (ret == 0) {
103-
return -1;
104-
}
105-
return (int)buf[0];
148+
if (available()) {
149+
if (ring_buf_get(&rxRingBuffer.rb, buf, 1)) {
150+
return (int) buf[0];
151+
}
106152
}
107153
return -1;
108154
}
@@ -113,17 +159,73 @@ int arduino::ZephyrI2C::available() {
113159

114160
int arduino::ZephyrI2C::peek() {
115161
uint8_t buf[1];
116-
int bytes_read = ring_buf_peek(&rxRingBuffer.rb, buf, 1);
117-
if (bytes_read == 0){
118-
return 0;
162+
if (!ring_buf_peek(&rxRingBuffer.rb, buf, 1)) {
163+
return -1;
119164
}
120-
return (int)buf[0];
165+
return (int) buf[0];
121166
}
122167

123-
void arduino::ZephyrI2C::flush() {}
168+
void arduino::ZephyrI2C::flush() {
124169

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

128230
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), i2cs)
129231
#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)