From dd995683ea1f233b79724d524a9a3dbcdc171d30 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Sun, 24 Jan 2010 11:13:23 +0000 Subject: [PATCH] Enhance TemperatureDatalogger project -- add RTC capabilities so that data is logged along with the current time and date. Make logging interval configurable, set by a C# PC host application. --- LUFA.pnproj | 2 +- LUFA/ManPages/FutureChanges.txt | 3 + LUFA/ManPages/VIDAndPIDValues.txt | 2 +- Projects/AVRISP-MKII/makefile | 1 + Projects/TemperatureDataLogger/Descriptors.c | 87 ++++++++- Projects/TemperatureDataLogger/Descriptors.h | 48 ++--- Projects/TemperatureDataLogger/Lib/DS1307.c | 129 +++++++++++++ Projects/TemperatureDataLogger/Lib/DS1307.h | 111 +++++++++++ .../TemperatureDataLogger/Lib/FATFs/diskio.c | 14 +- .../TemperatureDataLogger/Lib/FATFs/ffconf.h | 2 +- .../TemperatureDataLogger/TempDataLogger.c | 165 +++++++++++++--- .../TemperatureDataLogger/TempDataLogger.h | 25 ++- .../TempLoggerHostApp/TempLoggerHostApp.sln | 20 ++ .../TempLoggerHostApp/TempLoggerHostApp.suo | Bin 0 -> 17408 bytes .../DataLoggerSettings.Designer.cs | 181 ++++++++++++++++++ .../TempLoggerHostApp/DataLoggerSettings.cs | 172 +++++++++++++++++ .../TempLoggerHostApp/DataLoggerSettings.resx | 120 ++++++++++++ .../TempLoggerHostApp/Hid.Linux.dll | Bin 0 -> 9216 bytes .../TempLoggerHostApp/Hid.Net.dll | Bin 0 -> 24576 bytes .../TempLoggerHostApp/Hid.Win32.dll | Bin 0 -> 94208 bytes .../TempLoggerHostApp/Program.cs | 21 ++ .../TempLoggerHostApp.csproj | 95 +++++++++ .../TemperatureDataLogger.txt | 29 ++- Projects/TemperatureDataLogger/makefile | 3 + 24 files changed, 1147 insertions(+), 83 deletions(-) create mode 100644 Projects/TemperatureDataLogger/Lib/DS1307.c create mode 100644 Projects/TemperatureDataLogger/Lib/DS1307.h create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.sln create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.suo create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.Designer.cs create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.cs create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.resx create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Linux.dll create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Net.dll create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Win32.dll create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Program.cs create mode 100644 Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/TempLoggerHostApp.csproj diff --git a/LUFA.pnproj b/LUFA.pnproj index 54dce2e1ef..f50eba3a45 100644 --- a/LUFA.pnproj +++ b/LUFA.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/LUFA/ManPages/FutureChanges.txt b/LUFA/ManPages/FutureChanges.txt index 38cbf0ccf3..9006040d3d 100644 --- a/LUFA/ManPages/FutureChanges.txt +++ b/LUFA/ManPages/FutureChanges.txt @@ -17,6 +17,8 @@ * -# Add ability to get number of bytes not written with pipe/endpoint write routines after an error * -# Add standardized descriptor names to class driver structures * -# Correct mishandling of error cases in Mass Storage demos + * -# FIX BROKEN RNDIS HOST CLASS DRIVER (BLOCKING) + * -# TEST AND CORRECT TPI PROGRAMMING SUPPORT IN THE AVRISP-MKII PROJECT (BLOCKING) * - Documentation/Support * -# Remake AVRStudio project files * -# Add detailed overviews of how each demo works @@ -32,6 +34,7 @@ * -# Finish MIDI class Bootloader * -# Finish SideShow demo * -# Finish StandaloneProgrammer project + * -# Finish Webserver project * - Ports * -# AVR32 UC3B series microcontrollers * -# Atmel ARM7 series microcontrollers diff --git a/LUFA/ManPages/VIDAndPIDValues.txt b/LUFA/ManPages/VIDAndPIDValues.txt index 1a101a8933..339fd47b23 100644 --- a/LUFA/ManPages/VIDAndPIDValues.txt +++ b/LUFA/ManPages/VIDAndPIDValues.txt @@ -265,7 +265,7 @@ * 0x2063 * * - * Currently Unallocated + * Mass Storage/HID Interface Datalogger Project * * * diff --git a/Projects/AVRISP-MKII/makefile b/Projects/AVRISP-MKII/makefile index 58d2a46d09..5c0fe0f64f 100644 --- a/Projects/AVRISP-MKII/makefile +++ b/Projects/AVRISP-MKII/makefile @@ -197,6 +197,7 @@ CDEFS += -DAUX_LINE_MASK="(1 << 4)" CDEFS += -DVTARGET_ADC_CHANNEL=2 CDEFS += -DENABLE_ISP_PROTOCOL CDEFS += -DENABLE_XPROG_PROTOCOL +#CDEFS += -DXPROG_VIA_HARDWARE_USART # Place -D or -U options here for ASM sources diff --git a/Projects/TemperatureDataLogger/Descriptors.c b/Projects/TemperatureDataLogger/Descriptors.c index 40ce620a64..e4f5666e5f 100644 --- a/Projects/TemperatureDataLogger/Descriptors.c +++ b/Projects/TemperatureDataLogger/Descriptors.c @@ -49,6 +49,32 @@ #warning USE_INTERNAL_SERIAL is not available on this AVR - please manually construct a device serial descriptor. #endif +/** HID class report descriptor. This is a special descriptor constructed with values from the + * USBIF HID class specification to describe the reports and capabilities of the HID device. This + * descriptor is parsed by the host and its contents used to determine what data (and in what encoding) + * the device will send, and what it may be sent back from the host. Refer to the HID specification for + * more details on HID report descriptors. + */ +USB_Descriptor_HIDReport_Datatype_t PROGMEM GenericReport[] = +{ + 0x06, 0x9c, 0xff, /* Usage Page (Vendor Defined) */ + 0x09, 0x01, /* Usage (Vendor Defined) */ + 0xa1, 0x01, /* Collection (Vendor Defined) */ + 0x09, 0x02, /* Usage (Vendor Defined) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, GENERIC_REPORT_SIZE, /* Report Count (GENERIC_REPORT_SIZE) */ + 0x15, 0x80, /* Logical Minimum (-128) */ + 0x25, 0x7F, /* Logical Maximum (127) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x09, 0x03, /* Usage (Vendor Defined) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, GENERIC_REPORT_SIZE, /* Report Count (GENERIC_REPORT_SIZE) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0xff, /* Logical Maximum (255) */ + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ + 0xc0 /* End Collection */ +}; + /** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall * device characteristics, including the supported USB version, control endpoint size and the * number of device configurations. The descriptor is read out by the USB host when the enumeration @@ -66,7 +92,7 @@ USB_Descriptor_Device_t PROGMEM DeviceDescriptor = .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, .VendorID = 0x03EB, - .ProductID = 0x2045, + .ProductID = 0x2063, .ReleaseNumber = 0x0000, .ManufacturerStrIndex = 0x01, @@ -88,7 +114,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), - .TotalInterfaces = 1, + .TotalInterfaces = 2, .ConfigurationNumber = 1, .ConfigurationStrIndex = NO_DESCRIPTOR, @@ -98,7 +124,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) }, - .Interface = + .MSInterface = { .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, @@ -114,7 +140,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .InterfaceStrIndex = NO_DESCRIPTOR }, - .DataInEndpoint = + .MSDataInEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, @@ -124,7 +150,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .PollingIntervalMS = 0x00 }, - .DataOutEndpoint = + .MSDataOutEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, @@ -132,7 +158,44 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = MASS_STORAGE_IO_EPSIZE, .PollingIntervalMS = 0x00 - } + }, + + .HIDInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 1, + .AlternateSetting = 0, + + .TotalEndpoints = 1, + + .Class = 0x03, + .SubClass = 0x00, + .Protocol = HID_NON_BOOT_PROTOCOL, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .HIDInfo = + { + .Header = {.Size = sizeof(USB_HID_Descriptor_t), .Type = DTYPE_HID}, + + .HIDSpec = VERSION_BCD(01.11), + .CountryCode = 0x00, + .TotalReportDescriptors = 1, + .HIDReportType = DTYPE_Report, + .HIDReportLength = sizeof(GenericReport) + }, + + .HIDDataInEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | GENERIC_IN_EPNUM), + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = GENERIC_EPSIZE, + .PollingIntervalMS = 0x0A + }, }; /** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests @@ -163,9 +226,9 @@ USB_Descriptor_String_t PROGMEM ManufacturerString = */ USB_Descriptor_String_t PROGMEM ProductString = { - .Header = {.Size = USB_STRING_LEN(22), .Type = DTYPE_String}, + .Header = {.Size = USB_STRING_LEN(10), .Type = DTYPE_String}, - .UnicodeString = L"LUFA Mass Storage Demo" + .UnicodeString = L"Datalogger" }; /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" @@ -209,6 +272,14 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, break; } + break; + case DTYPE_HID: + Address = (void*)&ConfigurationDescriptor.HIDInfo; + Size = sizeof(USB_HID_Descriptor_t); + break; + case DTYPE_Report: + Address = (void*)&GenericReport; + Size = sizeof(GenericReport); break; } diff --git a/Projects/TemperatureDataLogger/Descriptors.h b/Projects/TemperatureDataLogger/Descriptors.h index dcaaddaf7d..a0f03c38d9 100644 --- a/Projects/TemperatureDataLogger/Descriptors.h +++ b/Projects/TemperatureDataLogger/Descriptors.h @@ -5,33 +5,6 @@ dean [at] fourwalledcubicle [dot] com www.fourwalledcubicle.com */ - -/* - Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Header file for Descriptors.c. - */ #ifndef _DESCRIPTORS_H_ #define _DESCRIPTORS_H_ @@ -41,6 +14,9 @@ #include #include + #include + + #include "TempDataLogger.h" /* Macros: */ /** Endpoint number of the Mass Storage device-to-host data IN endpoint. */ @@ -51,6 +27,15 @@ /** Size in bytes of the Mass Storage data endpoints. */ #define MASS_STORAGE_IO_EPSIZE 64 + + /** Endpoint number of the Generic HID reporting IN endpoint. */ + #define GENERIC_IN_EPNUM 1 + + /** Size in bytes of the Generic HID reporting endpoint. */ + #define GENERIC_EPSIZE 16 + + /** Size in bytes of the Generic HID reports (including report ID byte). */ + #define GENERIC_REPORT_SIZE sizeof(Device_Report_t) /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the @@ -60,9 +45,12 @@ typedef struct { USB_Descriptor_Configuration_Header_t Config; - USB_Descriptor_Interface_t Interface; - USB_Descriptor_Endpoint_t DataInEndpoint; - USB_Descriptor_Endpoint_t DataOutEndpoint; + USB_Descriptor_Interface_t MSInterface; + USB_Descriptor_Endpoint_t MSDataInEndpoint; + USB_Descriptor_Endpoint_t MSDataOutEndpoint; + USB_Descriptor_Interface_t HIDInterface; + USB_HID_Descriptor_t HIDInfo; + USB_Descriptor_Endpoint_t HIDDataInEndpoint; } USB_Descriptor_Configuration_t; /* Function Prototypes: */ diff --git a/Projects/TemperatureDataLogger/Lib/DS1307.c b/Projects/TemperatureDataLogger/Lib/DS1307.c new file mode 100644 index 0000000000..37817e97f6 --- /dev/null +++ b/Projects/TemperatureDataLogger/Lib/DS1307.c @@ -0,0 +1,129 @@ +/* + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +#include "DS1307.h" + +void DS1307_Init(void) +{ + // Nothing to initialize +} + +void DS1307_SetDate(uint8_t Day, uint8_t Month, uint8_t Year) +{ +#if defined(DUMMY_RTC) + return; +#endif + + DS1307_DateRegs_t CurrentRTCDate; + CurrentRTCDate.Byte1.TenDay = (Day / 10); + CurrentRTCDate.Byte1.Day = (Day % 10); + CurrentRTCDate.Byte2.TenMonth = (Month / 10); + CurrentRTCDate.Byte2.Month = (Month % 10); + CurrentRTCDate.Byte3.TenYear = (Year / 10); + CurrentRTCDate.Byte3.Year = (Year % 10); + + if (TWI_StartTransmission(DS1307_ADDRESS_WRITE)) + { + TWI_SendByte(DS1307_DATEREG_START); + TWI_SendByte(CurrentRTCDate.Byte1.IntVal); + TWI_SendByte(CurrentRTCDate.Byte2.IntVal); + TWI_SendByte(CurrentRTCDate.Byte3.IntVal); + + TWI_StopTransmission(); + } +} + +void DS1307_SetTime(uint8_t Hour, uint8_t Minute, uint8_t Second) +{ +#if defined(DUMMY_RTC) + return; +#endif + + DS1307_TimeRegs_t CurrentRTCTime; + CurrentRTCTime.Byte1.TenSec = (Second / 10); + CurrentRTCTime.Byte1.Sec = (Second % 10); + CurrentRTCTime.Byte1.CH = false; + CurrentRTCTime.Byte2.TenMin = (Minute / 10); + CurrentRTCTime.Byte2.Min = (Minute % 10); + CurrentRTCTime.Byte3.TenHour = (Hour / 10); + CurrentRTCTime.Byte3.Hour = (Hour % 10); + CurrentRTCTime.Byte3.TwelveHourMode = false; + + if (TWI_StartTransmission(DS1307_ADDRESS_WRITE)) + { + TWI_SendByte(DS1307_TIMEREG_START); + TWI_SendByte(CurrentRTCTime.Byte1.IntVal); + TWI_SendByte(CurrentRTCTime.Byte2.IntVal); + TWI_SendByte(CurrentRTCTime.Byte3.IntVal); + + TWI_StopTransmission(); + } +} + +void DS1307_GetDate(uint8_t* Day, uint8_t* Month, uint8_t* Year) +{ +#if defined(DUMMY_RTC) + *Day = 1; + *Month = 1; + *Year = 1; + return; +#endif + + if (TWI_StartTransmission(DS1307_ADDRESS_WRITE)) + { + TWI_SendByte(DS1307_DATEREG_START); + + TWI_StopTransmission(); + } + + DS1307_DateRegs_t CurrentRTCDate; + + if (TWI_StartTransmission(DS1307_ADDRESS_READ)) + { + TWI_ReceiveByte(&CurrentRTCDate.Byte1.IntVal, false); + TWI_ReceiveByte(&CurrentRTCDate.Byte2.IntVal, false); + TWI_ReceiveByte(&CurrentRTCDate.Byte3.IntVal, true); + + TWI_StopTransmission(); + } + + *Day = (CurrentRTCDate.Byte1.TenDay * 10) + CurrentRTCDate.Byte1.Day; + *Month = (CurrentRTCDate.Byte2.TenMonth * 10) + CurrentRTCDate.Byte2.Month; + *Year = (CurrentRTCDate.Byte3.TenYear * 10) + CurrentRTCDate.Byte3.Year; +} + +void DS1307_GetTime(uint8_t* Hour, uint8_t* Minute, uint8_t* Second) +{ +#if defined(DUMMY_RTC) + *Hour = 1; + *Minute = 1; + *Second = 1; + return; +#endif + + if (TWI_StartTransmission(DS1307_ADDRESS_WRITE)) + { + TWI_SendByte(DS1307_TIMEREG_START); + + TWI_StopTransmission(); + } + + DS1307_TimeRegs_t CurrentRTCTime; + + if (TWI_StartTransmission(DS1307_ADDRESS_READ)) + { + TWI_ReceiveByte(&CurrentRTCTime.Byte1.IntVal, false); + TWI_ReceiveByte(&CurrentRTCTime.Byte2.IntVal, false); + TWI_ReceiveByte(&CurrentRTCTime.Byte3.IntVal, true); + + TWI_StopTransmission(); + } + + *Second = (CurrentRTCTime.Byte1.TenSec * 10) + CurrentRTCTime.Byte1.Sec; + *Minute = (CurrentRTCTime.Byte2.TenMin * 10) + CurrentRTCTime.Byte2.Min; + *Hour = (CurrentRTCTime.Byte3.TenHour * 10) + CurrentRTCTime.Byte3.Hour; +} diff --git a/Projects/TemperatureDataLogger/Lib/DS1307.h b/Projects/TemperatureDataLogger/Lib/DS1307.h new file mode 100644 index 0000000000..4918360795 --- /dev/null +++ b/Projects/TemperatureDataLogger/Lib/DS1307.h @@ -0,0 +1,111 @@ +/* + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +#ifndef _DS1307_H_ +#define _DS1307_H_ + + /* Includes: */ + #include + + #include + + /* Type Defines: */ + typedef struct + { + union + { + struct + { + unsigned int Sec : 4; + unsigned int TenSec : 3; + unsigned int CH : 1; + }; + + uint8_t IntVal; + } Byte1; + + union + { + struct + { + unsigned int Min : 4; + unsigned int TenMin : 3; + unsigned int _RESERVED : 1; + }; + + uint8_t IntVal; + } Byte2; + + union + { + struct + { + unsigned int Hour : 4; + unsigned int TenHour : 2; + unsigned int TwelveHourMode : 1; + unsigned int _RESERVED : 1; + }; + + uint8_t IntVal; + } Byte3; + } DS1307_TimeRegs_t; + + typedef struct + { + union + { + struct + { + unsigned int Day : 4; + unsigned int TenDay : 2; + unsigned int _RESERVED : 2; + }; + + uint8_t IntVal; + } Byte1; + + union + { + struct + { + unsigned int Month : 4; + unsigned int TenMonth : 1; + unsigned int _RESERVED : 3; + }; + + uint8_t IntVal; + } Byte2; + + union + { + struct + { + unsigned int Year : 4; + unsigned int TenYear : 4; + }; + + uint8_t IntVal; + } Byte3; + } DS1307_DateRegs_t; + + /* Macros: */ + #define DS1307_TIMEREG_START 0x00 + #define DS1307_DATEREG_START 0x04 + + #define DS1307_ADDRESS_READ 0b11010001 + #define DS1307_ADDRESS_WRITE 0b11010000 + + /* Function Prototypes: */ + void DS1307_Init(void); + + void DS1307_SetDate(uint8_t Day, uint8_t Month, uint8_t Year); + void DS1307_SetTime(uint8_t Hour, uint8_t Minute, uint8_t Second); + + void DS1307_GetDate(uint8_t* Day, uint8_t* Month, uint8_t* Year); + void DS1307_GetTime(uint8_t* Hour, uint8_t* Minute, uint8_t* Second); + +#endif diff --git a/Projects/TemperatureDataLogger/Lib/FATFs/diskio.c b/Projects/TemperatureDataLogger/Lib/FATFs/diskio.c index e6be687343..0c0083bacc 100644 --- a/Projects/TemperatureDataLogger/Lib/FATFs/diskio.c +++ b/Projects/TemperatureDataLogger/Lib/FATFs/diskio.c @@ -83,5 +83,17 @@ DRESULT disk_ioctl ( DWORD get_fattime (void) { - return (1UL << 25) | (1UL << 21) | (1UL << 16) | (1UL << 11) | (1UL << 5) | (1UL << 0); + uint8_t Day, Month, Year; + uint8_t Hour, Minute, Second; + + DS1307_GetDate(&Day, &Month, &Year); + DS1307_GetTime(&Hour, &Minute, &Second); + + + return ((DWORD)(20 + Year) << 25) | + ((DWORD)Month << 21) | + ((DWORD)Day << 16) | + ((DWORD)Hour << 11) | + ((DWORD)Minute << 5) | + (((DWORD)Second >> 1) << 0); } diff --git a/Projects/TemperatureDataLogger/Lib/FATFs/ffconf.h b/Projects/TemperatureDataLogger/Lib/FATFs/ffconf.h index 18510157d6..9b414e979f 100644 --- a/Projects/TemperatureDataLogger/Lib/FATFs/ffconf.h +++ b/Projects/TemperatureDataLogger/Lib/FATFs/ffconf.h @@ -36,7 +36,7 @@ / 3: f_lseek is removed in addition to level 2. */ -#define _USE_STRFUNC 1 /* 0, 1 or 2 */ +#define _USE_STRFUNC 0 /* 0, 1 or 2 */ /* To enable string functions, set _USE_STRFUNC to 1 or 2. */ diff --git a/Projects/TemperatureDataLogger/TempDataLogger.c b/Projects/TemperatureDataLogger/TempDataLogger.c index b181ec2f83..538a6a5e81 100644 --- a/Projects/TemperatureDataLogger/TempDataLogger.c +++ b/Projects/TemperatureDataLogger/TempDataLogger.c @@ -58,52 +58,93 @@ USB_ClassInfo_MS_Device_t Disk_MS_Interface = }, }; +/** Buffer to hold the previously generated HID report, for comparison purposes inside the HID class driver. */ +uint8_t PrevHIDReportBuffer[GENERIC_REPORT_SIZE]; + +/** LUFA HID Class driver interface configuration and state information. This structure is + * passed to all HID Class driver functions, so that multiple instances of the same class + * within a device can be differentiated from one another. + */ +USB_ClassInfo_HID_Device_t Generic_HID_Interface = + { + .Config = + { + .InterfaceNumber = 1, + + .ReportINEndpointNumber = GENERIC_IN_EPNUM, + .ReportINEndpointSize = GENERIC_EPSIZE, + .ReportINEndpointDoubleBank = false, + + .PrevReportINBuffer = PrevHIDReportBuffer, + .PrevReportINBufferSize = sizeof(PrevHIDReportBuffer), + }, + }; + +/** Non-volatile Logging Interval value in EEPROM, stored as a number of 500ms ticks */ +uint8_t EEMEM LoggingInterval500MS_EEPROM; + +/** SRAM Logging Interval value fetched from EEPROM, stored as a number of 500ms ticks */ +uint8_t LoggingInterval500MS_SRAM; + +/** Total number of 500ms logging ticks elapsed since the last log value was recorded */ +uint16_t CurrentLoggingTicks; + /** FAT Fs structure to hold the internal state of the FAT driver for the dataflash contents. */ FATFS DiskFATState; /** FAT Fs structure to hold a FAT file handle for the log data write destination. */ FIL TempLogFile; -/** Counter to count the number of 10 millisecond ticks that has elapsed since the last sample */ -uint16_t CurrentLogTick; - ISR(TIMER1_COMPA_vect, ISR_BLOCK) { - if (CurrentLogTick++ != LOG_INTERVAL_10MS) - return; - uint8_t LEDMask = LEDs_GetLEDs(); + /* Check to see if the logging interval has expired */ + if (CurrentLoggingTicks++ < LoggingInterval500MS_SRAM) + return; + LEDs_SetAllLEDs(LEDMASK_USB_BUSY); - CurrentLogTick = 0; - + /* Reset log tick counter to prepare for next logging interval */ + CurrentLoggingTicks = 0; + if (USB_DeviceState == DEVICE_STATE_Unattached) { - f_printf(&TempLogFile, "%d Degrees\r\n", Temperature_GetTemperature()); + uint8_t Day, Month, Year; + uint8_t Hour, Minute, Second; + + DS1307_GetDate(&Day, &Month, &Year); + DS1307_GetTime(&Hour, &Minute, &Second); + + char LineBuffer[100]; + uint16_t BytesWritten; + + BytesWritten = sprintf(LineBuffer, "%02d/%02d/20%04d, %02d:%02d:%02d, %d Degrees\r\n", + Day, Month, Year, Hour, Minute, Second, Temperature_GetTemperature()); + + f_write(&TempLogFile, LineBuffer, BytesWritten, &BytesWritten); f_sync(&TempLogFile); } LEDs_SetAllLEDs(LEDMask); } - /** Main program entry point. This routine contains the overall program flow, including initial * setup of all components and the main program loop. */ int main(void) { - SetupHardware(); + /* Fetch logging interval from EEPROM */ + LoggingInterval500MS_SRAM = eeprom_read_byte(&LoggingInterval500MS_EEPROM); LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); + SetupHardware(); + /* Mount and open the log file on the dataflash FAT partition */ - f_mount(0, &DiskFATState); - f_open(&TempLogFile, LOG_FILENAME, FA_OPEN_ALWAYS | FA_WRITE); - f_lseek(&TempLogFile, TempLogFile.fsize); - f_printf(&TempLogFile, "===========================\r\n"); - + OpenLogFile(); + /* Discard the first sample from the temperature sensor, as it is generally incorrect */ uint8_t Dummy = Temperature_GetTemperature(); (void)Dummy; @@ -111,10 +152,33 @@ int main(void) for (;;) { MS_Device_USBTask(&Disk_MS_Interface); + HID_Device_USBTask(&Generic_HID_Interface); USB_USBTask(); } } +void OpenLogFile(void) +{ + char LogFileName[12]; + + /* Get the current date for the filename as "DDMMYY.csv" */ + uint8_t Day, Month, Year; + DS1307_GetDate(&Day, &Month, &Year); + sprintf(LogFileName, "%02d%02d%02d.csv", Day, Month, Year); + + /* Mount the storage device, open the file */ + f_mount(0, &DiskFATState); + f_open(&TempLogFile, LogFileName, FA_OPEN_ALWAYS | FA_WRITE); + f_lseek(&TempLogFile, TempLogFile.fsize); +} + +void CloseLogFile(void) +{ + /* Sync any data waiting to be written, unmount the storage device */ + f_sync(&TempLogFile); + f_close(&TempLogFile); +} + /** Configures the board hardware and chip peripherals for the demo's functionality. */ void SetupHardware(void) { @@ -133,9 +197,9 @@ void SetupHardware(void) Dataflash_Init(); USB_Init(); - /* 10ms interval timer configuration */ - OCR1A = (((F_CPU / 1024) / 100) - 1); - TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); // CTC mode, Fcpu/1024 speed + /* 500ms logging interval timer configuration */ + OCR1A = ((F_CPU / 1024) / 2); + TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); TIMSK1 = (1 << OCIE1A); /* Clear Dataflash sector protections, if enabled */ @@ -148,7 +212,7 @@ void EVENT_USB_Device_Connect(void) LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); /* Close the log file so that the host has exclusive filesystem access */ - f_close(&TempLogFile); + CloseLogFile(); } /** Event handler for the library USB Disconnection event. */ @@ -156,11 +220,8 @@ void EVENT_USB_Device_Disconnect(void) { LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); - /* When disconnected from the host, re-open log file so we can resume logging */ - f_mount(0, &DiskFATState); - f_open(&TempLogFile, LOG_FILENAME, FA_OPEN_ALWAYS | FA_WRITE); - f_lseek(&TempLogFile, TempLogFile.fsize); - f_printf(&TempLogFile, "===========================\r\n"); + /* Mount and open the log file on the dataflash FAT partition */ + OpenLogFile(); } /** Event handler for the library USB Configuration Changed event. */ @@ -170,12 +231,16 @@ void EVENT_USB_Device_ConfigurationChanged(void) if (!(MS_Device_ConfigureEndpoints(&Disk_MS_Interface))) LEDs_SetAllLEDs(LEDMASK_USB_ERROR); + + if (!(HID_Device_ConfigureEndpoints(&Generic_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } /** Event handler for the library USB Unhandled Control Request event. */ void EVENT_USB_Device_UnhandledControlRequest(void) { MS_Device_ProcessControlRequest(&Disk_MS_Interface); + HID_Device_ProcessControlRequest(&Generic_HID_Interface); } /** Mass Storage class driver callback function the reception of SCSI commands from the host, which must be processed. @@ -192,3 +257,53 @@ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfa return CommandSuccess; } + +/** HID class driver callback function for the creation of HID reports to the host. + * + * \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced + * \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID + * \param[in] ReportType Type of the report to create, either REPORT_ITEM_TYPE_In or REPORT_ITEM_TYPE_Feature + * \param[out] ReportData Pointer to a buffer where the created report should be stored + * \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent + * + * \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent + */ +bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, + const uint8_t ReportType, void* ReportData, uint16_t* ReportSize) +{ + Device_Report_t* ReportParams = (Device_Report_t*)ReportData; + + DS1307_GetDate(&ReportParams->Day, &ReportParams->Month, &ReportParams->Year); + DS1307_GetTime(&ReportParams->Hour, &ReportParams->Minute, &ReportParams->Second); + + ReportParams->LogInterval500MS = LoggingInterval500MS_SRAM; + + *ReportSize = sizeof(Device_Report_t); + return true; +} + +/** HID class driver callback function for the processing of HID reports from the host. + * + * \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced + * \param[in] ReportID Report ID of the received report from the host + * \param[in] ReportData Pointer to a buffer where the created report has been stored + * \param[in] ReportSize Size in bytes of the received HID report + */ +void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, + const void* ReportData, const uint16_t ReportSize) +{ + Device_Report_t* ReportParams = (Device_Report_t*)ReportData; + + GPIOR0 = ReportParams->Day; + GPIOR1 = ReportParams->Month; + GPIOR2 = ReportParams->Year; + + DS1307_SetDate(ReportParams->Day, ReportParams->Month, ReportParams->Year); + DS1307_SetTime(ReportParams->Hour, ReportParams->Minute, ReportParams->Second); + + if (LoggingInterval500MS_SRAM != ReportParams->LogInterval500MS) + { + LoggingInterval500MS_SRAM = ReportParams->LogInterval500MS; + eeprom_write_byte(&LoggingInterval500MS_EEPROM, LoggingInterval500MS_SRAM); + } +} diff --git a/Projects/TemperatureDataLogger/TempDataLogger.h b/Projects/TemperatureDataLogger/TempDataLogger.h index b9d1b9114d..ee10a09713 100644 --- a/Projects/TemperatureDataLogger/TempDataLogger.h +++ b/Projects/TemperatureDataLogger/TempDataLogger.h @@ -40,12 +40,14 @@ #include #include #include - + #include + #include "Descriptors.h" #include "Lib/SCSI.h" #include "Lib/DataflashManager.h" #include "Lib/FATFs/ff.h" + #include "Lib/DS1307.h" #include #include @@ -53,6 +55,7 @@ #include #include #include + #include /* Macros: */ /** LED mask for the library LED driver, to indicate that the USB interface is not ready. */ @@ -76,8 +79,24 @@ /** Data log interval between samples, in tens of milliseconds */ #define LOG_INTERVAL_10MS 1000 + /* Type Defines: */ + typedef struct + { + uint8_t Day; + uint8_t Month; + uint8_t Year; + + uint8_t Hour; + uint8_t Minute; + uint8_t Second; + + uint8_t LogInterval500MS; + } Device_Report_t; + /* Function Prototypes: */ void SetupHardware(void); + void OpenLogFile(void); + void CloseLogFile(void); void EVENT_USB_Device_Connect(void); void EVENT_USB_Device_Disconnect(void); @@ -85,5 +104,9 @@ void EVENT_USB_Device_UnhandledControlRequest(void); bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfaceInfo); + bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, + const uint8_t ReportType, void* ReportData, uint16_t* ReportSize); + void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, + const void* ReportData, const uint16_t ReportSize); #endif diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.sln b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.sln new file mode 100644 index 0000000000..f3fbdb2cf6 --- /dev/null +++ b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TempLoggerHostApp", "TempLoggerHostApp\TempLoggerHostApp.csproj", "{A2D66069-8CF9-4104-828C-49A73D7DB5D1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A2D66069-8CF9-4104-828C-49A73D7DB5D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2D66069-8CF9-4104-828C-49A73D7DB5D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2D66069-8CF9-4104-828C-49A73D7DB5D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2D66069-8CF9-4104-828C-49A73D7DB5D1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.suo b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp.suo new file mode 100644 index 0000000000000000000000000000000000000000..647c7e68a7d5f2071f9ec436be891da64d469e33 GIT binary patch literal 17408 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≧#TN4Ox?G9QgFQkpWT7eFZUHBYbj53Ic-TP1tj~7dL+?jre z%}UA7lLf6tp?HZx%l8)>&y=))%?@i-*sg(A!%Dlo)+*mSZd0ad()&tPs%F+O{?0>? zPSy%f3TYB|xD{;e6>@uqs?E(xMi^l@#^P8Flfxw{uLkc{YPsH3?LRoi2o^y4cfwfL zO5CEWid)=RuUR7znF@)JH4DOEEJ41+E=3V%4za92M89P6gete=lTRktix{kIxTKs-} zu$>>@wPx?MSHVx)NZC$5zm4>d<90?T(!4>Otv~6J&6SP(g ysip93P1bk4Gc&8fe7w!tFJ}ki1~to-8oM~2eC0mv=CFB+`g@X=v-fi)WcPnDi#%cg literal 0 HcmV?d00001 diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.Designer.cs b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.Designer.cs new file mode 100644 index 0000000000..c6b106f98f --- /dev/null +++ b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.Designer.cs @@ -0,0 +1,181 @@ +namespace Project1HostApp +{ + partial class frmDataloggerSettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnSetValues = new System.Windows.Forms.Button(); + this.dtpTime = new System.Windows.Forms.DateTimePicker(); + this.lblTime = new System.Windows.Forms.Label(); + this.lblLoggingInterval = new System.Windows.Forms.Label(); + this.nudLogInterval = new System.Windows.Forms.NumericUpDown(); + this.lblSeconds = new System.Windows.Forms.Label(); + this.btnGetValues = new System.Windows.Forms.Button(); + this.lblDate = new System.Windows.Forms.Label(); + this.dtpDate = new System.Windows.Forms.DateTimePicker(); + ((System.ComponentModel.ISupportInitialize)(this.nudLogInterval)).BeginInit(); + this.SuspendLayout(); + // + // btnSetValues + // + this.btnSetValues.Location = new System.Drawing.Point(168, 136); + this.btnSetValues.Name = "btnSetValues"; + this.btnSetValues.Size = new System.Drawing.Size(90, 35); + this.btnSetValues.TabIndex = 0; + this.btnSetValues.Text = "Set Values"; + this.btnSetValues.UseVisualStyleBackColor = true; + this.btnSetValues.Click += new System.EventHandler(this.btnSetValues_Click); + // + // dtpTime + // + this.dtpTime.CustomFormat = ""; + this.dtpTime.Format = System.Windows.Forms.DateTimePickerFormat.Time; + this.dtpTime.Location = new System.Drawing.Point(148, 61); + this.dtpTime.Name = "dtpTime"; + this.dtpTime.ShowUpDown = true; + this.dtpTime.Size = new System.Drawing.Size(110, 20); + this.dtpTime.TabIndex = 1; + // + // lblTime + // + this.lblTime.AutoSize = true; + this.lblTime.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTime.Location = new System.Drawing.Point(51, 67); + this.lblTime.Name = "lblTime"; + this.lblTime.Size = new System.Drawing.Size(82, 13); + this.lblTime.TabIndex = 2; + this.lblTime.Text = "Device Time:"; + // + // lblLoggingInterval + // + this.lblLoggingInterval.AutoSize = true; + this.lblLoggingInterval.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblLoggingInterval.Location = new System.Drawing.Point(30, 101); + this.lblLoggingInterval.Name = "lblLoggingInterval"; + this.lblLoggingInterval.Size = new System.Drawing.Size(103, 13); + this.lblLoggingInterval.TabIndex = 3; + this.lblLoggingInterval.Text = "Logging Interval:"; + // + // nudLogInterval + // + this.nudLogInterval.Location = new System.Drawing.Point(148, 94); + this.nudLogInterval.Maximum = new decimal(new int[] { + 60, + 0, + 0, + 0}); + this.nudLogInterval.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.nudLogInterval.Name = "nudLogInterval"; + this.nudLogInterval.Size = new System.Drawing.Size(51, 20); + this.nudLogInterval.TabIndex = 5; + this.nudLogInterval.Value = new decimal(new int[] { + 5, + 0, + 0, + 0}); + // + // lblSeconds + // + this.lblSeconds.AutoSize = true; + this.lblSeconds.Location = new System.Drawing.Point(209, 101); + this.lblSeconds.Name = "lblSeconds"; + this.lblSeconds.Size = new System.Drawing.Size(49, 13); + this.lblSeconds.TabIndex = 6; + this.lblSeconds.Text = "Seconds"; + // + // btnGetValues + // + this.btnGetValues.Location = new System.Drawing.Point(30, 136); + this.btnGetValues.Name = "btnGetValues"; + this.btnGetValues.Size = new System.Drawing.Size(90, 35); + this.btnGetValues.TabIndex = 7; + this.btnGetValues.Text = "Get Values"; + this.btnGetValues.UseVisualStyleBackColor = true; + this.btnGetValues.Click += new System.EventHandler(this.btnGetValues_Click); + // + // lblDate + // + this.lblDate.AutoSize = true; + this.lblDate.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblDate.Location = new System.Drawing.Point(51, 33); + this.lblDate.Name = "lblDate"; + this.lblDate.Size = new System.Drawing.Size(82, 13); + this.lblDate.TabIndex = 8; + this.lblDate.Text = "Device Date:"; + // + // dtpDate + // + this.dtpDate.CustomFormat = "dd/MM/yyyy"; + this.dtpDate.Format = System.Windows.Forms.DateTimePickerFormat.Custom; + this.dtpDate.Location = new System.Drawing.Point(148, 27); + this.dtpDate.Name = "dtpDate"; + this.dtpDate.Size = new System.Drawing.Size(110, 20); + this.dtpDate.TabIndex = 9; + // + // frmDataloggerSettings + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(300, 197); + this.Controls.Add(this.dtpDate); + this.Controls.Add(this.lblDate); + this.Controls.Add(this.btnGetValues); + this.Controls.Add(this.lblSeconds); + this.Controls.Add(this.nudLogInterval); + this.Controls.Add(this.lblLoggingInterval); + this.Controls.Add(this.lblTime); + this.Controls.Add(this.dtpTime); + this.Controls.Add(this.btnSetValues); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "frmDataloggerSettings"; + this.Text = "DataLogger"; + this.Load += new System.EventHandler(this.frmDataloggerSettings_Load); + ((System.ComponentModel.ISupportInitialize)(this.nudLogInterval)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnSetValues; + private System.Windows.Forms.DateTimePicker dtpTime; + private System.Windows.Forms.Label lblTime; + private System.Windows.Forms.Label lblLoggingInterval; + private System.Windows.Forms.NumericUpDown nudLogInterval; + private System.Windows.Forms.Label lblSeconds; + private System.Windows.Forms.Button btnGetValues; + private System.Windows.Forms.Label lblDate; + private System.Windows.Forms.DateTimePicker dtpDate; + } +} + diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.cs b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.cs new file mode 100644 index 0000000000..370dfbd69f --- /dev/null +++ b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using Hid; + +namespace Project1HostApp +{ + public partial class frmDataloggerSettings : Form + { + private const int DEVICE_VID = 0x03EB; + private const int DEVICE_PID = 0xFAFA; + + private struct Device_Report_t + { + public Byte Day; + public Byte Month; + public Byte Year; + + public Byte Hour; + public Byte Minute; + public Byte Second; + + public Byte LogInterval500MS; + + public Byte[] ToReport() + { + Byte[] Report = new Byte[7]; + + Report[0] = this.Day; + Report[1] = this.Month; + Report[2] = this.Year; + Report[3] = this.Hour; + Report[4] = this.Minute; + Report[5] = this.Second; + Report[6] = this.LogInterval500MS; + + return Report; + } + + public void FromReport(Byte[] Report) + { + this.Day = Report[0]; + this.Month = Report[1]; + this.Year = Report[2]; + this.Hour = Report[3]; + this.Minute = Report[4]; + this.Second = Report[5]; + this.LogInterval500MS = Report[6]; + } + }; + + private IDevice GetDeviceConnection() + { + IDevice[] ConnectedDevices = DeviceFactory.Enumerate(DEVICE_VID, DEVICE_PID); + IDevice ConnectionHandle = null; + + if (ConnectedDevices.Count() > 0) + ConnectionHandle = ConnectedDevices[0]; + else + return null; + + // Fix report handle under Windows + if (ConnectionHandle is Hid.Win32.Win32DeviceSet) + { + ((Hid.Win32.Win32DeviceSet)ConnectionHandle).AddDevice(0x00, + ((Hid.Win32.Win32DeviceSet)ConnectionHandle).UnallocatedDevices[0]); + } + + return ConnectionHandle; + } + + public frmDataloggerSettings() + { + InitializeComponent(); + } + + private void btnSetValues_Click(object sender, EventArgs e) + { + IDevice ConnectionHandle = GetDeviceConnection(); + + if (ConnectionHandle == null) + { + MessageBox.Show("Error: Cannot connect to DataLogger device."); + return; + } + + Device_Report_t DeviceReport = new Device_Report_t(); + DeviceReport.Day = (byte)dtpDate.Value.Day; + DeviceReport.Month = (byte)dtpDate.Value.Month; + DeviceReport.Year = (byte)((dtpDate.Value.Year < 2000) ? 0 : (dtpDate.Value.Year - 2000)); + DeviceReport.Hour = (byte)dtpTime.Value.Hour; + DeviceReport.Minute = (byte)dtpTime.Value.Minute; + DeviceReport.Second = (byte)dtpTime.Value.Second; + DeviceReport.LogInterval500MS = (byte)(nudLogInterval.Value * 2); + + try + { + ConnectionHandle.Write(0x00, DeviceReport.ToReport()); + MessageBox.Show("Device parameters updated sucessfully."); + } + catch (Exception ex) + { + MessageBox.Show("Error: " + ex.Message); + } + } + + private void btnGetValues_Click(object sender, EventArgs e) + { + IDevice ConnectionHandle = GetDeviceConnection(); + + if (ConnectionHandle == null) + { + MessageBox.Show("Error: Cannot connect to DataLogger device."); + return; + } + + Device_Report_t DeviceReport = new Device_Report_t(); + + try + { + Byte[] Report = new Byte[7]; + + ConnectionHandle.Read(0x00, Report); + DeviceReport.FromReport(Report); + + try + { + dtpDate.Value = new DateTime( + (2000 + DeviceReport.Year), + DeviceReport.Month, + DeviceReport.Day); + + dtpTime.Value = new DateTime( + DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, + DeviceReport.Hour, + DeviceReport.Minute, + DeviceReport.Second); + } + catch (Exception ex) + { + dtpDate.Value = DateTime.Now; + dtpTime.Value = DateTime.Now; + } + + try + { + nudLogInterval.Value = (DeviceReport.LogInterval500MS / 2); + } + catch (Exception ex) + { + nudLogInterval.Value = nudLogInterval.Minimum; + } + + MessageBox.Show("Device parameters retrieved sucessfully."); + } + catch (Exception ex) + { + MessageBox.Show("Error: " + ex.Message); + } + } + + private void frmDataloggerSettings_Load(object sender, EventArgs e) + { + + } + } +} diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.resx b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.resx new file mode 100644 index 0000000000..ff31a6db56 --- /dev/null +++ b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/DataLoggerSettings.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Linux.dll b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Linux.dll new file mode 100644 index 0000000000000000000000000000000000000000..4c19edd212c44e0c785bcd621e3d290e79159d83 GIT binary patch literal 9216 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 R$^RKpd1C+k`k9Ns{{nZKK9~Ri literal 0 HcmV?d00001 diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Net.dll b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Net.dll new file mode 100644 index 0000000000000000000000000000000000000000..2a7112fc090f3a60ad10d974f4771077612ca61e GIT binary patch literal 24576 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 Via;p>r3jQFP>Mh)0`DdQ{|Rcpa8CdL literal 0 HcmV?d00001 diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Win32.dll b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Hid.Win32.dll new file mode 100644 index 0000000000000000000000000000000000000000..3693c6ca04e053021ad62856d2b60034e8085d86 GIT binary patch literal 94208 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 z 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 HpuqnDlGl2| literal 0 HcmV?d00001 diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Program.cs b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Program.cs new file mode 100644 index 0000000000..dc818c822e --- /dev/null +++ b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace Project1HostApp +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new frmDataloggerSettings()); + } + } +} diff --git a/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/TempLoggerHostApp.csproj b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/TempLoggerHostApp.csproj new file mode 100644 index 0000000000..e3b08928f8 --- /dev/null +++ b/Projects/TemperatureDataLogger/TempLoggerHostApp/TempLoggerHostApp/TempLoggerHostApp.csproj @@ -0,0 +1,95 @@ + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {A2D66069-8CF9-4104-828C-49A73D7DB5D1} + WinExe + Properties + TemperatureLoggerHostApp + TemperatureLoggerHostApp + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + .\Hid.Net.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + Form + + + DataLoggerSettings.cs + + + + + DataLoggerSettings.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + \ No newline at end of file diff --git a/Projects/TemperatureDataLogger/TemperatureDataLogger.txt b/Projects/TemperatureDataLogger/TemperatureDataLogger.txt index d31e24f36d..3e13fd3853 100644 --- a/Projects/TemperatureDataLogger/TemperatureDataLogger.txt +++ b/Projects/TemperatureDataLogger/TemperatureDataLogger.txt @@ -24,12 +24,14 @@ * Device * * - * USB Class: + * USB Classes: * Mass Storage Device + * Human Interface Device * * - * USB Subclass: + * USB Subclasses: * Bulk-Only Transport + * Keyboard Subclass * * * Relevant Standards: @@ -37,6 +39,7 @@ * USB Bulk-Only Transport Standard * SCSI Primary Commands Specification * SCSI Block Commands Specification + * USBIF HID Specification, USBIF HID Usage Tables * * * Usable Speeds: @@ -49,10 +52,12 @@ * Temperature Data Logger project. This project is a very basic USB data logger for the current temperature as reported by * the board's temperature sensor, writing the temperature to a file stored on the board's Dataflash in a FAT filesystem * each time a specified interval elapses. When inserted into a PC, the datalogger will appear as a standard USB Mass Storage - * device with a single text file, which contains the logged data. + * device with a single text file, which contains the logged data. Files are named according to the current date when the + * logging commences. * - * Currently there is no timestamp associated with the logged data; this project can be extended by the addition of a Real - * Time Clock chip to retain the current time/date which could be stored along with each sample. + * A DS1307 or compatible RTC IC is designed to be attached to the AVR's TWI bus, for the management of timestamps on the + * sampled data. This project will not function correctly if the RTC chip is omitted unless the DUMMY_RTC compile time token + * is specified - see \ref SSec_Options. * * Due to the host's need for exclusive access to the filesystem, the device will not log samples while connected to a host. * For the logger to store data, the Dataflash must first be formatted by the host so that it contains a valid FAT filesystem. @@ -68,16 +73,10 @@ * Description: * * - * LOG_FILENAME - * TempDataLogger.h - * Filename of the log file to write to on the device's FAT filesystem. - * - * - * LOG_INTERVAL_10MS - * TempDataLogger.h - * Time between each data sample, in tens of milliseconds. Each time this period elapses, a - * temperature sample is taken and the result stored to the Dataflash's FAT filesystem. - * + * DUMMY_RTC + * Makefile CDEFS + * When a DS1307 RTC chip is not fitted, this token can be defined to make the demo assume a 1/1/1 01:01:01 date/time + * stamp at all times, effectively transforming the project into a basic data logger with no specified sample times. * * */ diff --git a/Projects/TemperatureDataLogger/makefile b/Projects/TemperatureDataLogger/makefile index 1e495526c1..ab29bb1bea 100644 --- a/Projects/TemperatureDataLogger/makefile +++ b/Projects/TemperatureDataLogger/makefile @@ -130,6 +130,7 @@ SRC = $(TARGET).c \ Lib/SCSI.c \ Lib/FATFs/diskio.c \ Lib/FATFs/ff.c \ + Lib/DS1307.c \ $(LUFA_PATH)/LUFA/Drivers/Board/Temperature.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \ @@ -143,6 +144,8 @@ SRC = $(TARGET).c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \ $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/MassStorage.c \ $(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/MassStorage.c \ + $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/HID.c \ + $(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/HID.c \ # List C++ source files here. (C dependencies are automatically generated.)