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