-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtask_ctrl.c
185 lines (160 loc) · 5.92 KB
/
task_ctrl.c
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
/*
* This file is part of RXSMS.
* Copyright 2014, 2015 Nicolas Benes
*
* RXSMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RXSMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RXSMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <avr/io.h>
#include "task_ctrl.h"
#include "task_buttons.h"
#include "task_adc.h"
#define STATUS_LED_PORT PORTA
#define STATUS_LED_LO_bm PIN7_bm
#define STATUS_LED_ERRINH_bm PIN6_bm
#define RXSM_LO_PORT PORTD
#define RXSM_LO_bm PIN0_bm
#define RXSM_LO_bp PIN0_bp
#define RXSM_SOE_PORT PORTD
#define RXSM_SOE_bm PIN1_bm
#define RXSM_SODS_PORT PORTC
#define RXSM_SODS_bm PIN5_bm
#define RXSM_EXPPWR_PORT PORTC
#define RXSM_EXPPWR_bm PIN4_bm
static void init(void);
static void run(void);
const struct task task_ctrl = { .init = &init, .run = &run };
static void
update_lo_led(void)
{
// For multi-channel operation, LO is connected between all simulators.
// There are four cases for the LO LED:
//
// | our LO unasserted | our LO asserted
// ----------------------+-------------------+----------------
// other's LO unasserted | LED OFF | LED cont. ON
// other's LO asserted | LED flashing | LED cont. ON
//
// "our LO": the LO line we control (local)
// "other's LO": the LO line another simulator controls (remote)
const uint16_t led_period = 5000;
static uint16_t led_cnt = led_period;
if (!(RXSM_LO_PORT.OUT & RXSM_LO_bm)) { // our LO is asserted
led_cnt = led_period;
STATUS_LED_PORT.OUTSET = STATUS_LED_LO_bm; // LED always ON
return;
}
if (!task_ctrl_signals.lo_asserted) { // LO is unasserted
led_cnt = led_period;
STATUS_LED_PORT.OUTCLR = STATUS_LED_LO_bm; // LED always OFF
return;
}
// LO is asserted by another simulator -- LED flashing
if (led_cnt > led_period / 2)
STATUS_LED_PORT.OUTSET = STATUS_LED_LO_bm;
else
STATUS_LED_PORT.OUTCLR = STATUS_LED_LO_bm;
// decrement with underflow wrap-around
if (0 == --led_cnt)
led_cnt = led_period;
}
static void
update_error_inhibit_led(void)
{
// There are four cases for the Error Inhibit LED:
//
// | error inhibit ON | error inhibit OFF
// ----------------------+---------------------+--------------------
// poti errors disabled | LED cont. ON | LED flashing
// poti errors enabled | LED cont. ON | LED OFF
const uint16_t led_period = 5000;
static uint16_t led_cnt = led_period;
if (task_ctrl_signals.error_inhibit) { // error inhibit ON
led_cnt = led_period;
STATUS_LED_PORT.OUTSET = STATUS_LED_ERRINH_bm; // LED always OFF
return;
}
if (task_adc_generator.biterror_rate_bin || // error inhibit OFF
task_adc_generator.dropout_rate_bin) { // and poti errors ON
led_cnt = led_period;
STATUS_LED_PORT.OUTCLR = STATUS_LED_ERRINH_bm; // LED always OFF
return;
}
// error inhibit is OFF but NO poti errors are set -- LED flashing
if (led_cnt > led_period / 2)
STATUS_LED_PORT.OUTSET = STATUS_LED_ERRINH_bm;
else
STATUS_LED_PORT.OUTCLR = STATUS_LED_ERRINH_bm;
// decrement with underflow wrap-around
if (0 == --led_cnt)
led_cnt = led_period;
}
static void
read_signal_states(void)
{
task_ctrl_signals.lo_asserted = !(RXSM_LO_PORT.IN & RXSM_LO_bm);
task_ctrl_signals.soe_asserted = !(RXSM_SOE_PORT.IN & RXSM_SOE_bm);
task_ctrl_signals.sods_asserted = !(RXSM_SODS_PORT.IN & RXSM_SODS_bm);
task_ctrl_signals.pwr_on = 0 != (RXSM_EXPPWR_PORT.IN & RXSM_EXPPWR_bm);
}
static void
init(void)
{
// first set the outputs, then the directions.
// this way, we can ensure that the outputs are undriven/passive but the
// OUTPUT register is already set correctly. Then the pins are switched to
// drive loads and already have the correct output value.
#define PINCTRL_CONCAT(num) PIN##num##CTRL
#define PINCTRL(num) PINCTRL_CONCAT(num)
RXSM_LO_PORT.PINCTRL(RXSM_LO_bp) = PORT_OPC_WIREDAND_gc;
#undef PINCTRL
#undef PINCTRL_CONCAT
// by default, the error inhibit is ON, all others OFF/UNASSERTED
#define OUTINIT(port, out) RXSM_##port##_PORT.OUT##out = RXSM_##port##_bm
OUTINIT(LO, SET);
OUTINIT(SOE, SET);
OUTINIT(SODS, SET);
OUTINIT(EXPPWR, CLR);
#undef OUTINIT
#define DIRINIT(port) RXSM_##port##_PORT.DIRSET = RXSM_##port##_bm
DIRINIT(LO);
DIRINIT(SOE);
DIRINIT(SODS);
DIRINIT(EXPPWR);
#undef DIRINIT
// update our internal state
read_signal_states();
task_ctrl_signals.error_inhibit = 1;
// update the LEDs
update_lo_led();
update_error_inhibit_led();
STATUS_LED_PORT.DIRSET = STATUS_LED_LO_bm | STATUS_LED_ERRINH_bm;
}
static void
run(void)
{
// update output signals according to task_buttons
if (task_buttons_toggle_request.lo)
RXSM_LO_PORT.OUTTGL = RXSM_LO_bm;
if (task_buttons_toggle_request.soe)
RXSM_SOE_PORT.OUTTGL = RXSM_SOE_bm;
if (task_buttons_toggle_request.sods)
RXSM_SODS_PORT.OUTTGL = RXSM_SODS_bm;
if (task_buttons_toggle_request.pwr)
RXSM_EXPPWR_PORT.OUTTGL = RXSM_EXPPWR_bm;
if (task_buttons_toggle_request.errinh)
task_ctrl_signals.error_inhibit ^= 1;
read_signal_states();
update_lo_led();
update_error_inhibit_led();
}