Subversion Repositories DashDisplay

Rev

Rev 75 | Rev 77 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
66 mjames 1
/*
2
 * display.cpp
3
 *
4
 *  Created on: 30 Nov 2020
5
 *      Author: mike
6
 */
7
 
8
#include "main.h"
9
#include "display.h"
10
#include "switches.h"
11
#include "nvram.h"
12
#include <cstring>
13
#include "libOLED/stm32_halDisplay.H"
14
#include "libOLED/fontclass.H"
15
#include "libOLED/displayDial.H"
16
#include "libPlx/displayInfo.H"
17
#include "libOLED/ap_math.h"
70 mjames 18
#include "libSmallPrintf/small_printf.h"
66 mjames 19
 
20
#include "splash.H"
21
 
22
namespace
23
{
24
        int const WIDTH = 128;
25
        int const HEIGHT = 64;
26
        int const DISPLAY_RAMWIDTH = 132;
74 mjames 27
 
66 mjames 28
}
29
 
30
uint8_t displayBuffer[2][dataSize(WIDTH, HEIGHT)];
31
 
32
stm32_halDisplay_t displays[MAX_DISPLAYS] =
33
        {stm32_halDisplay_t(WIDTH, HEIGHT, DISPLAY_RAMWIDTH, displayBuffer[0],
34
                                                &hspi1,
35
                                                SPI_CD_GPIO_Port,
36
                                                SPI_CD_Pin,
37
                                                SPI_RESET_GPIO_Port,
38
                                                SPI_RESET_Pin,
39
                                                SPI_NSS1_GPIO_Port,
40
                                                SPI_NSS1_Pin),
41
         stm32_halDisplay_t(WIDTH, HEIGHT,
42
                                                DISPLAY_RAMWIDTH,
43
                                                displayBuffer[1],
44
                                                &hspi1,
45
                                                SPI_CD_GPIO_Port,
46
                                                SPI_CD_Pin,
47
                                                SPI_RESET_GPIO_Port,
48
                                                SPI_RESET_Pin,
49
                                                SPI_NSS2_GPIO_Port,
50
                                                SPI_NSS2_Pin)};
51
 
52
displayDial_t dials[MAX_DISPLAYS] =
67 mjames 53
        {displayFullDial_t(displays[0]), displayFullDial_t(displays[1])};
