Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_module_rs485.c
1 #include <bc_module_rs485.h>
2 
3 
4 #define _BC_MODULE_RS485_I2C_UART_ADDRESS 0x4e
5 #define _BC_MODULE_RS485_I2C_TLA2021_ADDRESS 0x48
6 
7 #define _BC_SC16IS7x0_REG_IER (0x01 << 3)
8 #define _BC_SC16IS7X0_REG_IODIR (0x0a << 3)
9 #define _BC_SC16IS7X0_REG_IOSTATE (0x0b << 3)
10 #define _BC_SC16IS7X0_REG_IOINTENA (0x0c << 3)
11 #define _BC_SC16IS7X0_REG_EFCR (0x0f << 3)
12 
13 #define _BC_MODULE_RS485_DELAY_RUN 50
14 #define _BC_MODULE_RS485_DELAY_MEASUREMENT 100
15 
16 #define _BC_MODULE_RS485_ASYNC_WRITE_TASK_PERIOD 10
17 
18 typedef enum
19 {
20  BC_MODULE_RS485_STATE_ERROR = -1,
21  BC_MODULE_RS485_STATE_INITIALIZE = 0,
22  BC_MODULE_RS485_STATE_MEASURE = 1,
23  BC_MODULE_RS485_STATE_READ = 2,
24  BC_MODULE_RS485_STATE_UPDATE = 3
25 
26 } bc_module_rs485_state_t;
27 
28 static struct
29 {
30  bool _initialized;
31  bc_module_rs485_state_t _state;
32  bc_sc16is740_t _sc16is750;
33 
34  bc_scheduler_task_id_t _task_id_measure;
35  bc_scheduler_task_id_t _task_id_interval;
36  bc_tick_t _update_interval;
37  bc_tick_t _tick_ready;
38  uint16_t _reg_result;
39  bool _voltage_valid;
40  bool _measurement_active;
41  void (*_event_handler)(bc_module_rs485_event_t, void *);
42  void *_event_param;
43 
44  bc_fifo_t *_write_fifo;
45  bc_fifo_t *_read_fifo;
46  bc_scheduler_task_id_t _async_write_task_id;
47  bc_scheduler_task_id_t _async_read_task_id;
48 
49  bool _async_write_in_progress;
50  bool _async_read_in_progress;
51 
52  uint8_t _async_buffer[64];
53  bc_tick_t _async_read_timeout;
54 
55 } _bc_module_rs485;
56 
57 static void _bc_module_rs485_async_write_task(void *param);
58 static void _bc_module_rs485_async_read_task(void *param);
59 
60 static void _bc_module_rs485_task_measure(void *param);
61 static void _bc_module_rs485_task_interval(void *param);
62 
64 {
65  memset(&_bc_module_rs485, 0, sizeof(_bc_module_rs485));
66 
67  if (!bc_sc16is740_init(&_bc_module_rs485._sc16is750, BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS))
68  {
69  return false;
70  }
71 
72  bc_sc16is740_reset_fifo(&_bc_module_rs485._sc16is750, BC_SC16IS740_FIFO_RX);
73 
74  // Disable sleep
75  bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7x0_REG_IER, 0x01);
76 
77  // Enable Auto RS-485 RTS output and RTS output inversion
78  bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7X0_REG_EFCR, 0x30);
79 
80  // GPIO0 set ouput (/RE)
81  bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7X0_REG_IODIR, 0x01);
82 
83  // Set GPIO0 and all other to 0 (/RE)
84  bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7X0_REG_IOSTATE, 0x00);
85 
86  _bc_module_rs485._task_id_interval = bc_scheduler_register(_bc_module_rs485_task_interval, NULL, BC_TICK_INFINITY);
87  _bc_module_rs485._task_id_measure = bc_scheduler_register(_bc_module_rs485_task_measure, NULL, _BC_MODULE_RS485_DELAY_RUN);
88 
89  _bc_module_rs485._initialized = true;
90 
91  return true;
92 }
93 
95 {
96  _bc_module_rs485._update_interval = interval;
97 
98  if (_bc_module_rs485._update_interval == BC_TICK_INFINITY)
99  {
100  bc_scheduler_plan_absolute(_bc_module_rs485._task_id_interval, BC_TICK_INFINITY);
101  }
102  else
103  {
104  bc_scheduler_plan_relative(_bc_module_rs485._task_id_interval, _bc_module_rs485._update_interval);
105 
107  }
108 }
109 
111 {
112  if (!_bc_module_rs485._voltage_valid)
113  {
114  return false;
115  }
116 
117  int16_t reg_result = _bc_module_rs485._reg_result;
118 
119  if (reg_result < 0)
120  {
121  reg_result = 0;
122  }
123 
124  reg_result >>= 4;
125 
126  *volt = 23.33f * reg_result / 2047.f;
127 
128  return true;
129 }
130 
132 {
133  if (_bc_module_rs485._measurement_active)
134  {
135  return false;
136  }
137 
138  _bc_module_rs485._measurement_active = true;
139 
140  bc_scheduler_plan_absolute(_bc_module_rs485._task_id_measure, _bc_module_rs485._tick_ready);
141 
142  return true;
143 }
144 
145 static void _bc_module_rs485_async_write_task(void *param)
146 {
147  (void) param;
148 
149  size_t space_available;
150 
151  if (bc_fifo_is_empty(_bc_module_rs485._write_fifo))
152  {
153  bc_scheduler_unregister(_bc_module_rs485._async_write_task_id);
154  _bc_module_rs485._async_write_in_progress = false;
155 
156  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ASYNC_WRITE_DONE, _bc_module_rs485._event_param);
157 
158  return;
159  }
160 
161  if (!bc_sc16is740_get_spaces_available(&_bc_module_rs485._sc16is750, &space_available))
162  {
163  bc_scheduler_unregister(_bc_module_rs485._async_write_task_id);
164  _bc_module_rs485._async_write_in_progress = false;
165 
166  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ERROR, _bc_module_rs485._event_param);
167  return;
168  }
169 
170  size_t bytes_read = bc_fifo_read(_bc_module_rs485._write_fifo, _bc_module_rs485._async_buffer, space_available);
171  bc_module_rs485_write(_bc_module_rs485._async_buffer, bytes_read);
172 
173  bc_scheduler_plan_current_relative(_BC_MODULE_RS485_ASYNC_WRITE_TASK_PERIOD);
174 }
175 
176 static void _bc_module_rs485_async_read_task(void *param)
177 {
178  (void) param;
179 
180  size_t available = 0;
181 
182  if (!bc_sc16is740_available(&_bc_module_rs485._sc16is750, &available))
183  {
184  return;
185  }
186 
187  if (available)
188  {
189  bc_sc16is740_read(&_bc_module_rs485._sc16is750, _bc_module_rs485._async_buffer, available, 0);
190  bc_fifo_write(_bc_module_rs485._read_fifo, _bc_module_rs485._async_buffer, available);
191  }
192 
193  if (!bc_fifo_is_empty(_bc_module_rs485._read_fifo))
194  {
195  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ASYNC_READ_DATA, _bc_module_rs485._event_param);
196  }
197  else
198  {
199  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ASYNC_READ_TIMEOUT, _bc_module_rs485._event_param);
200  }
201 
202  bc_scheduler_plan_current_relative(_bc_module_rs485._async_read_timeout);
203 }
204 
205 static void _bc_module_rs485_task_interval(void *param)
206 {
207  (void) param;
208 
210  bc_scheduler_plan_current_relative(_bc_module_rs485._update_interval);
211 }
212 
213 static void _bc_module_rs485_task_measure(void *param)
214 {
215  (void) param;
216 
217  start:
218 
219  switch (_bc_module_rs485._state)
220  {
221  case BC_MODULE_RS485_STATE_ERROR:
222  {
223  if (_bc_module_rs485._event_handler != NULL)
224  {
225  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ERROR, _bc_module_rs485._event_param);
226  }
227 
228  _bc_module_rs485._state = BC_MODULE_RS485_STATE_INITIALIZE;
229 
230  return;
231  }
232  case BC_MODULE_RS485_STATE_INITIALIZE:
233  {
234  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
235 
236  if (!bc_i2c_memory_write_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, 0x0503))
237  {
238  goto start;
239  }
240 
241  _bc_module_rs485._state = BC_MODULE_RS485_STATE_MEASURE;
242 
243  _bc_module_rs485._tick_ready = bc_tick_get();
244 
245  if (_bc_module_rs485._measurement_active)
246  {
247  bc_scheduler_plan_current_absolute(_bc_module_rs485._tick_ready);
248  }
249 
250  return;
251  }
252  case BC_MODULE_RS485_STATE_MEASURE:
253  {
254  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
255 
256  if (!bc_i2c_memory_write_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, 0x8503))
257  {
258  goto start;
259  }
260 
261  _bc_module_rs485._state = BC_MODULE_RS485_STATE_READ;
262 
263  bc_scheduler_plan_current_from_now(_BC_MODULE_RS485_DELAY_MEASUREMENT);
264 
265  return;
266  }
267  case BC_MODULE_RS485_STATE_READ:
268  {
269  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
270 
271  uint16_t reg_configuration;
272 
273  if (!bc_i2c_memory_read_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, &reg_configuration))
274  {
275  goto start;
276  }
277 
278  if ((reg_configuration & 0x8000) != 0x8000)
279  {
280  goto start;
281  }
282 
283  if (!bc_i2c_memory_read_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x00, &_bc_module_rs485._reg_result))
284  {
285  goto start;
286  }
287 
288  _bc_module_rs485._voltage_valid = true;
289 
290  _bc_module_rs485._state = BC_MODULE_RS485_STATE_UPDATE;
291 
292  goto start;
293  }
294  case BC_MODULE_RS485_STATE_UPDATE:
295  {
296  _bc_module_rs485._measurement_active = false;
297 
298  if (_bc_module_rs485._event_handler != NULL)
299  {
300  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_VOLTAGE, _bc_module_rs485._event_param);
301  }
302 
303  _bc_module_rs485._state = BC_MODULE_RS485_STATE_MEASURE;
304 
305  return;
306  }
307  default:
308  {
309  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
310 
311  goto start;
312  }
313  }
314 }
315 
317 {
318  _bc_module_rs485._write_fifo = write_fifo;
319  _bc_module_rs485._read_fifo = read_fifo;
320 }
321 
322 size_t bc_module_rs485_async_write(uint8_t *buffer, size_t length)
323 {
324  if (!_bc_module_rs485._initialized || _bc_module_rs485._write_fifo == NULL)
325  {
326  return 0;
327  }
328 
329  size_t bytes_written = bc_fifo_write(_bc_module_rs485._write_fifo, (uint8_t *) buffer, length);
330 
331  if (bytes_written != 0)
332  {
333  if (!_bc_module_rs485._async_write_in_progress)
334  {
335  _bc_module_rs485._async_write_task_id = bc_scheduler_register(_bc_module_rs485_async_write_task, NULL, 10);
336  _bc_module_rs485._async_write_in_progress = true;
337  }
338  }
339 
340  return bytes_written;
341 }
342 
344 {
345  if (!_bc_module_rs485._initialized || _bc_module_rs485._read_fifo == NULL || _bc_module_rs485._async_read_in_progress)
346  {
347  return false;
348  }
349 
350  _bc_module_rs485._async_read_timeout = timeout;
351  _bc_module_rs485._async_read_task_id = bc_scheduler_register(_bc_module_rs485_async_read_task, NULL, _bc_module_rs485._async_read_timeout);
352  _bc_module_rs485._async_read_in_progress = true;
353 
354  return true;
355 }
356 
358 {
359  if (!_bc_module_rs485._initialized || !_bc_module_rs485._async_read_in_progress)
360  {
361  return false;
362  }
363 
364  _bc_module_rs485._async_read_in_progress = false;
365  bc_scheduler_unregister(_bc_module_rs485._async_read_task_id);
366 
367  return true;
368 }
369 
370 size_t bc_module_rs485_async_read(void *buffer, size_t length)
371 {
372  if (!_bc_module_rs485._initialized || _bc_module_rs485._read_fifo == NULL || !_bc_module_rs485._async_read_in_progress)
373  {
374  return 0;
375  }
376 
377  return bc_fifo_read(_bc_module_rs485._read_fifo, buffer, length);
378 }
379 
380 void bc_module_rs485_set_event_handler(void (*event_handler)(bc_module_rs485_event_t, void *), void *event_param)
381 {
382  _bc_module_rs485._event_handler = event_handler;
383  _bc_module_rs485._event_param = event_param;
384 }
385 
386 size_t bc_module_rs485_write(uint8_t *buffer, size_t length)
387 {
388  return bc_sc16is740_write(&_bc_module_rs485._sc16is750, buffer, length);
389 }
390 
391 bool bc_module_rs485_available(size_t *available)
392 {
393  return bc_sc16is740_available(&_bc_module_rs485._sc16is750, available);
394 }
395 
396 size_t bc_module_rs485_read(uint8_t *buffer, size_t length, bc_tick_t timeout)
397 {
398  return bc_sc16is740_read(&_bc_module_rs485._sc16is750, buffer, length, timeout);
399 }
400 
402 {
403  return bc_sc16is740_set_baudrate(&_bc_module_rs485._sc16is750, baudrate);
404 }
405 
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
bool bc_i2c_memory_write_16b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t data)
Memory write 2 bytes to I2C channel.
Definition: bc_i2c.c:414
Structure of FIFO instance.
Definition: bc_fifo.h:12
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
I2C channel I2C0.
Definition: bc_i2c.h:18
size_t bc_module_rs485_write(uint8_t *buffer, size_t length)
Write data to RS-485 bus.
size_t bc_module_rs485_async_write(uint8_t *buffer, size_t length)
Add data to be transmited in async mode.
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_current_absolute(bc_tick_t tick)
Schedule current task to absolute tick.
Definition: bc_scheduler.c:144
size_t bc_sc16is740_read(bc_sc16is740_t *self, uint8_t *buffer, size_t length, bc_tick_t timeout)
Read.
Definition: bc_sc16is740.c:150
bool bc_module_rs485_measure(void)
Start single voltage measurement.
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
bool bc_sc16is740_get_spaces_available(bc_sc16is740_t *self, size_t *spaces_available)
Get TX FIXO space available.
Definition: bc_sc16is740.c:88
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
size_t bc_module_rs485_read(uint8_t *buffer, size_t length, bc_tick_t timeout)
Read the received data.
bool bc_sc16is740_init(bc_sc16is740_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
SC16IS740 instance.
Definition: bc_sc16is740.c:23
bc_module_rs485_event_t
Callback events.
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
size_t bc_sc16is740_write(bc_sc16is740_t *self, uint8_t *buffer, size_t length)
Write.
Definition: bc_sc16is740.c:102
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
void bc_module_rs485_set_update_interval(bc_tick_t interval)
Set measurement interval.
void bc_module_rs485_set_event_handler(void(*event_handler)(bc_module_rs485_event_t, void *), void *event_param)
Set callback function.
bc_module_rs485_baudrate_t
Baudrates.
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
bool bc_module_rs485_async_read_stop(void)
Stop async reading.
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
size_t bc_fifo_write(bc_fifo_t *fifo, const void *buffer, size_t length)
Write data to FIFO.
Definition: bc_fifo.c:18
bool bc_module_rs485_set_baudrate(bc_module_rs485_baudrate_t baudrate)
Set baudrate.
bool bc_sc16is740_available(bc_sc16is740_t *self, size_t *available)
Get RX FIXO available data.
Definition: bc_sc16is740.c:136
bool bc_module_rs485_async_read_start(bc_tick_t timeout)
Start async reading.
size_t bc_fifo_read(bc_fifo_t *fifo, void *buffer, size_t length)
Read data from FIFO.
Definition: bc_fifo.c:63
void bc_module_rs485_set_async_fifo(bc_fifo_t *write_fifo, bc_fifo_t *read_fifo)
Set FIFO.
bool bc_sc16is740_set_baudrate(bc_sc16is740_t *self, bc_sc16is740_baudrate_t baudrate)
Set baudrate.
Definition: bc_sc16is740.c:202
bool bc_fifo_is_empty(bc_fifo_t *fifo)
Is empty.
Definition: bc_fifo.c:161
bool bc_module_rs485_get_voltage(float *volt)
Get measured voltage.
bool bc_module_rs485_available(size_t *available)
Get number of received bytes.
bool bc_i2c_memory_read_16b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t *data)
Memory read 2 bytes from I2C channel.
Definition: bc_i2c.c:443
size_t bc_module_rs485_async_read(void *buffer, size_t length)
Get data that has been received in async mode.
void bc_scheduler_unregister(bc_scheduler_task_id_t task_id)
Unregister specified task.
Definition: bc_scheduler.c:80
bool bc_sc16is740_reset_fifo(bc_sc16is740_t *self, bc_sc16is740_fifo_t fifo)
Reset FIFO.
Definition: bc_sc16is740.c:79
bool bc_module_rs485_init(void)
Initialize RS-485 Module.
bool bc_i2c_memory_write_8b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t data)
Memory write 1 byte to I2C channel.
Definition: bc_i2c.c:402