/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 2011,2012,2013 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT 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 3 of the License, or (at your option) any later version. ChibiOS/RT 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "ch.h" #include "hal.h" #include "usb_cdc.h" #include "shell.h" #include "chprintf.h" #include "chrtclib.h" #include "ff.h" /*===========================================================================*/ /* USB related stuff. */ /*===========================================================================*/ /* * Serial over USB Driver structure. */ static SerialUSBDriver SDU1; /* * USB Device Descriptor. */ static const uint8_t vcom_device_descriptor_data[18] = { USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ 0x02, /* bDeviceClass (CDC). */ 0x00, /* bDeviceSubClass. */ 0x00, /* bDeviceProtocol. */ 0x40, /* bMaxPacketSize. */ 0x0483, /* idVendor (ST). */ 0x5740, /* idProduct. */ 0x0200, /* bcdDevice. */ 1, /* iManufacturer. */ 2, /* iProduct. */ 3, /* iSerialNumber. */ 1) /* bNumConfigurations. */ }; /* * Device Descriptor wrapper. */ static const USBDescriptor vcom_device_descriptor = { sizeof vcom_device_descriptor_data, vcom_device_descriptor_data }; /* Configuration Descriptor tree for a CDC.*/ static const uint8_t vcom_configuration_descriptor_data[67] = { /* Configuration Descriptor.*/ USB_DESC_CONFIGURATION(67, /* wTotalLength. */ 0x02, /* bNumInterfaces. */ 0x01, /* bConfigurationValue. */ 0, /* iConfiguration. */ 0xC0, /* bmAttributes (self powered). */ 50), /* bMaxPower (100mA). */ /* Interface Descriptor.*/ USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ 0x00, /* bAlternateSetting. */ 0x01, /* bNumEndpoints. */ 0x02, /* bInterfaceClass (Communications Interface Class, CDC section 4.2). */ 0x02, /* bInterfaceSubClass (Abstract Control Model, CDC section 4.3). */ 0x01, /* bInterfaceProtocol (AT commands, CDC section 4.4). */ 0), /* iInterface. */ /* Header Functional Descriptor (CDC section 5.2.3).*/ USB_DESC_BYTE (5), /* bLength. */ USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header Functional Descriptor. */ USB_DESC_BCD (0x0110), /* bcdCDC. */ /* Call Management Functional Descriptor. */ USB_DESC_BYTE (5), /* bFunctionLength. */ USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management Functional Descriptor). */ USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ USB_DESC_BYTE (0x01), /* bDataInterface. */ /* ACM Functional Descriptor.*/ USB_DESC_BYTE (4), /* bFunctionLength. */ USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract Control Management Descriptor). */ USB_DESC_BYTE (0x02), /* bmCapabilities. */ /* Union Functional Descriptor.*/ USB_DESC_BYTE (5), /* bFunctionLength. */ USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union Functional Descriptor). */ USB_DESC_BYTE (0x00), /* bMasterInterface (Communication Class Interface). */ USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class Interface). */ /* Endpoint 2 Descriptor.*/ USB_DESC_ENDPOINT (USB_CDC_INTERRUPT_REQUEST_EP|0x80, 0x03, /* bmAttributes (Interrupt). */ 0x0008, /* wMaxPacketSize. */ 0xFF), /* bInterval. */ /* Interface Descriptor.*/ USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ 0x00, /* bAlternateSetting. */ 0x02, /* bNumEndpoints. */ 0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */ 0x00, /* bInterfaceSubClass (CDC section 4.6). */ 0x00, /* bInterfaceProtocol (CDC section 4.7). */ 0x00), /* iInterface. */ /* Endpoint 3 Descriptor.*/ USB_DESC_ENDPOINT (USB_CDC_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ 0x02, /* bmAttributes (Bulk). */ 0x0040, /* wMaxPacketSize. */ 0x00), /* bInterval. */ /* Endpoint 1 Descriptor.*/ USB_DESC_ENDPOINT (USB_CDC_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ 0x02, /* bmAttributes (Bulk). */ 0x0040, /* wMaxPacketSize. */ 0x00) /* bInterval. */ }; /* * Configuration Descriptor wrapper. */ static const USBDescriptor vcom_configuration_descriptor = { sizeof vcom_configuration_descriptor_data, vcom_configuration_descriptor_data }; /* * U.S. English language identifier. */ static const uint8_t vcom_string0[] = { USB_DESC_BYTE(4), /* bLength. */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ }; /* * Vendor string. */ static const uint8_t vcom_string1[] = { USB_DESC_BYTE(38), /* bLength. */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, 'c', 0, 's', 0 }; /* * Device Description string. */ static const uint8_t vcom_string2[] = { USB_DESC_BYTE(56), /* bLength. */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, 'o', 0, 'r', 0, 't', 0 }; /* * Serial Number string. */ static const uint8_t vcom_string3[] = { USB_DESC_BYTE(8), /* bLength. */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ '0' + CH_KERNEL_MAJOR, 0, '0' + CH_KERNEL_MINOR, 0, '0' + CH_KERNEL_PATCH, 0 }; /* * Strings wrappers array. */ static const USBDescriptor vcom_strings[] = { {sizeof vcom_string0, vcom_string0}, {sizeof vcom_string1, vcom_string1}, {sizeof vcom_string2, vcom_string2}, {sizeof vcom_string3, vcom_string3} }; /* * Handles the GET_DESCRIPTOR callback. All required descriptors must be * handled here. */ static const USBDescriptor *get_descriptor(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) { (void)usbp; (void)lang; switch (dtype) { case USB_DESCRIPTOR_DEVICE: return &vcom_device_descriptor; case USB_DESCRIPTOR_CONFIGURATION: return &vcom_configuration_descriptor; case USB_DESCRIPTOR_STRING: if (dindex < 4) return &vcom_strings[dindex]; } return NULL; } /** * @brief IN EP1 state. */ static USBInEndpointState ep1instate; /** * @brief OUT EP1 state. */ static USBOutEndpointState ep1outstate; /** * @brief EP1 initialization structure (both IN and OUT). */ static const USBEndpointConfig ep1config = { USB_EP_MODE_TYPE_BULK, NULL, sduDataTransmitted, sduDataReceived, 0x0040, 0x0040, &ep1instate, &ep1outstate, 1, NULL }; /** * @brief IN EP2 state. */ static USBInEndpointState ep2instate; /** * @brief EP2 initialization structure (IN only). */ static const USBEndpointConfig ep2config = { USB_EP_MODE_TYPE_INTR, NULL, sduInterruptTransmitted, NULL, 0x0010, 0x0000, &ep2instate, NULL, 1, NULL }; /* * Handles the USB driver global events. */ static void usb_event(USBDriver *usbp, usbevent_t event) { switch (event) { case USB_EVENT_RESET: return; case USB_EVENT_ADDRESS: return; case USB_EVENT_CONFIGURED: chSysLockFromIsr(); /* Enables the endpoints specified into the configuration. Note, this callback is invoked from an ISR so I-Class functions must be used.*/ usbInitEndpointI(usbp, USB_CDC_DATA_REQUEST_EP, &ep1config); usbInitEndpointI(usbp, USB_CDC_INTERRUPT_REQUEST_EP, &ep2config); /* Resetting the state of the CDC subsystem.*/ sduConfigureHookI(usbp); chSysUnlockFromIsr(); return; case USB_EVENT_SUSPEND: return; case USB_EVENT_WAKEUP: return; case USB_EVENT_STALLED: return; } return; } /* * USB driver configuration. */ static const USBConfig usbcfg = { usb_event, get_descriptor, sduRequestsHook, NULL }; /* * Serial over USB driver configuration. */ static const SerialUSBConfig serusbcfg = { &USBD1 }; /** * @brief FS object. */ FATFS MMC_FS; /** * MMC driver instance. */ MMCDriver MMCD1; /* FS mounted and ready.*/ static bool_t fs_ready = FALSE; /* Maximum speed SPI configuration (18MHz, CPHA=0, CPOL=0, MSb first).*/ static SPIConfig hs_spicfg = {NULL, IOPORT2, GPIOB_SPI2NSS, 0}; /* Low speed SPI configuration (281.250kHz, CPHA=0, CPOL=0, MSb first).*/ static SPIConfig ls_spicfg = {NULL, IOPORT2, GPIOB_SPI2NSS, SPI_CR1_BR_2 | SPI_CR1_BR_1}; /* MMC/SD over SPI driver configuration.*/ static MMCConfig mmccfg = {&SPID2, &ls_spicfg, &hs_spicfg}; /** * */ bool_t mmc_lld_is_write_protected(MMCDriver *sdcp) { (void)sdcp; return FALSE; } /** * */ bool_t mmc_lld_is_card_inserted(MMCDriver *sdcp) { (void)sdcp; return !palReadPad(GPIOC, GPIOC_MMCCP); } /** * */ void cmd_sdiotest(BaseSequentialStream *chp, int argc, char *argv[]){ (void)argc; (void)argv; FRESULT err; uint32_t clusters; FATFS *fsp; FIL FileObject; //FILINFO FileInfo; size_t bytes_written; struct tm timp; // set time to 2011-03-13 07:06:40 //rtcSetTimeUnixSec(&RTCD1, 1300000000); #if !HAL_USE_RTC chprintf(chp, "ERROR! Chibios compiled without RTC support."); chprintf(chp, "Enable HAL_USE_RCT in you halconf.h"); chThdSleepMilliseconds(100); return; #endif chprintf(chp, "Trying to connect SDIO... "); chThdSleepMilliseconds(100); if (!mmcConnect(&MMCD1)) { chprintf(chp, "OK\r\n"); chprintf(chp, "Register working area for filesystem... "); chThdSleepMilliseconds(100); err = f_mount(0, &MMC_FS); if (err != FR_OK){ chSysHalt(); } else{ fs_ready = TRUE; chprintf(chp, "OK\r\n"); } chprintf(chp, "Mounting filesystem... "); chThdSleepMilliseconds(100); err = f_getfree("/", &clusters, &fsp); if (err != FR_OK) { chSysHalt(); } chprintf(chp, "OK\r\n"); chprintf(chp, "FS: %lu free clusters, %lu sectors per cluster, %lu bytes free\r\n", clusters, (uint32_t)MMC_FS.csize, clusters * (uint32_t)MMC_FS.csize * (uint32_t)MMCSD_BLOCK_SIZE); rtcGetTimeTm(&RTCD1, &timp); chprintf(chp, "Current RTC time is: "); chprintf(chp, "%u-%u-%u %u:%u:%u\r\n", timp.tm_year+1900, timp.tm_mon+1, timp.tm_mday, timp.tm_hour, timp.tm_min, timp.tm_sec); chprintf(chp, "Creating empty file 'tmstmp.tst'... "); chThdSleepMilliseconds(100); err = f_open(&FileObject, "0:tmstmp.tst", FA_WRITE | FA_OPEN_ALWAYS); if (err != FR_OK) { chSysHalt(); } chprintf(chp, "OK\r\n"); chprintf(chp, "Write some data in it... "); chThdSleepMilliseconds(100); err = f_write(&FileObject, "tst", sizeof("tst"), (void *)&bytes_written); if (err != FR_OK) { chSysHalt(); } else chprintf(chp, "OK\r\n"); chprintf(chp, "Closing file 'tmstmp.tst'... "); chThdSleepMilliseconds(100); err = f_close(&FileObject); if (err != FR_OK) { chSysHalt(); } else chprintf(chp, "OK\r\n"); // chprintf(chp, "Obtaining file info ... "); // chThdSleepMilliseconds(100); // err = f_stat("0:tmstmp.tst", &FileInfo); // if (err != FR_OK) { // chSysHalt(); // } // else{ // chprintf(chp, "OK\r\n"); // chprintf(chp, " Timestamp: %u-%u-%u %u:%u:%u\r\n", // ((FileInfo.fdate >> 9) & 127) + 1980, // (FileInfo.fdate >> 5) & 15, // FileInfo.fdate & 31, // (FileInfo.ftime >> 11) & 31, // (FileInfo.ftime >> 5) & 63, // (FileInfo.ftime & 31) * 2); // } chprintf(chp, "Umounting filesystem... "); f_mount(0, NULL); chprintf(chp, "OK\r\n"); chprintf(chp, "Disconnecting from SDIO..."); chThdSleepMilliseconds(100); if (mmcDisconnect(&MMCD1)) chSysHalt(); chprintf(chp, " OK\r\n"); chprintf(chp, "------------------------------------------------------\r\n"); chprintf(chp, "Now you can remove memory card and check timestamp on PC.\r\n"); chThdSleepMilliseconds(100); } else{ chSysHalt(); } } /*===========================================================================*/ /* Command line related. */ /*===========================================================================*/ #define SHELL_WA_SIZE THD_WA_SIZE(2048) static const ShellCommand commands[] = { {"sdiotest", cmd_sdiotest}, {NULL, NULL} }; static const ShellConfig shell_cfg1 = { (BaseSequentialStream *)&SDU1, commands }; /*===========================================================================*/ /* Generic code. */ /*===========================================================================*/ /* * Application entry point. */ int main(void) { Thread *shelltp = NULL; /* * System initializations. * - HAL initialization, this also initializes the configured device drivers * and performs the board-specific initializations. * - Kernel initialization, the main() function becomes a thread and the * RTOS is active. */ halInit(); chSysInit(); /* * Initializes a serial-over-USB CDC driver. */ sduObjectInit(&SDU1); sduStart(&SDU1, &serusbcfg); /* * Activates the USB driver and then the USB bus pull-up on D+. * Note, a delay is inserted in order to not have to disconnect the cable * after a reset. */ usbDisconnectBus(serusbcfg.usbp); chThdSleepMilliseconds(1000); usbStart(serusbcfg.usbp, &usbcfg); usbConnectBus(serusbcfg.usbp); chThdSleepMilliseconds(100); /* * Shell manager initialization. */ shellInit(); /* * Initializes the SDIO drivers. */ mmcObjectInit(&MMCD1); mmcStart(&MMCD1, &mmccfg); /* * Normal main() thread activity, in this demo it does nothing except * sleeping in a loop and check the button state. */ while (TRUE) { if (!shelltp && (SDU1.config->usbp->state == USB_ACTIVE)) shelltp = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO); else if (chThdTerminated(shelltp)) { chThdRelease(shelltp); /* Recovers memory of the previous shell. */ shelltp = NULL; /* Triggers spawning of a new shell. */ } chThdSleepMilliseconds(1000); } }