1 // Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //         http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifdef __cpp_exceptions
16 
17 #include "i2c_cxx.hpp"
18 
19 using namespace std;
20 
21 namespace idf {
22 
23 #define I2C_CHECK_THROW(err) CHECK_THROW_SPECIFIC((err), I2CException)
24 
I2CException(esp_err_t error)25 I2CException::I2CException(esp_err_t error) : ESPException(error) { }
26 
I2CTransferException(esp_err_t error)27 I2CTransferException::I2CTransferException(esp_err_t error) : I2CException(error) { }
28 
I2CBus(i2c_port_t i2c_number)29 I2CBus::I2CBus(i2c_port_t i2c_number) : i2c_num(i2c_number) { }
30 
~I2CBus()31 I2CBus::~I2CBus() { }
32 
I2CMaster(i2c_port_t i2c_number,int scl_gpio,int sda_gpio,uint32_t clock_speed,bool scl_pullup,bool sda_pullup)33 I2CMaster::I2CMaster(i2c_port_t i2c_number,
34                      int scl_gpio,
35                      int sda_gpio,
36                      uint32_t clock_speed,
37                      bool scl_pullup,
38                      bool sda_pullup)
39     : I2CBus(i2c_number)
40 {
41     i2c_config_t conf = {};
42     conf.mode = I2C_MODE_MASTER;
43     conf.scl_io_num = scl_gpio;
44     conf.scl_pullup_en = scl_pullup;
45     conf.sda_io_num = sda_gpio;
46     conf.sda_pullup_en = sda_pullup;
47     conf.master.clk_speed = clock_speed;
48     I2C_CHECK_THROW(i2c_param_config(i2c_num, &conf));
49     I2C_CHECK_THROW(i2c_driver_install(i2c_num, conf.mode, 0, 0, 0));
50 }
51 
~I2CMaster()52 I2CMaster::~I2CMaster()
53 {
54     i2c_driver_delete(i2c_num);
55 }
56 
sync_write(uint8_t i2c_addr,const vector<uint8_t> & data)57 void I2CMaster::sync_write(uint8_t i2c_addr, const vector<uint8_t> &data)
58 {
59     I2CWrite writer(data);
60 
61     writer.do_transfer(i2c_num, i2c_addr);
62 }
63 
sync_read(uint8_t i2c_addr,size_t n_bytes)64 std::vector<uint8_t> I2CMaster::sync_read(uint8_t i2c_addr, size_t n_bytes)
65 {
66     I2CRead reader(n_bytes);
67 
68     return reader.do_transfer(i2c_num, i2c_addr);
69 }
70 
sync_transfer(uint8_t i2c_addr,const std::vector<uint8_t> & write_data,size_t read_n_bytes)71 vector<uint8_t> I2CMaster::sync_transfer(uint8_t i2c_addr,
72         const std::vector<uint8_t> &write_data,
73         size_t read_n_bytes)
74 {
75     if (!read_n_bytes) throw I2CException(ESP_ERR_INVALID_ARG);
76 
77     I2CComposed composed_transfer;
78     composed_transfer.add_write(write_data);
79     composed_transfer.add_read(read_n_bytes);
80 
81     return composed_transfer.do_transfer(i2c_num, i2c_addr)[0];
82 }
83 
I2CSlave(i2c_port_t i2c_number,int scl_gpio,int sda_gpio,uint8_t slave_addr,size_t rx_buf_len,size_t tx_buf_len,bool scl_pullup,bool sda_pullup)84 I2CSlave::I2CSlave(i2c_port_t i2c_number,
85         int scl_gpio,
86         int sda_gpio,
87         uint8_t slave_addr,
88         size_t rx_buf_len,
89         size_t tx_buf_len,
90         bool scl_pullup,
91         bool sda_pullup)
92     : I2CBus(i2c_number)
93 {
94     i2c_config_t conf = {};
95     conf.mode = I2C_MODE_SLAVE;
96     conf.scl_io_num = scl_gpio;
97     conf.scl_pullup_en = scl_pullup;
98     conf.sda_io_num = sda_gpio;
99     conf.sda_pullup_en = sda_pullup;
100     conf.slave.addr_10bit_en = 0;
101     conf.slave.slave_addr = slave_addr;
102     I2C_CHECK_THROW(i2c_param_config(i2c_num, &conf));
103     I2C_CHECK_THROW(i2c_driver_install(i2c_num, conf.mode, rx_buf_len, tx_buf_len, 0));
104 }
105 
~I2CSlave()106 I2CSlave::~I2CSlave()
107 {
108     i2c_driver_delete(i2c_num);
109 }
110 
write_raw(const uint8_t * data,size_t data_len,chrono::milliseconds timeout)111 int I2CSlave::write_raw(const uint8_t *data, size_t data_len, chrono::milliseconds timeout)
112 {
113     return i2c_slave_write_buffer(i2c_num, data, data_len, (TickType_t) timeout.count() / portTICK_RATE_MS);
114 }
115 
read_raw(uint8_t * buffer,size_t buffer_len,chrono::milliseconds timeout)116 int I2CSlave::read_raw(uint8_t *buffer, size_t buffer_len, chrono::milliseconds timeout)
117 {
118     return i2c_slave_read_buffer(i2c_num, buffer, buffer_len, (TickType_t) timeout.count() / portTICK_RATE_MS);
119 }
120 
I2CWrite(const vector<uint8_t> & bytes,chrono::milliseconds driver_timeout)121 I2CWrite::I2CWrite(const vector<uint8_t> &bytes, chrono::milliseconds driver_timeout)
122     : I2CTransfer<void>(driver_timeout), bytes(bytes) { }
123 
queue_cmd(i2c_cmd_handle_t handle,uint8_t i2c_addr)124 void I2CWrite::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
125 {
126     I2C_CHECK_THROW(i2c_master_start(handle));
127     I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_WRITE, true));
128     I2C_CHECK_THROW(i2c_master_write(handle, bytes.data(), bytes.size(), true));
129 }
130 
process_result()131 void I2CWrite::process_result() { }
132 
I2CRead(size_t size,chrono::milliseconds driver_timeout)133 I2CRead::I2CRead(size_t size, chrono::milliseconds driver_timeout)
134     : I2CTransfer<vector<uint8_t> >(driver_timeout), bytes(size) { }
135 
queue_cmd(i2c_cmd_handle_t handle,uint8_t i2c_addr)136 void I2CRead::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
137 {
138     I2C_CHECK_THROW(i2c_master_start(handle));
139     I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_READ, true));
140     I2C_CHECK_THROW(i2c_master_read(handle, bytes.data(), bytes.size(), I2C_MASTER_LAST_NACK));
141 }
142 
process_result()143 vector<uint8_t> I2CRead::process_result()
144 {
145     return bytes;
146 }
147 
I2CComposed(chrono::milliseconds driver_timeout)148 I2CComposed::I2CComposed(chrono::milliseconds driver_timeout)
149     : I2CTransfer<vector<vector<uint8_t> > >(driver_timeout), transfer_list() { }
150 
queue_cmd(i2c_cmd_handle_t handle,uint8_t i2c_addr)151 void I2CComposed::CompTransferNodeRead::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
152 {
153     I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_READ, true));
154     I2C_CHECK_THROW(i2c_master_read(handle, bytes.data(), bytes.size(), I2C_MASTER_LAST_NACK));
155 }
156 
process_result(std::vector<std::vector<uint8_t>> & read_results)157 void I2CComposed::CompTransferNodeRead::process_result(std::vector<std::vector<uint8_t> > &read_results)
158 {
159     read_results.push_back(bytes);
160 }
161 
queue_cmd(i2c_cmd_handle_t handle,uint8_t i2c_addr)162 void I2CComposed::CompTransferNodeWrite::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
163 {
164     I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_WRITE, true));
165     I2C_CHECK_THROW(i2c_master_write(handle, bytes.data(), bytes.size(), true));
166 }
167 
add_read(size_t size)168 void I2CComposed::add_read(size_t size)
169 {
170     if (!size) throw I2CException(ESP_ERR_INVALID_ARG);
171 
172     transfer_list.push_back(make_shared<CompTransferNodeRead>(size));
173 }
174 
add_write(std::vector<uint8_t> bytes)175 void I2CComposed::add_write(std::vector<uint8_t> bytes)
176 {
177     if (bytes.empty()) throw I2CException(ESP_ERR_INVALID_ARG);
178 
179     transfer_list.push_back(make_shared<CompTransferNodeWrite>(bytes));
180 }
181 
queue_cmd(i2c_cmd_handle_t handle,uint8_t i2c_addr)182 void I2CComposed::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
183 {
184     for (auto it = transfer_list.begin(); it != transfer_list.end(); it++) {
185         I2C_CHECK_THROW(i2c_master_start(handle));
186         (*it)->queue_cmd(handle, i2c_addr);
187     }
188 }
189 
process_result()190 std::vector<std::vector<uint8_t> > I2CComposed::process_result()
191 {
192     std::vector<std::vector<uint8_t> > results;
193     for (auto it = transfer_list.begin(); it != transfer_list.end(); it++) {
194         (*it)->process_result(results);
195     }
196     return results;
197 }
198 
199 } // idf
200 
201 #endif // __cpp_exceptions
202