Communicate Rx available antenna mode to the Tx (#3039)
[ExpressLRS.git] / src / lib / LED / devLED.cpp
blob312da26ee39c690ba7b345398de0983a7f86ba62
1 #include "targets.h"
2 #include "common.h"
3 #include "devLED.h"
5 #if defined(TARGET_TX)
6 #include "POWERMGNT.h"
7 #endif
9 constexpr uint8_t LEDSEQ_RADIO_FAILED[] = { 20, 100 }; // 200ms on, 1000ms off
10 constexpr uint8_t LEDSEQ_DISCONNECTED[] = { 50, 50 }; // 500ms on, 500ms off
11 constexpr uint8_t LEDSEQ_WIFI_UPDATE[] = { 2, 3 }; // 20ms on, 30ms off
12 constexpr uint8_t LEDSEQ_BINDING[] = { 10, 10, 10, 100 }; // 2x 100ms blink, 1s pause
13 constexpr uint8_t LEDSEQ_MODEL_MISMATCH[] = { 10, 10, 10, 10, 10, 100 }; // 3x 100ms blink, 1s pause
14 constexpr uint8_t LEDSEQ_UPDATE[] = { 20, 5, 5, 5, 5, 40 }; // 200ms on, 2x 50ms off/on, 400ms off
16 static int8_t _pin = -1;
17 static uint8_t _pin_inverted;
18 static const uint8_t *_durations;
19 static uint8_t _count;
20 static uint8_t _counter = 0;
21 static bool hasRGBLeds = false;
22 static bool hasGBLeds = false;
24 static uint16_t updateLED()
26 if (_pin == UNDEF_PIN)
28 return DURATION_NEVER;
30 if(_counter % 2 == 1)
31 digitalWrite(_pin, LOW ^ _pin_inverted);
32 else
33 digitalWrite(_pin, HIGH ^ _pin_inverted);
34 if (_counter >= _count)
36 _counter = 0;
38 return _durations[_counter++] * 10;
41 static uint16_t flashLED(int8_t pin, uint8_t pin_inverted, const uint8_t durations[], uint8_t count)
43 _counter = 0;
44 _pin = pin;
45 _pin_inverted = pin_inverted;
46 _durations = durations;
47 _count = count;
48 return updateLED();
51 static bool initialize()
53 bool hasLED = false;
54 if (GPIO_PIN_LED_BLUE != UNDEF_PIN)
56 pinMode(GPIO_PIN_LED_BLUE, OUTPUT);
57 digitalWrite(GPIO_PIN_LED_BLUE, LOW ^ GPIO_LED_BLUE_INVERTED);
58 hasLED = true;
60 if (GPIO_PIN_LED_GREEN != UNDEF_PIN)
62 pinMode(GPIO_PIN_LED_GREEN, OUTPUT);
63 digitalWrite(GPIO_PIN_LED_GREEN, HIGH ^ GPIO_LED_GREEN_INVERTED);
64 hasLED = true;
66 if (GPIO_PIN_LED_RED != UNDEF_PIN)
68 pinMode(GPIO_PIN_LED_RED, OUTPUT);
69 digitalWrite(GPIO_PIN_LED_RED, LOW ^ GPIO_LED_RED_INVERTED);
70 hasLED = true;
72 if (GPIO_PIN_LED_BLUE != UNDEF_PIN && GPIO_PIN_LED_GREEN != UNDEF_PIN && GPIO_PIN_LED_RED != UNDEF_PIN)
74 hasRGBLeds = true;
75 digitalWrite(GPIO_PIN_LED_GREEN, LOW);
76 digitalWrite(GPIO_PIN_LED_RED, HIGH);
77 digitalWrite(GPIO_PIN_LED_BLUE, LOW);
79 else if (GPIO_PIN_LED_BLUE != UNDEF_PIN && GPIO_PIN_LED_GREEN != UNDEF_PIN && GPIO_PIN_LED_RED == UNDEF_PIN)
81 hasGBLeds = true;
83 return hasLED || hasRGBLeds || hasGBLeds;
86 static int timeout()
88 return updateLED();
91 #if defined(TARGET_TX)
92 static void setPowerLEDs()
94 if (hasGBLeds)
96 switch (POWERMGNT::currPower())
98 case PWR_250mW:
99 digitalWrite(GPIO_PIN_LED_BLUE, HIGH);
100 digitalWrite(GPIO_PIN_LED_GREEN, HIGH);
101 break;
102 case PWR_500mW:
103 digitalWrite(GPIO_PIN_LED_BLUE, LOW);
104 digitalWrite(GPIO_PIN_LED_GREEN, HIGH);
105 break;
106 case PWR_10mW:
107 case PWR_25mW:
108 case PWR_50mW:
109 case PWR_100mW:
110 default:
111 digitalWrite(GPIO_PIN_LED_BLUE, HIGH);
112 digitalWrite(GPIO_PIN_LED_GREEN, LOW);
113 break;
117 #endif
119 static int event()
121 #if defined(TARGET_TX)
122 setPowerLEDs();
123 #else
124 if (InBindingMode && GPIO_PIN_LED_RED != UNDEF_PIN)
126 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_BINDING, sizeof(LEDSEQ_BINDING));
128 #endif
129 switch (connectionState)
131 case connected:
132 if (hasRGBLeds)
134 digitalWrite(GPIO_PIN_LED_GREEN, HIGH);
135 digitalWrite(GPIO_PIN_LED_RED, LOW);
136 digitalWrite(GPIO_PIN_LED_BLUE, LOW);
138 else if (GPIO_PIN_LED_GREEN != UNDEF_PIN)
140 digitalWrite(GPIO_PIN_LED_GREEN, HIGH ^ GPIO_LED_GREEN_INVERTED);
142 if (GPIO_PIN_LED_RED != UNDEF_PIN)
144 if (!connectionHasModelMatch || !teamraceHasModelMatch)
146 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_MODEL_MISMATCH, sizeof(LEDSEQ_MODEL_MISMATCH));
148 else if (!hasRGBLeds)
150 digitalWrite(GPIO_PIN_LED_RED, HIGH ^ GPIO_LED_RED_INVERTED); // turn on led
153 return DURATION_NEVER;
154 case disconnected:
155 if (hasRGBLeds)
157 digitalWrite(GPIO_PIN_LED_GREEN, LOW);
158 digitalWrite(GPIO_PIN_LED_BLUE, LOW);
159 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_DISCONNECTED, sizeof(LEDSEQ_DISCONNECTED));
161 else if (GPIO_PIN_LED_GREEN != UNDEF_PIN && GPIO_PIN_LED_RED != UNDEF_PIN)
163 digitalWrite(GPIO_PIN_LED_GREEN, LOW ^ GPIO_LED_GREEN_INVERTED);
164 digitalWrite(GPIO_PIN_LED_RED, LOW ^ GPIO_LED_RED_INVERTED);
166 else if (GPIO_PIN_LED_RED != UNDEF_PIN)
168 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_DISCONNECTED, sizeof(LEDSEQ_DISCONNECTED));
170 else if (GPIO_PIN_LED_GREEN != UNDEF_PIN)
172 return flashLED(GPIO_PIN_LED_GREEN, GPIO_LED_GREEN_INVERTED, LEDSEQ_DISCONNECTED, sizeof(LEDSEQ_DISCONNECTED));
174 return DURATION_NEVER;
175 case wifiUpdate:
176 if (hasRGBLeds)
178 digitalWrite(GPIO_PIN_LED_GREEN, LOW);
179 digitalWrite(GPIO_PIN_LED_RED, LOW);
180 return flashLED(GPIO_PIN_LED_BLUE, GPIO_LED_BLUE_INVERTED, LEDSEQ_WIFI_UPDATE, sizeof(LEDSEQ_WIFI_UPDATE));
182 else if (GPIO_PIN_LED_RED != UNDEF_PIN)
184 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_WIFI_UPDATE, sizeof(LEDSEQ_WIFI_UPDATE));
186 return DURATION_NEVER;
187 case radioFailed:
188 if (hasRGBLeds)
190 digitalWrite(GPIO_PIN_LED_GREEN, LOW);
191 digitalWrite(GPIO_PIN_LED_BLUE, LOW);
192 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_RADIO_FAILED, sizeof(LEDSEQ_RADIO_FAILED));
194 else if (GPIO_PIN_LED_GREEN != UNDEF_PIN)
196 digitalWrite(GPIO_PIN_LED_GREEN, LOW ^ GPIO_LED_GREEN_INVERTED);
198 if (GPIO_PIN_LED_RED != UNDEF_PIN)
200 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_RADIO_FAILED, sizeof(LEDSEQ_RADIO_FAILED));
202 return DURATION_NEVER;
203 case noCrossfire:
204 if (GPIO_PIN_LED_RED != UNDEF_PIN)
206 // technically nocrossfire is {10,100} but {20,100} is close enough
207 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_RADIO_FAILED, sizeof(LEDSEQ_RADIO_FAILED));
209 case serialUpdate:
210 if (GPIO_PIN_LED_RED != UNDEF_PIN)
212 return flashLED(GPIO_PIN_LED_RED, GPIO_LED_RED_INVERTED, LEDSEQ_UPDATE, sizeof(LEDSEQ_UPDATE));
214 default:
215 return DURATION_NEVER;
219 static int start()
221 return event();
224 device_t LED_device = {
225 .initialize = initialize,
226 .start = start,
227 .event = event,
228 .timeout = timeout,
229 .subscribe = EVENT_CONNECTION_CHANGED | EVENT_ENTER_BIND_MODE | EVENT_EXIT_BIND_MODE