Get rid of BERTOS_FAT leftovers
[rmslog.git] / rmslog / main.c
index 663386f45c0723008699f85f6d76a1abdf6c8d69..206f421c9a887e33c32aa8ee951e003ee0624a7c 100644 (file)
 /**
  * \file
- * <!--
- * This file is part of BeRTOS.
  *
- * Bertos is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * \author Bernie Innocenti <bernie@codewiz.org>
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * \brief Serial data logger for RMS
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * As a special exception, you may use this file as part of a free software
- * library without restriction.  Specifically, if other files instantiate
- * templates or use macros or inline functions from this file, or you compile
- * this file and link it with other files to produce an executable, this
- * file does not by itself cause the resulting executable to be covered by
- * the GNU General Public License.  This exception does not however
- * invalidate any other reasons why the executable file might be covered by
- * the GNU General Public License.
- *
- * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
- *
- * -->
- *
- * \author Andrea Righi <arighi@develer.com>
- *
- * \brief Kernel project.
- *
- * This is a minimalist kernel project: it just initializes the hardware and
- * creates an independent process to blink an LED, while the main loop
- * continues to monitor the stack utilization of all the processes.
+ * This application records all incoming data from an RS-232 serial port
+ * to a file on a FAT-formatted SD card. It can be used to log kernel
+ * console messages.
  */
 
+// Configuration
+#define FILE_NAME          "log.txt"
+#define FILE_OVERWRITE     1
+#define FILE_PREALLOC_SIZE 102400
+
+
 #include "hw/hw_led.h"
 
+#define LOG_LEVEL      3
+#include <cfg/log.h>
 #include <cfg/debug.h>
 
 #include <cpu/irq.h>
 #include <cpu/power.h>
 
-#include <drv/timer.h>
-#include <drv/ser.h>
+#include <FAT16/fat.h>
+#include <FAT16/partition.h>
+#include <FAT16/sd_raw.h>
 
+#include <drv/ser.h>
+#include <drv/timer.h>
 #include <kern/proc.h>
-#include <kern/monitor.h>
 
-static Serial out;
+#include <string.h>
 
