Be doubly-certain that the incomming CDC class driver's endpoint/pipe is flushed...
[pub/USBasp.git] / Projects / TemperatureDataLogger / TempDataLogger.c
index 6cb1792..2f2e8da 100644 (file)
@@ -1,13 +1,13 @@
 /*\r
              LUFA Library\r
-     Copyright (C) Dean Camera, 2009.\r
+     Copyright (C) Dean Camera, 2010.\r
               \r
   dean [at] fourwalledcubicle [dot] com\r
       www.fourwalledcubicle.com\r
 */\r
 \r
 /*\r
-  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
 \r
   Permission to use, copy, modify, distribute, and sell this \r
   software and its documentation for any purpose is hereby granted\r
@@ -58,56 +58,130 @@ USB_ClassInfo_MS_Device_t Disk_MS_Interface =
                        },\r
        };\r
 \r
+/** Buffer to hold the previously generated HID report, for comparison purposes inside the HID class driver. */\r
+uint8_t PrevHIDReportBuffer[GENERIC_REPORT_SIZE];\r
+\r
+/** LUFA HID Class driver interface configuration and state information. This structure is\r
+ *  passed to all HID Class driver functions, so that multiple instances of the same class\r
+ *  within a device can be differentiated from one another.\r
+ */\r
+USB_ClassInfo_HID_Device_t Generic_HID_Interface =\r
+       {\r
+               .Config =\r
+                       {\r
+                               .InterfaceNumber              = 1,\r
+\r
+                               .ReportINEndpointNumber       = GENERIC_IN_EPNUM,\r
+                               .ReportINEndpointSize         = GENERIC_EPSIZE,\r
+                               .ReportINEndpointDoubleBank   = false,\r
+                               \r
+                               .PrevReportINBuffer           = PrevHIDReportBuffer,\r
+                               .PrevReportINBufferSize       = sizeof(PrevHIDReportBuffer),\r
+                       },\r
+       };\r
+\r
+/** Non-volatile Logging Interval value in EEPROM, stored as a number of 500ms ticks */\r
+uint8_t EEMEM LoggingInterval500MS_EEPROM;\r
+\r
+/** SRAM Logging Interval value fetched from EEPROM, stored as a number of 500ms ticks */\r
+uint8_t LoggingInterval500MS_SRAM;\r
+\r
+/** Total number of 500ms logging ticks elapsed since the last log value was recorded */\r
+uint16_t CurrentLoggingTicks;\r
+\r
 /** FAT Fs structure to hold the internal state of the FAT driver for the dataflash contents. */\r
 FATFS DiskFATState;\r
 \r
 /** FAT Fs structure to hold a FAT file handle for the log data write destination. */\r
 FIL TempLogFile;\r
 \r
-/** Counter to count the number of 10 millisecond tick that has elapsed since the last sample */\r
-uint16_t CurrentLogTick;\r
-\r
 \r
+/** ISR to handle the 500ms ticks for sampling and data logging */\r
 ISR(TIMER1_COMPA_vect, ISR_BLOCK)\r
 {\r
-       if (CurrentLogTick++ != LOG_INTERVAL_10MS)\r
+       uint8_t LEDMask = LEDs_GetLEDs();\r
+\r
+       /* Check to see if the logging interval has expired */\r
+       if (CurrentLoggingTicks++ < LoggingInterval500MS_SRAM)\r
          return;\r
-         \r
-       CurrentLogTick = 0;\r
+           \r
+       LEDs_SetAllLEDs(LEDMASK_USB_BUSY);\r
 \r
+       /* Reset log tick counter to prepare for next logging interval */\r
+       CurrentLoggingTicks = 0;\r
+       \r
        if (USB_DeviceState == DEVICE_STATE_Unattached)\r
        {\r
-               f_printf(&TempLogFile, "%d Degrees\r\n", Temperature_GetTemperature());\r
+               uint8_t Day,  Month,  Year;\r
+               uint8_t Hour, Minute, Second;\r
+\r
+               DS1307_GetDate(&Day,  &Month,  &Year);\r
+               DS1307_GetTime(&Hour, &Minute, &Second);\r
+\r
+               char     LineBuffer[100];\r
+               uint16_t BytesWritten;\r
+\r
+               BytesWritten = sprintf(LineBuffer, "%02d/%02d/20%04d, %02d:%02d:%02d, %d Degrees\r\n",\r
+                                                          Day, Month, Year, Hour, Minute, Second, Temperature_GetTemperature());\r
+\r
+               f_write(&TempLogFile, LineBuffer, BytesWritten, &BytesWritten);\r
                f_sync(&TempLogFile);\r
        }\r
+       \r
+       LEDs_SetAllLEDs(LEDMask);\r
 }\r
 \r
