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  if (!bc_sc16is740_reset_fifo(&_bc_module_rs485._sc16is750, BC_SC16IS740_FIFO_RX))
73  {
74  return false;
75  }
76 
77  // Disable sleep
78  if (!bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7x0_REG_IER, 0x01))
79  {
80  return false;
81  }
82 
83  // Enable Auto RS-485 RTS output and RTS output inversion
84  if (!bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7X0_REG_EFCR, 0x30))
85  {
86  return false;
87  }
88 
89  // GPIO0 set ouput (/RE)
90  if (!bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7X0_REG_IODIR, 0x01))
91  {
92  return false;
93  }
94 
95  // Set GPIO0 and all other to 0 (/RE)
96  if (!bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7X0_REG_IOSTATE, 0x00))
97  {
98  return false;
99  }
100 
101  _bc_module_rs485._task_id_interval = bc_scheduler_register(_bc_module_rs485_task_interval, NULL, BC_TICK_INFINITY);
102  _bc_module_rs485._task_id_measure = bc_scheduler_register(_bc_module_rs485_task_measure, NULL, _BC_MODULE_RS485_DELAY_RUN);
103 
104  _bc_module_rs485._initialized = true;
105 
106  return true;
107 }
108 
109 
111 {
112  if (_bc_module_rs485._initialized)
113  {
114  bc_scheduler_unregister(_bc_module_rs485._task_id_interval);
115  bc_scheduler_unregister(_bc_module_rs485._task_id_measure);
116  }
117 
118  _bc_module_rs485._initialized = false;
119 
120  // Enable sleep
121  bc_i2c_memory_write_8b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_UART_ADDRESS, _BC_SC16IS7x0_REG_IER, 0x00);
122  {
123  return false;
124  }
125 
126  return true;
127 }
128 
129 
131 {
132  _bc_module_rs485._update_interval = interval;
133 
134  if (_bc_module_rs485._update_interval == BC_TICK_INFINITY)
135  {
136  bc_scheduler_plan_absolute(_bc_module_rs485._task_id_interval, BC_TICK_INFINITY);
137  }
138  else
139  {
140  bc_scheduler_plan_relative(_bc_module_rs485._task_id_interval, _bc_module_rs485._update_interval);
141 
143  }
144 }
145 
147 {
148  if (!_bc_module_rs485._voltage_valid)
149  {
150  return false;
151  }
152 
153  int16_t reg_result = _bc_module_rs485._reg_result;
154 
155  if (reg_result < 0)
156  {
157  reg_result = 0;
158  }
159 
160  reg_result >>= 4;
161 
162  *volt = 39.62f * reg_result / 2047.f;
163 
164  return true;
165 }
166 
168 {
169  if (_bc_module_rs485._measurement_active)
170  {
171  return false;
172  }
173 
174  _bc_module_rs485._measurement_active = true;
175 
176  bc_scheduler_plan_absolute(_bc_module_rs485._task_id_measure, _bc_module_rs485._tick_ready);
177 
178  return true;
179 }
180 
181 static void _bc_module_rs485_async_write_task(void *param)
182 {
183  (void) param;
184 
185  size_t space_available;
186 
187  if (bc_fifo_is_empty(_bc_module_rs485._write_fifo))
188  {
189  bc_scheduler_unregister(_bc_module_rs485._async_write_task_id);
190  _bc_module_rs485._async_write_in_progress = false;
191 
192  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ASYNC_WRITE_DONE, _bc_module_rs485._event_param);
193 
194  return;
195  }
196 
197  if (!bc_sc16is740_get_spaces_available(&_bc_module_rs485._sc16is750, &space_available))
198  {
199  bc_scheduler_unregister(_bc_module_rs485._async_write_task_id);
200  _bc_module_rs485._async_write_in_progress = false;
201 
202  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ERROR, _bc_module_rs485._event_param);
203  return;
204  }
205 
206  size_t bytes_read = bc_fifo_read(_bc_module_rs485._write_fifo, _bc_module_rs485._async_buffer, space_available);
207  bc_module_rs485_write(_bc_module_rs485._async_buffer, bytes_read);
208 
209  bc_scheduler_plan_current_relative(_BC_MODULE_RS485_ASYNC_WRITE_TASK_PERIOD);
210 }
211 
212 static void _bc_module_rs485_async_read_task(void *param)
213 {
214  (void) param;
215 
216  size_t available = 0;
217 
218  if (!bc_sc16is740_available(&_bc_module_rs485._sc16is750, &available))
219  {
220  return;
221  }
222 
223  if (available)
224  {
225  bc_sc16is740_read(&_bc_module_rs485._sc16is750, _bc_module_rs485._async_buffer, available, 0);
226  bc_fifo_write(_bc_module_rs485._read_fifo, _bc_module_rs485._async_buffer, available);
227  }
228 
229  if (!bc_fifo_is_empty(_bc_module_rs485._read_fifo))
230  {
231  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ASYNC_READ_DATA, _bc_module_rs485._event_param);
232  }
233  else
234  {
235  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ASYNC_READ_TIMEOUT, _bc_module_rs485._event_param);
236  }
237 
238  bc_scheduler_plan_current_relative(_bc_module_rs485._async_read_timeout);
239 }
240 
241 static void _bc_module_rs485_task_interval(void *param)
242 {
243  (void) param;
244 
246  bc_scheduler_plan_current_relative(_bc_module_rs485._update_interval);
247 }
248 
249 static void _bc_module_rs485_task_measure(void *param)
250 {
251  (void) param;
252 
253  start:
254 
255  switch (_bc_module_rs485._state)
256  {
257  case BC_MODULE_RS485_STATE_ERROR:
258  {
259  if (_bc_module_rs485._event_handler != NULL)
260  {
261  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_ERROR, _bc_module_rs485._event_param);
262  }
263 
264  _bc_module_rs485._state = BC_MODULE_RS485_STATE_INITIALIZE;
265 
266  return;
267  }
268  case BC_MODULE_RS485_STATE_INITIALIZE:
269  {
270  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
271 
272  if (!bc_i2c_memory_write_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, 0x0503))
273  {
274  goto start;
275  }
276 
277  _bc_module_rs485._state = BC_MODULE_RS485_STATE_MEASURE;
278 
279  _bc_module_rs485._tick_ready = bc_tick_get();
280 
281  if (_bc_module_rs485._measurement_active)
282  {
283  bc_scheduler_plan_current_absolute(_bc_module_rs485._tick_ready);
284  }
285 
286  return;
287  }
288  case BC_MODULE_RS485_STATE_MEASURE:
289  {
290  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
291 
292  if (!bc_i2c_memory_write_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, 0x8503))
293  {
294  goto start;
295  }
296 
297  _bc_module_rs485._state = BC_MODULE_RS485_STATE_READ;
298 
299  bc_scheduler_plan_current_from_now(_BC_MODULE_RS485_DELAY_MEASUREMENT);
300 
301  return;
302  }
303  case BC_MODULE_RS485_STATE_READ:
304  {
305  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
306 
307  uint16_t reg_configuration;
308 
309  if (!bc_i2c_memory_read_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, &reg_configuration))
310  {
311  goto start;
312  }
313 
314  if ((reg_configuration & 0x8000) != 0x8000)
315  {
316  goto start;
317  }
318 
319  if (!bc_i2c_memory_read_16b(BC_I2C_I2C0, _BC_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x00, &_bc_module_rs485._reg_result))
320  {
321  goto start;
322  }
323 
324  _bc_module_rs485._voltage_valid = true;
325 
326  _bc_module_rs485._state = BC_MODULE_RS485_STATE_UPDATE;
327 
328  goto start;
329  }
330  case BC_MODULE_RS485_STATE_UPDATE:
331  {
332  _bc_module_rs485._measurement_active = false;
333 
334  if (_bc_module_rs485._event_handler != NULL)
335  {
336  _bc_module_rs485._event_handler(BC_MODULE_RS485_EVENT_VOLTAGE, _bc_module_rs485._event_param);
337  }
338 
339  _bc_module_rs485._state = BC_MODULE_RS485_STATE_MEASURE;
340 
341  return;
342  }
343  default:
344  {
345  _bc_module_rs485._state = BC_MODULE_RS485_STATE_ERROR;
346 
347  goto start;
348  }
349  }
350 }
351 
353 {
354  _bc_module_rs485._write_fifo = write_fifo;
355  _bc_module_rs485._read_fifo = read_fifo;
356 }
357 
358 size_t bc_module_rs485_async_write(uint8_t *buffer, size_t length)
359 {
360  if (!_bc_module_rs485._initialized || _bc_module_rs485._write_fifo == NULL)
361  {
362  return 0;
363  }
364 
365  size_t bytes_written = bc_fifo_write(_bc_module_rs485._write_fifo, (uint8_t *) buffer, length);
366 
367  if (bytes_written != 0)
368  {
369  if (!_bc_module_rs485._async_write_in_progress)
370  {
371  _bc_module_rs485._async_write_task_id = bc_scheduler_register(_bc_module_rs485_async_write_task, NULL, 10);
372  _bc_module_rs485._async_write_in_progress = true;
373  }
374  }
375 
376  return bytes_written;
377 }
378 
380 {
381  if (!_bc_module_rs485._initialized || _bc_module_rs485._read_fifo == NULL || _bc_module_rs485._async_read_in_progress)
382  {
383  return false;
384  }
385 
386  _bc_module_rs485._async_read_timeout = timeout;
387  _bc_module_rs485._async_read_task_id = bc_scheduler_register(_bc_module_rs485_async_read_task, NULL, _bc_module_rs485._async_read_timeout);
388  _bc_module_rs485._async_read_in_progress = true;
389 
390  return true;
391 }
392 
394 {
395  if (!_bc_module_rs485._initialized || !_bc_module_rs485._async_read_in_progress)
396  {
397  return false;
398  }
399 
400  _bc_module_rs485._async_read_in_progress = false;
401  bc_scheduler_unregister(_bc_module_rs485._async_read_task_id);
402 
403  return true;
404 }
405 
406 size_t bc_module_rs485_async_read(void *buffer, size_t length)
407 {
408  if (!_bc_module_rs485._initialized || _bc_module_rs485._read_fifo == NULL || !_bc_module_rs485._async_read_in_progress)
409  {
410  return 0;
411  }
412 
413  return bc_fifo_read(_bc_module_rs485._read_fifo, buffer, length);
414 }
415 
416 void bc_module_rs485_set_event_handler(void (*event_handler)(bc_module_rs485_event_t, void *), void *event_param)
417 {
418  _bc_module_rs485._event_handler = event_handler;
419  _bc_module_rs485._event_param = event_param;
420 }
421 
422 size_t bc_module_rs485_write(uint8_t *buffer, size_t length)
423 {
424  return bc_sc16is740_write(&_bc_module_rs485._sc16is750, buffer, length);
425 }
426 
427 bool bc_module_rs485_available(size_t *available)
428 {
429  return bc_sc16is740_available(&_bc_module_rs485._sc16is750, available);
430 }
431 
432 size_t bc_module_rs485_read(uint8_t *buffer, size_t length, bc_tick_t timeout)
433 {
434  return bc_sc16is740_read(&_bc_module_rs485._sc16is750, buffer, length, timeout);
435 }
436 
438 {
439  return bc_sc16is740_set_baudrate(&_bc_module_rs485._sc16is750, baudrate);
440 }
441 
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
bool bc_module_rs485_deinit(void)
Deinitialize RS-485 Module.
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