36#if defined(ESP_PLATFORM)
50#if CONFIG_VFS_SUPPORT_TERMIOS
60namespace openmrn_arduino
74static ssize_t i2c_vfs_write(
void *ctx,
int fd,
const void *buf,
size_t size)
77 Esp32HardwareI2C *i2c =
reinterpret_cast<Esp32HardwareI2C *
>(ctx);
78 return i2c->write(fd, buf, size);
89static ssize_t i2c_vfs_read(
void *ctx,
int fd,
void *buf,
size_t size)
92 Esp32HardwareI2C *i2c =
reinterpret_cast<Esp32HardwareI2C *
>(ctx);
93 return i2c->read(fd, buf, size);
107static int i2c_vfs_open(
void *ctx,
const char *path,
int flags,
int mode)
110 Esp32HardwareI2C *i2c =
reinterpret_cast<Esp32HardwareI2C *
>(ctx);
111 return i2c->open(path, flags, mode);
123static int i2c_vfs_close(
void *ctx,
int fd)
126 Esp32HardwareI2C *i2c =
reinterpret_cast<Esp32HardwareI2C *
>(ctx);
127 return i2c->close(fd);
138static int i2c_vfs_ioctl(
void *ctx,
int fd,
int cmd, va_list args)
141 Esp32HardwareI2C *i2c =
reinterpret_cast<Esp32HardwareI2C *
>(ctx);
142 return i2c->ioctl(fd, cmd, args);
155static int i2c_vfs_fcntl(
void *ctx,
int fd,
int cmd,
int arg)
168Esp32HardwareI2C::~Esp32HardwareI2C()
170 for (
size_t idx = 0; idx < SOC_I2C_NUM; idx++)
172 if (i2cInitialized_[idx])
174 ESP_ERROR_CHECK(i2c_driver_delete(
static_cast<i2c_port_t
>(idx)));
179 ESP_ERROR_CHECK(esp_vfs_unregister(path_));
183void Esp32HardwareI2C::hw_init(
const gpio_num_t sda,
const gpio_num_t scl,
184 const uint32_t bus_speed,
const i2c_port_t port)
186 if (!i2cInitialized_[port])
188 i2c_config_t i2c_config = {};
189 i2c_config.mode = I2C_MODE_MASTER;
190 i2c_config.sda_io_num = sda;
191 i2c_config.sda_pullup_en = GPIO_PULLUP_ENABLE;
192 i2c_config.scl_io_num = scl;
193 i2c_config.scl_pullup_en = GPIO_PULLUP_ENABLE;
194 i2c_config.master.clk_speed = bus_speed;
197 "[I2C] Initializing I2C%d using SDA:%d, SCL:%d, "
198 "bus-speed: %" PRIu32, port, sda, scl, bus_speed);
199 ESP_ERROR_CHECK(i2c_param_config(port, &i2c_config));
200 ESP_ERROR_CHECK(i2c_driver_install(port, I2C_MODE_MASTER,
201 I2C_SLAVE_RX_BUF_SIZE, I2C_SLAVE_TX_BUF_SIZE, I2C_ISR_FLAGS));
203 i2cInitialized_[port] =
true;
207 LOG_ERROR(
"[I2C] I2C%d has already been initialized!", port);
210 if (!vfsInitialized_)
213 vfs.write_p = i2c_vfs_write;
214 vfs.read_p = i2c_vfs_read;
215 vfs.open_p = i2c_vfs_open;
216 vfs.close_p = i2c_vfs_close;
217 vfs.fcntl_p = i2c_vfs_fcntl;
218 vfs.ioctl_p = i2c_vfs_ioctl;
219 vfs.flags = ESP_VFS_FLAG_CONTEXT_PTR;
220 ESP_ERROR_CHECK(esp_vfs_register(path_, &vfs,
this));
222 vfsInitialized_ =
true;
226void Esp32HardwareI2C::scan(
const i2c_port_t port)
229 std::string scanresults =
230 " 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"
232 scanresults.reserve(256);
234 HASSERT(i2cInitialized_[port]);
235 for (uint8_t addr = 0; addr < 0x7F; addr++)
239 scanresults.append(StringPrintf(
"\n%02x: ", addr));
241 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
242 i2c_master_start(cmd);
243 i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE,
true);
244 i2c_master_stop(cmd);
245 esp_err_t ret = i2c_master_cmd_begin(port, cmd, I2C_SCAN_TIMEOUT);
246 i2c_cmd_link_delete(cmd);
249 scanresults.append(StringPrintf(
"%02x ", addr));
251 else if (ret == ESP_ERR_TIMEOUT)
253 scanresults.append(
"?? ");
257 scanresults.append(
"-- ");
260 LOG(
INFO, scanresults.c_str());
263ssize_t Esp32HardwareI2C::write(
int fd,
const void *buf,
size_t size)
271 auto entry = std::find_if(devices_.begin(), devices_.end(),
272 [fd](
const auto &device)
274 return device.fd == fd;
277 if (entry == devices_.end())
283 else if (entry->fd < 0)
289 address = entry->address;
293 esp_err_t res = ESP_ERROR_CHECK_WITHOUT_ABORT(
294 i2c_master_write_to_device(port, address, (uint8_t *)buf, size,
297 if (res == ESP_ERR_TIMEOUT)
301 else if (res == ESP_ERR_INVALID_STATE)
305 else if (res != ESP_OK)
312ssize_t Esp32HardwareI2C::read(
int fd,
void *buf,
size_t size)
320 auto entry = std::find_if(devices_.begin(), devices_.end(),
321 [fd](
const auto &device)
323 return device.fd == fd;
326 if (entry == devices_.end())
332 else if (entry->fd < 0)
338 address = entry->address;
343 esp_err_t res = ESP_ERROR_CHECK_WITHOUT_ABORT(
344 i2c_master_read_from_device(port, address, (uint8_t *)buf, size,
347 if (res == ESP_ERR_TIMEOUT)
351 else if (res == ESP_ERR_INVALID_STATE)
355 else if (res != ESP_OK)
362int Esp32HardwareI2C::open(
const char *path,
int flags,
int mode)
364 std::string path_str = path;
365 i2c_device_t new_dev =
372 if (path_str.back() ==
'0')
374 new_dev.port = I2C_NUM_0;
377 else if (path_str.back() ==
'1')
379 new_dev.port = I2C_NUM_1;
384 LOG_ERROR(
"[I2C] Unsupported I2C path: %s", path);
388 if (!i2cInitialized_[new_dev.port])
390 LOG_ERROR(
"[I2C] Uninitialized I2C path: %s", path);
402 if (!devices_.empty())
404 for (
auto &entry: devices_)
406 if (entry.fd >= new_dev.fd)
408 new_dev.fd = entry.fd + 1;
412 devices_.push_back(new_dev);
415 LOG(
INFO,
"[I2C] Using fd: %d (I2C%d) for %s", new_dev.fd, new_dev.port,
421int Esp32HardwareI2C::close(
int fd)
425 auto entry = std::find_if(devices_.begin(), devices_.end(),
426 [fd](
const auto &device)
428 return device.fd == fd;
432 if (entry != devices_.end())
434 devices_.erase(entry);
439int Esp32HardwareI2C::ioctl(
int fd,
int cmd, va_list args)
444 auto entry = std::find_if(devices_.begin(), devices_.end(),
445 [fd](
const auto &device)
447 return device.fd == fd;
449 if (entry == devices_.end())
455 switch(
static_cast<unsigned int>(cmd))
460 entry->address =
static_cast<int>(va_arg(args,
int));
463 struct i2c_rdwr_ioctl_data *data =
464 reinterpret_cast<struct i2c_rdwr_ioctl_data *
>(va_arg(args, uintptr_t));
465 return transfer_messages(entry->port, data->msgs, data->nmsgs);
471int Esp32HardwareI2C::transfer_messages(
472 const i2c_port_t port,
struct i2c_msg *msgs,
int num)
475 esp_err_t res = ESP_OK;
477 for (
int idx = 0; idx < num; idx++)
479 struct i2c_msg *msg = msgs + idx;
480 if (msg->flags & I2C_M_RD)
483 ESP_ERROR_CHECK_WITHOUT_ABORT(
484 i2c_master_read_from_device(port, msg->addr,
485 (uint8_t *)msg->buf, msg->len, I2C_OP_TIMEOUT));
490 ESP_ERROR_CHECK_WITHOUT_ABORT(
491 i2c_master_write_to_device(port, msg->addr,
492 (uint8_t *)msg->buf, msg->len, I2C_OP_TIMEOUT));
494 if (res == ESP_ERR_TIMEOUT)
498 else if (res == ESP_ERR_INVALID_STATE)
502 else if (res != ESP_OK)
506 total_len += msg->len;
See OSMutexLock in os/OS.hxx.
Esp32HardwareI2C(const char *const path="/dev/i2c")
Constructor.
#define IOC_TYPE(_num)
Decode ioctl type.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#define LOG_ERROR(message...)
Shorthand for LOG(LEVEL_ERROR, message...). See LOG.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.