-static void init(void)
+
+// Our serial port
+static Serial ser;
+
+// FAT global state
+struct fat_fs_struct        *fs;
+struct partition_struct     *partition;
+struct fat_dir_struct       *dd;
+struct fat_dir_entry_struct dir_entry;
+struct fat_file_struct      *fd;
+
+
+static void fat_init(void)
 {
-       /* Enable all the interrupts */
-       IRQ_ENABLE;
+       partition = partition_open(
+               sd_raw_read,
+               sd_raw_read_interval,
+               sd_raw_write,
+               sd_raw_write_interval,
+               0
+       );
+
+       if (!partition)
+       {
+               // If the partition did not open, assume the storage device
+               // is a "superfloppy", i.e. has no MBR.
+               partition = partition_open(
+                       sd_raw_read,
+                       sd_raw_read_interval,
+                       sd_raw_write,
+                       sd_raw_write_interval,
+                       0
+               );
+       }
+       if (!partition)
+       {
+               ASSERT(0); for(;;) {}
+       }
+
+       if (!(fs = fat_open(partition)))
+       {
+               ASSERT(0); for(;;) {}
+       }
+
+    // Open root directory
+    fat_get_dir_entry_of_path(fs, "/", &dir_entry);
+    if (!(dd = fat_open_dir(fs, &dir_entry)))
+       {
+               ASSERT(0); for(;;) {}
+       }
+}
+
+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)
+{
+       fat_reset_dir(dd);      //Make sure to start from the beginning of the directory!
+    while(fat_read_dir(dd, dir_entry))
+    {
+        if(strcmp(dir_entry->long_name, name) == 0)
+        {
+            //fat_reset_dir(dd);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static struct fat_file_struct *open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
+{
+    struct fat_dir_entry_struct file_entry;
+    if(!find_file_in_dir(fs, dd, name, &file_entry))
+        return 0;
+
+    return fat_open_file(fs, &file_entry);
+}
 
+
+static void init(void)
+{
        /* Initialize debugging module (allow kprintf(), etc.) */
        kdbg_init();
+
        /* Initialize system timer */
        timer_init();
-       /*
-        * XXX: Arduino has a single UART port that was previously
-        * initialized for debugging purpose.
-        * In order to activate the serial driver you should disable 
-        * the debugging module.
-        */
-#if 0
+
+       /* Enable all the interrupts */
+       IRQ_ENABLE;
+
+       /* Kernel initialization: processes */
+       proc_init();
+
        /* Initialize UART0 */
-       ser_init(&out, SER_UART0);
-       /* Configure UART0 to work at 115.200 bps */
-       ser_setbaudrate(&out, 115200);
-#else
-       (void)out;
-#endif
-       /* Initialize LED driver */
+       ser_init(&ser, SER_UART0);
+
+       //FIXME: The 16MHz arduino clock causes 3.5% baudrate error at 115200
+       //ser_setbaudrate(&ser, 115200);
+       ser_setbaudrate(&ser, 57600);
+       UCSR0A = BV(U2X0);
+
+       // At this baud rate, we're fast enought to write a continuous
+       // input stream to the SD card
+       //ser_setbaudrate(&ser, 19200);
+
+       // Initialize LED driver
        LED_INIT();
 
        /*
-        * Kernel initialization: processes (allow to create and dispatch
-        * processes using proc_new()).
+        * This gives avrdude some time to start reflashing in case
+        * the bug caused the program to do continous serial output
         */
-       proc_init();
-}
-
-static void NORETURN led_process(void)
-{
-       int i;
+       timer_delay(1000);
 
-       /* Periodically blink the led (toggle each 100 ms) */
-       for (i = 0; ; i = !i)
+       DDRB |= BV(PORTB0) | BV(PORTB2) | BV(PORTB3) | BV(PORTB5);
+       if (!sd_raw_init())
        {
-               if (i)
-                       LED_ON();
-               else
-                       LED_OFF();
-               timer_delay(100);
+               ASSERT(0); for(;;) {}
        }
+
+       fat_init();
 }
 
+
 int main(void)
 {
-       /* Hardware initialization */
        init();
 
-       /* Create a new child process */
-       proc_new(led_process, NULL, KERN_MINSTACKSIZE * 2, NULL);
+       size_t size;
+       char buf[256];
+       bool sync_pending = false;
+
+       /* create file */
+       if(!fat_create_file(dd, FILE_NAME, &dir_entry))
+       {
+               #if FILE_OVERWRITE
+                       fat_delete_file(fs, &dir_entry);
+                       fat_create_file(dd, FILE_NAME, &dir_entry);
+               #endif
+       }
+
+       fd = open_file_in_dir(fs, dd, FILE_NAME);
+
+       /* preallocate file */
+       #if FILE_PREALLOC_SIZE
+       {
+               LED_ON();
+               for (int i = 0; i < (int)(FILE_PREALLOC_SIZE / sizeof(buf)); ++i)
+                       fat_write_file(fd, (void *)buf, sizeof(buf));
+
+               int32_t offset = 0;
+               fat_seek_file(fd, &offset, FAT_SEEK_SET);
+               LED_OFF();
+       }
+       #endif
 
-       /*
-        * The main process is kept to periodically report the stack
-        * utilization of all the processes (1 probe per second).
-        */
        while (1)
        {
-               monitor_report();
-               timer_delay(1000);
+               if ((size = ser_read(&ser, buf, sizeof(buf))) != 0)
+               {
+                       LED_ON();
+                       fat_write_file(fd, (void *)buf, size);
+                       sync_pending = true;
+                       LED_OFF();
+               }
+               else
+               {
+                       serstatus_t err = ser_getstatus(&ser);
+                       if (err & ~SERRF_RXTIMEOUT)
+                       {
+                               LED_ON();
+                               kfile_printf(&ser.fd, "\r\n*** err=%d ***\r\n", err);
+                       }
+                       ser_setstatus(&ser, 0);
+
+                       if (sync_pending)
+                       {
+                               LED_ON();
+                               sd_raw_sync();
+                               LED_OFF();
+                               sync_pending = false;
+                       }
+               }
        }
+       fat_close_file(fd);
 }