Firmware SDK
twr_module_relay.c
1 #include <twr_module_relay.h>
2 
3 static void _twr_module_relay_task(void *param);
4 
5 #define TWR_MODULE_RELAY_POLARITY_F ((1 << 6) | (1 << 7))
6 #define TWR_MODULE_RELAY_POLARITY_T ((1 << 4) | (1 << 5))
7 #define TWR_MODULE_RELAY_POLARITY_NONE ((1 << 6) | (1 << 4))
8 
9 
10 static bool _twr_module_relay_hardware_init(twr_module_relay_t *self)
11 {
12  // Relay is bi-stable, in the begining we don't know the default state
13  self->_relay_state = TWR_MODULE_RELAY_STATE_UNKNOWN;
14 
15  // Init i2C expander driver
16  if (!twr_tca9534a_init(&self->_tca9534a, TWR_I2C_I2C0, self->_i2c_address))
17  {
18  return false;
19  }
20  // De-energize bistable relay coil - turn off
21  twr_tca9534a_write_port(&(self->_tca9534a), TWR_MODULE_RELAY_POLARITY_NONE);
22  // Enable outputs
23  twr_tca9534a_set_port_direction(&self->_tca9534a, 0x00); // inverted: 0 = output
24 
25  return true;
26 }
27 
28 bool twr_module_relay_init(twr_module_relay_t *self, uint8_t i2c_address)
29 {
30  // Init instance, set state machine initial state
31  memset(self, 0, sizeof(*self));
32  self->_i2c_address = i2c_address;
33  return _twr_module_relay_hardware_init(self);
34 }
35 
36 static void twr_module_relay_scheduler_unregister(twr_module_relay_t *self)
37 {
38  // Check if there is already a task running
39  if (self->_task_is_active)
40  {
41  // Unregister running task
42  twr_scheduler_unregister(self->_task_id);
43  // Clear task id
44  self->_task_id = 0;
45  self->_task_is_active = false;
46  }
47 }
48 
49 static void twr_module_relay_scheduler_register(twr_module_relay_t *self)
50 {
51  // Exit if there's already registered task
52  if (self->_task_is_active)
53  {
54  return;
55  }
56 
57  // Register relay task
58  self->_task_id = twr_scheduler_register(_twr_module_relay_task, self, 0);
59  self->_task_is_active = true;
60 }
61 
62 static void _twr_module_relay_set_output(twr_module_relay_t *self, twr_module_relay_state_t state)
63 {
64  if (state == TWR_MODULE_RELAY_STATE_TRUE)
65  {
66  if (!twr_tca9534a_write_port(&self->_tca9534a, TWR_MODULE_RELAY_POLARITY_T)) // pol A
67  {
68  self->_error = true;
69  }
70  }
71  else
72  {
73  if (!twr_tca9534a_write_port(&self->_tca9534a, TWR_MODULE_RELAY_POLARITY_F)) // pol B
74  {
75  self->_error = true;
76  }
77  }
78 }
79 
80 static void _twr_module_relay_set_output_disable(twr_module_relay_t *self)
81 {
82  if (!twr_tca9534a_write_port(&(self->_tca9534a), TWR_MODULE_RELAY_POLARITY_NONE))
83  {
84  self->_error = true;
85  }
86 }
87 
88 static twr_tick_t twr_module_relay_state_machine(twr_module_relay_t *self, twr_tick_t tick_now)
89 {
90  while (true)
91  {
92  switch (self->_state)
93  {
94  case TWR_MODULE_RELAY_TASK_STATE_IDLE:
95  // Handle Error
96  if (self->_error)
97  {
98  // Try to initialize relay module again
99  if (_twr_module_relay_hardware_init(self))
100  {
101  self->_error = false;
102  }
103  }
104 
105  // Handle commands
106  if (self->_command == TWR_MODULE_RELAY_COMMAND_SET)
107  {
108  self->_command = TWR_MODULE_RELAY_COMMAND_NONE;
109  self->_state = TWR_MODULE_RELAY_TASK_STATE_SET;
110  continue;
111  }
112 
113  if (self->_command == TWR_MODULE_RELAY_COMMAND_PULSE)
114  {
115  self->_command = TWR_MODULE_RELAY_COMMAND_NONE;
116  self->_state = TWR_MODULE_RELAY_TASK_STATE_PULSE;
117  continue;
118  }
119 
120  // Unregister task if no command is needed
121  twr_module_relay_scheduler_unregister(self);
122  return tick_now;
123 
124  //
125  // Relay set start state
126  //
127  case TWR_MODULE_RELAY_TASK_STATE_SET:
128  // Set relay to the selected polarity
129  _twr_module_relay_set_output(self, self->_desired_state);
130  self->_relay_state = self->_desired_state;
131 
132  self->_state = TWR_MODULE_RELAY_TASK_STATE_SET_DEMAGNETIZE;
133  return tick_now + 20;
134 
135  case TWR_MODULE_RELAY_TASK_STATE_SET_DEMAGNETIZE:
136  // De-energize bistable relay coil - turn off
137  _twr_module_relay_set_output_disable(self);
138 
139  self->_state = TWR_MODULE_RELAY_TASK_STATE_IDLE;
140  // Needs 100ms to let the capacitor on relay board to charge
141  return tick_now + 100;
142 
143  //
144  // Relay pulse start state
145  //
146  case TWR_MODULE_RELAY_TASK_STATE_PULSE:
147  // Create pulse of the set polarity
148  _twr_module_relay_set_output(self, self->_desired_state);
149  self->_relay_state = self->_desired_state;
150 
151  self->_state = TWR_MODULE_RELAY_TASK_STATE_PULSE_DEMAGNETIZE;
152  return tick_now + 20;
153 
154  case TWR_MODULE_RELAY_TASK_STATE_PULSE_DEMAGNETIZE:
155  // De-energize bistable relay coil - turn off
156  _twr_module_relay_set_output_disable(self);
157 
158  self->_state = TWR_MODULE_RELAY_TASK_STATE_PULSE_REVERSE;
159  return tick_now + self->_pulse_duration;
160 
161  case TWR_MODULE_RELAY_TASK_STATE_PULSE_REVERSE:
162  // Change actual relay state to the oposite polarity
163  self->_relay_state = (self->_relay_state == TWR_MODULE_RELAY_STATE_TRUE) ? TWR_MODULE_RELAY_STATE_FALSE : TWR_MODULE_RELAY_STATE_TRUE;
164  _twr_module_relay_set_output(self, self->_relay_state);
165 
166  self->_state = TWR_MODULE_RELAY_TASK_STATE_PULSE_DEMAGNETIZE_2;
167  return tick_now + 20;
168 
169  case TWR_MODULE_RELAY_TASK_STATE_PULSE_DEMAGNETIZE_2:
170  // De-energize bistable relay coil - turn off
171  _twr_module_relay_set_output_disable(self);
172 
173  self->_state = TWR_MODULE_RELAY_TASK_STATE_IDLE;
174  // Needs 100ms to let the capacitor on relay board to charge
175  return tick_now + 100;
176 
177  default:
178  break;
179  }
180  }
181 }
182 
183 static void _twr_module_relay_task(void *param)
184 {
185  twr_module_relay_t *self = param;
186 
187  twr_scheduler_plan_current_absolute(twr_module_relay_state_machine(self, twr_scheduler_get_spin_tick()));
188 }
189 
191 {
192  // Save set command
193  self->_command = TWR_MODULE_RELAY_COMMAND_SET;
194  self->_desired_state = (state) ? TWR_MODULE_RELAY_STATE_TRUE : TWR_MODULE_RELAY_STATE_FALSE;
195 
196  twr_module_relay_scheduler_register(self);
197 }
198 
200 {
201  if (self->_relay_state == TWR_MODULE_RELAY_STATE_FALSE)
202  {
204  }
205  else if (self->_relay_state == TWR_MODULE_RELAY_STATE_TRUE)
206  {
208  }
209 }
210 
211 void twr_module_relay_pulse(twr_module_relay_t *self, bool state, twr_tick_t duration)
212 {
213  // Save pulse duration
214  self->_command = TWR_MODULE_RELAY_COMMAND_PULSE;
215  self->_pulse_duration = duration;
216  self->_desired_state = (state) ? TWR_MODULE_RELAY_STATE_TRUE : TWR_MODULE_RELAY_STATE_FALSE;
217 
218  twr_module_relay_scheduler_register(self);
219 }
220 
222 {
223  return self->_relay_state;
224 }
@ TWR_I2C_I2C0
I2C channel I2C0.
Definition: twr_i2c.h:18
twr_module_relay_state_t
Reported relay states.
void twr_module_relay_set_state(twr_module_relay_t *self, bool state)
Set relay to specified state.
struct twr_module_relay_t twr_module_relay_t
HARDWARIO Relay Module instance.
void twr_module_relay_toggle(twr_module_relay_t *self)
Toggle relay to opposite state.
void twr_module_relay_pulse(twr_module_relay_t *self, bool state, twr_tick_t duration)
Generate pulse to specified state for given duration.
bool twr_module_relay_init(twr_module_relay_t *self, uint8_t i2c_address)
Initialize HARDWARIO Relay Module.
twr_module_relay_state_t twr_module_relay_get_state(twr_module_relay_t *self)
Get current relay state.
@ TWR_MODULE_RELAY_STATE_UNKNOWN
State is unknown.
@ TWR_MODULE_RELAY_STATE_FALSE
State is false.
@ TWR_MODULE_RELAY_STATE_TRUE
State is true.
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
Definition: twr_scheduler.c:77
twr_tick_t twr_scheduler_get_spin_tick(void)
Get current tick of spin in which task has been run.
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
bool twr_tca9534a_write_port(twr_tca9534a_t *self, uint8_t state)
Write state to all pins.
Definition: twr_tca9534a.c:35
bool twr_tca9534a_init(twr_tca9534a_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize TCA9534A.
Definition: twr_tca9534a.c:8
bool twr_tca9534a_set_port_direction(twr_tca9534a_t *self, uint8_t direction)
Set direction of all pins.
Definition: twr_tca9534a.c:87
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16