-\r
 /** Main program entry point. This routine contains the overall program flow, including initial\r
  *  setup of all components and the main program loop.\r
  */\r
 int main(void)\r
 {\r
-       SetupHardware();\r
+       /* Fetch logging interval from EEPROM */\r
+       LoggingInterval500MS_SRAM = eeprom_read_byte(&LoggingInterval500MS_EEPROM);\r
 \r
        LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
 \r
-       /* Mount and open the log file on the dataflash FAT partition */\r
-       f_mount(0, &DiskFATState);\r
-       f_open(&TempLogFile, LOG_FILENAME, FA_OPEN_ALWAYS | FA_WRITE);\r
-       f_lseek(&TempLogFile, TempLogFile.fsize);\r
+       SetupHardware();\r
 \r
-       /* Write out the log seperator line */\r
-       f_printf(&TempLogFile, "===========================\r\n");\r
-       Temperature_GetTemperature(); // Discard first temperature reading to ensure accuracy\r
+       /* Mount and open the log file on the dataflash FAT partition */\r
+       OpenLogFile();\r
 \r
+       /* Discard the first sample from the temperature sensor, as it is generally incorrect */\r
+       uint8_t Dummy = Temperature_GetTemperature();\r
+       (void)Dummy;\r
+       \r
        for (;;)\r
        {\r
                MS_Device_USBTask(&Disk_MS_Interface);\r
+               HID_Device_USBTask(&Generic_HID_Interface);\r
                USB_USBTask();\r
        }\r
 }\r
 \r
+/** Opens the log file on the Dataflash's FAT formatted partition according to the current date */\r
+void OpenLogFile(void)\r
+{\r
+       char LogFileName[12];\r
+\r
+       /* Get the current date for the filename as "DDMMYY.csv" */\r
+       uint8_t Day, Month, Year;\r
+       DS1307_GetDate(&Day, &Month, &Year);\r
+       sprintf(LogFileName, "%02d%02d%02d.csv", Day, Month, Year);\r
+\r
+       /* Mount the storage device, open the file */\r
+       f_mount(0, &DiskFATState);\r
+       f_open(&TempLogFile, LogFileName, FA_OPEN_ALWAYS | FA_WRITE);\r
+       f_lseek(&TempLogFile, TempLogFile.fsize);\r
+}\r
+\r
+/** Closes the open data log file on the Dataflash's FAT formatted partition */\r
+void CloseLogFile(void)\r
+{\r
+       /* Sync any data waiting to be written, unmount the storage device */\r
+       f_sync(&TempLogFile);\r
+       f_close(&TempLogFile);\r
+}\r
+\r
 /** Configures the board hardware and chip peripherals for the demo's functionality. */\r
 void SetupHardware(void)\r
 {\r
@@ -121,15 +195,14 @@ void SetupHardware(void)
        /* Hardware Initialization */\r
        LEDs_Init();\r
        SPI_Init(SPI_SPEED_FCPU_DIV_2 | SPI_SCK_LEAD_FALLING | SPI_SAMPLE_TRAILING | SPI_MODE_MASTER);\r
-       Dataflash_Init();\r
-       USB_Init();\r
        ADC_Init(ADC_REFERENCE_AVCC | ADC_FREE_RUNNING | ADC_PRESCALE_128);\r
        Temperature_Init();\r
+       Dataflash_Init();\r
+       USB_Init();\r
        \r
-       /* 10ms interval timer configuration */\r
-       OCR1A   = (((F_CPU / 1024) / 100) - 1);\r
-       TCCR1A  = (1 << WGM01);  // CTC mode\r
-       TCCR1B  = (1 << CS12) | (1 << CS10);   // Fcpu/1024 speed\r
+       /* 500ms logging interval timer configuration */\r
+       OCR1A   = ((F_CPU / 1024) / 2);\r
+       TCCR1B  = (1 << WGM12) | (1 << CS12) | (1 << CS10);\r
        TIMSK1  = (1 << OCIE1A);\r
 \r
        /* Clear Dataflash sector protections, if enabled */\r
@@ -142,7 +215,7 @@ void EVENT_USB_Device_Connect(void)
        LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);\r
 \r
        /* Close the log file so that the host has exclusive filesystem access */\r