66 mjames 54
#if defined __cplusplus
55
extern "C"
56
{
57
#endif
58
        static void
59
        showMinMax(display_t &display, uint8_t dp_pos, int16_t int_min,
60
                           uint16_t int_max)
61
        {
62
                const char padding[] = "      ";
63
                // left justified display of minimum
64
                int8_t width = display.fontSigDigits(small_font, 0, 0, 0, dp_pos, int_min, WHITE);
65
                // pad with spaces if fewer than 6 characters are used.
66
                if (width != 6)
67
                        display.printString(small_font, padding, 6 - width, WHITE);
68
 
69
                display.gotoxy(0, 8);
70
                display.printString(small_font, "Min", 3, WHITE);
71
 
72
                // right justified display of maximum
73
                width = display.fontSigDigits(small_font, 120, 0, 1, dp_pos, int_max, WHITE);
74
                // right justified display of maximum : pad spaces to left
75
                if (width != 6)
76
                        display.printString(small_font, padding, 6 - width, WHITE);
77
 
78
                display.gotoxy(110, 8);
79
                display.printString(small_font, "Max", 3, WHITE);
80
        }
81
 
82
        void
83
        cc_init()
84
        {
85
                for (auto i = 0; i < MAX_DISPLAYS; i++)
86
                {
87
                        display_t &display = displays[i];
88
                        if (i == 0)
89
                                display.reset();
90
                        display.init();
91
                        display.clearDisplay(BLACK);
92
                        displaySplash(display);
93
                        display.gotoxy(8, 32);
94
                        display.printString(large_font, i == 0 ? "1" : "2", 1, BLACK);
95
                        display.display();
96
                }
97
 
98
                HAL_Delay(1000);
99
 
100
                for (auto i = 0; i < MAX_DISPLAYS; i++)
101
                {
102
                        display_t &display = displays[i];
103
                        display.clearDisplay(BLACK);
104
                        display.setPixelMode(WHITE);
105
                        display.display();
106
                        context_t &context = contexts[i];
71 mjames 107
                        context.dial_timer = 500; // enough time to see at least one frame of PLX before NVRAM check
66 mjames 108
                        context.dial1 = -1;
74 mjames 109
                        context.OldObservation = nullObs;
66 mjames 110
                }
111
        }
112
 
113
        // Check to see if there is an observation/instance in the dynamic data array
114
        // that matches the current observation/instance in the NVRAM
115
 
116
        void
117
        cc_check_nvram(int dialIndex)
118
        {
119
                if (dialIndex < 0 && dialIndex > MAX_DISPLAYS)
120
                        return;
70 mjames 121
                // algorithm only works when there is a vector of observations
74 mjames 122
 
66 mjames 123
                context_t &context = contexts[dialIndex];
124
 
125
                // check for timer timeout on consistent timer
126
 
127
                if (context.dial_timer)
128
                {
129
                        context.dial_timer--;
75 mjames 130
                }
131
                if (context.dial_timer == 0)
132
                {
133
                        context.dial_timer = DialTimeout;
134
                        int i;
135
                        // use dialIndex+1 as tag for data : always non-zero.
136
                        nvram_info_t *dial_nvram = find_nvram_data(dialIndex + 1);
137
 
138
                        if (dial_nvram && context.knobPos < 0)
66 mjames 139
                        {
75 mjames 140
                                for (i = 0; i < MAXRDG; i++)
141
                                        if (isValid(i) && (Info[i].observation.Obs == dial_nvram->data.observation) && (Info[i].observation.Instance == dial_nvram->data.instance))
142
                                        {
143
                                                context.knobPos = i;
144
                                                return;
145
                                        }
146
                        }
147
                        if (context.knobPos == -1)
148
                                context.knobPos = dialIndex; // timed out , not in NVRAM, use a default
66 mjames 149
 
75 mjames 150
                        // dont save dial info for invalid data
151
                        if (!isValid(context.knobPos))
152
                                return;
153
                        // is this a change since the last timeout ?
66 mjames 154
 
75 mjames 155
                        if (!dial_nvram || (Info[context.knobPos].observation.Obs != dial_nvram->data.observation) || (Info[context.knobPos].observation.Instance != dial_nvram->data.instance))
156
                        {
70 mjames 157
 
75 mjames 158
                                // store the observation and instance in the NVRAM, not dial position.
159
                                nvram_info_t curr_val;
160
                                curr_val.data.observation = Info[context.knobPos].observation.Obs;
161
                                curr_val.data.instance = Info[context.knobPos].observation.Instance;
162
                                curr_val.data.tag = dialIndex + 1;
66 mjames 163
 
75 mjames 164
                                write_nvram_data(curr_val);
66 mjames 165
                        }
166
                }
167
        }
168
 
169
        int
170
        cc_display(int dialIndex, int suppressIndex)
171
 
172
        {
74 mjames 173
 
66 mjames 174
                if (dialIndex < 0 && dialIndex > MAX_DISPLAYS)
175
                        return -1;
176
                context_t &context = contexts[dialIndex];
177
                displayDial_t &dial = dials[dialIndex];
178
                stm32_halDisplay_t &display = displays[dialIndex];
179
                int itemIndex = context.knobPos;
180
                char buff[10];
181
                int i;
75 mjames 182
                const char *msg;
70 mjames 183
                int len;
74 mjames 184
                // check for startup phase
72 mjames 185
                if (itemIndex < 0)
186
                {
187
                        display.clearDisplay(BLACK);
188
                        i = small_sprintf(buff, "Wait");
189
                        display.gotoxy(64 - i * 4, 48);
190
                        display.printString(large_font, buff, i, WHITE);
66 mjames 191
 
72 mjames 192
                        display.display();
74 mjames 193
                        return -1;
72 mjames 194
                }
195
 
66 mjames 196
                // check for item suppression
197
                if (itemIndex == suppressIndex)
198
                {
199
                        context.dial1 = -1;
74 mjames 200
                        context.OldObservation = nullObs;
70 mjames 201
                        display.clearDisplay(BLACK);
202
                        i = small_sprintf(buff, "Supp-%02d", itemIndex);
203
                        display.gotoxy(64 - i * 4, 48);
204
                        display.printString(large_font, buff, i, WHITE);
205
 
66 mjames 206
                        display.display();
207
                        return -1; // we suppressed this display
208
                }
209
 
74 mjames 210
                // check for item validity
211
                if (!isValid(itemIndex))
70 mjames 212
                {
213
                        context.dial1 = -1;
74 mjames 214
                        context.OldObservation = nullObs;
70 mjames 215
                        display.clearDisplay(BLACK);
216
                        i = small_sprintf(buff, "Inval-%02d", itemIndex);
217
                        display.gotoxy(64 - i * 4, 48);
218
                        display.printString(large_font, buff, i, WHITE);
219
 
220
                        display.display();
221
                        return itemIndex;
222
                }
223
 
66 mjames 224
                // clear startup display off the screen
74 mjames 225
                if (context.OldObservation.Obs == -1)
66 mjames 226
                        display.clearDisplay(BLACK);
227
 
228
                int DataVal = Info[itemIndex].data; // data reading
74 mjames 229
                PLX_Observations Observation = Info[itemIndex].observation.Obs;
230
                uint8_t Instance = Info[itemIndex].observation.Instance;
66 mjames 231
                // now to convert the readings and format strings
232
                // find out limits
233
                // if the user presses the dial then reset min/max to current value
234
                if (push_pos[dialIndex] == 1)
235
                {
236
                        Info[itemIndex].Max = DataVal;
237
                        Info[itemIndex].Min = DataVal; // 12 bit max value
238
                }
239
 
240
                // detect change in observation being displayed, reset the dial
241
                if (Observation < PLX_MAX_OBS)
76 mjames 242
                {      
74 mjames 243
                        if (Observation != context.OldObservation.Obs || Instance != context.OldObservation.Instance)
66 mjames 244
                        {
76 mjames 245
 
70 mjames 246
                                display.clearDisplay(BLACK);
66 mjames 247
                                dial.draw_scale(DisplayInfo[Observation].Low,
248
                                                                DisplayInfo[Observation].High, 12, 1,
249
                                                                DisplayInfo[Observation].TickScale);
250
 
251
                                dial.draw_limits();
252
 
253
                                msg = DisplayInfo[Observation].name;
254
                                len = 7;
74 mjames 255
                                int len1 = Instance > 0 ? len - 1 : len;
66 mjames 256
                                for (i = 0; i < len1 && msg[i]; i++)
257
                                {
258
                                        buff[i] = msg[i];
259
                                }
74 mjames 260
                                if (Instance > 0 && i < len)
66 mjames 261
                                {
74 mjames 262
                                        buff[i++] = Instance + '1';
66 mjames 263
                                }
264
 
265
                                display.gotoxy(64 - i * 4, 48);
266
                                display.printString(large_font, buff, i, WHITE);
267
 
74 mjames 268
                                context.OldObservation.Obs = Observation;
269
                                context.OldObservation.Instance = Instance;
66 mjames 270
                                context.dial1 = -1; // do not display old needle, cleared screen
271
                                display.display();
272
                        }
273
                }
274
 
275
                if (Info[itemIndex].updated)
276
                {
277
                        Info[itemIndex].updated = 0;
278
 
279
                        double max_rdg;
280
                        double min_rdg;
281
                        double cur_rdg;
282
                        int int_rdg;
283
                        int int_max;
284
                        int int_min;
285
 
286
                        max_rdg = ConveriMFDRaw2Data((enum PLX_Observations)Observation, DisplayInfo[Observation].Units,
287
                                                                                 Info[itemIndex].Max);
288
                        min_rdg = ConveriMFDRaw2Data((enum PLX_Observations)Observation, DisplayInfo[Observation].Units,
289
                                                                                 Info[itemIndex].Min);
290
                        cur_rdg = ConveriMFDRaw2Data((enum PLX_Observations)Observation, DisplayInfo[Observation].Units,
291
                                                                                 Info[itemIndex].data);
292
                        int dp_pos; // where to print the decimal place
293
                        float scale = 1.0;
294
                        switch (DisplayInfo[Observation].DP)
295
                        {
296
                        default:
297
                        case 0:
298
                                scale = 1.0;
299
                                dp_pos = display_t::NO_DECIMAL;
300
                                break;
301
                        case 1:
302
                                scale = 10.0;
303
                                dp_pos = 1;
304
                                break;
305
                        case 2:
306
                                scale = 100.0;
307
                                dp_pos = 2;
308
                                break;
309
                        }
310
                        int_rdg = (int)(cur_rdg * scale);
311
                        int_max = (int)(max_rdg * scale);
312
                        int_min = (int)(min_rdg * scale);
313
 
314
                        cur_rdg -= DisplayInfo[Observation].Low;
315
                        cur_rdg = ap_math::SINE_STEPS * cur_rdg / (DisplayInfo[Observation].High - DisplayInfo[Observation].Low);
316
 
317
                        context.dial0 = (int)cur_rdg;
318
 
319
                        display.gotoxy(32, 28);
320
                        display.fontDigits(large_font, 4, dp_pos, int_rdg, WHITE);
321
 
322
                        display.printString(small_font, DisplayInfo[Observation].suffix,
323
                                                                strlen(DisplayInfo[Observation].suffix));
324
                        display.printString(small_font, "    ",
325
                                                                3 - strlen(DisplayInfo[Observation].suffix));
326
                        // print value overlaid by needle
327
 
328
                        /* old needle un-draw */
329
                        if (context.dial1 >= 0)
330
                        {
331
                                dial.draw_needle(context.dial1);
332
                        }
333
                        dial.draw_needle(context.dial0);
334
                        context.dial1 = context.dial0;
335
                        showMinMax(display, dp_pos, int_min, int_max);
336
                }
337
                else
338
                {
339
                        if (Info[itemIndex].lastUpdated && ((HAL_GetTick() - Info[itemIndex].lastUpdated) > 1000))
340
                        {
74 mjames 341
                                context.OldObservation = nullObs; // force a redraw on next update
342
                                Info[itemIndex].lastUpdated = 0;  // and stop further timeouts.
66 mjames 343
                        }
344
                }
345
 
346
                display.gotoxy(0, 32);
347
 
348
                // display BT connection status
349
                display.printString(small_font, btConnected() ? "\x81" : " ", 1);
350
 
351
                display.display();
352
 
353
                return itemIndex;
354
        }
355
}