Add at91sam7x board. Add sd example.
[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  */
50
51 #include <cfg/debug.h>
52
53 // Define logging setting (for cfg/log.h module).
54 #define LOG_LEVEL         3
55 #define LOG_VERBOSITY     0
56 #include <cfg/log.h>
57 #include <cfg/macros.h>
58
59 #include <cpu/irq.h>
60
61 #include <drv/timer.h>
62 #include <drv/sd.h>
63 #include <drv/ser.h>
64 #include <drv/tmp123.h>
65 #include <drv/spi_dma_at91.h>
66 #include <drv/mpxx6115a.h>
67 #include <drv/adc.h>
68
69 #include <fs/fat.h>
70
71 #include <mware/ini_reader.h>
72
73 #include <verstag.h>
74 #include <buildrev.h>
75
76 #include <string.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79
80 /*
81  * Setting structure define
82  */
83 typedef struct INISetting
84 {
85         // INI Log section
86         char name[80];              ///< Name of log file
87         bool log_on_serial;         ///< Enable the logging on serial device
88         bool log_on_file;           ///< Enable logging on sd file
89         mtime_t sample_time;        ///< Period between two log (millisecond)
90
91         //INI serial log section
92         int port;                   ///< Select serial port where log
93         int baud;                   ///< Serial port baudrate
94
95         // INI log format section
96         char line_header[80];       ///< Default text to insert on each log line
97         char field_sep[10];         ///< Use this char to separate each log field
98
99         // INI temperature section
100         char temp_unit_label[10];   ///< Default label for measure unit
101
102         // INI pressure section
103         char press_unit_label[10];  ///< Default label for measure unit
104
105         // INI voltage section
106         char voltage_unit_label[10];  ///< Default label for measure unit
107
108
109 } INISetting;
110
111 /*
112  * Setting and various defines.
113  */
114 #define INI_FILE_NAME     "sd_fat.ini"   ///< Default ini file name on SD card.
115
116 // INI Log section
117 #define LOG_SECTION        "log"           ///< Log section
118 #define LOG_NAME_KEY       "name"          ///< Name of log file
119 #define LOG_ON_SERIAL      "log_on_serial" ///< Enable the logging on serial device
120 #define LOG_ON_FILE        "log_on_file"   ///< Enable logging on sd file
121 #define LOG_SAMPLE_TIME    "sample_time"   ///< Period between two log
122
123 //INI serial log section
124 #define SERIAL_LOG         "serial_log"    ///< Serial log section
125 #define SERIAL_PORT        "port"          ///< Select serial port where log
126 #define SERIAL_BAUD        "baud"          ///< Serial port baudrate
127
128 // INI log format section
129 #define LOG_FORMAT_SEC     "log_format"    ///< log format section
130 #define FORMAT_LINE_HEADER "line_header"   ///< Default text to insert on each log line
131 #define FORMAT_FIELD_SEP   "field_sep"     ///< Use this char to separate each log field
132
133 // INI temperature section
134 #define TEMPERATURE        "temperature"   ///< temperarute section
135 #define TEMP_UNIT_LABEL    "unit_label"    ///< Default label for measure unit
136
137 // INI pressure section
138 #define PRESSURE           "pressure"      ///< pressure section
139 #define PRESS_UNIT_LABEL   "unit_label"    ///< Default label for measure unit
140
141 // INI voltsge section
142 #define VOLTAGE            "voltage"      ///< voltage section
143 #define VOLTAGE_UNIT_LABEL "unit_label"   ///< Default label for measure unit
144
145 /**
146  * Voltage reference in volts for ADC.
147  * \note This value should be complied to jumper J13 on AT91SAM7X-EK board, and
148  * the supply voltade for sensor.
149  * See schamatics for more info.
150  */
151 #define ADC_VOLTAGE_REF             3300
152 /**
153  * Channel where the sensor we connect it (AD6)
154  * See schamatics for more info.
155  */
156 #define PRESSURE_SENSOR_CH          6
157
158 /**
159  * ADC channle to read voltage supplay
160  * \note we connect board power supplay (+3.3V) to AD3 port with wire.
161  */
162 #define SUPPLAY_VOLTAGE_CH          3
163 #define ADC_SUPPLAY_VOLTAGE         3300
164
165 /*
166  * Static definition for application devices.
167  */
168 static SpiDmaAt91 spi_dma;
169 static Serial temp_sensor_bus;
170 static Serial log_port;
171
172 static void init(void)
173 {
174         IRQ_ENABLE;
175         kdbg_init();
176
177         timer_init();
178         LOG_INFO("TIMER init..ok\n");
179
180         /*
181          * Init temperature sensor device.
182          * - init the temperature driver
183          * - init the spi communication channel
184          */
185         tmp123_init();
186         // Init SPI connected to sensor temperature
187         spimaster_init(&temp_sensor_bus, SER_SPI1);
188         ser_setbaudrate(&temp_sensor_bus, 1000000L);
189         LOG_INFO("TMP123 sensor init..ok\n");
190
191         // Init SPI bus to communicate to SD card
192         spi_dma_init(&spi_dma);
193         spi_dma_setclock(20000000L);
194         LOG_INFO("SD SPI init..ok\n");
195
196         adc_init();
197         LOG_INFO("ADC init..ok\n");
198
199 }
200
201 int main(void)
202 {
203         // SD fat filesystem context
204         FATFS fs;
205
206         // Context files that we would manage
207         FatFile ini_file;
208         FatFile log_file;
209
210         init();
211
212         LOG_INFO("SD fat example project %s: %d times\n", VERS_HOST, VERS_BUILD);
213
214         while (1)
215         {
216                 bool sd_ok = true;
217                 FRESULT result;
218
219                 // Setting info
220                 INISetting ini_set;
221                 memset(&ini_set, 0, sizeof(ini_set));
222
223                 sd_ok = sd_init(&spi_dma.fd);
224
225                 if (sd_ok)
226                 {
227                         LOG_INFO("Mount FAT filesystem.\n");
228                         if ((result = f_mount(0, &fs)) != FR_OK)
229                         {
230                                 LOG_ERR("Mounting FAT volumes error[%d]\n", result);
231                                 sd_ok = false;
232                         }
233
234                         LOG_INFO("Read setting from ini file: %s\n", INI_FILE_NAME);
235                         if (sd_ok && ((result = fatfile_open(&ini_file, INI_FILE_NAME, FA_READ)) != FR_OK))
236                         {
237                                 LOG_ERR("Could not open ini file: %s error[%d,]\n", INI_FILE_NAME, result);
238                                 sd_ok = false;
239                         }
240
241                         if (sd_ok)
242                         {
243                                 /*
244                                  * If sd is ok, we read all setting from INI file.
245                                  * NOTE: if one ini key or section was not found into INI
246                                  * file, the iniparser return the defaul value.
247                                  */
248                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_NAME_KEY, "default.log", ini_set.name, sizeof(ini_set.name));
249                                 LOG_INFO("Log file name [%s]\n", ini_set.name);
250
251                                 char tmp[25];
252                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_SERIAL,   "1", tmp, sizeof(tmp));
253                                 ini_set.log_on_serial = atoi(tmp);
254                                 LOG_INFO("Log serial [%d]\n", ini_set.log_on_serial);
255                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_FILE,     "1", tmp, sizeof(tmp));
256                                 ini_set.log_on_file = atoi(tmp);
257                                 LOG_INFO("Log sd [%d]\n", ini_set.log_on_file);
258                                 ini_getString(&ini_file.fd, LOG_SECTION, LOG_SAMPLE_TIME, "500", tmp, sizeof(tmp));
259                                 ini_set.sample_time = atoi(tmp);
260                                 LOG_INFO("Sample time [%ld]\n", ini_set.sample_time);
261
262                                 ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_PORT, "0", tmp, sizeof(tmp));
263                                 ini_set.port = atoi(tmp);
264                                 LOG_INFO("Serial port [%d]\n", ini_set.port);
265                                 ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_BAUD, "115200", tmp, sizeof(tmp));
266                                 ini_set.baud = atoi(tmp);
267                                 LOG_INFO("Serial buad [%d]\n", ini_set.baud);
268
269                                 ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_LINE_HEADER, "BeRTOS: ", ini_set.line_header, sizeof(ini_set.line_header));
270                                 LOG_INFO("Serial line header[%s]\n", ini_set.line_header);
271
272                                 ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_FIELD_SEP, ",", ini_set.field_sep, sizeof(ini_set.field_sep));
273                                 LOG_INFO("Serial char sep[%s]\n", ini_set.field_sep);
274
275                                 ini_getString(&ini_file.fd, TEMPERATURE, TEMP_UNIT_LABEL, "C", ini_set.temp_unit_label, sizeof(ini_set.temp_unit_label));
276                                 LOG_INFO("Temp unit label[%s]\n", ini_set.temp_unit_label);
277
278                                 ini_getString(&ini_file.fd, PRESSURE, PRESS_UNIT_LABEL, "hPa", ini_set.press_unit_label, sizeof(ini_set.press_unit_label));
279                                 LOG_INFO("Press unit label[%s]\n", ini_set.press_unit_label);
280
281                                 ini_getString(&ini_file.fd, VOLTAGE, VOLTAGE_UNIT_LABEL, "V", ini_set.voltage_unit_label, sizeof(ini_set.voltage_unit_label));
282                                 LOG_INFO("Press unit label[%s]\n", ini_set.voltage_unit_label);
283
284                         }
285                 }
286
287                 if (ini_set.log_on_serial)
288                 {
289                         // Init serial log port
290                         ser_init(&log_port, ini_set.port);
291                         ser_setbaudrate(&log_port, ini_set.baud);
292                         LOG_INFO("SERIAL init..port[%d] buad[%d]\n", ini_set.port, ini_set.baud);
293                 }
294
295                 char log_string[160];
296                 memset(log_string, 0, sizeof(log_string));
297
298                 // Supplay voltage
299                 uint16_t vdd = ADC_RANGECONV(adc_read(SUPPLAY_VOLTAGE_CH), 0, ADC_SUPPLAY_VOLTAGE);
300
301                 // Read temperature
302                 int16_t tmp = tmp123_read(&temp_sensor_bus.fd);
303
304                 // Read pressure
305                 uint16_t vout = ADC_RANGECONV(adc_read(PRESSURE_SENSOR_CH), 0, vdd);
306                 int16_t press = mpxx6115a_press(vout,  vdd);
307
308                 /*
309                  * Format string whit read data
310                  * line_header + temp + temp_unit_label + field_sep + press + press_unit_label + field_sep + vdd + voltage_unit_label
311                  */
312                 int wr_len = sprintf(log_string, "%s%d.%01d%s%s%d%s%s%d.%d%s\r\n", ini_set.line_header,
313                                                                                                                                 tmp / 10, ABS(tmp % 10),
314                                                                                                                                 ini_set.temp_unit_label,
315                                                                                                                                 ini_set.field_sep,
316                                                                                                                                 press,
317                                                                                                                                 ini_set.press_unit_label,
318                                                                                                                                 ini_set.field_sep,
319                                                                                                                                 vdd / 1000, ABS(vdd % 1000),
320                                                                                                                                 ini_set.voltage_unit_label);
321
322
323                 /*
324                  * if SD is ok, try to open log file and write our data and, only
325                  * if by configuration we have enable the log on file
326                  */
327                 if (sd_ok && ini_set.log_on_file)
328                 {
329                         // Open log file and do not overwrite the previous log file
330                         result = fatfile_open(&log_file, ini_set.name,  FA_OPEN_EXISTING | FA_WRITE);
331
332                         // If the log file there isn't we create the new one
333                         if (result == FR_NO_FILE)
334                         {
335                                 result = fatfile_open(&log_file, ini_set.name,  FA_CREATE_NEW | FA_WRITE);
336                                 LOG_INFO("Create the log file: %s\n", ini_set.name);
337                         }
338
339                         if ( result == FR_OK)
340                         {
341                                 LOG_INFO("Opened log file '%s' size %ld\n", ini_set.name, log_file.fat_file.fsize);
342
343                                 // To append data we should go to end of file before to start to write
344                                 kfile_seek(&log_file.fd, 0, KSM_SEEK_END);
345
346                                 int len = kfile_write(&log_file.fd, log_string, wr_len);
347
348                                 // Flush data and close the files.
349                                 kfile_flush(&log_file.fd);
350                                 kfile_close(&log_file.fd);
351
352                                 // Unmount always to prevent accidental sd remove.
353                                 f_mount(0, NULL);
354                                 LOG_INFO("Wrote [%d]\n", len);
355                         }
356                         else
357                         {
358                                 LOG_ERR("Unable to open file: '%s' error[%d]\n", ini_set.name, result);
359                         }
360                 }
361
362                 // If by configuration we have enable the log on serial, we log it
363                 if (ini_set.log_on_serial)
364                         kfile_write(&log_port.fd, log_string, wr_len);
365
366                 timer_delay(ini_set.sample_time);
367         }
368
369         return 0;
370 }
371