Skip to content

Commit f60ee5c

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

File tree

2 files changed

+158
-57
lines changed

2 files changed

+158
-57
lines changed

libraries/Wire/Wire.cpp

Lines changed: 137 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,115 @@
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;
5094
}
5195

5296
uint8_t arduino::ZephyrI2C::endTransmission(bool stopBit) {
53-
int ret = i2c_write(i2c_dev, txBuffer, usedTxBuffer, _address);
54-
if (ret) {
55-
return 1; // fail
97+
uint8_t *data = NULL;
98+
size_t max = ring_buf_capacity_get(&txRingBuffer.rb);
99+
size_t len = ring_buf_get_claim(&txRingBuffer.rb, &data, max);
100+
101+
if (data) {
102+
if (i2c_write(i2c_dev, data, len, _address)) {
103+
return 1; // fail
104+
} else {
105+
ring_buf_get_finish(&txRingBuffer.rb, len);
106+
}
56107
}
108+
57109
return 0;
58110
}
59111

60-
uint8_t arduino::ZephyrI2C::endTransmission(void) { // TODO for ADS1115
112+
uint8_t arduino::ZephyrI2C::endTransmission(void) {
61113
return endTransmission(true);
62114
}
63115

64-
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len,
65-
bool stopBit) {
116+
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len, bool stopBit) {
66117
uint8_t buf[len];
67118
int ret = i2c_read(i2c_dev, buf, len, address);
68119
if (ret != 0)
@@ -77,22 +128,16 @@ size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len,
77128
return len;
78129
}
79130

80-
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len) { // TODO for ADS1115
131+
size_t arduino::ZephyrI2C::requestFrom(uint8_t address, size_t len) {
81132
return requestFrom(address, len, true);
82133
}
83134

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

89139
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;
140+
return ring_buf_put(&txRingBuffer.rb, buffer, size);
96141
}
97142

98143
int arduino::ZephyrI2C::read() {
@@ -115,15 +160,58 @@ int arduino::ZephyrI2C::peek() {
115160
uint8_t buf[1];
116161
int bytes_read = ring_buf_peek(&rxRingBuffer.rb, buf, 1);
117162
if (bytes_read == 0){
118-
return 0;
163+
return -1;
119164
}
120165
return (int)buf[0];
121166
}
122167

123-
void arduino::ZephyrI2C::flush() {}
168+
void arduino::ZephyrI2C::flush() {
169+
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+
return 0;
182+
}
183+
184+
int arduino::ZephyrI2C::writeReceivedCallback(struct i2c_target_config *config, uint8_t val) {
185+
return 0;
186+
}
187+
188+
int arduino::ZephyrI2C::readRequestedCallback(struct i2c_target_config *config, uint8_t *val) {
189+
// Reset the buffer on new read requests.
190+
ring_buf_reset(&txRingBuffer.rb);
124191

125-
void arduino::ZephyrI2C::onReceive(voidFuncPtrParamInt cb) {}
126-
void arduino::ZephyrI2C::onRequest(voidFuncPtr cb) {}
192+
if (onRequestCb) {
193+
onRequestCb();
194+
}
195+
196+
return readProcessedCallback(config, val);
197+
}
198+
199+
int arduino::ZephyrI2C::readProcessedCallback(struct i2c_target_config *config, uint8_t *val) {
200+
if (!ring_buf_peek(&txRingBuffer.rb, val, 1)) {
201+
*val = 0xFF;
202+
} else {
203+
ring_buf_get(&txRingBuffer.rb, val, 1);
204+
}
205+
206+
// Contrary to what's documented, returning a negative value to
207+
// indicate that there's no more data is not handled gracefully,
208+
// and will halt the target, at least with ST drivers.
209+
return 0;
210+
}
211+
212+
int arduino::ZephyrI2C::stopCallback(struct i2c_target_config *config) {
213+
return 0;
214+
}
127215

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