Subversion Repositories DashDisplay

Rev

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