-       f_close(&TempLogFile);\r
+       CloseLogFile();\r
 }\r
 \r
 /** Event handler for the library USB Disconnection event. */\r
@@ -150,10 +223,8 @@ void EVENT_USB_Device_Disconnect(void)
 {\r
        LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
        \r
-       /* When disconnected from the host, re-open log file so we can resume logging */\r
-       f_mount(0, &DiskFATState);\r
-       f_open(&TempLogFile, LOG_FILENAME, FA_OPEN_ALWAYS | FA_WRITE);\r
-       f_lseek(&TempLogFile, TempLogFile.fsize);\r
+       /* Mount and open the log file on the dataflash FAT partition */\r
+       OpenLogFile();\r
 }\r
 \r
 /** Event handler for the library USB Configuration Changed event. */\r
@@ -163,12 +234,16 @@ void EVENT_USB_Device_ConfigurationChanged(void)
 \r
        if (!(MS_Device_ConfigureEndpoints(&Disk_MS_Interface)))\r
          LEDs_SetAllLEDs(LEDMASK_USB_ERROR);\r
+         \r
+       if (!(HID_Device_ConfigureEndpoints(&Generic_HID_Interface)))\r
+         LEDs_SetAllLEDs(LEDMASK_USB_ERROR);   \r
 }\r
 \r
 /** Event handler for the library USB Unhandled Control Request event. */\r
 void EVENT_USB_Device_UnhandledControlRequest(void)\r
 {\r
        MS_Device_ProcessControlRequest(&Disk_MS_Interface);\r
+       HID_Device_ProcessControlRequest(&Generic_HID_Interface);\r
 }\r
 \r
 /** Mass Storage class driver callback function the reception of SCSI commands from the host, which must be processed.\r
@@ -185,3 +260,54 @@ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfa
        \r
        return CommandSuccess;\r
 }\r
+\r
+/** HID class driver callback function for the creation of HID reports to the host.\r
+ *\r
+ *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced\r
+ *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID\r
+ *  \param[in] ReportType  Type of the report to create, either REPORT_ITEM_TYPE_In or REPORT_ITEM_TYPE_Feature\r
+ *  \param[out] ReportData  Pointer to a buffer where the created report should be stored\r
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent\r
+ *\r
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent\r
+ */\r
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,\r
+                                         const uint8_t ReportType, void* ReportData, uint16_t* ReportSize)\r
+{\r
+       Device_Report_t* ReportParams = (Device_Report_t*)ReportData;\r
+\r
+       DS1307_GetDate(&ReportParams->Day,  &ReportParams->Month,  &ReportParams->Year);\r
+       DS1307_GetTime(&ReportParams->Hour, &ReportParams->Minute, &ReportParams->Second);\r
+       \r
+       ReportParams->LogInterval500MS = LoggingInterval500MS_SRAM;\r
+\r
+       *ReportSize = sizeof(Device_Report_t);\r
+       return true;\r
+}\r
+\r
+/** HID class driver callback function for the processing of HID reports from the host.\r
+ *\r
+ *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced\r
+ *  \param[in] ReportID  Report ID of the received report from the host\r
+ *  \param[in] ReportData  Pointer to a buffer where the created report has been stored\r
+ *  \param[in] ReportSize  Size in bytes of the received HID report\r
+ */\r
+void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID,\r
+                                          const void* ReportData, const uint16_t ReportSize)\r
+{\r
+       Device_Report_t* ReportParams = (Device_Report_t*)ReportData;\r
+       \r
+       GPIOR0 = ReportParams->Day;\r
+       GPIOR1 = ReportParams->Month;\r
+       GPIOR2 = ReportParams->Year;\r
+       \r
+       DS1307_SetDate(ReportParams->Day,  ReportParams->Month,  ReportParams->Year);\r
+       DS1307_SetTime(ReportParams->Hour, ReportParams->Minute, ReportParams->Second);\r
+       \r
+       /* If the logging interval has changed from its current value, write it to EEPROM */\r
+       if (LoggingInterval500MS_SRAM != ReportParams->LogInterval500MS)\r
+       {\r
+               LoggingInterval500MS_SRAM = ReportParams->LogInterval500MS;\r
+               eeprom_write_byte(&LoggingInterval500MS_EEPROM, LoggingInterval500MS_SRAM);\r
+       }\r
+}\r