Speedup write to SD card with various tricks
[rmslog.git] / rmslog / main.c
1 /**
2  * \file
3  *
4  * \author Bernie Innocenti <bernie@codewiz.org>
5  *
6  * \brief Serial data logger for RMS
7  *
8  * This application records all incoming data from an RS-232 serial port
9  * to a file on a FAT-formatted SD card. It can be used to log kernel
10  * console messages.
11  */
12
13 #define FILE_NAME          "log.txt"
14 #define FILE_OVERWRITE     1
15 #define FILE_PREALLOC_SIZE 102400
16
17
18 #include "hw/hw_led.h"
19
20 #define LOG_LEVEL      3
21 #include <cfg/log.h>
22 #include <cfg/debug.h>
23
24 #include <cpu/irq.h>
25 #include <cpu/power.h>
26
27 #ifdef BERTOS_FAT
28         #include <drv/sd.h>
29         #include <fs/fat.h>
30 #else
31         #include <FAT16/fat.h>
32         #include <FAT16/partition.h>
33         #include <FAT16/sd_raw.h>
34 #endif
35
36 #include <drv/ser.h>
37 #include <drv/timer.h>
38 #include <kern/proc.h>
39
40 #include <string.h>
41
42
43 static Serial ser;
44
45 #ifdef BERTOS_FAT
46         static Serial spi;
47         static FATFS fs;
48         static FatFile file;
49         static Sd sd;
50 #else
51         struct fat_fs_struct        *fs;
52         struct partition_struct     *partition;
53         struct fat_dir_struct       *dd;
54         struct fat_dir_entry_struct dir_entry;
55         struct fat_file_struct      *fd;
56 #endif
57
58
59 #ifndef BERTOS_FAT
60 static void fat_init(void)
61 {
62         partition = partition_open(
63                 sd_raw_read,
64                 sd_raw_read_interval,
65                 sd_raw_write,
66                 sd_raw_write_interval,
67                 0
68         );
69
70         if (!partition)
71         {
72                 // If the partition did not open, assume the storage device
73                 // is a "superfloppy", i.e. has no MBR.
74                 partition = partition_open(
75                         sd_raw_read,
76                         sd_raw_read_interval,
77                         sd_raw_write,
78                         sd_raw_write_interval,
79                         0
80                 );
81         }
82         if (!partition)
83         {
84                 ASSERT(0); for(;;) {}
85         }
86
87         if (!(fs = fat_open(partition)))
88         {
89                 ASSERT(0); for(;;) {}
90         }
91
92     //Open root directory
93     fat_get_dir_entry_of_path(fs, "/", &dir_entry);
94     if (!(dd = fat_open_dir(fs, &dir_entry)))
95         {
96                 ASSERT(0); for(;;) {}
97         }
98 }
99
100 static uint8_t find_file_in_dir(UNUSED_ARG(struct fat_fs_struct *, fs), struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
101 {
102         fat_reset_dir(dd);      //Make sure to start from the beginning of the directory!
103     while(fat_read_dir(dd, dir_entry))
104     {
105         if(strcmp(dir_entry->long_name, name) == 0)
106         {
107             //fat_reset_dir(dd);
108             return 1;
109         }
110     }
111
112     return 0;
113 }
114
115 static struct fat_file_struct *open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
116 {
117     struct fat_dir_entry_struct file_entry;
118     if(!find_file_in_dir(fs, dd, name, &file_entry))
119         return 0;
120
121     return fat_open_file(fs, &file_entry);
122 }
123
124 #endif // !BERTOS_FAT
125
126 static void init(void)
127 {
128         /* Initialize debugging module (allow kprintf(), etc.) */
129         kdbg_init();
130
131         /* Initialize system timer */
132         timer_init();
133
134         /* Enable all the interrupts */
135         IRQ_ENABLE;
136
137         /* Kernel initialization: processes */
138         proc_init();
139
140         /* Initialize UART0 */
141         ser_init(&ser, SER_UART0);
142
143         //FIXME: The 16MHz arduino clock causes 3.5% baudrate error at 115200
144         //ser_setbaudrate(&ser, 115200);
145         ser_setbaudrate(&ser, 57600);
146         UCSR0A = BV(U2X0);
147
148         // At this baud rate, we're fast enought to write a continuous
149         // input stream to the SD card
150         //ser_setbaudrate(&ser, 19200);
151
152         /* Initialize LED driver */
153         LED_INIT();
154
155         timer_delay(1000);
156         kfile_printf(&ser.fd, "Hello, world!\r\n");
157
158         DDRB |= BV(PORTB0) | BV(PORTB2) | BV(PORTB3) | BV(PORTB5);
159         if (!sd_raw_init())
160         {
161                 ASSERT(0); for(;;) {}
162         }
163 #endif
164
165         fat_init();
166 }
167
168
169 int main(void)
170 {
171         init();
172
173         size_t size;
174         char buf[256];
175         bool sync_pending = false;
176
177         /* create file */
178         if(!fat_create_file(dd, FILE_NAME, &dir_entry))
179         {
180                 #if FILE_OVERWRITE
181                         fat_delete_file(fs, &dir_entry);
182                         fat_create_file(dd, FILE_NAME, &dir_entry);
183                 #endif
184         }
185
186         fd = open_file_in_dir(fs, dd, FILE_NAME);
187
188         /* preallocate file */
189         #if FILE_PREALLOC_SIZE
190         {
191                 LED_ON();
192                 for (int i = 0; i < (int)(FILE_PREALLOC_SIZE / sizeof(buf)); ++i)
193                         fat_write_file(fd, (void *)buf, sizeof(buf));
194
195                 int32_t offset = 0;
196                 fat_seek_file(fd, &offset, FAT_SEEK_SET);
197                 LED_OFF();
198         }
199         #endif
200
201         while (1)
202         {
203                 if ((size = ser_read(&ser, buf, sizeof(buf))) != 0)
204                 {
205                         LED_ON();
206                         fat_write_file(fd, (void *)buf, size);
207                         sync_pending = true;
208                         LED_OFF();
209                 }
210                 else
211                 {
212                         serstatus_t err = ser_getstatus(&ser);
213                         if (err & ~SERRF_RXTIMEOUT)
214                         {
215                                 LED_ON();
216                                 kfile_printf(&ser.fd, "\r\n*** err=%d ***\r\n", err);
217                         }
218                         ser_setstatus(&ser, 0);
219
220                         if (sync_pending)
221                         {
222                                 LED_ON();
223                                 sd_raw_sync();
224                                 LED_OFF();
225                                 sync_pending = false;
226                         }
227                 }
228         }
229         fat_close_file(fd);
230 }