idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
master.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
21#include <idfxx/error>
22#include <idfxx/gpio>
23#include <idfxx/intr_alloc>
24
25#include <cassert>
26#include <chrono>
27#include <frequency/frequency>
28#include <initializer_list>
29#include <memory>
30#include <mutex>
31#include <optional>
32#include <span>
33#include <string>
34#include <vector>
35
36typedef struct i2c_master_bus_t* i2c_master_bus_handle_t;
37typedef struct i2c_master_dev_t* i2c_master_dev_handle_t;
38
43namespace idfxx::i2c {
44
46static constexpr auto DEFAULT_TIMEOUT = std::chrono::milliseconds(50);
47
52enum class port : int {
53 i2c0 = 0,
54#if SOC_HP_I2C_NUM >= 2
55 i2c1 = 1,
56#endif
57#if SOC_LP_I2C_NUM >= 1
58 lp_i2c0 = 2,
59#endif
60};
61
62// Clock source enums use sequential values rather than matching the ESP-IDF
63// constants directly, since the underlying SOC_MOD_CLK_* values differ per
64// target. Conversion to ESP-IDF types is done in the implementation.
65
70enum class clk_source : int {
71 default_source = 0,
72#if SOC_I2C_SUPPORT_APB
73 apb,
74#endif
75#if SOC_I2C_SUPPORT_REF_TICK
76 ref_tick,
77#endif
78#if SOC_I2C_SUPPORT_XTAL
79 xtal,
80#endif
81#if SOC_I2C_SUPPORT_RTC
82 rc_fast,
83#endif
84};
85
86#if SOC_LP_I2C_SUPPORTED
91enum class lp_clk_source : int {
92 default_source = 0,
93 lp_fast,
94 xtal_d2,
95};
96#endif
97
111public:
127 struct config {
130 freq::hertz frequency{0};
132#if SOC_LP_I2C_SUPPORTED
133 enum lp_clk_source lp_source_clk = lp_clk_source::default_source;
134#endif
136 std::optional<idfxx::intr_level> intr_level = {};
137 size_t trans_queue_depth = 0;
139 bool allow_pd = false;
140 };
141
142#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
161 [[nodiscard]] explicit master_bus(enum port port, const struct config& config);
162
174 [[nodiscard]] explicit master_bus(enum port port, gpio sda, gpio scl, freq::hertz frequency);
175#endif
176
194 [[nodiscard]] static result<master_bus> make(enum port port, const struct config& config);
195
206 [[nodiscard]] static result<master_bus> make(enum port port, gpio sda, gpio scl, freq::hertz frequency);
207
209
210 master_bus(const master_bus&) = delete;
211 master_bus& operator=(const master_bus&) = delete;
212 master_bus(master_bus&& other) noexcept;
213 master_bus& operator=(master_bus&& other) noexcept;
214
216 void lock() const {
217 if (!_mux) {
218 return;
219 }
220 _mux->lock();
221 }
222
225 if (!_mux) {
226 return false;
227 }
228 return _mux->try_lock();
229 }
230
232 void unlock() const {
233 if (!_mux) {
234 return;
235 }
236 _mux->unlock();
237 }
238
240 [[nodiscard]] i2c_master_bus_handle_t handle() const { return _handle; }
241
243 [[nodiscard]] enum port port() const { return _port; }
244
246 [[nodiscard]] freq::hertz frequency() const { return _frequency; }
247
255 [[nodiscard]] std::vector<uint8_t> scan_devices() const { return scan_devices(DEFAULT_TIMEOUT); }
256
266 template<typename Rep, typename Period>
267 [[nodiscard]] std::vector<uint8_t> scan_devices(const std::chrono::duration<Rep, Period>& timeout) const {
268 return _scan_devices(std::chrono::ceil<std::chrono::milliseconds>(timeout));
269 }
270
271#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
280 void probe(uint16_t address) const { probe(address, DEFAULT_TIMEOUT); }
281
291 template<typename Rep, typename Period>
292 void probe(uint16_t address, const std::chrono::duration<Rep, Period>& timeout) const {
293 unwrap(_probe(address, std::chrono::ceil<std::chrono::milliseconds>(timeout)));
294 }
295#endif
296
304 [[nodiscard]] result<void> try_probe(uint16_t address) const { return try_probe(address, DEFAULT_TIMEOUT); }
305
314 template<typename Rep, typename Period>
315 [[nodiscard]] result<void> try_probe(uint16_t address, const std::chrono::duration<Rep, Period>& timeout) const {
316 return _probe(address, std::chrono::ceil<std::chrono::milliseconds>(timeout));
317 }
318
319private:
320 explicit master_bus(i2c_master_bus_handle_t handle, enum port port, freq::hertz frequency);
321
322 void _delete() noexcept;
323
324 [[nodiscard]] std::vector<uint8_t> _scan_devices(std::chrono::milliseconds timeout) const;
325 [[nodiscard]] result<void> _probe(uint16_t address, std::chrono::milliseconds timeout) const;
326
327 mutable std::unique_ptr<std::recursive_mutex> _mux;
328 i2c_master_bus_handle_t _handle = nullptr;
329 enum port _port;
330 freq::hertz _frequency;
331};
332
345public:
358 struct config {
359 freq::hertz scl_speed{0};
360 uint32_t scl_wait_us = 0;
361 bool addr_10bit = false;
362 bool disable_ack_check = false;
363 };
364
365#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
385 [[nodiscard]] explicit master_device(master_bus& bus, uint16_t address, const struct config& config);
386
399 [[nodiscard]] explicit master_device(master_bus& bus, uint16_t address);
400#endif
401
420 [[nodiscard]] static result<master_device> make(master_bus& bus, uint16_t address, const struct config& config);
421
434
436
437 master_device(const master_device&) = delete;
439 master_device(master_device&& other) noexcept;
441
446 [[nodiscard]] master_bus& bus() const {
447 assert(_bus != nullptr);
448 return *_bus;
449 }
450
452 [[nodiscard]] i2c_master_dev_handle_t handle() const { return _handle; }
453
455 [[nodiscard]] uint16_t address() const { return _address; }
456
457#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
464 void probe() const { probe(DEFAULT_TIMEOUT); }
465
474 template<typename Rep, typename Period>
475 void probe(const std::chrono::duration<Rep, Period>& timeout) const {
477 }
478#endif
479
486
494 template<typename Rep, typename Period>
495 [[nodiscard]] result<void> try_probe(const std::chrono::duration<Rep, Period>& timeout) const {
496 if (_handle == nullptr) {
498 }
499 return _bus->try_probe(_address, std::chrono::ceil<std::chrono::milliseconds>(timeout));
500 }
501
502#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
511 void transmit(std::span<const uint8_t> data) { unwrap(try_transmit(data)); }
512
522 template<typename Rep, typename Period>
523 void transmit(std::span<const uint8_t> data, const std::chrono::duration<Rep, Period>& timeout) {
524 unwrap(try_transmit(data, timeout));
525 }
526
536 void transmit(const uint8_t* buf, size_t size) { unwrap(try_transmit(buf, size)); }
537
548 template<typename Rep, typename Period>
549 void transmit(const uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
550 unwrap(try_transmit(buf, size, timeout));
551 }
552#endif
553
561 [[nodiscard]] result<void> try_transmit(std::span<const uint8_t> data) {
562 return try_transmit(data, DEFAULT_TIMEOUT);
563 }
564
573 template<typename Rep, typename Period>
575 try_transmit(std::span<const uint8_t> data, const std::chrono::duration<Rep, Period>& timeout) {
576 return try_transmit(data.data(), data.size(), timeout);
577 }
578
587 [[nodiscard]] result<void> try_transmit(const uint8_t* buf, size_t size) {
588 return try_transmit(buf, size, DEFAULT_TIMEOUT);
589 }
590
600 template<typename Rep, typename Period>
602 try_transmit(const uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
603 return _try_transmit(buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
604 }
605
606#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
617 [[nodiscard]] std::vector<uint8_t> receive(size_t size) { return unwrap(try_receive(size)); }
618
630 template<typename Rep, typename Period>
631 [[nodiscard]] std::vector<uint8_t> receive(size_t size, const std::chrono::duration<Rep, Period>& timeout) {
632 return unwrap(try_receive(size, timeout));
633 }
634
644 void receive(uint8_t* buf, size_t size) { unwrap(try_receive(buf, size)); }
645
656 template<typename Rep, typename Period>
657 void receive(uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
658 unwrap(try_receive(buf, size, timeout));
659 }
660
669 void receive(std::span<uint8_t> buf) { unwrap(try_receive(buf)); }
670
680 template<typename Rep, typename Period>
681 void receive(std::span<uint8_t> buf, const std::chrono::duration<Rep, Period>& timeout) {
682 unwrap(try_receive(buf, timeout));
683 }
684#endif
685
694
703 template<typename Rep, typename Period>
705 try_receive(size_t size, const std::chrono::duration<Rep, Period>& timeout) {
706 std::vector<uint8_t> buf(size);
707 return try_receive(buf, timeout).transform([&]() { return buf; });
708 }
709
719 return try_receive(buf, size, DEFAULT_TIMEOUT);
720 }
721
731 template<typename Rep, typename Period>
733 try_receive(uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
734 return _try_receive(buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
735 }
736
745
754 template<typename Rep, typename Period>
755 [[nodiscard]] result<void> try_receive(std::span<uint8_t> buf, const std::chrono::duration<Rep, Period>& timeout) {
756 return try_receive(buf.data(), buf.size(), timeout);
757 }
758
759#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
769 void write_register(uint16_t reg, std::span<const uint8_t> buf) { unwrap(try_write_register(reg, buf)); }
770
781 template<typename Rep, typename Period>
782 void write_register(uint16_t reg, std::span<const uint8_t> buf, const std::chrono::duration<Rep, Period>& timeout) {
783 unwrap(try_write_register(reg, buf, timeout));
784 }
785
796 void write_register(uint16_t reg, const uint8_t* buf, size_t size) { unwrap(try_write_register(reg, buf, size)); }
797
809 template<typename Rep, typename Period>
810 void
811 write_register(uint16_t reg, const uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
812 unwrap(try_write_register(reg, buf, size, timeout));
813 }
814#endif
815
824 [[nodiscard]] result<void> try_write_register(uint16_t reg, std::span<const uint8_t> buf) {
825 return try_write_register(reg, buf.data(), buf.size(), DEFAULT_TIMEOUT);
826 }
827
837 template<typename Rep, typename Period>
839 try_write_register(uint16_t reg, std::span<const uint8_t> buf, const std::chrono::duration<Rep, Period>& timeout) {
840 return try_write_register(reg, buf.data(), buf.size(), timeout);
841 }
842
853 return try_write_register(reg, buf, size, DEFAULT_TIMEOUT);
854 }
855
866 template<typename Rep, typename Period>
869 const uint8_t* buf,
870 size_t size,
871 const std::chrono::duration<Rep, Period>& timeout
872 ) {
873 return _try_write_register(reg, buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
874 }
875
876#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
887 void write_register(uint8_t high, uint8_t low, std::span<const uint8_t> buf) {
888 unwrap(try_write_register(high, low, buf));
889 }
890
902 template<typename Rep, typename Period>
904 uint8_t high,
905 uint8_t low,
906 std::span<const uint8_t> buf,
907 const std::chrono::duration<Rep, Period>& timeout
908 ) {
909 unwrap(try_write_register(high, low, buf, timeout));
910 }
911
923 void write_register(uint8_t high, uint8_t low, const uint8_t* buf, size_t size) {
924 unwrap(try_write_register(high, low, buf, size));
925 }
926
939 template<typename Rep, typename Period>
941 uint8_t high,
942 uint8_t low,
943 const uint8_t* buf,
944 size_t size,
945 const std::chrono::duration<Rep, Period>& timeout
946 ) {
947 unwrap(try_write_register(high, low, buf, size, timeout));
948 }
949#endif
950
960 [[nodiscard]] result<void> try_write_register(uint8_t high, uint8_t low, std::span<const uint8_t> buf) {
961 return try_write_register(high, low, buf, DEFAULT_TIMEOUT);
962 }
963
974 template<typename Rep, typename Period>
976 uint8_t high,
977 uint8_t low,
978 std::span<const uint8_t> buf,
979 const std::chrono::duration<Rep, Period>& timeout
980 ) {
981 return try_write_register(high, low, buf.data(), buf.size(), timeout);
982 }
983
994 [[nodiscard]] result<void> try_write_register(uint8_t high, uint8_t low, const uint8_t* buf, size_t size) {
995 return try_write_register(high, low, buf, size, DEFAULT_TIMEOUT);
996 }
997
1009 template<typename Rep, typename Period>
1011 uint8_t high,
1012 uint8_t low,
1013 const uint8_t* buf,
1014 size_t size,
1015 const std::chrono::duration<Rep, Period>& timeout
1016 ) {
1017 return _try_write_register(high, low, buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
1018 }
1019
1020#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
1030 void write_registers(std::span<const uint16_t> registers, std::span<const uint8_t> buf) {
1031 unwrap(try_write_registers(registers, buf));
1032 }
1033
1044 template<typename Rep, typename Period>
1046 std::span<const uint16_t> registers,
1047 std::span<const uint8_t> buf,
1048 const std::chrono::duration<Rep, Period>& timeout
1049 ) {
1050 unwrap(try_write_registers(registers, buf, timeout));
1051 }
1052
1063 void write_registers(std::span<const uint16_t> registers, const uint8_t* buf, size_t size) {
1064 unwrap(try_write_registers(registers, buf, size));
1065 }
1066
1078 template<typename Rep, typename Period>
1080 std::span<const uint16_t> registers,
1081 const uint8_t* buf,
1082 size_t size,
1083 const std::chrono::duration<Rep, Period>& timeout
1084 ) {
1085 unwrap(try_write_registers(registers, buf, size, timeout));
1086 }
1087
1088 // C++23: std::span cannot be constructed from a braced initializer list until C++26 (P2447).
1089 // Remove these overloads when C++26 becomes the minimum standard.
1090
1100 void write_registers(std::initializer_list<uint16_t> registers, std::span<const uint8_t> buf) {
1101 write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf);
1102 }
1103
1114 template<typename Rep, typename Period>
1116 std::initializer_list<uint16_t> registers,
1117 std::span<const uint8_t> buf,
1118 const std::chrono::duration<Rep, Period>& timeout
1119 ) {
1120 write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf, timeout);
1121 }
1122
1133 void write_registers(std::initializer_list<uint16_t> registers, const uint8_t* buf, size_t size) {
1134 write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf, size);
1135 }
1136
1148 template<typename Rep, typename Period>
1150 std::initializer_list<uint16_t> registers,
1151 const uint8_t* buf,
1152 size_t size,
1153 const std::chrono::duration<Rep, Period>& timeout
1154 ) {
1155 write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf, size, timeout);
1156 }
1157#endif
1158
1167 [[nodiscard]] result<void> try_write_registers(std::span<const uint16_t> registers, std::span<const uint8_t> buf) {
1168 return try_write_registers(registers, buf, DEFAULT_TIMEOUT);
1169 }
1170
1180 template<typename Rep, typename Period>
1182 std::span<const uint16_t> registers,
1183 std::span<const uint8_t> buf,
1184 const std::chrono::duration<Rep, Period>& timeout
1185 ) {
1186 return try_write_registers(registers, buf.data(), buf.size(), timeout);
1187 }
1188
1199 try_write_registers(std::span<const uint16_t> registers, const uint8_t* buf, size_t size) {
1200 return try_write_registers(registers, buf, size, DEFAULT_TIMEOUT);
1201 }
1202
1213 template<typename Rep, typename Period>
1215 std::span<const uint16_t> registers,
1216 const uint8_t* buf,
1217 size_t size,
1218 const std::chrono::duration<Rep, Period>& timeout
1219 ) {
1220 return _try_write_registers(registers, buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
1221 }
1222
1223 // C++23: std::span cannot be constructed from a braced initializer list until C++26 (P2447).
1224 // Remove these overloads when C++26 becomes the minimum standard.
1225
1235 try_write_registers(std::initializer_list<uint16_t> registers, std::span<const uint8_t> buf) {
1236 return try_write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf);
1237 }
1238
1248 template<typename Rep, typename Period>
1250 std::initializer_list<uint16_t> registers,
1251 std::span<const uint8_t> buf,
1252 const std::chrono::duration<Rep, Period>& timeout
1253 ) {
1254 return try_write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf, timeout);
1255 }
1256
1267 try_write_registers(std::initializer_list<uint16_t> registers, const uint8_t* buf, size_t size) {
1268 return try_write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf, size);
1269 }
1270
1281 template<typename Rep, typename Period>
1283 std::initializer_list<uint16_t> registers,
1284 const uint8_t* buf,
1285 size_t size,
1286 const std::chrono::duration<Rep, Period>& timeout
1287 ) {
1288 return try_write_registers(std::span<const uint16_t>{registers.begin(), registers.size()}, buf, size, timeout);
1289 }
1290
1291#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
1303 [[nodiscard]] std::vector<uint8_t> read_register(uint16_t reg, size_t size) {
1304 return unwrap(try_read_register(reg, size));
1305 }
1306
1319 template<typename Rep, typename Period>
1320 [[nodiscard]] std::vector<uint8_t>
1321 read_register(uint16_t reg, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
1322 return unwrap(try_read_register(reg, size, timeout));
1323 }
1324
1334 void read_register(uint16_t reg, std::span<uint8_t> buf) { unwrap(try_read_register(reg, buf)); }
1335
1346 template<typename Rep, typename Period>
1347 void read_register(uint16_t reg, std::span<uint8_t> buf, const std::chrono::duration<Rep, Period>& timeout) {
1348 unwrap(try_read_register(reg, buf, timeout));
1349 }
1350
1361 void read_register(uint16_t reg, uint8_t* buf, size_t size) { unwrap(try_read_register(reg, buf, size)); }
1362
1374 template<typename Rep, typename Period>
1375 void read_register(uint16_t reg, uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
1376 unwrap(try_read_register(reg, buf, size, timeout));
1377 }
1378#endif
1379
1389 return try_read_register(reg, size, DEFAULT_TIMEOUT);
1390 }
1391
1401 template<typename Rep, typename Period>
1403 try_read_register(uint16_t reg, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
1404 std::vector<uint8_t> buf(size);
1405 return try_read_register(reg, buf, timeout).transform([&]() { return buf; });
1406 }
1407
1417 return try_read_register(reg, buf, DEFAULT_TIMEOUT);
1418 }
1419
1428 template<typename Rep, typename Period>
1430 try_read_register(uint16_t reg, std::span<uint8_t> buf, const std::chrono::duration<Rep, Period>& timeout) {
1431 return try_read_register(reg, buf.data(), buf.size(), timeout);
1432 }
1433
1444 return try_read_register(reg, buf, size, DEFAULT_TIMEOUT);
1445 }
1446
1457 template<typename Rep, typename Period>
1459 try_read_register(uint16_t reg, uint8_t* buf, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
1460 return _try_read_register(reg, buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
1461 }
1462
1463#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
1476 [[nodiscard]] std::vector<uint8_t> read_register(uint8_t high, uint8_t low, size_t size) {
1477 return unwrap(try_read_register(high, low, size));
1478 }
1479
1493 template<typename Rep, typename Period>
1494 [[nodiscard]] std::vector<uint8_t>
1495 read_register(uint8_t high, uint8_t low, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
1496 return unwrap(try_read_register(high, low, size, timeout));
1497 }
1498
1510 void read_register(uint8_t high, uint8_t low, uint8_t* buf, size_t size) {
1511 unwrap(try_read_register(high, low, buf, size));
1512 }
1513
1526 template<typename Rep, typename Period>
1528 uint8_t high,
1529 uint8_t low,
1530 uint8_t* buf,
1531 size_t size,
1532 const std::chrono::duration<Rep, Period>& timeout
1533 ) {
1534 unwrap(try_read_register(high, low, buf, size, timeout));
1535 }
1536#endif
1537
1548 return try_read_register(high, low, size, DEFAULT_TIMEOUT);
1549 }
1550
1561 template<typename Rep, typename Period>
1563 try_read_register(uint8_t high, uint8_t low, size_t size, const std::chrono::duration<Rep, Period>& timeout) {
1564 std::vector<uint8_t> buf(size);
1565 return try_read_register(high, low, buf, timeout).transform([&]() { return buf; });
1566 }
1567
1577 [[nodiscard]] result<void> try_read_register(uint8_t high, uint8_t low, std::span<uint8_t> buf) {
1578 return try_read_register(high, low, buf, DEFAULT_TIMEOUT);
1579 }
1580
1591 template<typename Rep, typename Period>
1593 uint8_t high,
1594 uint8_t low,
1595 std::span<uint8_t> buf,
1596 const std::chrono::duration<Rep, Period>& timeout
1597 ) {
1598 return try_read_register(high, low, buf.data(), buf.size(), timeout);
1599 }
1600
1612 return try_read_register(high, low, buf, size, DEFAULT_TIMEOUT);
1613 }
1614
1626 template<typename Rep, typename Period>
1628 uint8_t high,
1629 uint8_t low,
1630 uint8_t* buf,
1631 size_t size,
1632 const std::chrono::duration<Rep, Period>& timeout
1633 ) {
1634 return _try_read_register(high, low, buf, size, std::chrono::ceil<std::chrono::milliseconds>(timeout));
1635 }
1636
1637private:
1639
1640 void _delete() noexcept;
1641
1642 [[nodiscard]] result<void> _try_transmit(const uint8_t* buf, size_t size, std::chrono::milliseconds timeout);
1643 [[nodiscard]] result<void> _try_receive(uint8_t* buf, size_t size, std::chrono::milliseconds timeout);
1644
1645 [[nodiscard]] result<void>
1646 _try_write_register(uint16_t reg, const uint8_t* buf, size_t size, std::chrono::milliseconds timeout);
1647 [[nodiscard]] result<void>
1648 _try_write_register(uint8_t high, uint8_t low, const uint8_t* buf, size_t size, std::chrono::milliseconds timeout);
1649 [[nodiscard]] result<void> _try_write_registers(
1651 const uint8_t* buf,
1652 size_t size,
1653 std::chrono::milliseconds timeout
1654 );
1655 [[nodiscard]] result<void>
1656 _try_read_register(uint16_t reg, uint8_t* buf, size_t size, std::chrono::milliseconds timeout);
1657 [[nodiscard]] result<void>
1658 _try_read_register(uint8_t high, uint8_t low, uint8_t* buf, size_t size, std::chrono::milliseconds timeout);
1659
1660 master_bus* _bus = nullptr;
1661 i2c_master_dev_handle_t _handle = nullptr;
1662 uint16_t _address = 0;
1663};
1664
// end of idfxx_i2c
1666
1667} // namespace idfxx::i2c
1668
1670
1678[[nodiscard]] inline std::string to_string(i2c::port p) {
1679 switch (p) {
1680 case i2c::port::i2c0:
1681 return "I2C0";
1682#if SOC_HP_I2C_NUM >= 2
1683 case i2c::port::i2c1:
1684 return "I2C1";
1685#endif
1686#if SOC_LP_I2C_NUM >= 1
1687 case i2c::port::lp_i2c0:
1688 return "LP_I2C0";
1689#endif
1690 default:
1691 return "unknown(" + std::to_string(static_cast<int>(p)) + ")";
1692 }
1693}
1694
1695} // namespace idfxx
1696
1697#include "sdkconfig.h"
1698#ifdef CONFIG_IDFXX_STD_FORMAT
1700#include <algorithm>
1701#include <format>
1702namespace std {
1703template<>
1704struct formatter<idfxx::i2c::port> {
1705 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
1706
1707 template<typename FormatContext>
1708 auto format(idfxx::i2c::port p, FormatContext& ctx) const {
1709 auto s = idfxx::to_string(p);
1710 return std::copy(s.begin(), s.end(), ctx.out());
1711 }
1712};
1713} // namespace std
1715#endif // CONFIG_IDFXX_STD_FORMAT
A GPIO pin.
Definition gpio.hpp:61
static constexpr gpio nc()
Returns a GPIO representing "not connected".
Definition gpio.hpp:254
I2C master bus controller with thread-safe device access.
Definition master.hpp:110
master_bus(enum port port, gpio sda, gpio scl, freq::hertz frequency)
Creates a new I2C master bus with default settings.
result< void > try_probe(uint16_t address) const
Probes for a device at the specified address.
Definition master.hpp:304
std::vector< uint8_t > scan_devices() const
Scans for devices on the bus.
Definition master.hpp:255
enum port port() const
Returns the I2C port.
Definition master.hpp:243
std::vector< uint8_t > scan_devices(const std::chrono::duration< Rep, Period > &timeout) const
Scans for devices on the bus.
Definition master.hpp:267
void probe(uint16_t address, const std::chrono::duration< Rep, Period > &timeout) const
Probes for a device at the specified address.
Definition master.hpp:292
master_bus & operator=(const master_bus &)=delete
static result< master_bus > make(enum port port, gpio sda, gpio scl, freq::hertz frequency)
Creates a new I2C master bus with default settings.
result< void > try_probe(uint16_t address, const std::chrono::duration< Rep, Period > &timeout) const
Probes for a device at the specified address.
Definition master.hpp:315
static result< master_bus > make(enum port port, const struct config &config)
Creates a new I2C master bus.
i2c_master_bus_handle_t handle() const
Returns the underlying ESP-IDF bus handle.
Definition master.hpp:240
freq::hertz frequency() const
Returns the bus clock frequency in Hz.
Definition master.hpp:246
void unlock() const
Releases exclusive access to the bus.
Definition master.hpp:232
master_bus(const master_bus &)=delete
master_bus(master_bus &&other) noexcept
bool try_lock() const noexcept
Tries to acquire exclusive access without blocking.
Definition master.hpp:224
master_bus(enum port port, const struct config &config)
Creates a new I2C master bus.
void probe(uint16_t address) const
Probes for a device at the specified address.
Definition master.hpp:280
void lock() const
Acquires exclusive access to the bus.
Definition master.hpp:216
master_bus & operator=(master_bus &&other) noexcept
I2C device at a specific address with register operations.
Definition master.hpp:344
void transmit(const uint8_t *buf, size_t size)
Transmits data to the device.
Definition master.hpp:536
result< void > try_write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1214
result< void > try_probe() const
Probes the device.
Definition master.hpp:485
result< void > try_read_register(uint16_t reg, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1459
void read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size)
Reads data from a register.
Definition master.hpp:1510
void write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1045
result< void > try_write_register(uint16_t reg, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:867
result< std::vector< uint8_t > > try_receive(size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
Definition master.hpp:705
void write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1149
void write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf)
Writes data to a register.
Definition master.hpp:887
void write_register(uint16_t reg, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:811
result< void > try_write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1181
void write_register(uint16_t reg, const uint8_t *buf, size_t size)
Writes data to a register.
Definition master.hpp:796
result< void > try_write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:975
void write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:903
std::vector< uint8_t > read_register(uint16_t reg, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1321
master_device(master_bus &bus, uint16_t address)
Creates a new device on the specified bus.
result< std::vector< uint8_t > > try_read_register(uint16_t reg, size_t size)
Reads data from a register.
Definition master.hpp:1388
void write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
Definition master.hpp:1100
result< void > try_write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1249
void write_register(uint16_t reg, std::span< const uint8_t > buf)
Writes data to a register.
Definition master.hpp:769
result< void > try_read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1627
void read_register(uint16_t reg, std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1347
result< void > try_write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
Definition master.hpp:1267
void write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
Definition master.hpp:1063
result< void > try_write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:1010
result< void > try_write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
Definition master.hpp:1199
result< void > try_read_register(uint16_t reg, std::span< uint8_t > buf)
Reads data from a register.
Definition master.hpp:1416
result< void > try_write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size)
Writes data to a register.
Definition master.hpp:994
void transmit(std::span< const uint8_t > data, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
Definition master.hpp:523
void receive(uint8_t *buf, size_t size)
Receives data from the device.
Definition master.hpp:644
void probe() const
Probes the device.
Definition master.hpp:464
result< void > try_read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size)
Reads data from a register.
Definition master.hpp:1611
void receive(uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
Definition master.hpp:657
result< void > try_receive(uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
Definition master.hpp:733
void probe(const std::chrono::duration< Rep, Period > &timeout) const
Probes the device.
Definition master.hpp:475
result< std::vector< uint8_t > > try_receive(size_t size)
Receives data from the device.
Definition master.hpp:693
result< void > try_write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf)
Writes data to a register.
Definition master.hpp:960
result< std::vector< uint8_t > > try_read_register(uint8_t high, uint8_t low, size_t size)
Reads data from a register.
Definition master.hpp:1547
result< std::vector< uint8_t > > try_read_register(uint8_t high, uint8_t low, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1563
void read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1527
result< void > try_read_register(uint8_t high, uint8_t low, std::span< uint8_t > buf)
Reads data from a register.
Definition master.hpp:1577
master_device(const master_device &)=delete
std::vector< uint8_t > read_register(uint8_t high, uint8_t low, size_t size)
Reads data from a register.
Definition master.hpp:1476
result< void > try_write_register(uint16_t reg, std::span< const uint8_t > buf)
Writes data to a register.
Definition master.hpp:824
result< void > try_write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1282
result< void > try_write_register(uint16_t reg, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:839
void transmit(std::span< const uint8_t > data)
Transmits data to the device.
Definition master.hpp:511
master_device(master_device &&other) noexcept
void write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
Definition master.hpp:1030
static result< master_device > make(master_bus &bus, uint16_t address, const struct config &config)
Creates a new device on the specified bus.
void write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
Definition master.hpp:1133
master_device(master_bus &bus, uint16_t address, const struct config &config)
Creates a new device on the specified bus.
void write_register(uint16_t reg, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:782
result< std::vector< uint8_t > > try_read_register(uint16_t reg, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1403
uint16_t address() const
Returns the device address.
Definition master.hpp:455
result< void > try_read_register(uint8_t high, uint8_t low, std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1592
void read_register(uint16_t reg, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1375
result< void > try_transmit(const uint8_t *buf, size_t size)
Transmits data to the device.
Definition master.hpp:587
void write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
Definition master.hpp:940
result< void > try_receive(std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
Definition master.hpp:755
result< void > try_receive(uint8_t *buf, size_t size)
Receives data from the device.
Definition master.hpp:718
i2c_master_dev_handle_t handle() const
Returns the underlying ESP-IDF device handle.
Definition master.hpp:452
void read_register(uint16_t reg, std::span< uint8_t > buf)
Reads data from a register.
Definition master.hpp:1334
void transmit(const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
Definition master.hpp:549
result< void > try_write_register(uint16_t reg, const uint8_t *buf, size_t size)
Writes data to a register.
Definition master.hpp:852
result< void > try_receive(std::span< uint8_t > buf)
Receives data from the device.
Definition master.hpp:744
std::vector< uint8_t > read_register(uint8_t high, uint8_t low, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1495
result< void > try_read_register(uint16_t reg, uint8_t *buf, size_t size)
Reads data from a register.
Definition master.hpp:1443
result< void > try_transmit(const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
Definition master.hpp:602
result< void > try_transmit(std::span< const uint8_t > data)
Transmits data to the device.
Definition master.hpp:561
void write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1115
std::vector< uint8_t > receive(size_t size)
Receives data from the device.
Definition master.hpp:617
std::vector< uint8_t > read_register(uint16_t reg, size_t size)
Reads data from a register.
Definition master.hpp:1303
result< void > try_write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
Definition master.hpp:1167
result< void > try_transmit(std::span< const uint8_t > data, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
Definition master.hpp:575
std::vector< uint8_t > receive(size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
Definition master.hpp:631
result< void > try_write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
Definition master.hpp:1235
master_device & operator=(const master_device &)=delete
master_device & operator=(master_device &&other) noexcept
void write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size)
Writes data to a register.
Definition master.hpp:923
result< void > try_probe(const std::chrono::duration< Rep, Period > &timeout) const
Probes the device.
Definition master.hpp:495
void receive(std::span< uint8_t > buf)
Receives data from the device.
Definition master.hpp:669
void write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
Definition master.hpp:1079
void read_register(uint16_t reg, uint8_t *buf, size_t size)
Reads data from a register.
Definition master.hpp:1361
master_bus & bus() const
Returns the parent bus.
Definition master.hpp:446
result< void > try_read_register(uint16_t reg, std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
Definition master.hpp:1430
static result< master_device > make(master_bus &bus, uint16_t address)
Creates a new device on the specified bus.
void receive(std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
Definition master.hpp:681
std::string to_string(core_id c)
Returns a string representation of a CPU core identifier.
Definition cpu.hpp:52
struct i2c_master_bus_t * i2c_master_bus_handle_t
Definition master.hpp:36
struct i2c_master_dev_t * i2c_master_dev_handle_t
Definition master.hpp:37
clk_source
I2C master bus clock source.
Definition master.hpp:70
port
I2C port identifiers.
Definition master.hpp:52
static constexpr auto DEFAULT_TIMEOUT
Default timeout for I2C operations.
Definition master.hpp:46
@ default_source
Default clock source for the target.
@ i2c0
I2C port 0.
I2C master driver classes.
Definition master.hpp:43
intr_level
Hardware interrupt priority levels.
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
Definition error.hpp:187
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:307
@ invalid_state
Invalid state.
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120
I2C master bus configuration.
Definition master.hpp:127
freq::hertz frequency
Clock frequency in Hz.
Definition master.hpp:130
bool allow_pd
Allow powering down the bus during light sleep.
Definition master.hpp:139
idfxx::gpio scl
GPIO pin for the SCL line.
Definition master.hpp:129
idfxx::gpio sda
GPIO pin for the SDA line.
Definition master.hpp:128
size_t trans_queue_depth
Depth of internal transfer queue for asynchronous transactions.
Definition master.hpp:137
uint8_t glitch_ignore_cnt
Glitch filter count (0-7). Higher values filter more noise.
Definition master.hpp:135
bool enable_internal_pullup
Enable internal pull-up resistors on SDA and SCL.
Definition master.hpp:138
I2C device configuration.
Definition master.hpp:358