DIY Logging Volt/Ampmeter
display.c
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file display.c
3  * @brief Display updating functionality for high-precision logging voltage/current meter.
4  * @version 1.0
5  * @author Brecht Van Eeckhoudt
6  *
7  * ******************************************************************************
8  *
9  * @section Versions
10  *
11  * @li v1.0: Initial version.
12  *
13  * ******************************************************************************
14  *
15  * @todo
16  * **Future improvements:**@n
17  * - Change left/right display selection logic so the two update methods can
18  * work independently and without `finishDisplayUpdates`.
19  * - Check/optimize flow in display updating logic.
20  * - Add page for setting min/max volt/amp (/watt/time?) values for relay opening functionality.
21  * - Add status message display functionality on left display/save icon location,
22  * stops running & gets removed by any (?) key-press.
23  *
24  * ******************************************************************************
25  *
26  * @section License
27  *
28  * **Copyright (C) 2021 - Brecht Van Eeckhoudt**
29  *
30  * This program is free software: you can redistribute it and/or modify
31  * it under the terms of the **GNU General Public License** as published by
32  * the Free Software Foundation, either **version 3** of the License, or
33  * (at your option) any later version.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38  * GNU General Public License for more details.
39  *
40  * *A copy of the GNU General Public License can be found in the `LICENSE`
41  * file along with this source code.*
42  *
43  ******************************************************************************/
44 
45 
46 #include "display.h" /* Include corresponding header file */
47 
48 #include <stdint.h> /* (u)intXX_t */
49 #include "ssd1306.h" /* Lower-level display functionality */
50 #include "conversion.h" /* Conversion and settings */
51 #include "util.h" /* Utility functionality */
52 #include "rtc.h" /* Date and Time functionality */
53 
54 
55 /* Local definitions */
56 // None
57 
58 
59 /* Local variables */
60 // None
61 
62 
63 /* Local prototypes */
64 // None
65 
66 
67 /**************************************************************************//**
68  * @brief
69  * Function to initialize the OLED displays.
70  *****************************************************************************/
71 void initDisplays(void)
72 {
73  /* Initialize LEFT display */
75  ssd1306_Init();
76  ssd1306_SetContrast(0xFF); /* 90 about equals 255/0xFF of RIGHT display... */
78 
79  /* Initialize RIGHT display */
81  ssd1306_Init();
82  ssd1306_SetContrast(0xFF);
84 }
85 
86 
87 /**************************************************************************//**
88  * @brief
89  * Function to display updated info on the LEFT OLED screen.
90  *
91  * @details
92  * Only updated and visible items on the OLED screens get redrawn.
93  *****************************************************************************/
95 {
96  /* Variable for selective screen updating logic */
97  uint8_t needsUpdate = 0;
98 
99  /* Select LEFT display */
101 
102 
103  /* Update POWER value if necessary */
104  if (cData.newPow)
105  {
106  ssd1306_SetCursor(2, 0);
111 
112  cData.newPow = 0;
113 
114  needsUpdate = 1;
115  }
116 
117  if (settings.leftPage == 0)
118  {
119  /* Update MAX VOLT value if necessary */
120  if (cData.newMaxVolt)
121  {
122  /* Erase previous pixels above smaller text */
123  ssd1306_SetCursor(2, 26);
125 
126  /* Draw new text */
127  ssd1306_SetCursor(2, 32);
129  ssd1306_SetCursor(37, 26);
134 
135  cData.newMaxVolt = 0;
136 
137  needsUpdate = 1;
138  }
139 
140  /* Update MIN VOLT value if necessary */
141  if (cData.newMinVolt)
142  {
143  /* Erase previous pixels above smaller text */
144  ssd1306_SetCursor(2, 44);
146 
147  /* Draw new text */
148  ssd1306_SetCursor(2, 52);
150  ssd1306_SetCursor(37, 44);
155 
156  cData.newMinVolt = 0;
157 
158  needsUpdate = 1;
159  }
160  }
161  else if (settings.leftPage == 1)
162  {
163  /* Update MAX CURR value if necessary */
164  if (cData.newMaxCurr)
165  {
166  /* Erase previous pixels above smaller text */
167  ssd1306_SetCursor(2, 26);
169 
170  /* Draw new text */
171  ssd1306_SetCursor(2, 32);
173  ssd1306_SetCursor(37, 26);
178 
179  cData.newMaxCurr = 0;
180 
181  needsUpdate = 1;
182  }
183 
184  /* Update MIN CURR value if necessary */
185  if (cData.newMinCurr)
186  {
187  /* Erase previous pixels above smaller text */
188  ssd1306_SetCursor(2, 44);
190 
191  /* Draw new text */
192  ssd1306_SetCursor(2, 52);
194  ssd1306_SetCursor(37, 44);
199 
200  cData.newMinCurr = 0;
201 
202  needsUpdate = 1;
203  }
204  }
205  else if (settings.leftPage == 2)
206  {
207  /* Update Ah value if necessary */
208  if (cData.newAh)
209  {
210  ssd1306_SetCursor(2, 26);
215  ssd1306_SetCursor(104, 26);
217 
218  cData.newAh = 0;
219 
220  needsUpdate = 1;
221  }
222 
223  /* Update Wh value if necessary */
224  if (cData.newWh)
225  {
226  ssd1306_SetCursor(2, 44);
231  ssd1306_SetCursor(104, 44);
233 
234  cData.newWh = 0;
235 
236  needsUpdate = 1;
237  }
238  }
239 
240 
241  /* Update display selection lines if necessary */
243  {
244  /* Draw display selection-lines */
245  ssd1306_Line(2, 63, 129, 63, White);
246  ssd1306_Line(129, 53, 129, 63, White);
247 
248  needsUpdate = 1;
249  }
250  else if ((settings.selectedDisplay == 1) && settings.newSelDisplay)
251  {
252  /* Remove display selection-lines */
253  ssd1306_Line(2, 63, 129, 63, Black);
254  ssd1306_Line(129, 53, 129, 63, Black);
255 
256  needsUpdate = 1;
257  }
258 
259 
260  /* Write changes to LEFT display if necessary */
261  if (needsUpdate)
262  {
263 // SEGGER_RTT_printf(0, "Left");
265  }
266 }
267 
268 
269 /**************************************************************************//**
270  * @brief
271  * Function to display updated info on the RIGHT OLED screen.
272  *
273  * @details
274  * Only updated and visible items on the OLED screens get redrawn.
275  *****************************************************************************/
277 {
278  /* Variable for selective screen updating logic */
279  uint8_t needsUpdate = 0;
280 
281  /* Select RIGHT display */
283 
284 
285  /* Update internal battery voltage value if necessary */
286  if (settings.newCharVbat)
287  {
288  ssd1306_SetCursor(2, 4);
293 
294  settings.newCharVbat = 0;
295 
296  needsUpdate = 1;
297  }
298 
299 
300  /* Update mode indication field if necessary */
301  if (settings.newMode)
302  {
303  if (settings.mode == 0)
304  {
305  ssd1306_SetCursor(80, 0);
307  }
308  else if (settings.mode == 1)
309  {
310  ssd1306_SetCursor(80, 0);
312  }
313 
314  settings.newMode = 0;
315 
316  needsUpdate = 1;
317  }
318 
319 
320  /* Enter logic if we're on the correct page and a second has passed or the time was manually changed */
322  {
323  /* Update day if necessary */
325  {
326  ssd1306_SetCursor(2, 26);
328  rtc.newCharDay = 0;
330  }
331 
332  /* Update month if necessary */
334  {
335  ssd1306_SetCursor(35, 26);
337  rtc.newCharMonth = 0;
339  }
340 
341  /* Update year if necessary */
343  {
344  ssd1306_SetCursor(68, 26);
346  rtc.newCharYear = 0;
347  }
348 
349  /* Update hour if necessary */
351  {
352  ssd1306_SetCursor(2, 44);
355  rtc.newCharHour = 0;
357  }
358 
359  /* Update minutes if necessary */
361  {
362  ssd1306_SetCursor(46, 44);
364  rtc.newCharMin = 0;
366  }
367 
368  /* Update seconds if necessary */
370  {
371  ssd1306_SetCursor(79, 44);
373  rtc.newCharSec = 0;
375  }
376 
377  /* Draw editing-line under day-field if necessary */
379  {
380  ssd1306_Line(2, 42, 22, 42, White);
381  ssd1306_Line(2, 43, 22, 43, White);
382  }
383 
384  /* Draw editing-line under month-field if necessary */
386  {
387  ssd1306_Line(35, 42, 55, 42, White);
388  ssd1306_Line(35, 43, 55, 43, White);
389  }
390 
391  /* Draw editing-line under year-field if necessary */
393  {
394  ssd1306_Line(68, 42, 110, 42, White);
395  ssd1306_Line(68, 43, 110, 43, White);
396  }
397 
398  /* Draw editing-line under hour-field if necessary */
400  {
401  ssd1306_Line(13, 60, 35, 60, White);
402  ssd1306_Line(13, 61, 35, 61, White);
403  }
404 
405  /* Draw editing-line under minutes-field if necessary */
407  {
408  ssd1306_Line(46, 60, 68, 60, White);
409  ssd1306_Line(46, 61, 68, 61, White);
410  }
411 
412  /* Draw editing-line under seconds-field if necessary */
414  {
415  ssd1306_Line(79, 60, 101, 60, White);
416  ssd1306_Line(79, 61, 101, 61, White);
417  }
418 
419  /* Reset date/time updating logic if time was manually changed */
421 
422  needsUpdate = 1;
423  }
424  /* Update measurement-period if necessary */
425  else if ((settings.rightPage == 1) && settings.periodChanged)
426  {
427  ssd1306_SetCursor(2, 26);
428  ssd1306_WriteString(" Period ", Font_11x18, White);
429 
430  ssd1306_SetCursor(2, 44);
432 
433  /* Calculate hours-mins-secs from selected period value */
434  uint16_t secs = settings.measPeriodS;
435  uint16_t mins = secs / 60;
436  secs = secs - (60 * mins);
437  uint8_t hours = mins / 60;
438  mins = mins - (60 * hours);
439 
440  /* Write hours to screen if necessary */
441  if (hours > 0)
442  {
443  char charHours[3]; /* Value won't exceed 99 (2 chars + NULL termination = 3) */
444  uint32_to_charDec(charHours, hours, 2);
445  ssd1306_WriteString(charHours, Font_11x18, White);
447  }
448 
449  /* Write minutes to screen if necessary */
450  if (mins > 0)
451  {
452  char charMins[3]; /* Value won't exceed 59 (2 chars + NULL termination = 3) */
453  uint32_to_charDec(charMins, mins, 2);
456  }
457 
458  /* Write seconds to screen if necessary */
459  if (secs > 0)
460  {
461  char charSecs[3]; /* Value won't exceed 59 (2 chars + NULL termination = 3) */
462  uint32_to_charDec(charSecs, secs, 2);
465  }
466 
468 
469 
470  /* Draw editing-line under period field if necessary */
471  if (settings.changePeriod == 1)
472  {
473  ssd1306_Line(35, 60, 68, 60, White);
474  ssd1306_Line(35, 61, 68, 61, White);
475  }
476 
478 
479  needsUpdate = 1;
480  }
481  /* Update runtime hour/minute values if necessary */
482  else if ((settings.rightPage == 2) && (cData.newRunHours || cData.newRunMins))
483  {
484  ssd1306_SetCursor(2, 26);
485  ssd1306_WriteString(" Runtime ", Font_11x18, White);
486  ssd1306_SetCursor(2, 44);
487 
493 
494  cData.newRunHours = 0;
495  cData.newRunMins = 0;
496 
497  needsUpdate = 1;
498  }
499 
500  /* Update runtime second value if necessary */
501  if ((settings.rightPage == 2) && cData.newRunSecs)
502  {
503  ssd1306_SetCursor(77, 44);
506 
507  cData.newRunSecs = 0;
508 
509  needsUpdate = 1;
510  }
511 
512 
513  /* Update display selection lines if necessary */
515  {
516  /* Draw display selection-lines */
517  ssd1306_Line(2, 63, 129, 63, White);
518  ssd1306_Line(129, 53, 129, 63, White);
519 
520  needsUpdate = 1;
521  }
522  else if ((settings.selectedDisplay == 0) && settings.newSelDisplay)
523  {
524  /* Remove display selection-lines */
525  ssd1306_Line(2, 63, 129, 63, Black);
526  ssd1306_Line(129, 53, 129, 63, Black);
527 
528  needsUpdate = 1;
529  }
530 
531 
532  /* Write changes to RIGHT display if necessary */
533  if (needsUpdate)
534  {
535 // SEGGER_RTT_printf(0, "Right");
537  }
538 }
539 
540 
541 /**************************************************************************//**
542  * @brief
543  * Function to finish the screen-updates.
544  *
545  * @details
546  * This function partially handles the selected-screen line logic.
547  *****************************************************************************/
549 {
551 }
552 
553 
554 /**************************************************************************//**
555  * @brief
556  * Function to display the SAVE status icon on the RIGHT OLED screen.
557  *****************************************************************************/
558 void displaySaveIcon(void)
559 {
560  /* Select RIGHT display */
562 
563  ssd1306_SetCursor(80, 0);
565 
566  /* Make sure other display logic replaces the icon again */
567  settings.newMode = 1;
568 
569  /* Write changes to RIGHT display */
571 }
Settings_t::rightPage
uint8_t rightPage
Definition: conversion.h:151
Settings_t::selectedDisplay
uint8_t selectedDisplay
Definition: conversion.h:148
settings
struct Settings_t settings
cData_t::aMaxLeft
char aMaxLeft[2]
Definition: conversion.h:109
finishDisplayUpdates
void finishDisplayUpdates(void)
Function to finish the screen-updates.
Definition: display.c:548
cData_t::aMaxRight
char aMaxRight[5]
Definition: conversion.h:110
cData_t::newMaxCurr
uint8_t newMaxCurr
Definition: conversion.h:111
ssd1306_SetCursor
void ssd1306_SetCursor(uint8_t x, uint8_t y)
Definition: ssd1306.c:344
cData_t::newRunHours
uint8_t newRunHours
Definition: conversion.h:128
cData_t::ahLeft
char ahLeft[5]
Definition: conversion.h:120
Settings_t::leftPage
uint8_t leftPage
Definition: conversion.h:150
Black
@ Black
Definition: ssd1306.h:106
cData_t::newPow
uint8_t newPow
Definition: conversion.h:118
rtc
struct RTC_dateTime_t rtc
ssd1306_WriteString
char ssd1306_WriteString(char *str, FontDef Font, SSD1306_COLOR color)
Definition: ssd1306.c:327
cData_t::charRunHours
char charRunHours[3]
Definition: conversion.h:127
cData
struct cData_t cData
ssd1306_UpdateScreen
void ssd1306_UpdateScreen(void)
Definition: ssd1306.c:220
ssd1306_SelectDisplay
void ssd1306_SelectDisplay(uint8_t display)
Definition: ssd1306.c:19
RTC_dateTime_t::newCharMonth
uint8_t newCharMonth
Definition: rtc.h:80
initDisplays
void initDisplays(void)
Function to initialize the OLED displays.
Definition: display.c:71
RTC_dateTime_t::charMonth
char charMonth[3]
Definition: rtc.h:79
Font_11x18
FontDef Font_11x18
Definition: ssd1306_fonts.c:409
RTC_dateTime_t::charHour
char charHour[3]
Definition: rtc.h:57
Settings_t::changePeriod
uint8_t changePeriod
Definition: conversion.h:156
Settings_t::newMode
uint8_t newMode
Definition: conversion.h:147
cData_t::whLeft
char whLeft[5]
Definition: conversion.h:123
RTC_dateTime_t::newCharMin
uint8_t newCharMin
Definition: rtc.h:63
cData_t::whRight
char whRight[4]
Definition: conversion.h:124
Font_16x26
FontDef Font_16x26
Definition: ssd1306_fonts.c:412
RTC_dateTime_t::charSec
char charSec[3]
Definition: rtc.h:67
RTC_dateTime_t::charDay
char charDay[3]
Definition: rtc.h:72
cData_t::pLeft
char pLeft[4]
Definition: conversion.h:116
cData_t::charRunMins
char charRunMins[3]
Definition: conversion.h:129
cData_t::pRight
char pRight[4]
Definition: conversion.h:117
RTC_dateTime_t::newCharDay
uint8_t newCharDay
Definition: rtc.h:73
cData_t::newMaxVolt
uint8_t newMaxVolt
Definition: conversion.h:101
RTC_dateTime_t::newCharYear
uint8_t newCharYear
Definition: rtc.h:85
Settings_t::vbatRight
char vbatRight[3]
Definition: conversion.h:142
cData_t::newAh
uint8_t newAh
Definition: conversion.h:122
RTC_dateTime_t::newCharHour
uint8_t newCharHour
Definition: rtc.h:58
ssd1306.h
Settings_t::periodChanged
uint8_t periodChanged
Definition: conversion.h:157
cData_t::aMinRight
char aMinRight[5]
Definition: conversion.h:113
Settings_t::dateTimeChanged
uint8_t dateTimeChanged
Definition: conversion.h:159
RTC_dateTime_t::charMin
char charMin[3]
Definition: rtc.h:62
displaySaveIcon
void displaySaveIcon(void)
Function to display the SAVE status icon on the RIGHT OLED screen.
Definition: display.c:558
Settings_t::measPeriodS
uint16_t measPeriodS
Definition: conversion.h:155
cData_t::charRunSecs
char charRunSecs[3]
Definition: conversion.h:131
cData_t::newMinCurr
uint8_t newMinCurr
Definition: conversion.h:114
RTC_dateTime_t::charYear
char charYear[5]
Definition: rtc.h:84
cData_t::ahRight
char ahRight[4]
Definition: conversion.h:121
Settings_t::newCharVbat
uint8_t newCharVbat
Definition: conversion.h:143
ssd1306_SetContrast
void ssd1306_SetContrast(const uint8_t value)
Sets the contrast of the display.
Definition: ssd1306.c:522
ssd1306_WriteChar
char ssd1306_WriteChar(char ch, FontDef Font, SSD1306_COLOR color)
Definition: ssd1306.c:274
Settings_t::newSelDisplay
uint8_t newSelDisplay
Definition: conversion.h:149
Font_7x10
FontDef Font_7x10
Definition: ssd1306_fonts.c:406
RTC_dateTime_t::newCharSec
uint8_t newCharSec
Definition: rtc.h:68
cData_t::newMinVolt
uint8_t newMinVolt
Definition: conversion.h:104
Settings_t::changeDateTime
uint8_t changeDateTime
Definition: conversion.h:158
conversion.h
Conversion and settings-related methods and structs for high-precision logging voltage/current meter.
cData_t::vMaxRight
char vMaxRight[4]
Definition: conversion.h:100
ssd1306_Init
void ssd1306_Init(void)
Definition: ssd1306.c:94
cData_t::aMinLeft
char aMinLeft[2]
Definition: conversion.h:112
updateRightDisplay
void updateRightDisplay(void)
Function to display updated info on the RIGHT OLED screen.
Definition: display.c:276
display.h
Display updating functionality for high-precision logging voltage/current meter.
cData_t::vMaxLeft
char vMaxLeft[3]
Definition: conversion.h:99
cData_t::vMinRight
char vMinRight[4]
Definition: conversion.h:103
cData_t::newRunMins
uint8_t newRunMins
Definition: conversion.h:130
cData_t::newRunSecs
uint8_t newRunSecs
Definition: conversion.h:132
Settings_t::vbatLeft
char vbatLeft[2]
Definition: conversion.h:141
cData_t::newWh
uint8_t newWh
Definition: conversion.h:125
rtc.h
RTC functionality for high-precision logging voltage/current meter.
ssd1306_Line
void ssd1306_Line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, SSD1306_COLOR color)
Definition: ssd1306.c:358
White
@ White
Definition: ssd1306.h:107
cData_t::vMinLeft
char vMinLeft[3]
Definition: conversion.h:102
Settings_t::mode
uint8_t mode
Definition: conversion.h:146
uint32_to_charDec
void uint32_to_charDec(char *buf, uint32_t value, uint8_t totalChars)
Convert a uint32_t value to a decimal char array (string).
Definition: util.c:149
updateLeftDisplay
void updateLeftDisplay(void)
Function to display updated info on the LEFT OLED screen.
Definition: display.c:94
util.h
Utility functionality for high-precision logging voltage/current meter.