Add missing sd context.
[bertos.git] / boards / at91sam7x-ek / examples / sd_fat / main.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos 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 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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 this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \author Daniele Basile <asterix@develer.com>
34  *
35  * \brief Simple application that implement a log device, running on the AT91SAM7X-EK board.
36  *
37  * The main scope of this application is to show you how use the SD memory card and read and write
38  * settings and logs. Thanks the ini parser module we can read settings, stored on memory card,
39  * and change the application behaviour.
40  * Generally the application work in this way:
41  * - Try to access to SD memory card, if it is present we read the inifile
42  * - If we have read correctly from SD, we compute the value that we want log
43  *   (temperature, pressure and supplay voltage)
44  * - If we have enable (from ini file) to log on the file we write the log on it.
45  * - If we have enable (from ini file) to log on the serial we write the log on it.
46  * - wait the sample_time (from ini file)
47  * - contine from beginning.
48  *
49  * Here we put the ini file that this example uses. To use it copy
50  * the folling configutation line into the file called sd_fat.ini (or see INI_FILE_NAME
51  * define if you want chande the name).
52  * \code
53  *
54  *   # Bertos SD fat project example
55  *   #
56  *   # Basic configurarion
57  *   #
58  *
59  *   [log]
60  *   # Name of log file
61  *   name = test.log
62  *   # Enable the logging on serial device (enable = 1, disable = 0)
63  *   log_on_serial = 1
64  *   # Enable logging on sd file (enable = 1, disable = 0)
65  *   log_on_file = 1
66  *   # Period between two log in millisecond
67  *   sample_time = 1000
68  *
69  *   [serial_log]
70  *   # Select serial port where log
71  *   port = 0
72  *   # Serial port baudrate
73  *   baud = 115200
74  *
75  *   [log_format]
76  *   # Default text to insert on each log line
77  *   line_header = BeRTOS Log:
78  *   # Use this char to separate each log field
79  *   field_sep = ;
80  *
81  *   [temperature]
82  *   unit_label = C
83  *
84  *   [pressure]
85  *   unit_label = hPa
86  *
87  *   [voltage]
88  *   unit_label = V
89  *
90  * \endcode
91  */
92
93 #include <cfg/debug.h>
94
95 // Define logging setting (for cfg/log.h module).
96 #define LOG_LEVEL         3
97 #define LOG_VERBOSITY     0
98 #include <cfg/log.h>
99 #include <cfg/macros.h>
100
101 #include <cpu/irq.h>
102
103 #include <drv/timer.h>
104 #include <drv/sd.h>
105 #include <drv/ser.h>
106 #include <drv/tmp123.h>
107 #include <drv/spi_dma_at91.h>
108 #include <drv/mpxx6115a.h>
109 #include <drv/adc.h>
110
111 #include <fs/fat.h>
112
113 #include <mware/ini_reader.h>
114
115 #include <verstag.h>
116 #include <buildrev.h>
117
118 #include <string.h>
119 #include <stdio.h>
120 #include <stdlib.h>
121
122 /*
123  * Setting structure define
124  */
125 typedef struct INISetting
126 {
127         // INI Log section
128         char name[80];              ///< Name of log file
129         bool log_on_serial;         ///< Enable the logging on serial device
130         bool log_on_file;           ///< Enable logging on sd file
131         mtime_t sample_time;        ///< Period between two log (millisecond)
132
133         //INI serial log section
134         int port;                   ///< Select serial port where log
135         int baud;                   ///< Serial port baudrate
136
137         // INI log format section
138         char line_header[80];       ///< Default text to insert on each log line
139         char field_sep[10];         ///< Use this char to separate each log field
140
141         // INI temperature section
142         char temp_unit_label[10];   ///< Default label for measure unit
143
144         // INI pressure section
145         char press_unit_label[10];  ///< Default label for measure unit
146
147         // INI voltage section
148         char voltage_unit_label[10];  ///< Default label for measure unit
149
150
151 } INISetting;
152
153 /*
154  * Setting and various defines.
155  */
156 #define INI_FILE_NAME     "sd_fat.ini"   ///< Default ini file name on SD card.
157
158 // INI Log section
159 #define LOG_SECTION        "log"           ///< Log section
160 #define LOG_NAME_KEY       "name"          ///< Name of log file
161 #define LOG_ON_SERIAL      "log_on_serial" ///< Enable the logging on serial device
162 #define LOG_ON_FILE        "log_on_file"   ///< Enable logging on sd file
163 #define LOG_SAMPLE_TIME    "sample_time"   ///< Period between two log
164
165 //INI serial log section
166 #define SERIAL_LOG         "serial_log"    ///< Serial log section
167 #define SERIAL_PORT        "port"          ///< Select serial port where log
168 #define SERIAL_BAUD        "baud"          ///< Serial port baudrate
169
170 // INI log format section
171 #define LOG_FORMAT_SEC     "log_format"    ///< log format section
172 #define FORMAT_LINE_HEADER "line_header"   ///< Default text to insert on each log line
173 #define FORMAT_FIELD_SEP   "field_sep"     ///< Use this char to separate each log field
174
175 // INI temperature section
176 #define TEMPERATURE        "temperature"   ///< temperarute section
177 #define TEMP_UNIT_LABEL    "unit_label"    ///< Default label for measure unit
178
179 // INI pressure section
180 #define PRESSURE           "pressure"      ///< pressure section
181 #define PRESS_UNIT_LABEL   "unit_label"    ///< Default label for measure unit
182
183 // INI voltsge section
184 #define VOLTAGE            "voltage"      ///< voltage section
185 #define VOLTAGE_UNIT_LABEL "unit_label"   ///< Default label for measure unit
186
187 /**
188  * Voltage reference in volts for ADC.
189  * \note This value should be complied to jumper J13 on AT91SAM7X-EK board, and
190  * the supply voltade for sensor.
191  * See schamatics for more info.
192  */
193 #define ADC_VOLTAGE_REF             3300
194 /**
195  * Channel where the sensor we connect it (AD6)
196  * See schamatics for more info.
197  */
198 #define PRESSURE_SENSOR_CH          6
199
200 /**
201  * ADC channle to read voltage supplay
202  * \note we connect board power supplay (+3.3V) to AD3 port with wire.
203  */
204 #define SUPPLAY_VOLTAGE_CH          3
205 #define ADC_SUPPLAY_VOLTAGE         3300
206
207 /*
208  * Static definition for application devices.
209  */
210 static SpiDmaAt91 spi_dma;
211 static Serial temp_sensor_bus;
212 static Serial log_port;
213 static Sd sd;
214
215 static void init(void)
216 {
217         IRQ_ENABLE;
218         kdbg_init();
219
220         timer_init();
221         LOG_INFO("TIMER init..ok\n");
222
223         /*
224          * Init temperature sensor device.
225          * - init the temperature driver
226          * - init the spi communication channel
227          */
228         tmp123_init();
229         // Init SPI connected to sensor temperature
230         spimaster_init(&temp_sensor_bus, SER_SPI1);
231         ser_setbaudrate(&temp_sensor_bus, 1000000L);
232         LOG_INFO("TMP123 sensor init..ok\n");
233
234         // Init SPI bus to communicate to SD card
235         spi_dma_init(&spi_dma);
236         spi_dma_setclock(20000000L);
237         LOG_INFO("SD SPI init..ok\n");
238
239         adc_init();
240         LOG_INFO("ADC init..ok\n");
241
242 }
243
244 int main(void)
245 {
246         // SD fat filesystem context
247         FATFS fs;
248
249         // Context files that we would manage
250         FatFile ini_file;
251         FatFile log_file;
252
253         init();
254
255         LOG_INFO("SD fat example project %s: %d times\n", VERS_HOST, VERS_BUILD);
256
257         while (1)
258         {
259                 bool sd_ok = true;
260                 FRESULT result;
261
262                 // Setting info
263                 INISetting ini_set;
264                 memset(&ini_set, 0, sizeof(ini_set));
265
266                 sd_ok = sd_init(&sd, &spi_dma.fd, 0);
267
268                 if (sd_ok)
269                 {
270                         LOG_INFO("Mount FAT filesystem.\n");
271                         if ((result = f_mount(0, &fs)) != FR_OK)
272                         {
273                                 LOG_ERR("Mounting FAT volumes error[%d]\n", result);
274                                 sd_ok = false;
275                         }
276
277                         LOG_INFO("Read setting from ini file: %s\n", INI_FILE_NAME);
278                         if (sd_ok && ((result = fatfile_open(&ini_file, INI_FILE_NAME, FA_READ)) != FR_OK))
279                         {
280                                 LOG_ERR("Could not open ini file: %s error[%d,]\n", INI_FILE_NAME, result);
281                                 sd_ok = false;
282                         }
283
284                         if (sd_ok)
285                         {
286                                 /*
287                                  * If sd is ok, we read all setting from INI file.
288                                  * NOTE: if one ini key or section was not found into INI
289                                  * file, the iniparser return the defaul value.
290                                  */
291                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_NAME_KEY, "default.log", ini_set.name, sizeof(ini_set.name));
292                                 LOG_INFO("Log file name [%s]\n", ini_set.name);
293
294                                 char tmp[25];
295                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_SERIAL,   "1", tmp, sizeof(tmp));
296                                 ini_set.log_on_serial = atoi(tmp);
297                                 LOG_INFO("Log serial [%d]\n", ini_set.log_on_serial);
298                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_FILE,     "1", tmp, sizeof(tmp));
299                                 ini_set.log_on_file = atoi(tmp);
300                                 LOG_INFO("Log sd [%d]\n", ini_set.log_on_file);
301                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_SAMPLE_TIME, "500", tmp, sizeof(tmp));
302                                 ini_set.sample_time = atoi(tmp);
303                                 LOG_INFO("Sample time [%ld]\n", ini_set.sample_time);
304
305                                 ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_PORT, "0", tmp, sizeof(tmp));
306                                 ini_set.port = atoi(tmp);
307                                 LOG_INFO("Serial port [%d]\n", ini_set.port);
308                                 ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_BAUD, "115200", tmp, sizeof(tmp));
309                                 ini_set.baud = atoi(tmp);
310                                 LOG_INFO("Serial buad [%d]\n", ini_set.baud);
311
312                                 ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_LINE_HEADER, "BeRTOS: ", ini_set.line_header, sizeof(ini_set.line_header));
313                                 LOG_INFO("Serial line header[%s]\n", ini_set.line_header);
314
315                                 ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_FIELD_SEP, ",", ini_set.field_sep, sizeof(ini_set.field_sep));
316                                 LOG_INFO("Serial char sep[%s]\n", ini_set.field_sep);
317
318                                 ini_getString(&ini_file.fd, TEMPERATURE, TEMP_UNIT_LABEL, "C", ini_set.temp_unit_label, sizeof(ini_set.temp_unit_label));
319                                 LOG_INFO("Temp unit label[%s]\n", ini_set.temp_unit_label);
320
321                                 ini_getString(&ini_file.fd, PRESSURE, PRESS_UNIT_LABEL, "hPa", ini_set.press_unit_label, sizeof(ini_set.press_unit_label));
322                                 LOG_INFO("Press unit label[%s]\n", ini_set.press_unit_label);
323
324                                 ini_getString(&ini_file.fd, VOLTAGE, VOLTAGE_UNIT_LABEL, "V", ini_set.voltage_unit_label, sizeof(ini_set.voltage_unit_label));
325                                 LOG_INFO("Press unit label[%s]\n", ini_set.voltage_unit_label);
326
327                         }
328                 }
329
330                 if (ini_set.log_on_serial)
331                 {
332                         // Init serial log port
333                         ser_init(&log_port, ini_set.port);
334                         ser_setbaudrate(&log_port, ini_set.baud);
335                         LOG_INFO("SERIAL init..port[%d] buad[%d]\n", ini_set.port, ini_set.baud);
336                 }
337
338                 char log_string[160];
339                 memset(log_string, 0, sizeof(log_string));
340
341                 // Supplay voltage
342                 uint16_t vdd = ADC_RANGECONV(adc_read(SUPPLAY_VOLTAGE_CH), 0, ADC_SUPPLAY_VOLTAGE);
343
344                 // Read temperature
345                 int16_t tmp = tmp123_read(&temp_sensor_bus.fd);
346
347                 // Read pressure
348                 uint16_t vout = ADC_RANGECONV(adc_read(PRESSURE_SENSOR_CH), 0, vdd);
349                 int16_t press = mpxx6115a_press(vout,  vdd);
350
351                 /*
352                  * Format string whit read data
353                  * line_header + temp + temp_unit_label + field_sep + press + press_unit_label + field_sep + vdd + voltage_unit_label
354                  */
355                 int wr_len = sprintf(log_string, "%s%d.%01d%s%s%d%s%s%d.%d%s\r\n", ini_set.line_header,
356                                                                                                                                 tmp / 10, ABS(tmp % 10),
357                                                                                                                                 ini_set.temp_unit_label,
358                                                                                                                                 ini_set.field_sep,
359                                                                                                                                 press,
360                                                                                                                                 ini_set.press_unit_label,
361                                                                                                                                 ini_set.field_sep,
362                                                                                                                                 vdd / 1000, ABS(vdd % 1000),
363                                                                                                                                 ini_set.voltage_unit_label);
364
365
366                 /*
367                  * if SD is ok, try to open log file and write our data and, only
368                  * if by configuration we have enable the log on file
369                  */
370                 if (sd_ok && ini_set.log_on_file)
371                 {
372                         // Open log file and do not overwrite the previous log file
373                         result = fatfile_open(&log_file, ini_set.name,  FA_OPEN_EXISTING | FA_WRITE);
374
375                         // If the log file there isn't we create the new one
376                         if (result == FR_NO_FILE)
377                         {
378                                 result = fatfile_open(&log_file, ini_set.name,  FA_CREATE_NEW | FA_WRITE);
379                                 LOG_INFO("Create the log file: %s\n", ini_set.name);
380                         }
381
382                         if ( result == FR_OK)
383                         {
384                                 LOG_INFO("Opened log file '%s' size %ld\n", ini_set.name, log_file.fat_file.fsize);
385
386                                 // To append data we should go to end of file before to start to write
387                                 kfile_seek(&log_file.fd, 0, KSM_SEEK_END);
388
389                                 int len = kfile_write(&log_file.fd, log_string, wr_len);
390
391                                 // Flush data and close the files.
392                                 kfile_flush(&log_file.fd);
393                                 kfile_close(&log_file.fd);
394
395                                 // Unmount always to prevent accidental sd remove.
396                                 f_mount(0, NULL);
397                                 LOG_INFO("Wrote [%d]\n", len);
398                         }
399                         else
400                         {
401                                 LOG_ERR("Unable to open file: '%s' error[%d]\n", ini_set.name, result);
402                         }
403                 }
404
405                 // If by configuration we have enable the log on serial, we log it
406                 if (ini_set.log_on_serial)
407                         kfile_write(&log_port.fd, log_string, wr_len);
408
409                 timer_delay(ini_set.sample_time);
410         }
411
412         return 0;
413 }
414