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