sd-card: Only add header to the results file if it’s empty
[brewing-logger:firmware.git] / test.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Brewing Logger.
4  * Copyright (C) Philip Withnall 2012 <philip@tecnocode.co.uk>
5  *
6  * Brewing Logger is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Brewing Logger is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Brewing Logger.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "button.h"
27 #include "flash-rom.h"
28 #include "gas.h"
29 #include "heater.h"
30 #include "humidity.h"
31 #include "krausen-level.h"
32 #include "lcd.h"
33 #include "log.h"
34 #include "power.h"
35 #include "rtc.h"
36 #include "sleep.h"
37 #include "spi.h"
38 #include "test.h"
39 #include "temperature.h"
40
41 /* NOTE: Keep me up to date! */
42 #define NUM_TESTS 11
43
44 static void _display_test_result (uint8_t test_number, const char *message_format, ...) __attribute__((format (printf, 2, 3))) NONNULL (2);
45
46 static void _display_test_result (uint8_t test_number, const char *message_format, ...)
47 {
48         char message[LCD_COLUMNS + 1 /* nul */];
49         va_list args;
50
51         /* Format the message. */
52         va_start (args, message_format);
53         vsnprintf (message, sizeof (message) / sizeof (*message), message_format, args);
54         va_end (args);
55
56         /* Display some metadata. */
57         clear_lcd ();
58         LCD_display_string ("Test ");
59         LCD_display_uint8 (test_number);
60         LCD_display_string ("/");
61         LCD_display_uint8 (NUM_TESTS);
62         LCD_display_string (":");
63
64         /* Display the message. */
65         row2_lcd ();
66         LCD_display_string (message);
67
68         _delay_ms (500);
69 }
70
71 static void _test_lcd (void)
72 {
73         /* Initialise the LCD and display some text. */
74         lcd_init ();
75
76         _display_test_result (1, "The quick brown fox...");
77 }
78
79 /* Simple test for the RTC. */
80 static void _test_rtc (void)
81 {
82         /* Reference: ds3231.h. */
83         uint8_t new_time[8] = { 0x00, 12 /* seconds */, 27 /* minutes */, 15 /* hours */,
84                                 5 /* day of week */, 23 /* day */, 11 /* month */, 12 /* year */ };
85
86         /* Set up the RTC and get the current time. */
87         rtc_init ();
88
89         /* Set the time. */
90         _display_test_result (2, "Setting time: %u", write_to_rtc (new_time));
91
92         /* Print out the time a few times. */
93         _display_test_result (3, "Time 1: %lu", get_fattime ());
94         _display_test_result (3, "Time 2: %lu", get_fattime ());
95         _display_test_result (3, "Time 3: %lu", get_fattime ());
96         _display_test_result (3, "Time 4: %lu", get_fattime ());
97         _display_test_result (3, "Time 5: %lu", get_fattime ());
98 }
99
100 static void _test_humidity (void)
101 {
102         MeasurementResponse response;
103         HumidityTemperatureReading reading;
104
105         /* Initialise the humidity sensor. */
106         humidity_init ();
107
108         /* Take a humidity measurement. */
109         response = humidity_take_measurement (&reading);
110         _display_test_result (4, "Humidity: %u, %3u.%1u%%, %2u.%1uC", response,
111                               HUMIDITY_READING_TO_PERCENT_INT (reading.relative_humidity),
112                               HUMIDITY_READING_TO_PERCENT_FRAC (reading.relative_humidity),
113                               TEMPERATURE_READING_TO_DEGREES_INT (reading.temperature), TEMPERATURE_READING_TO_DEGREES_FRAC (reading.temperature));
114 }
115
116 static void _test_temperature (void)
117 {
118         MeasurementResponse response;
119         TemperatureReading reading[NUM_THERMOMETERS];
120
121         /* Initialise the thermometers. */
122         temperature_init ();
123
124         /* Take a temperature measurement. */
125         response = temperature_take_measurement (reading);
126         _display_test_result (5, "Temperatures: %u, %u.%uC, %u.%uC", response,
127                               TEMPERATURE_READING_TO_DEGREES_INT (reading[0]), TEMPERATURE_READING_TO_DEGREES_FRAC (reading[0]),
128                               TEMPERATURE_READING_TO_DEGREES_INT (reading[1]), TEMPERATURE_READING_TO_DEGREES_FRAC (reading[1]));
129 }
130
131 static void _test_krausen_level (void)
132 {
133         MeasurementResponse response;
134         KrausenLevelReading reading;
135
136         /* Initialise the proximity sensor. */
137         krausen_level_init ();
138
139         /* Take a krausen level measurement. */
140         response = krausen_level_take_measurement (&reading);
141         _display_test_result (6, "Krausen level: %u, %u.%ucm", response,
142                               KRAUSEN_LEVEL_READING_TO_CM_INT (reading), KRAUSEN_LEVEL_READING_TO_CM_FRAC (reading));
143 }
144
145 static void _test_gas (void)
146 {
147         MeasurementResponse response;
148         GasReading reading;
149
150         /* Initialise the gas concentration sensor. */
151         gas_init ();
152
153         /* Take a gas concentration measurement. */
154         response = gas_take_measurement (&reading, GAS_READING_DEFAULT_TEMPERATURE, GAS_READING_DEFAULT_HUMIDITY);
155         _display_test_result (7, "Gas conc.: %u, %u.%02u mg/l", response, GAS_READING_TO_MG_L_INT (reading), GAS_READING_TO_MG_L_FRAC (reading));
156
157         /* Try turning the heater on and off. (The LED on the board should light up as appropriate.) */
158         gas_heater_on ();
159         _display_test_result (7, "Gas heater on.");
160
161         gas_heater_off ();
162         _display_test_result (7, "Gas heater off.");
163 }
164
165 static void _test_button (void)
166 {
167         WakeupReason response;
168
169         /* Initialise the button and watchdog timer. */
170         sleep_init ();
171         button_init ();
172
173         /* Wait for the button to be pressed. */
174         _display_test_result (8, "Please press button.");
175         response = sleep_until_event (8 /* seconds */);
176
177         /* Why did we wake up? */
178         switch (response) {
179                 case WAKEUP_TIMER:
180                         _display_test_result (8, "Button not pressed.");
181                         break;
182                 case WAKEUP_BUTTON:
183                         _display_test_result (8, "Button pressed!");
184                         break;
185                 default:
186                         ASSERT_NOT_REACHED ();
187         }
188 }
189
190 static void _test_flash_rom (void)
191 {
192         LogEntry log_entry, log_entry_copy;
193
194         /* Initialise SPI and the Flash ROM. Display a message because this takes a while. */
195         _display_test_result (9, "Initialising flash...");
196
197         spi_init ();
198         flash_rom_init ();
199
200         /* Erase all the sectors. */
201         _display_test_result (9, "Erasing flash...");
202         flash_rom_erase ();
203
204         /* Try appending an entry to the Flash ROM. The values used are chosen arbitrarily. */
205         log_entry.time = 1234;
206         log_entry.humidity_reading.relative_humidity = 0xfcde;
207         log_entry.humidity_reading.temperature = 0xfedc;
208         log_entry.temperature_reading[0] = 0x8000;
209         log_entry.temperature_reading[1] = 0x8001;
210         log_entry.krausen_level_reading = 0x54;
211         log_entry.gas_reading = 0x6994;
212
213         flash_rom_append_entry (&log_entry);
214
215         /* Try reading the entry back and compare the two. */
216         switch (flash_rom_read_head_entry (&log_entry_copy)) {
217                 case FLASH_ROM_READ_ENTRY_CHECKSUM_FAILURE:
218                         _display_test_result (9, "Checksum failure.");
219                         break;
220                 case FLASH_ROM_READ_ENTRY_SUCCESS:
221                         if (memcmp (&log_entry, &log_entry_copy, sizeof (log_entry)) == 0) {
222                                 _display_test_result (9, "Entries matched!");
223                         } else {
224                                 _display_test_result (9, "Entries did not match.");
225                         }
226                         break;
227                 default:
228                         ASSERT_NOT_REACHED ();
229         }
230
231         /* Try overwriting the checksum and check the entries no longer match (because read_head_entry() will zero out the entry on a checksum
232          * failure). */
233         flash_rom_overwrite_head_entry_checksum ();
234
235         switch (flash_rom_read_head_entry (&log_entry_copy)) {
236                 case FLASH_ROM_READ_ENTRY_SUCCESS:
237                         _display_test_result (10, "Overwrite failure.");
238                         break;
239                 case FLASH_ROM_READ_ENTRY_CHECKSUM_FAILURE:
240                         _display_test_result (10, "Overwrite success!");
241                         break;
242                 default:
243                         ASSERT_NOT_REACHED ();
244         }
245 }
246
247 static void _test_heater (void)
248 {
249         /* Initialise the heater. */
250         heater_init ();
251
252         /* Try turning the heater on and off. (The LED on the board should light up as appropriate.) */
253         heater_set_state (HEATER_ON);
254         _display_test_result (11, "Heater on.");
255
256         heater_set_state (HEATER_OFF);
257         _display_test_result (11, "Heater off.");
258 }
259
260 /* Run all the tests. */
261 void test (void)
262 {
263         /* Initialise power management so the sensors can be turned on. */
264         power_init ();
265         sensor_power_set_state (SENSOR_POWER_ON);
266
267         /* Globally enable interrupts so sensor readings can be taken. */
268         SREG = (1 << 7);
269
270         _test_lcd ();
271         _test_rtc ();
272         _test_humidity ();
273         _test_temperature ();
274         _test_krausen_level ();
275         _test_gas ();
276         _test_button ();
277         _test_flash_rom ();
278         _test_heater ();
279 }