i2c_cxx.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #ifdef __cpp_exceptions
  7. #include "driver/i2c.h"
  8. #include "i2c_cxx.hpp"
  9. using namespace std;
  10. namespace idf {
  11. #define I2C_CHECK_THROW(err) CHECK_THROW_SPECIFIC((err), I2CException)
  12. esp_err_t check_i2c_num(uint32_t i2c_num) noexcept
  13. {
  14. if (i2c_num >= I2C_NUM_MAX) {
  15. return ESP_ERR_INVALID_ARG;
  16. }
  17. return ESP_OK;
  18. }
  19. esp_err_t check_i2c_addr(uint32_t addr) noexcept
  20. {
  21. // maximum I2C address currently supported in the C++ classes is 127
  22. if (addr > 0x7f) {
  23. return ESP_ERR_INVALID_ARG;
  24. }
  25. return ESP_OK;
  26. }
  27. I2CException::I2CException(esp_err_t error) : ESPException(error) { }
  28. I2CTransferException::I2CTransferException(esp_err_t error) : I2CException(error) { }
  29. uint32_t I2CNumber::get_num()
  30. {
  31. return get_value();
  32. }
  33. I2CAddress::I2CAddress(uint8_t addr) : StrongValueComparable<uint8_t> (addr)
  34. {
  35. esp_err_t error = check_i2c_addr(addr);
  36. if (error != ESP_OK) {
  37. throw I2CException(error);
  38. }
  39. }
  40. uint8_t I2CAddress::get_addr()
  41. {
  42. return get_value();
  43. }
  44. I2CCommandLink::I2CCommandLink()
  45. {
  46. handle = i2c_cmd_link_create();
  47. if (!handle) {
  48. throw I2CException(ESP_ERR_NO_MEM);
  49. }
  50. }
  51. I2CCommandLink::~I2CCommandLink()
  52. {
  53. i2c_cmd_link_delete(handle);
  54. }
  55. void I2CCommandLink::start()
  56. {
  57. I2C_CHECK_THROW(i2c_master_start(handle));
  58. }
  59. void I2CCommandLink::write(const std::vector<uint8_t> &bytes, bool expect_ack)
  60. {
  61. I2C_CHECK_THROW(i2c_master_write(handle, bytes.data(), bytes.size(), expect_ack));
  62. }
  63. void I2CCommandLink::write_byte(uint8_t byte, bool expect_ack)
  64. {
  65. I2C_CHECK_THROW(i2c_master_write_byte(handle, byte, expect_ack));
  66. }
  67. void I2CCommandLink::read(std::vector<uint8_t> &bytes)
  68. {
  69. I2C_CHECK_THROW(i2c_master_read(handle, bytes.data(), bytes.size(), I2C_MASTER_LAST_NACK));
  70. }
  71. void I2CCommandLink::stop()
  72. {
  73. I2C_CHECK_THROW(i2c_master_stop(handle));
  74. }
  75. void I2CCommandLink::execute_transfer(I2CNumber i2c_num, chrono::milliseconds driver_timeout)
  76. {
  77. esp_err_t err = i2c_master_cmd_begin(i2c_num.get_num(), handle, driver_timeout.count() / portTICK_PERIOD_MS);
  78. if (err != ESP_OK) {
  79. throw I2CTransferException(err);
  80. }
  81. }
  82. I2CBus::I2CBus(I2CNumber i2c_number) : i2c_num(std::move(i2c_number)) { }
  83. I2CBus::~I2CBus() { }
  84. I2CMaster::I2CMaster(I2CNumber i2c_number,
  85. SCL_GPIO scl_gpio,
  86. SDA_GPIO sda_gpio,
  87. Frequency clock_speed,
  88. bool scl_pullup,
  89. bool sda_pullup)
  90. : I2CBus(std::move(i2c_number))
  91. {
  92. i2c_config_t conf = {};
  93. conf.mode = I2C_MODE_MASTER;
  94. conf.scl_io_num = scl_gpio.get_num();
  95. conf.scl_pullup_en = scl_pullup;
  96. conf.sda_io_num = sda_gpio.get_num();
  97. conf.sda_pullup_en = sda_pullup;
  98. conf.master.clk_speed = clock_speed.get_value();
  99. I2C_CHECK_THROW(i2c_param_config(i2c_num.get_value(), &conf));
  100. I2C_CHECK_THROW(i2c_driver_install(i2c_num.get_value(), conf.mode, 0, 0, 0));
  101. }
  102. I2CMaster::~I2CMaster()
  103. {
  104. i2c_driver_delete(i2c_num.get_value());
  105. }
  106. void I2CMaster::sync_write(I2CAddress i2c_addr, const vector<uint8_t> &data)
  107. {
  108. I2CWrite writer(data);
  109. writer.do_transfer(i2c_num, i2c_addr);
  110. }
  111. std::vector<uint8_t> I2CMaster::sync_read(I2CAddress i2c_addr, size_t n_bytes)
  112. {
  113. I2CRead reader(n_bytes);
  114. return reader.do_transfer(i2c_num, i2c_addr);
  115. }
  116. vector<uint8_t> I2CMaster::sync_transfer(I2CAddress i2c_addr,
  117. const std::vector<uint8_t> &write_data,
  118. size_t read_n_bytes)
  119. {
  120. I2CComposed composed_transfer;
  121. composed_transfer.add_write(write_data);
  122. composed_transfer.add_read(read_n_bytes);
  123. return composed_transfer.do_transfer(i2c_num, i2c_addr)[0];
  124. }
  125. #if CONFIG_SOC_I2C_SUPPORT_SLAVE
  126. I2CSlave::I2CSlave(I2CNumber i2c_number,
  127. SCL_GPIO scl_gpio,
  128. SDA_GPIO sda_gpio,
  129. I2CAddress slave_addr,
  130. size_t rx_buf_len,
  131. size_t tx_buf_len,
  132. bool scl_pullup,
  133. bool sda_pullup)
  134. : I2CBus(std::move(i2c_number))
  135. {
  136. i2c_config_t conf = {};
  137. conf.mode = I2C_MODE_SLAVE;
  138. conf.scl_io_num = scl_gpio.get_value();
  139. conf.scl_pullup_en = scl_pullup;
  140. conf.sda_io_num = sda_gpio.get_value();
  141. conf.sda_pullup_en = sda_pullup;
  142. conf.slave.addr_10bit_en = 0;
  143. conf.slave.slave_addr = slave_addr.get_addr();
  144. I2C_CHECK_THROW(i2c_param_config(i2c_num.get_value(), &conf));
  145. I2C_CHECK_THROW(i2c_driver_install(i2c_num.get_value(), conf.mode, rx_buf_len, tx_buf_len, 0));
  146. }
  147. I2CSlave::~I2CSlave()
  148. {
  149. i2c_driver_delete(i2c_num.get_value());
  150. }
  151. int I2CSlave::write_raw(const uint8_t *data, size_t data_len, chrono::milliseconds timeout)
  152. {
  153. return i2c_slave_write_buffer(i2c_num.get_value(), data, data_len, (TickType_t) timeout.count() / portTICK_PERIOD_MS);
  154. }
  155. int I2CSlave::read_raw(uint8_t *buffer, size_t buffer_len, chrono::milliseconds timeout)
  156. {
  157. return i2c_slave_read_buffer(i2c_num.get_value(), buffer, buffer_len, (TickType_t) timeout.count() / portTICK_PERIOD_MS);
  158. }
  159. #endif // CONFIG_SOC_I2C_SUPPORT_SLAVE
  160. I2CWrite::I2CWrite(const vector<uint8_t> &bytes, chrono::milliseconds driver_timeout)
  161. : I2CTransfer<void>(driver_timeout), bytes(bytes)
  162. {
  163. if (bytes.empty()) {
  164. throw I2CException(ESP_ERR_INVALID_ARG);
  165. }
  166. }
  167. void I2CWrite::queue_cmd(I2CCommandLink &handle, I2CAddress i2c_addr)
  168. {
  169. handle.start();
  170. handle.write_byte(i2c_addr.get_value() << 1 | I2C_MASTER_WRITE);
  171. handle.write(bytes);
  172. }
  173. void I2CWrite::process_result() { }
  174. I2CRead::I2CRead(size_t size, chrono::milliseconds driver_timeout)
  175. : I2CTransfer<vector<uint8_t> >(driver_timeout), bytes(size)
  176. {
  177. if (size == 0) {
  178. throw I2CException(ESP_ERR_INVALID_ARG);
  179. }
  180. }
  181. void I2CRead::queue_cmd(I2CCommandLink &handle, I2CAddress i2c_addr)
  182. {
  183. handle.start();
  184. handle.write_byte(i2c_addr.get_value() << 1 | I2C_MASTER_READ);
  185. handle.read(bytes);
  186. }
  187. vector<uint8_t> I2CRead::process_result()
  188. {
  189. return bytes;
  190. }
  191. I2CComposed::I2CComposed(chrono::milliseconds driver_timeout)
  192. : I2CTransfer<vector<vector<uint8_t> > >(driver_timeout), transfer_list() { }
  193. void I2CComposed::CompTransferNodeRead::queue_cmd(I2CCommandLink &handle, I2CAddress i2c_addr)
  194. {
  195. handle.write_byte(i2c_addr.get_value() << 1 | I2C_MASTER_READ);
  196. handle.read(bytes);
  197. }
  198. void I2CComposed::CompTransferNodeRead::process_result(std::vector<std::vector<uint8_t> > &read_results)
  199. {
  200. read_results.push_back(bytes);
  201. }
  202. void I2CComposed::CompTransferNodeWrite::queue_cmd(I2CCommandLink &handle, I2CAddress i2c_addr)
  203. {
  204. handle.write_byte(i2c_addr.get_value() << 1 | I2C_MASTER_WRITE);
  205. handle.write(bytes);
  206. }
  207. void I2CComposed::add_read(size_t size)
  208. {
  209. if (!size) {
  210. throw I2CException(ESP_ERR_INVALID_ARG);
  211. }
  212. transfer_list.push_back(make_shared<CompTransferNodeRead>(size));
  213. }
  214. void I2CComposed::add_write(std::vector<uint8_t> bytes)
  215. {
  216. if (bytes.empty()) {
  217. throw I2CException(ESP_ERR_INVALID_ARG);
  218. }
  219. transfer_list.push_back(make_shared<CompTransferNodeWrite>(bytes));
  220. }
  221. void I2CComposed::queue_cmd(I2CCommandLink &handle, I2CAddress i2c_addr)
  222. {
  223. for (auto it = transfer_list.begin(); it != transfer_list.end(); it++) {
  224. handle.start();
  225. (*it)->queue_cmd(handle, i2c_addr);
  226. }
  227. }
  228. std::vector<std::vector<uint8_t> > I2CComposed::process_result()
  229. {
  230. std::vector<std::vector<uint8_t> > results;
  231. for (auto it = transfer_list.begin(); it != transfer_list.end(); it++) {
  232. (*it)->process_result(results);
  233. }
  234. return results;
  235. }
  236. } // idf
  237. #endif // __cpp_exceptions