-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLogic_out.c
More file actions
273 lines (228 loc) · 7.12 KB
/
Logic_out.c
File metadata and controls
273 lines (228 loc) · 7.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/*!\file Logic_out.c
** \author SMFSW
** \copyright MIT (c) 2017-2026, SMFSW
** \brief Logic output handling
** \note Define \c LOGIC_OUT_IT symbol at project level to use \ref Logic_out from timer interrupts (for more timing precision if required)
** \note When using \ref Logic_out from interrupts, \c LOGIC_OUT_IT_PER period is defined by default with a period of 1000µs (can be customly defined)
** \warning \ref Logic_out & \ref GPIO_out shares interrupt behavior, thus needs to be implemented the same way (it or loop) if both are used at the same time
**/
/****************************************************************/
#include "Logic_out.h"
/****************************************************************/
/*!\brief Logic output variable setter
** \param[in] out - Logic_out instance
** \param[in] state - Logic_out state
**/
__STATIC_INLINE void NONNULL_INLINE__ Logic_out_setter(const Logic_out * const out, const GPIO_PinState state)
{
const uint32_t bit_mask = LSHIFT(1UL, out->cfg.LOG_Pos);
if (out->cfg.LOGx != NULL) { SET_BITS_VAL(*((uint32_t *) out->cfg.LOGx), bit_mask, state ? bit_mask : 0UL); }
}
/*!\brief Set GPIO port value
** \param[in,out] out - Logic_out instance
** \return Error code
**/
FctERR NONNULL__ Logic_out_update(Logic_out * const out)
{
if (out->action == Reset) { out->currentState = GPIO_PIN_RESET; }
else if (out->action == Set) { out->currentState = GPIO_PIN_SET; }
else if (out->action == Toggle) { out->currentState ^= GPIO_PIN_SET; }
else { return ERROR_VALUE; }
const GPIO_PinState val = out->currentState ^ (out->cfg.polarity ? GPIO_PIN_RESET : GPIO_PIN_SET);
if (out->cfg.set != NULL) { out->cfg.set(out, val); }
else { Logic_out_setter(out, val); }
return ERROR_OK;
}
FctERR NONNULLX__(1) Logic_out_init(Logic_out * const out,
void (*setter)(const Logic_out * const, const GPIO_PinState),
uint32_t * const addr,
const uint16_t pos,
const GPIO_PinState polarity)
{
/* Check the parameters */
//assert_param(pos < 32); // Would raise an assert error in case of GPIO pin
out->cfg.set = setter;
out->cfg.LOGx = addr;
out->cfg.LOG_Pos = pos;
out->cfg.polarity = polarity;
out->currentState = GPIO_PIN_RESET;
out->memState = GPIO_PIN_RESET;
out->action = Reset;
out->idle = true;
out->init = true;
return Logic_out_update(out); // Immediately set to reset value
}
FctERR NONNULL__ Logic_out_Abort(Logic_out * const out)
{
FctERR err = ERROR_OK;
if ((out->init) && (!out->idle))
{
err = Logic_out_SetStatic(out, (eGPIOState) out->memState, 0);
}
return err;
}
/*!\brief Start Logic_out change
** \param[in,out] out - Logic_out instance
** \param[in] mode - Logic_out mode
** \param[in] action - action to perform on output port pin for active state (Reset/Set/Toggle)
** \param[in] delay - delay before pulse (in ms)
** \param[in] active - active time (in ms) for pulse/blink mode only
** \param[in] inactive - inactive time (in ms) for blink mode only
** \param[in] count - blink count (0 for infinite) for blink mode only
** \return Error code
**/
static FctERR NONNULL__ Logic_out_Start(Logic_out * const out,
const eLogic_out_mode mode,
const eGPIOState action,
uint32_t delay,
uint32_t active,
uint32_t inactive,
const uint32_t count)
{
FctERR err = ERROR_OK;
if (!out->init) { err = ERROR_INSTANCE; }
if (action > Toggle) { err = ERROR_VALUE; }
if (err == ERROR_OK)
{
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
delay = (delay * LOGIC_OUT_IT_PER) / 1000UL;
active = (active * LOGIC_OUT_IT_PER) / 1000UL;
inactive = (inactive * LOGIC_OUT_IT_PER) / 1000UL;
out->hOut = 0U;
diInterrupts();
#else
out->hOut = HALTicks();
#endif
out->mode = mode;
out->action = action;
out->delay = delay;
out->timeActive = active;
out->timeInactive = inactive;
out->infinite = count ? false : true;
out->cnt = count;
out->start = true;
out->active = true;
out->idle = false;
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
enInterrupts();
#endif
}
return err;
}
FctERR NONNULL__ Logic_out_SetStatic(Logic_out * const out, const eGPIOState action, const uint32_t delay)
{
return Logic_out_Start(out, outStatic, action, delay, 0, 0, 0);
}
FctERR NONNULL__ Logic_out_StartPulse(Logic_out * const out, const eGPIOState action, const uint32_t delay, const uint32_t active)
{
return Logic_out_Start(out, outPulse, action, delay, active, 0, 0);
}
FctERR NONNULL__ Logic_out_StartBlink( Logic_out * const out,
const eGPIOState action,
const uint32_t delay,
const uint32_t active,
const uint32_t inactive,
const uint32_t count)
{
return Logic_out_Start(out, outBlink, action, delay, active, inactive, count);
}
void NONNULL__ Logic_out_handler(Logic_out * const out)
{
if ((out->init) && (!out->idle))
{
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
out->hOut++; // Increment timer count
if ( (!out->delay)
|| (out->hOut > out->delay))
#else
if ( (!out->delay)
|| (TPSSUP_MS(out->hOut, out->delay)))
#endif
{
out->delay = 0U;
switch (out->mode)
{
case outPulse:
{
if (out->start)
{
UNUSED_RET Logic_out_update(out);
out->start = false;
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
out->hOut = 0U;
#else
out->hOut = HALTicks();
#endif
}
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
if (out->hOut > out->timeActive)
#else
if (TPSSUP_MS(out->hOut, out->timeActive))
#endif
{
UNUSED_RET Logic_out_Abort(out);
goto stop; // Go back to memorized state in current cycle
}
}
break;
case outBlink:
{
bool set = false;
if (out->start)
{
UNUSED_RET Logic_out_update(out);
out->action = Toggle; // Force toggle if action set was Reset or Set
out->start = false;
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
out->hOut = 0U;
#else
out->hOut = HALTicks();
#endif
}
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
if ((out->active) && (out->hOut > out->timeActive))
#else
if ((out->active) && (TPSSUP_MS(out->hOut, out->timeActive)))
#endif
{
set = true;
}
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
else if ((!out->active) && (out->hOut > out->timeInactive))
#else
else if ((!out->active) && (TPSSUP_MS(out->hOut, out->timeInactive)))
#endif
{
if (--out->cnt == 0U)
{
UNUSED_RET Logic_out_Abort(out);
goto stop; // Go back to memorized state in current cycle
}
set = true;
}
if (set)
{
UNUSED_RET Logic_out_update(out);
out->active ^= true;
#if defined(LOGIC_OUT_IT) || defined(GPIO_OUT_IT)
out->hOut = 0U;
#else
out->hOut = HALTicks();
#endif
}
}
break;
case outStatic:
{
stop: // label used only by Pulse and Blink cases when finished to revert to memorized state in current cycle
UNUSED_RET Logic_out_update(out);
out->memState = out->currentState;
out->idle = true;
}
break;
default:
break;
}
}
}
}