Firmware SDK
twr_module_rs485.c
1 #include <twr_module_rs485.h>
2 
3 
4 #define _TWR_MODULE_RS485_I2C_UART_ADDRESS 0x4e
5 #define _TWR_MODULE_RS485_I2C_TLA2021_ADDRESS 0x48
6 
7 #define _TWR_SC16IS7x0_REG_IER (0x01 << 3)
8 #define _TWR_SC16IS7X0_REG_IODIR (0x0a << 3)
9 #define _TWR_SC16IS7X0_REG_IOSTATE (0x0b << 3)
10 #define _TWR_SC16IS7X0_REG_IOINTENA (0x0c << 3)
11 #define _TWR_SC16IS7X0_REG_EFCR (0x0f << 3)
12 
13 #define _TWR_MODULE_RS485_DELAY_RUN 50
14 #define _TWR_MODULE_RS485_DELAY_MEASUREMENT 100
15 
16 #define _TWR_MODULE_RS485_ASYNC_WRITE_TASK_PERIOD 10
17 
18 typedef enum
19 {
20  TWR_MODULE_RS485_STATE_ERROR = -1,
21  TWR_MODULE_RS485_STATE_INITIALIZE = 0,
22  TWR_MODULE_RS485_STATE_MEASURE = 1,
23  TWR_MODULE_RS485_STATE_READ = 2,
24  TWR_MODULE_RS485_STATE_UPDATE = 3
25 
26 } twr_module_rs485_state_t;
27 
28 static struct
29 {
30  bool _initialized;
31  twr_module_rs485_state_t _state;
32  twr_sc16is740_t _sc16is750;
33 
34  twr_scheduler_task_id_t _task_id_measure;
35  twr_scheduler_task_id_t _task_id_interval;
36  twr_tick_t _update_interval;
37  twr_tick_t _tick_ready;
38  uint16_t _reg_result;
39  bool _voltage_valid;
40  bool _measurement_active;
41  void (*_event_handler)(twr_module_rs485_event_t, void *);
42  void *_event_param;
43 
44  twr_fifo_t *_write_fifo;
45  twr_fifo_t *_read_fifo;
46  twr_scheduler_task_id_t _async_write_task_id;
47  twr_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  twr_tick_t _async_read_timeout;
54 
55 } _twr_module_rs485;
56 
57 static void _twr_module_rs485_async_write_task(void *param);
58 static void _twr_module_rs485_async_read_task(void *param);
59 
60 static void _twr_module_rs485_task_measure(void *param);
61 static void _twr_module_rs485_task_interval(void *param);
62 
64 {
65  memset(&_twr_module_rs485, 0, sizeof(_twr_module_rs485));
66 
67  if (!twr_sc16is740_init(&_twr_module_rs485._sc16is750, TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_UART_ADDRESS))
68  {
69  return false;
70  }
71 
72  if (!twr_sc16is740_reset_fifo(&_twr_module_rs485._sc16is750, TWR_SC16IS740_FIFO_RX))
73  {
74  return false;
75  }
76 
77  // Disable sleep
78  if (!twr_i2c_memory_write_8b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_UART_ADDRESS, _TWR_SC16IS7x0_REG_IER, 0x01))
79  {
80  return false;
81  }
82 
83  // Enable Auto RS-485 RTS output and RTS output inversion
84  if (!twr_i2c_memory_write_8b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_UART_ADDRESS, _TWR_SC16IS7X0_REG_EFCR, 0x30))
85  {
86  return false;
87  }
88 
89  // GPIO0 set ouput (/RE)
90  if (!twr_i2c_memory_write_8b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_UART_ADDRESS, _TWR_SC16IS7X0_REG_IODIR, 0x01))
91  {
92  return false;
93  }
94 
95  // Set GPIO0 and all other to 0 (/RE)
96  if (!twr_i2c_memory_write_8b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_UART_ADDRESS, _TWR_SC16IS7X0_REG_IOSTATE, 0x00))
97  {
98  return false;
99  }
100 
101  _twr_module_rs485._task_id_interval = twr_scheduler_register(_twr_module_rs485_task_interval, NULL, TWR_TICK_INFINITY);
102  _twr_module_rs485._task_id_measure = twr_scheduler_register(_twr_module_rs485_task_measure, NULL, _TWR_MODULE_RS485_DELAY_RUN);
103 
104  _twr_module_rs485._initialized = true;
105 
106  return true;
107 }
108 
109 
111 {
112  if (_twr_module_rs485._initialized)
113  {
114  twr_scheduler_unregister(_twr_module_rs485._task_id_interval);
115  twr_scheduler_unregister(_twr_module_rs485._task_id_measure);
116  }
117 
118  _twr_module_rs485._initialized = false;
119 
120  // Enable sleep
121  twr_i2c_memory_write_8b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_UART_ADDRESS, _TWR_SC16IS7x0_REG_IER, 0x00);
122  {
123  return false;
124  }
125 
126  return true;
127 }
128 
129 
131 {
132  _twr_module_rs485._update_interval = interval;
133 
134  if (_twr_module_rs485._update_interval == TWR_TICK_INFINITY)
135  {
136  twr_scheduler_plan_absolute(_twr_module_rs485._task_id_interval, TWR_TICK_INFINITY);
137  }
138  else
139  {
140  twr_scheduler_plan_relative(_twr_module_rs485._task_id_interval, _twr_module_rs485._update_interval);
141 
143  }
144 }
145 
147 {
148  if (!_twr_module_rs485._voltage_valid)
149  {
150  return false;
151  }
152 
153  int16_t reg_result = _twr_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 (_twr_module_rs485._measurement_active)
170  {
171  return false;
172  }
173 
174  _twr_module_rs485._measurement_active = true;
175 
176  twr_scheduler_plan_absolute(_twr_module_rs485._task_id_measure, _twr_module_rs485._tick_ready);
177 
178  return true;
179 }
180 
181 static void _twr_module_rs485_async_write_task(void *param)
182 {
183  (void) param;
184 
185  size_t space_available;
186 
187  if (twr_fifo_is_empty(_twr_module_rs485._write_fifo))
188  {
189  twr_scheduler_unregister(_twr_module_rs485._async_write_task_id);
190  _twr_module_rs485._async_write_in_progress = false;
191 
192  _twr_module_rs485._event_handler(TWR_MODULE_RS485_EVENT_ASYNC_WRITE_DONE, _twr_module_rs485._event_param);
193 
194  return;
195  }
196 
197  if (!twr_sc16is740_get_spaces_available(&_twr_module_rs485._sc16is750, &space_available))
198  {
199  twr_scheduler_unregister(_twr_module_rs485._async_write_task_id);
200  _twr_module_rs485._async_write_in_progress = false;
201 
202  _twr_module_rs485._event_handler(TWR_MODULE_RS485_EVENT_ERROR, _twr_module_rs485._event_param);
203  return;
204  }
205 
206  size_t bytes_read = twr_fifo_read(_twr_module_rs485._write_fifo, _twr_module_rs485._async_buffer, space_available);
207  twr_module_rs485_write(_twr_module_rs485._async_buffer, bytes_read);
208 
209  twr_scheduler_plan_current_relative(_TWR_MODULE_RS485_ASYNC_WRITE_TASK_PERIOD);
210 }
211 
212 static void _twr_module_rs485_async_read_task(void *param)
213 {
214  (void) param;
215 
216  size_t available = 0;
217 
218  if (!twr_sc16is740_available(&_twr_module_rs485._sc16is750, &available))
219  {
220  return;
221  }
222 
223  if (available)
224  {
225  twr_sc16is740_read(&_twr_module_rs485._sc16is750, _twr_module_rs485._async_buffer, available, 0);
226  twr_fifo_write(_twr_module_rs485._read_fifo, _twr_module_rs485._async_buffer, available);
227  }
228 
229  if (!twr_fifo_is_empty(_twr_module_rs485._read_fifo))
230  {
231  _twr_module_rs485._event_handler(TWR_MODULE_RS485_EVENT_ASYNC_READ_DATA, _twr_module_rs485._event_param);
232  }
233  else
234  {
235  _twr_module_rs485._event_handler(TWR_MODULE_RS485_EVENT_ASYNC_READ_TIMEOUT, _twr_module_rs485._event_param);
236  }
237 
238  twr_scheduler_plan_current_relative(_twr_module_rs485._async_read_timeout);
239 }
240 
241 static void _twr_module_rs485_task_interval(void *param)
242 {
243  (void) param;
244 
246  twr_scheduler_plan_current_relative(_twr_module_rs485._update_interval);
247 }
248 
249 static void _twr_module_rs485_task_measure(void *param)
250 {
251  (void) param;
252 
253  start:
254 
255  switch (_twr_module_rs485._state)
256  {
257  case TWR_MODULE_RS485_STATE_ERROR:
258  {
259  if (_twr_module_rs485._event_handler != NULL)
260  {
261  _twr_module_rs485._event_handler(TWR_MODULE_RS485_EVENT_ERROR, _twr_module_rs485._event_param);
262  }
263 
264  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_INITIALIZE;
265 
266  return;
267  }
268  case TWR_MODULE_RS485_STATE_INITIALIZE:
269  {
270  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_ERROR;
271 
272  if (!twr_i2c_memory_write_16b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, 0x0503))
273  {
274  goto start;
275  }
276 
277  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_MEASURE;
278 
279  _twr_module_rs485._tick_ready = twr_tick_get();
280 
281  if (_twr_module_rs485._measurement_active)
282  {
283  twr_scheduler_plan_current_absolute(_twr_module_rs485._tick_ready);
284  }
285 
286  return;
287  }
288  case TWR_MODULE_RS485_STATE_MEASURE:
289  {
290  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_ERROR;
291 
292  if (!twr_i2c_memory_write_16b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x01, 0x8503))
293  {
294  goto start;
295  }
296 
297  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_READ;
298 
299  twr_scheduler_plan_current_from_now(_TWR_MODULE_RS485_DELAY_MEASUREMENT);
300 
301  return;
302  }
303  case TWR_MODULE_RS485_STATE_READ:
304  {
305  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_ERROR;
306 
307  uint16_t reg_configuration;
308 
309  if (!twr_i2c_memory_read_16b(TWR_I2C_I2C0, _TWR_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 (!twr_i2c_memory_read_16b(TWR_I2C_I2C0, _TWR_MODULE_RS485_I2C_TLA2021_ADDRESS, 0x00, &_twr_module_rs485._reg_result))
320  {
321  goto start;
322  }
323 
324  _twr_module_rs485._voltage_valid = true;
325 
326  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_UPDATE;
327 
328  goto start;
329  }
330  case TWR_MODULE_RS485_STATE_UPDATE:
331  {
332  _twr_module_rs485._measurement_active = false;
333 
334  if (_twr_module_rs485._event_handler != NULL)
335  {
336  _twr_module_rs485._event_handler(TWR_MODULE_RS485_EVENT_VOLTAGE, _twr_module_rs485._event_param);
337  }
338 
339  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_MEASURE;
340 
341  return;
342  }
343  default:
344  {
345  _twr_module_rs485._state = TWR_MODULE_RS485_STATE_ERROR;
346 
347  goto start;
348  }
349  }
350 }
351 
353 {
354  _twr_module_rs485._write_fifo = write_fifo;
355  _twr_module_rs485._read_fifo = read_fifo;
356 }
357 
358 size_t twr_module_rs485_async_write(uint8_t *buffer, size_t length)
359 {
360  if (!_twr_module_rs485._initialized || _twr_module_rs485._write_fifo == NULL)
361  {
362  return 0;
363  }
364 
365  size_t bytes_written = twr_fifo_write(_twr_module_rs485._write_fifo, (uint8_t *) buffer, length);
366 
367  if (bytes_written != 0)
368  {
369  if (!_twr_module_rs485._async_write_in_progress)
370  {
371  _twr_module_rs485._async_write_task_id = twr_scheduler_register(_twr_module_rs485_async_write_task, NULL, 10);
372  _twr_module_rs485._async_write_in_progress = true;
373  }
374  }
375 
376  return bytes_written;
377 }
378 
380 {
381  if (!_twr_module_rs485._initialized || _twr_module_rs485._read_fifo == NULL || _twr_module_rs485._async_read_in_progress)
382  {
383  return false;
384  }
385 
386  _twr_module_rs485._async_read_timeout = timeout;
387  _twr_module_rs485._async_read_task_id = twr_scheduler_register(_twr_module_rs485_async_read_task, NULL, _twr_module_rs485._async_read_timeout);
388  _twr_module_rs485._async_read_in_progress = true;
389 
390  return true;
391 }
392 
394 {
395  if (!_twr_module_rs485._initialized || !_twr_module_rs485._async_read_in_progress)
396  {
397  return false;
398  }
399 
400  _twr_module_rs485._async_read_in_progress = false;
401  twr_scheduler_unregister(_twr_module_rs485._async_read_task_id);
402 
403  return true;
404 }
405 
406 size_t twr_module_rs485_async_read(void *buffer, size_t length)
407 {
408  if (!_twr_module_rs485._initialized || _twr_module_rs485._read_fifo == NULL || !_twr_module_rs485._async_read_in_progress)
409  {
410  return 0;
411  }
412 
413  return twr_fifo_read(_twr_module_rs485._read_fifo, buffer, length);
414 }
415 
416 void twr_module_rs485_set_event_handler(void (*event_handler)(twr_module_rs485_event_t, void *), void *event_param)
417 {
418  _twr_module_rs485._event_handler = event_handler;
419  _twr_module_rs485._event_param = event_param;
420 }
421 
422 size_t twr_module_rs485_write(uint8_t *buffer, size_t length)
423 {
424  return twr_sc16is740_write(&_twr_module_rs485._sc16is750, buffer, length);
425 }
426 
427 bool twr_module_rs485_available(size_t *available)
428 {
429  return twr_sc16is740_available(&_twr_module_rs485._sc16is750, available);
430 }
431 
432 size_t twr_module_rs485_read(uint8_t *buffer, size_t length, twr_tick_t timeout)
433 {
434  return twr_sc16is740_read(&_twr_module_rs485._sc16is750, buffer, length, timeout);
435 }
436 
438 {
439  return twr_sc16is740_set_baudrate(&_twr_module_rs485._sc16is750, baudrate);
440 }
441 
bool twr_sc16is740_get_spaces_available(twr_sc16is740_t *self, size_t *spaces_available)
Get TX FIXO space available.
Definition: twr_sc16is740.c:88
size_t twr_fifo_write(twr_fifo_t *fifo, const void *buffer, size_t length)
Write data to FIFO.
Definition: twr_fifo.c:18
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
bool twr_i2c_memory_write_16b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t data)
Memory write 2 bytes to I2C channel.
Definition: twr_i2c.c:420
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
size_t twr_module_rs485_async_read(void *buffer, size_t length)
Get data that has been received in async mode.
bool twr_sc16is740_set_baudrate(twr_sc16is740_t *self, twr_sc16is740_baudrate_t baudrate)
Set baudrate.
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
bool twr_fifo_is_empty(twr_fifo_t *fifo)
Is empty.
Definition: twr_fifo.c:161
bool twr_module_rs485_set_baudrate(twr_module_rs485_baudrate_t baudrate)
Set baudrate.
void twr_module_rs485_set_update_interval(twr_tick_t interval)
Set measurement interval.
bool twr_module_rs485_measure(void)
Start single voltage measurement.
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
bool twr_module_rs485_async_read_start(twr_tick_t timeout)
Start async reading.
void twr_module_rs485_set_async_fifo(twr_fifo_t *write_fifo, twr_fifo_t *read_fifo)
Set FIFO.
size_t twr_module_rs485_write(uint8_t *buffer, size_t length)
Write data to RS-485 bus.
bool twr_module_rs485_async_read_stop(void)
Stop async reading.
bool twr_sc16is740_reset_fifo(twr_sc16is740_t *self, twr_sc16is740_fifo_t fifo)
Reset FIFO.
Definition: twr_sc16is740.c:79
size_t twr_module_rs485_read(uint8_t *buffer, size_t length, twr_tick_t timeout)
Read the received data.
bool twr_sc16is740_init(twr_sc16is740_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
SC16IS740 instance.
Definition: twr_sc16is740.c:23
bool twr_i2c_memory_read_16b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t *data)
Memory read 2 bytes from I2C channel.
Definition: twr_i2c.c:449
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_module_rs485_set_event_handler(void(*event_handler)(twr_module_rs485_event_t, void *), void *event_param)
Set callback function.
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
bool twr_i2c_memory_write_8b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t data)
Memory write 1 byte to I2C channel.
Definition: twr_i2c.c:408
twr_module_rs485_event_t
Callback events.
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
bool twr_module_rs485_deinit(void)
Deinitialize RS-485 Module.
size_t twr_module_rs485_async_write(uint8_t *buffer, size_t length)
Add data to be transmited in async mode.
twr_module_rs485_baudrate_t
Baudrates.
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
Definition: twr_scheduler.c:77
I2C channel I2C0.
Definition: twr_i2c.h:18
bool twr_module_rs485_get_voltage(float *volt)
Get measured voltage.
size_t twr_fifo_read(twr_fifo_t *fifo, void *buffer, size_t length)
Read data from FIFO.
Definition: twr_fifo.c:63
Structure of FIFO instance.
Definition: twr_fifo.h:12
size_t twr_sc16is740_write(twr_sc16is740_t *self, uint8_t *buffer, size_t length)
Write.
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
bool twr_sc16is740_available(twr_sc16is740_t *self, size_t *available)
Get RX FIXO available data.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
size_t twr_sc16is740_read(twr_sc16is740_t *self, uint8_t *buffer, size_t length, twr_tick_t timeout)
Read.
bool twr_module_rs485_init(void)
Initialize RS-485 Module.
bool twr_module_rs485_available(size_t *available)
Get number of received bytes.