Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • analog_gpio
  • card10.cfg
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • config
  • debug_module
  • dir
  • dualcore
  • esb
  • esb_py
  • esb_squashed_nopy
  • fat
  • fatfs-generation
  • fd_ownership
  • fileapi
  • fix-intid
  • freertos-btle
  • fs-deinit
  • gpio_fix
  • hula
  • hwlock_pc
  • jailbreak
  • master
  • moar_blacklist
  • mx_printf
  • poc-reboot
  • schneider/mp-for-old-bl
  • stacksize
  • tidy
  • usb
31 results

Target

Select target project
  • card10/firmware
  • annejan/firmware
  • astro/firmware
  • fpletz/firmware
  • gerd/firmware
  • fleur/firmware
  • swym/firmware
  • l/firmware
  • uberardy/firmware
  • wink/firmware
  • madonius/firmware
  • mot/firmware
  • filid/firmware
  • q3k/firmware
  • hauke/firmware
  • Woazboat/firmware
  • pink/firmware
  • mossmann/firmware
  • omniskop/firmware
  • zenox/firmware
  • trilader/firmware
  • Danukeru/firmware
  • shoragan/firmware
  • zlatko/firmware
  • sistason/firmware
  • datenwolf/firmware
  • bene/firmware
  • amedee/firmware
  • martinling/firmware
  • griffon/firmware
  • chris007/firmware
  • adisbladis/firmware
  • dbrgn/firmware
  • jelly/firmware
  • rnestler/firmware
  • mh/firmware
  • ln/firmware
  • penguineer/firmware
  • monkeydom/firmware
  • jens/firmware
  • jnaulty/firmware
  • jeffmakes/firmware
  • marekventur/firmware
  • pete/firmware
  • h2obrain/firmware
  • DooMMasteR/firmware
  • jackie/firmware
  • prof_r/firmware
  • Draradech/firmware
  • Kartoffel/firmware
  • hinerk/firmware
  • abbradar/firmware
  • JustTB/firmware
  • LuKaRo/firmware
  • iggy/firmware
  • ente/firmware
  • flgr/firmware
  • Lorphos/firmware
  • matejo/firmware
  • ceddral7/firmware
  • danb/firmware
  • joshi/firmware
  • melle/firmware
  • fitch/firmware
  • deurknop/firmware
  • sargon/firmware
  • markus/firmware
  • kloenk/firmware
  • lucaswerkmeister/firmware
  • derf/firmware
  • meh/firmware
  • dx/card10-firmware
  • torben/firmware
  • yuvadm/firmware
  • AndyBS/firmware
  • klausdieter1/firmware
  • katzenparadoxon/firmware
  • xiretza/firmware
  • ole/firmware
  • techy/firmware
  • thor77/firmware
  • TilCreator/firmware
  • fuchsi/firmware
  • dos/firmware
  • yrlf/firmware
  • PetePriority/firmware
  • SuperVirus/firmware
  • sur5r/firmware
  • tazz/firmware
  • Alienmaster/firmware
  • flo_h/firmware
  • baldo/firmware
  • mmu_man/firmware
  • Foaly/firmware
  • sodoku/firmware
  • Guinness/firmware
  • ssp/firmware
  • led02/firmware
  • Stormwind/firmware
  • arist/firmware
  • coon/firmware
  • mdik/firmware
  • pippin/firmware
  • royrobotiks/firmware
  • zigot83/firmware
  • mo_k/firmware
106 results
Select Git revision
  • add_menu_vibration
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • dualcore
  • dx/flatten-config-module
  • dx/meh-bdf-to-stm
  • freertos-btle
  • genofire/ble-follow-py
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bluetooth-app-favorite
  • rahix/bma
  • rahix/user-space-ctx
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/212-reset-hardware-when-entering-repl
  • schneider/ancs
  • schneider/ble-buffers
  • schneider/ble-central
  • schneider/ble-ecg-stream-visu
  • schneider/ble-fixes-2020-3
  • schneider/ble-mini-demo
  • schneider/ble-stability
  • schneider/ble-stability-new-phy
  • schneider/bonding
  • schneider/bonding-fail-if-full
  • schneider/bootloader-update-9a0d158
  • schneider/deepsleep
  • schneider/deepsleep2
  • schneider/deepsleep4
  • schneider/default-main
  • schneider/freertos-list-debug
  • schneider/fundamental-test
  • schneider/iaq-python
  • schneider/ir
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-exception-print
  • schneider/mp-for-old-bl
  • schneider/png
  • schneider/schleicher-test
  • schneider/sdk-0.2.1-11
  • schneider/sdk-0.2.1-7
  • schneider/sleep-display
  • schneider/spo2-playground
  • schneider/stream-locks
  • schneider/v1.17-changelog
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.10
  • v1.11
  • v1.12
  • v1.13
  • v1.14
  • v1.15
  • v1.16
  • v1.17
  • v1.18
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
82 results
Show changes
Commits on Source (4)
  • swym's avatar
    feat(epicardium): add usb module · 811e0fbb
    swym authored
    split three-way:
    
    usb/epc_usb
    ====
    
    Contains device-independent USB implementation, services MAXUSB stack
    and is given the actual USB descriptors & callbacks on initialization.
    Handles USB events and configures/deconfigures the device accordingly
    during the USB setup procedure.
    
    usb/mass_storage & cdcacm
    ====
    
    Contain device-specific implementations, service MAXUSB's device class
    APIs for cdcacm and mass storage.
    Here, mass storage is independent of the underlying storage device.
    
    modules/usb
    ====
    
    Public apic_usb API, configuration and storage device management.
    Defines the actual USB device descriptors and services the upc_usb API.
    
    If we want to add SD card functionality, this would be the place to add
    it.
    811e0fbb
  • swym's avatar
    3ef0e8f6
  • swym's avatar
    a31bc4e7
  • swym's avatar
    fix gcc warning and logging · 5b7abf61
    swym authored
    5b7abf61
Showing
with 1179 additions and 633 deletions
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelay 1 #define INCLUDE_vTaskDelay 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1 #define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTimerPendFunctionCall 1
/* Allow static allocation of data structures */ /* Allow static allocation of data structures */
#define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_STATIC_ALLOCATION 1
......
/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*
* $Id: main.c 32120 2017-11-28 23:51:11Z lorne.smith $
*
*******************************************************************************
*/
/**
* @file main.c
* @brief USB CDC-ACM example
* @details This project creates a virtual COM port, which loops back data sent to it.
* Load the project, connect a cable from the PC to the USB connector
* on the Evaluation Kit, and observe that the PC now recognizes a new COM port.
* A driver for the COM port, if needed, is located in the Driver/ subdirectory.
*
*/
#include <stdio.h>
#include <stddef.h>
#include "mxc_config.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "board.h"
#include "led.h"
#include "usb.h"
#include "usb_event.h"
#include "enumerate.h"
#include "cdc_acm.h"
#include "descriptors.h"
#include "modules/modules.h"
#include "modules/log.h"
#include <errno.h>
/***** Definitions *****/
#define EVENT_ENUM_COMP MAXUSB_NUM_EVENTS
#define BUFFER_SIZE 64
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
/***** Global Data *****/
//SWYM: rename to CDC_xy or put into struct CDC_state
volatile int configured; //SWYM: actually unused...
volatile int suspended;
volatile unsigned int event_flags;
int remote_wake_en;
/***** Function Prototypes *****/
static int setconfig_callback(usb_setup_pkt *sud, void *cbdata);
static int setfeature_callback(usb_setup_pkt *sud, void *cbdata);
static int clrfeature_callback(usb_setup_pkt *sud, void *cbdata);
static int event_callback(maxusb_event_t evt, void *data);
static void usb_app_sleep(void);
static void usb_app_wakeup(void);
static int usb_read_callback(void);
//static void echo_usb(void);
/***** File Scope Variables *****/
/* This EP assignment must match the Configuration Descriptor */
static const acm_cfg_t acm_cfg = {
1, /* EP OUT */
MXC_USBHS_MAX_PACKET, /* OUT max packet size */
2, /* EP IN */
MXC_USBHS_MAX_PACKET, /* IN max packet size */
3, /* EP Notify */
MXC_USBHS_MAX_PACKET, /* Notify max packet size */
};
static volatile int usb_read_complete;
int usb_startup_cb()
{
const sys_cfg_usbhs_t sys_usbhs_cfg = NULL;
return SYS_USBHS_Init(&sys_usbhs_cfg);
}
int usb_shutdown_cb()
{
return SYS_USBHS_Shutdown();
}
/* User-supplied function to delay usec micro-seconds */
void delay_us(unsigned int usec)
{
/* mxc_delay() takes unsigned long, so can't use it directly */
mxc_delay(usec);
}
/******************************************************************************/
int cdcacm_init(void)
{
maxusb_cfg_options_t usb_opts;
/* Initialize state */
configured = 0;
suspended = 0;
event_flags = 0;
remote_wake_en = 0;
/* Start out in full speed */
usb_opts.enable_hs = 0;
usb_opts.delay_us =
delay_us; /* Function which will be used for delays */
usb_opts.init_callback = usb_startup_cb;
usb_opts.shutdown_callback = usb_shutdown_cb;
/* Initialize the usb module */
if (usb_init(&usb_opts) != 0) {
LOG_ERR("cdcacm", "usb_init() failed");
return -EIO;
}
/* Initialize the enumeration module */
if (enum_init() != 0) {
LOG_ERR("cdcacm", "enum_init() failed");
return -EIO;
}
/* Register enumeration data */
enum_register_descriptor(
ENUM_DESC_DEVICE, (uint8_t *)&device_descriptor, 0
);
enum_register_descriptor(
ENUM_DESC_CONFIG, (uint8_t *)&config_descriptor, 0
);
enum_register_descriptor(ENUM_DESC_STRING, lang_id_desc, 0);
enum_register_descriptor(ENUM_DESC_STRING, mfg_id_desc, 1);
enum_register_descriptor(ENUM_DESC_STRING, prod_id_desc, 2);
/* Handle configuration */
enum_register_callback(ENUM_SETCONFIG, setconfig_callback, NULL);
/* Handle feature set/clear */
enum_register_callback(ENUM_SETFEATURE, setfeature_callback, NULL);
enum_register_callback(ENUM_CLRFEATURE, clrfeature_callback, NULL);
/* Initialize the class driver */
if (acm_init(&config_descriptor.comm_interface_descriptor) != 0) {
LOG_ERR("cdcacm", "acm_init() failed");
return -EIO;
}
/* Register callbacks */
usb_event_enable(MAXUSB_EVENT_NOVBUS, event_callback, NULL);
usb_event_enable(MAXUSB_EVENT_VBUS, event_callback, NULL);
acm_register_callback(ACM_CB_READ_READY, usb_read_callback);
usb_read_complete = 0;
/* Start with USB in low power mode */
usb_app_sleep();
/* TODO: Fix priority */
NVIC_SetPriority(USB_IRQn, 6);
NVIC_EnableIRQ(USB_IRQn);
return 0;
}
int cdcacm_num_read_avail(void)
{
return acm_canread();
}
uint8_t cdcacm_read(void)
{
while (acm_canread() <= 0) {
}
uint8_t buf;
acm_read(&buf, 1);
return buf;
}
void cdcacm_write(uint8_t *data, int len)
{
static int lockup_disable = 0;
if (acm_present() && !lockup_disable) {
int ret = acm_write(data, len);
if (ret < 0) {
lockup_disable = 1;
LOG_ERR("cdcacm", "fifo lockup detected");
} else if (ret != len) {
LOG_WARN(
"cdcacm", "write length mismatch, got %d", ret
);
}
}
}
/******************************************************************************/
#if 0
static void echo_usb(void)
{
int chars;
uint8_t buffer[BUFFER_SIZE];
if ((chars = acm_canread()) > 0) {
if (chars > BUFFER_SIZE) {
chars = BUFFER_SIZE;
}
// Read the data from USB
if (acm_read(buffer, chars) != chars) {
printf("acm_read() failed\n");
return;
}
// Echo it back
if (acm_present()) {
if (acm_write(buffer, chars) != chars) {
printf("acm_write() failed\n");
}
}
}
}
#endif
/******************************************************************************/
static int setconfig_callback(usb_setup_pkt *sud, void *cbdata)
{
/* Confirm the configuration value */
if (sud->wValue ==
config_descriptor.config_descriptor.bConfigurationValue) {
configured = 1;
MXC_SETBIT(&event_flags, EVENT_ENUM_COMP);
return acm_configure(&acm_cfg); /* Configure the device class */
} else if (sud->wValue == 0) {
configured = 0;
return acm_deconfigure();
}
return -1;
}
/******************************************************************************/
static int setfeature_callback(usb_setup_pkt *sud, void *cbdata)
{
if (sud->wValue == FEAT_REMOTE_WAKE) {
remote_wake_en = 1;
} else {
// Unknown callback
return -1;
}
return 0;
}
/******************************************************************************/
static int clrfeature_callback(usb_setup_pkt *sud, void *cbdata)
{
if (sud->wValue == FEAT_REMOTE_WAKE) {
remote_wake_en = 0;
} else {
// Unknown callback
return -1;
}
return 0;
}
/******************************************************************************/
static void usb_app_sleep(void)
{
/* TODO: Place low-power code here */
suspended = 1;
}
/******************************************************************************/
static void usb_app_wakeup(void)
{
/* TODO: Place low-power code here */
suspended = 0;
}
/******************************************************************************/
static int event_callback(maxusb_event_t evt, void *data)
{
/* Set event flag */
MXC_SETBIT(&event_flags, evt);
switch (evt) {
case MAXUSB_EVENT_NOVBUS:
usb_event_disable(MAXUSB_EVENT_BRST);
usb_event_disable(MAXUSB_EVENT_SUSP);
usb_event_disable(MAXUSB_EVENT_DPACT);
usb_disconnect();
configured = 0;
enum_clearconfig();
acm_deconfigure();
usb_app_sleep();
break;
case MAXUSB_EVENT_VBUS:
usb_event_clear(MAXUSB_EVENT_BRST);
usb_event_enable(MAXUSB_EVENT_BRST, event_callback, NULL);
usb_event_clear(MAXUSB_EVENT_SUSP);
usb_event_enable(MAXUSB_EVENT_SUSP, event_callback, NULL);
usb_connect();
usb_app_sleep();
break;
case MAXUSB_EVENT_BRST:
usb_app_wakeup();
enum_clearconfig();
acm_deconfigure();
configured = 0;
suspended = 0;
break;
case MAXUSB_EVENT_SUSP:
usb_app_sleep();
break;
case MAXUSB_EVENT_DPACT:
usb_app_wakeup();
break;
default:
break;
}
return 0;
}
/******************************************************************************/
static int usb_read_callback(void)
{
usb_read_complete = 1;
return 0;
}
/******************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
void USB_IRQHandler(void)
{
usb_event_handler();
if (serial_task_id != NULL) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(
serial_task_id, &xHigherPriorityTaskWoken
);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
/******************************************************************************/
/* TODO: We probably need to fix something related to this */
#if 0
void SysTick_Handler(void)
{
mxc_delay_handler();
}
#endif /* 0 */
/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*
* Description: Communications Device Class ACM (Serial Port) over USB
* $Id: descriptors.h 36682 2018-08-06 21:14:03Z michael.bayern $
*
*******************************************************************************
*/
#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_
#include <stdint.h>
#include "usb.h"
#include "hid_kbd.h"
usb_device_descriptor_t __attribute__((aligned(4))) device_descriptor = {
0x12, /* bLength = 18 */
0x01, /* bDescriptorType = Device */
0x0110, /* bcdUSB USB spec rev (BCD) */
0x02, /* bDeviceClass = comm class (2) */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 is 64 bytes */
0x0B6A, /* idVendor (Maxim Integrated) */
0x003C, /* idProduct */
0x0100, /* bcdDevice */
0x01, /* iManufacturer Descriptor ID */
0x02, /* iProduct Descriptor ID */
0x00, /* iSerialNumber = (0) No string */
0x01 /* bNumConfigurations */
};
__attribute__((aligned(4)))
struct __attribute__((packed)) {
usb_configuration_descriptor_t config_descriptor;
usb_interface_descriptor_t comm_interface_descriptor;
uint8_t header_functional_descriptor[5];
uint8_t call_management_descriptor[5];
uint8_t acm_functional_descriptor[4];
uint8_t union_functional_descriptor[5];
usb_endpoint_descriptor_t endpoint_descriptor_3;
usb_interface_descriptor_t data_interface_descriptor;
usb_endpoint_descriptor_t endpoint_descriptor_1;
usb_endpoint_descriptor_t endpoint_descriptor_2;
} config_descriptor =
{
{
0x09, /* bLength = 9 */
0x02, /* bDescriptorType = Config (2) */
0x0043, /* wTotalLength(L/H) */
0x02, /* bNumInterfaces */
0x01, /* bConfigValue */
0x00, /* iConfiguration */
0xE0, /* bmAttributes (self-powered, remote wakeup) */
0x01, /* MaxPower is 2ma (units are 2ma/bit) */
},
{ /* First Interface Descriptor For Comm Class Interface */
0x09, /* bLength = 9 */
0x04, /* bDescriptorType = Interface (4) */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints (one for OUT) */
0x02, /* bInterfaceClass = Communications Interface Class (2) */
0x02, /* bInterfaceSubClass = Abstract Control Model (2) */
0x01, /* bInterfaceProtocol = Common "AT" commands (1), no class specific protocol (0) */
0x00, /* iInterface */
},
{ /* Header Functional Descriptor */
0x05, /* bFunctionalLength = 5 */
0x24, /* bDescriptorType */
0x00, /* bDescriptorSubtype */
0x10, 0x01, /* bcdCDC */
},
{ /* Call Management Descriptor */
0x05, /* bFunctionalLength = 5 */
0x24, /* bDescriptorType */
0x01, /* bDescriptorSubtype */
0x03, /* bmCapabilities = Device handles call management itself (0x01), management over data class (0x02) */
0x01, /* bmDataInterface */
},
{ /* Abstract Control Management Functional Descriptor */
0x04, /* bFunctionalLength = 4 */
0x24, /* bDescriptorType */
0x02, /* bDescriptorSubtype */
0x02, /* bmCapabilities */
},
{ /* Union Functional Descriptor */
0x05, /* bFunctionalLength = 5 */
0x24, /* bDescriptorType */
0x06, /* bDescriptorSubtype */
0x00, /* bmMasterInterface */
0x01, /* bmSlaveInterface0 */
},
{ /* IN Endpoint 3 (Descriptor #1) */
0x07, /* bLength */
0x05, /* bDescriptorType (Endpoint) */
0x83, /* bEndpointAddress (EP3-IN) */
0x03, /* bmAttributes (interrupt) */
0x0040, /* wMaxPacketSize */
0xff, /* bInterval (milliseconds) */
},
{ /* Second Interface Descriptor For Data Interface */
0x09, /* bLength */
0x04, /* bDescriptorType (Interface) */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x0a, /* bInterfaceClass = Data Interface (10) */
0x00, /* bInterfaceSubClass = none (0) */
0x00, /* bInterfaceProtocol = No class specific protocol (0) */
0x00, /* biInterface = No Text String (0) */
},
{ /* OUT Endpoint 1 (Descriptor #2) */
0x07, /* bLength */
0x05, /* bDescriptorType (Endpoint) */
0x01, /* bEndpointAddress (EP1-OUT) */
0x02, /* bmAttributes (bulk) */
0x0040, /* wMaxPacketSize */
0x00, /* bInterval (N/A) */
},
{ /* IN Endpoint 2 (Descriptor #3) */
0x07, /* bLength */
0x05, /* bDescriptorType (Endpoint) */
0x82, /* bEndpointAddress (EP2-IN) */
0x02, /* bmAttributes (bulk) */
0x0040, /* wMaxPacketSize */
0x00 /* bInterval (N/A) */
}
};
__attribute__((aligned(4)))
uint8_t lang_id_desc[] = {
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09, 0x04 /* bString = wLANGID (see usb_20.pdf 9.6.7 String) */
};
__attribute__((aligned(4)))
uint8_t mfg_id_desc[] = {
0x22, /* bLength */
0x03, /* bDescriptorType */
'M', 0,
'a', 0,
'x', 0,
'i', 0,
'm', 0,
' ', 0,
'I', 0,
'n', 0,
't', 0,
'e', 0,
'g', 0,
'r', 0,
'a', 0,
't', 0,
'e', 0,
'd', 0,
};
__attribute__((aligned(4)))
uint8_t prod_id_desc[] = {
0x22, /* bLength */
0x03, /* bDescriptorType */
'M', 0,
'A', 0,
'X', 0,
'3', 0,
'2', 0,
'6', 0,
'6', 0,
'5', 0,
' ', 0,
'C', 0,
'D', 0,
'C', 0,
'-', 0,
'A', 0,
'C', 0,
'M', 0,
};
/* Not currently used (see device descriptor), but could be enabled if desired */
__attribute__((aligned(4)))
uint8_t serial_id_desc[] = {
0x14, /* bLength */
0x03, /* bDescriptorType */
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'0', 0,
'1', 0
};
#endif /* _DESCRIPTORS_H_ */
...@@ -131,6 +131,10 @@ typedef _Bool bool; ...@@ -131,6 +131,10 @@ typedef _Bool bool;
#define API_MAX86150_GET_DATA 0x0101 #define API_MAX86150_GET_DATA 0x0101
#define API_MAX86150_SET_LED_AMPLITUDE 0x0102 #define API_MAX86150_SET_LED_AMPLITUDE 0x0102
#define API_USB_SHUTDOWN 0x110
#define API_USB_STORAGE 0x111
#define API_USB_CDCACM 0x112
/* clang-format on */ /* clang-format on */
typedef uint32_t api_int_id_t; typedef uint32_t api_int_id_t;
...@@ -1700,5 +1704,20 @@ API(API_MAX30001_DISABLE, int epic_max30001_disable_sensor( ...@@ -1700,5 +1704,20 @@ API(API_MAX30001_DISABLE, int epic_max30001_disable_sensor(
void void
)); ));
/**
* De-initialize the currently configured USB device (if any)
*
*/
API(API_USB_SHUTDOWN, int epic_usb_shutdown(void));
/**
* Configure the USB peripheral to export the internal FLASH
* as a Mass Storage device
*/
API(API_USB_STORAGE, int epic_usb_storage(void));
/**
* Configure the USB peripheral to provide card10's stdin/stdout
* on a USB CDC-ACM device
*/
API(API_USB_CDCACM, int epic_usb_cdcacm(void));
#endif /* _EPICARDIUM_H */ #endif /* _EPICARDIUM_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <semphr.h> #include <semphr.h>
#include <timers.h>
#include "fs/internal.h" #include "fs/internal.h"
#include "modules/filesystem.h" #include "modules/filesystem.h"
...@@ -57,7 +58,7 @@ struct FatObject { ...@@ -57,7 +58,7 @@ struct FatObject {
struct EpicFileSystem { struct EpicFileSystem {
struct FatObject pool[EPIC_FAT_MAX_OPENED]; struct FatObject pool[EPIC_FAT_MAX_OPENED];
uint32_t generationCount; uint32_t generationCount;
bool initialized; bool attached;
FATFS FatFs; FATFS FatFs;
int lockCoreMask; int lockCoreMask;
}; };
...@@ -102,6 +103,11 @@ static StaticSemaphore_t s_globalLockBuffer; ...@@ -102,6 +103,11 @@ static StaticSemaphore_t s_globalLockBuffer;
static SemaphoreHandle_t s_globalLock = NULL; static SemaphoreHandle_t s_globalLock = NULL;
static void cb_attachTimer(void *a, uint32_t b)
{
fatfs_attach();
}
void fatfs_init() void fatfs_init()
{ {
static volatile bool s_initCalled = false; static volatile bool s_initCalled = false;
...@@ -117,6 +123,7 @@ void fatfs_init() ...@@ -117,6 +123,7 @@ void fatfs_init()
#else #else
s_globalLock = xSemaphoreCreateMutex(); s_globalLock = xSemaphoreCreateMutex();
#endif #endif
s_globalFileSystem.generationCount = 1; s_globalFileSystem.generationCount = 1;
fatfs_attach(); fatfs_attach();
} }
...@@ -137,11 +144,11 @@ int fatfs_attach() ...@@ -137,11 +144,11 @@ int fatfs_attach()
int rc = 0; int rc = 0;
if (globalLockAccquire()) { if (globalLockAccquire()) {
EpicFileSystem *fs = &s_globalFileSystem; EpicFileSystem *fs = &s_globalFileSystem;
if (!fs->initialized) { if (!fs->attached) {
ff_res = f_mount(&fs->FatFs, "/", 0); ff_res = f_mount(&fs->FatFs, "/", 0);
if (ff_res == FR_OK) { if (ff_res == FR_OK) {
fs->initialized = true; fs->attached = true;
SSLOG_DEBUG("FatFs mounted\n"); SSLOG_INFO("attached\n");
} else { } else {
SSLOG_ERR( SSLOG_ERR(
"f_mount error %s\n", "f_mount error %s\n",
...@@ -158,11 +165,23 @@ int fatfs_attach() ...@@ -158,11 +165,23 @@ int fatfs_attach()
return rc; return rc;
} }
void fatfs_schedule_attach(void)
{
//if we're running in thread context, cont't call the *FromISR version
if (xPortIsInsideInterrupt()) {
xTimerPendFunctionCallFromISR(cb_attachTimer, NULL, 0, NULL);
} else {
xTimerPendFunctionCall(
cb_attachTimer, NULL, 0, 1); //wait 1 tick
}
}
void fatfs_detach() void fatfs_detach()
{ {
FRESULT ff_res; FRESULT ff_res;
EpicFileSystem *fs; EpicFileSystem *fs;
if (efs_lock_global(&fs) == 0) { if (efs_lock_global(&fs) == 0) {
if (fs->attached) {
efs_close_all(fs, EPICARDIUM_COREMASK_BOTH); efs_close_all(fs, EPICARDIUM_COREMASK_BOTH);
//unmount by passing NULL as fs object, will destroy our sync object via ff_del_syncobj //unmount by passing NULL as fs object, will destroy our sync object via ff_del_syncobj
...@@ -174,9 +193,10 @@ void fatfs_detach() ...@@ -174,9 +193,10 @@ void fatfs_detach()
); );
} }
fs->initialized = false; fs->attached = false;
disk_deinitialize(); disk_deinitialize();
SSLOG_INFO("detached\n"); SSLOG_INFO("detached\n");
}
efs_unlock_global(fs); efs_unlock_global(fs);
} }
} }
...@@ -223,7 +243,7 @@ int efs_lock_global(EpicFileSystem **fs) ...@@ -223,7 +243,7 @@ int efs_lock_global(EpicFileSystem **fs)
if (!globalLockAccquire()) { if (!globalLockAccquire()) {
return -EBUSY; return -EBUSY;
} }
if (!s_globalFileSystem.initialized) { if (!s_globalFileSystem.attached) {
globalLockRelease(); globalLockRelease();
return -ENODEV; return -ENODEV;
} }
......
...@@ -80,7 +80,9 @@ endif ...@@ -80,7 +80,9 @@ endif
elf = executable( elf = executable(
name + '.elf', name + '.elf',
'cdcacm.c', 'usb/epc_usb.c',
'usb/cdcacm.c',
'usb/mass_storage.c',
'main.c', 'main.c',
'support.c', 'support.c',
'fs/filesystem_fat.c', 'fs/filesystem_fat.c',
......
...@@ -16,9 +16,19 @@ void fatfs_init(void); ...@@ -16,9 +16,19 @@ void fatfs_init(void);
/** /**
* initialize and mount the FLASH storage * initialize and mount the FLASH storage
*
* NOTE: not safe to be called from an ISR
*/ */
int fatfs_attach(void); int fatfs_attach(void);
/**
* asynchronously attach the FLASH storage
*
* safe to be called from an ISR
*/
void fatfs_schedule_attach(void);
/** close all opened FDs, sync and deinitialize FLASH layer */ /** close all opened FDs, sync and deinitialize FLASH layer */
void fatfs_detach(void); void fatfs_detach(void);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include "api/dispatcher.h" #include "api/dispatcher.h"
#include "api/interrupt-sender.h" #include "api/interrupt-sender.h"
#include "cdcacm.h" #include "usb/epc_usb.h"
#include "modules/filesystem.h" #include "modules/filesystem.h"
#include "modules/log.h" #include "modules/log.h"
#include "modules/modules.h" #include "modules/modules.h"
...@@ -152,8 +152,8 @@ int hardware_early_init(void) ...@@ -152,8 +152,8 @@ int hardware_early_init(void)
/* /*
* USB-Serial * USB-Serial
*/ */
if (cdcacm_init() < 0) { if (epic_usb_cdcacm() < 0) {
LOG_ERR("init", "USB-Serial unavailable"); LOG_ERR("startup", "USB-Serial unavailable");
} }
/* /*
......
...@@ -21,4 +21,5 @@ module_sources = files( ...@@ -21,4 +21,5 @@ module_sources = files(
'trng.c', 'trng.c',
'vibra.c', 'vibra.c',
'watchdog.c', 'watchdog.c',
'usb.c'
) )
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "modules/modules.h" #include "modules/modules.h"
#include "max32665.h" #include "max32665.h"
#include "cdcacm.h" #include "usb/cdcacm.h"
#include "uart.h" #include "uart.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
......
/**
*
* Implementation of public epic_usb_ interface
*
* Configuration and FLASH-specific implementation of USB mass storage device
* Configuration of USB CDCACM device
*
* USB descriptors for both are defined here.
*
*/
#include "epicardium.h"
#include "modules/filesystem.h"
#include "usb/cdcacm.h"
#include "usb/mass_storage.h"
#include "usb/descriptors.h"
#include "usb/epc_usb.h"
#include "modules/log.h"
#include "mx25lba.h"
#include "msc.h"
/* memory access callbacks for the mass storage (FLASH) device */
static int mscmem_init();
static uint32_t mscmem_size(void);
static int mscmem_read(uint32_t lba, uint8_t *buffer);
static int mscmem_write(uint32_t lba, uint8_t *buffer);
static int mscmem_start();
static int mscmem_stop();
static int mscmem_ready();
/* USB descriptors, definition at the end of this file */
static usb_device_descriptor_t device_descriptor_cdcacm
__attribute__((aligned(4)));
static struct config_descriptor_cdcacm config_descriptor_cdcacm
__attribute__((aligned(4)));
static usb_device_descriptor_t device_descriptor_msc
__attribute__((aligned(4)));
static struct config_descriptor_msc config_descriptor_msc
__attribute__((aligned(4)));
/* definitions of config structs */
static const msc_mem_t s_mscCallbacks = {
mscmem_init, mscmem_start, mscmem_stop, mscmem_ready,
mscmem_size, mscmem_read, mscmem_write,
};
static struct esb_device_descriptors s_dd_cdcacm = {
.device = &device_descriptor_cdcacm, .cdcacm = &config_descriptor_cdcacm
};
static struct esb_device_descriptors s_dd_msc = {
.device = &device_descriptor_msc, .msc = &config_descriptor_msc
};
static struct esb_config s_cfg_cdcacm = {
.name = "cdcacm",
.init = esb_cdc_init,
.configure = esb_cdc_configure,
.deconfigure = esb_cdc_deconfigure,
.deinit = NULL,
.descriptors = &s_dd_cdcacm,
.deviceData = NULL,
};
static struct esb_config s_cfg_msc = {
.name = "msc FLASH",
.init = esb_msc_init,
.configure = esb_msc_configure,
.deconfigure = esb_msc_deconfigure,
.deinit = NULL,
.descriptors = &s_dd_msc,
.deviceData = (void *)&s_mscCallbacks,
};
/* function implementations */
static int dirty = 0;
static int mscmem_init()
{
LOG_DEBUG("msc", "mem.init");
fatfs_detach();
return mx25_init();
}
static uint32_t mscmem_size(void)
{
return mx25_size();
}
static int mscmem_read(uint32_t lba, uint8_t *buffer)
{
return mx25_read(lba, buffer);
}
static int mscmem_write(uint32_t lba, uint8_t *buffer)
{
if (dirty == 0) {
//bootloader_dirty();
}
dirty = 2;
return mx25_write(lba, buffer);
}
static int mscmem_start()
{
return mx25_start();
}
static int mscmem_stop()
{
LOG_DEBUG("msc", "mem.stop");
int ret = mx25_stop();
fatfs_schedule_attach();
return ret;
}
static int mscmem_ready()
{
if (dirty) {
dirty--;
if (dirty == 0) {
LOG_DEBUG("msc", "sync");
mx25_sync();
//bootloader_clean();
}
}
return mx25_ready();
}
static bool s_fsDetached = false;
int epic_usb_shutdown(void)
{
esb_deinit();
if (s_fsDetached) {
fatfs_attach();
}
return 0;
}
int epic_usb_storage(void)
{
esb_deinit();
s_fsDetached = true;
return esb_init(&s_cfg_msc);
}
int epic_usb_cdcacm(void)
{
esb_deinit();
if (s_fsDetached) {
fatfs_attach();
}
return esb_init(&s_cfg_cdcacm);
}
/* clang-format off */
static usb_device_descriptor_t device_descriptor_cdcacm = {
.bLength = 0x12,
.bDescriptorType = DT_DEVICE,
.bcdUSB = 0x0110,
.bDeviceClass = CLS_COMM,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize = 0x40,
.idVendor = VNDR_MAXIM,
.idProduct = 0x003C,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x00,
.bNumConfigurations = 0x01
};
static struct config_descriptor_cdcacm config_descriptor_cdcacm = {
.config = {
.bLength = 0x09,
.bDescriptorType = DT_CONFIG,
.wTotalLength = 0x0043, /* sizeof(struct config_descriptor_cdcacm) */
.bNumInterfaces = 0x02,
.bConfigurationValue= 0x01,
.iConfiguration = 0x00,
.bmAttributes = 0xE0, /* (self-powered, remote wakeup) */
.bMaxPower = 0x01, /* MaxPower is 2ma (units are 2ma/bit) */
},
.comm_interface = { /* First Interface Descriptor For Comm Class Interface */
.bLength = 0x09,
.bDescriptorType = DT_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x01,
.bInterfaceClass = CLS_COMM,
.bInterfaceSubClass = SCLS_ACM,
.bInterfaceProtocol = PROT_AT_CMDS,
.iInterface = 0x00,
},
.header_functional = {
0x05, /* bFunctionalLength = 5 */
DT_FUNCTIONAL,/* bDescriptorType */
0x00, /* bDescriptorSubtype */
0x10, 0x01, /* bcdCDC */
},
.call_management = {
0x05, /* bFunctionalLength = 5 */
DT_FUNCTIONAL,/* bDescriptorType */
0x01, /* bDescriptorSubtype */
0x03, /* bmCapabilities = Device handles call management itself (0x01), management over data class (0x02) */
0x01, /* bmDataInterface */
},
.acm_functional = {
0x04, /* bFunctionalLength = 4 */
DT_FUNCTIONAL,/* bDescriptorType */
0x02, /* bDescriptorSubtype */
0x02, /* bmCapabilities */
},
.union_functional = {
0x05, /* bFunctionalLength = 5 */
DT_FUNCTIONAL,/* bDescriptorType */
0x06, /* bDescriptorSubtype */
0x00, /* bmMasterInterface */
0x01, /* bmSlaveInterface0 */
},
.endpoint_notify = {
.bLength = 0x07,
.bDescriptorType = DT_ENDPOINT,
.bEndpointAddress = 0x80 | ESB_ENDPOINT_CDCACM_NOTIFY,
.bmAttributes = ATTR_INTERRUPT,
.wMaxPacketSize = 0x0040,
.bInterval = 0xff,
},
.data_interface = {
.bLength = 0x09,
.bDescriptorType = DT_INTERFACE,
.bInterfaceNumber = 0x01,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = CLS_DATA,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.iInterface = 0x00, //not 1?
},
.endpoint_out = {
.bLength = 0x07,
.bDescriptorType = DT_ENDPOINT,
.bEndpointAddress = ESB_ENDPOINT_CDCACM_OUT,
.bmAttributes = ATTR_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0x00,
},
.endpoint_in = {
.bLength = 0x07,
.bDescriptorType = DT_ENDPOINT,
.bEndpointAddress = 0x80 | ESB_ENDPOINT_CDCACM_IN,
.bmAttributes = ATTR_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0x00
}
};
static usb_device_descriptor_t device_descriptor_msc = {
.bLength = 0x12,
.bDescriptorType = DT_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = CLS_UNSPECIFIED,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize = 0x40,
.idVendor = VNDR_MAXIM,
.idProduct = 0x4402,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static struct config_descriptor_msc config_descriptor_msc =
{
.config = {
.bLength = 0x09,
.bDescriptorType = DT_CONFIG,
.wTotalLength = 0x0020,
.bNumInterfaces = 0x01,
.bConfigurationValue= 0x01,
.iConfiguration = 0x00,
.bmAttributes = 0xC0, /* (self-powered, no remote wakeup) */
.bMaxPower = 0x32,
},
.msc_interface = {
.bLength = 0x09,
.bDescriptorType = DT_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = CLS_MASS_STOR,
.bInterfaceSubClass = SCLS_SCSI_CMDS,
.bInterfaceProtocol = PROT_BULK_TRANS,
.iInterface = 0x00,
},
.endpoint_out = {
.bLength = 0x07,
.bDescriptorType = DT_ENDPOINT,
.bEndpointAddress = ESB_ENDPOINT_MSC_OUT,
.bmAttributes = ATTR_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0x00,
},
.endpoint_in = {
.bLength = 0x07,
.bDescriptorType = DT_ENDPOINT,
.bEndpointAddress = 0x80 | ESB_ENDPOINT_MSC_IN,
.bmAttributes = ATTR_BULK,
.wMaxPacketSize = 0x0040,
.bInterval = 0x00
}
};
/* clang-format on */
\ No newline at end of file
/**
*
* epicardium-specific implemnetation of cdcacm device
* services CDCACM API
*/
#include "usb/epc_usb.h"
#include "usb/cdcacm.h"
#include "usb/descriptors.h"
#include <stdio.h>
#include <stddef.h>
#include <errno.h>
#include "usb.h"
#include "usb_event.h"
#include "cdc_acm.h"
#include "modules/log.h"
#include "FreeRTOS.h"
#include "task.h"
static inline struct config_descriptor_cdcacm *
descriptors(struct esb_config *self)
{
return self->descriptors->cdcacm;
}
/******************************************************************************/
static volatile int usb_read_complete; // SWYM: only ever written to
static int cb_acm_read_ready(void)
{
usb_read_complete = 1;
return 0;
}
int esb_cdc_init(struct esb_config *self)
{
LOG_DEBUG("cdcacm", "init");
struct config_descriptor_cdcacm *dsc = descriptors(self);
usb_read_complete = 0;
acm_register_callback(
ACM_CB_READ_READY,
cb_acm_read_ready); //SWYM: actually not needed
return acm_init(&dsc->comm_interface);
}
int esb_cdc_configure(struct esb_config *self)
{
struct config_descriptor_cdcacm *dsc = descriptors(self);
//acm_configure does not keep the amc_cfg_t pointer around
//so stack-local lifetime is fine
acm_cfg_t acm_cfg = {
.in_ep = dsc->endpoint_in.bEndpointAddress & 0x0f,
.in_maxpacket = MXC_USBHS_MAX_PACKET,
.out_ep = dsc->endpoint_out.bEndpointAddress,
.out_maxpacket = MXC_USBHS_MAX_PACKET,
.notify_ep = dsc->endpoint_notify.bEndpointAddress & 0x0f,
.notify_maxpacket = MXC_USBHS_MAX_PACKET,
};
LOG_DEBUG(
"cdcacm",
"configure, endpoints %d,%d,%d",
acm_cfg.in_ep,
acm_cfg.out_ep,
acm_cfg.notify_ep
);
return acm_configure(&acm_cfg);
}
int esb_cdc_deconfigure(struct esb_config *self)
{
LOG_DEBUG("cdcacm", "deconfigure");
return acm_deconfigure();
}
int cdcacm_num_read_avail(void)
{
return acm_canread();
}
uint8_t cdcacm_read(void)
{
while (acm_canread() <= 0) {
}
uint8_t buf;
acm_read(&buf, 1);
return buf;
}
void cdcacm_write(uint8_t *data, int len)
{
static int lockup_disable = 0;
if (acm_present() && !lockup_disable) {
int ret = acm_write(data, len);
if (ret < 0) {
LOG_ERR("cdcacm", "fifo lockup detected");
lockup_disable = 1;
} else if (ret != len) {
LOG_WARN(
"cdcacm", "write length mismatch, got %d", ret
);
}
}
}
/******************************************************************************/
extern TaskHandle_t serial_task_id;
void USB_IRQHandler(void)
{
usb_event_handler();
if (serial_task_id != NULL) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(
serial_task_id, &xHigherPriorityTaskWoken
);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
#ifndef CDCACM_H #ifndef CDCACM_H
#define CDCACM_H #define CDCACM_H
#include <stdint.h>
int cdcacm_init(void); #include "usb/epc_usb.h"
// callbacks for esb_config
int esb_cdc_init(struct esb_config* self);
int esb_cdc_configure(struct esb_config* self);
int esb_cdc_deconfigure(struct esb_config* self);
int cdcacm_num_read_avail(void); int cdcacm_num_read_avail(void);
uint8_t cdcacm_read(void); uint8_t cdcacm_read(void);
void cdcacm_write(uint8_t *data, int len); void cdcacm_write(uint8_t *data, int len);
......
#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_
#include <stdint.h>
#include "usb.h"
#define ESB_ENDPOINT_MSC_IN 2
#define ESB_ENDPOINT_MSC_OUT 1
#define ESB_ENDPOINT_CDCACM_NOTIFY 3
#define ESB_ENDPOINT_CDCACM_IN 2
#define ESB_ENDPOINT_CDCACM_OUT 1
/* device types */
#define DT_DEVICE 0x01
#define DT_CONFIG 0x02
#define DT_INTERFACE 0x04
#define DT_ENDPOINT 0x05
#define DT_FUNCTIONAL 0x24
/* interface classes */
#define CLS_UNSPECIFIED 0x00
#define CLS_COMM 0x02
#define CLS_MASS_STOR 0x08
#define CLS_DATA 0x0a
/* sub-classes */
#define SCLS_NONE 0x00
#define SCLS_ACM 0x02
#define SCLS_SCSI_CMDS 0x06
/* interface protocols */
#define PROT_AT_CMDS 0x01
#define PROT_BULK_TRANS 0x50
/* endpoint attributes */
#define ATTR_BULK 0x02
#define ATTR_INTERRUPT 0x03
#define VNDR_MAXIM 0x0B6A
#if defined(__GNUC__)
#define PACKED_STRUCT struct __attribute__((packed))
#else
#define PACKED_STRUCT __packed struct
#endif
PACKED_STRUCT
config_descriptor_cdcacm {
usb_configuration_descriptor_t config;
usb_interface_descriptor_t comm_interface;
uint8_t header_functional[5];
uint8_t call_management[5];
uint8_t acm_functional[4];
uint8_t union_functional[5];
usb_endpoint_descriptor_t endpoint_notify;
usb_interface_descriptor_t data_interface;
usb_endpoint_descriptor_t endpoint_out;
usb_endpoint_descriptor_t endpoint_in;
};
PACKED_STRUCT
config_descriptor_msc {
usb_configuration_descriptor_t config;
usb_interface_descriptor_t msc_interface;
usb_endpoint_descriptor_t endpoint_out;
usb_endpoint_descriptor_t endpoint_in;
};
struct esb_device_descriptors {
usb_device_descriptor_t* device;
union {
usb_configuration_descriptor_t* config;
struct config_descriptor_cdcacm* cdcacm;
struct config_descriptor_msc* msc;
};
};
#endif /* _DESCRIPTORS_H_ */
/**
*
*
* Core of the USB implementation:
*
* - device independent
* - handles setup of MAXUSB stack
* - handles events and state of the MAXUSB stack
*
* Also contains definitions of device-independent String descriptors
*
*
*
*
*
* swym's USB ramblings:
*
* setting up USB basically consists of two parts:
*
* - set up descriptors
* - initialize the corresponding MAXUSB stacks - acm, msc...
*
* at the moment, the descriptors are statically configured in
* descriptors.h several descriptors point to enumeration descriptors
* via iFooBar indices. Those enumeration descriptors are registered
* via enum_register_descriptor(type, desc, idx), where the idx passed
* corresponds to the iFooBar index mentioned above.
*
* There are several callbacks, some of which do not perform anything meaningful
* at the moment. For example usb_write_callback sets a global flag that is never
* read from. These will be removed later on.
*
* The initialization routines of acm & msc refer to the descriptors from which,
* among other things, they get their enpoint IDs. These are hard-coded right now
* but it would make sense to allocate these IDs at runtime. There is, AFAICT, no
* reason for these endpoint IDs to be 3, 1, 2 in the CDCACM case for example.
*
* Allocating those at runtime would also make the setup less rigid: we can have all
* combinations of {cdcacm, storage} interfaces without the awkward descriptor hackery
* in epc_usb_init.
*
* To generalize even further, the descriptors could be malloced. The total length of
* the descriptor structure can easily be derived from the number of interfaces to be
* initialized. The memory allocated will then be split up (with alignment of the single
* descriptor structs taken care of) in a simple bump-allocator strategy on demand.
*
*
*/
#include "usb/epc_usb.h"
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <FreeRTOS.h>
#include <task.h>
#include <timers.h>
#include "mxc_config.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
// MAXUSB includes
#include "usb.h"
#include "usb_event.h"
#include "enumerate.h"
#include "msc.h"
#include "cdc_acm.h"
#include "usb/descriptors.h"
#include "modules/log.h"
#include "modules/filesystem.h"
//#define USE_REMOTE_WAKE_ENABLE
/***** Function Prototypes *****/
static int cb_usb_setconfig(usb_setup_pkt *sud, void *cbdata);
#ifdef USE_REMOTE_WAKE_ENABLE
static int cb_usb_setfeature(usb_setup_pkt *sud, void *cbdata);
static int cb_usb_clrfeature(usb_setup_pkt *sud, void *cbdata);
#endif
static int cb_usb_event(maxusb_event_t evt, void *data);
static int cb_usb_shutdown();
static int cb_usb_init();
static void usb_app_sleep(void);
static void usb_app_wakeup(void);
/* needed for usb_opts. mxc_delay() takes unsigned long, so can't use it directly */
static void delay_us(unsigned int usec);
static void device_deinit();
static bool device_deconfigure();
static int device_configure();
volatile int suspended;
#ifdef USE_REMOTE_WAKE_ENABLE
int remote_wake_en; //SWYM: unused, only written to!
#endif
static StaticTimer_t x;
static TimerHandle_t timerWakeup = NULL;
static void cb_timerReset(TimerHandle_t t);
static struct esb_config s_device = { 0 };
__attribute__((aligned(4))) uint8_t lang_id_desc[] = {
0x04, /* bLength */
0x03, /* bDescriptorType */
0x09,
0x04 /* bString = wLANGID (see usb_20.pdf 9.6.7 String) */
};
__attribute__((aligned(4))) uint8_t mfg_id_desc[] = {
0x22, /* bLength */
0x03, /* bDescriptorType */
'M', 0, 'a', 0, 'x', 0, 'i', 0, 'm', 0, ' ', 0, 'I', 0, 'n', 0,
't', 0, 'e', 0, 'g', 0, 'r', 0, 'a', 0, 't', 0, 'e', 0, 'd', 0,
};
__attribute__((aligned(4))) uint8_t prod_id_desc[] = {
0x24, /* bLength */
0x03, /* bDescriptorType */
'C', 0, 'A', 0, 'R', 0, 'D', 0, '1', 0, '0', 0, ' ', 0, 'U', 0, 'S', 0,
'B', 0, ' ', 0, 'G', 0, 'A', 0, 'D', 0, 'G', 0, 'E', 0, 'T', 0,
};
/* Not currently used (see device descriptor), but could be enabled if desired */
__attribute__((aligned(4)))
uint8_t serial_id_desc[] = { 0x14, /* bLength */
0x03, /* bDescriptorType */
'c', 0, 'a', 0, 'a', 0, 'a', 0, 'a',
0, 'd', 0, '1', 0, '0', 0, '0', 0 };
int cb_usb_init()
{
const sys_cfg_usbhs_t sys_usbhs_cfg = NULL;
LOG_DEBUG("usb", "init");
return SYS_USBHS_Init(&sys_usbhs_cfg);
}
volatile bool shutDownCompleted;
void do_usb_shutdown()
{
LOG_DEBUG("usb", "shutting down...");
shutDownCompleted = false;
usb_shutdown();
for (int i = 0; i < 10000 && !shutDownCompleted; ++i) {
}
}
int cb_usb_shutdown()
{
SYS_USBHS_Shutdown();
SYS_Reset_Periph(SYS_RESET_USB);
device_deinit();
LOG_DEBUG("usb", "shutdown complete");
shutDownCompleted = true;
return 0;
}
/* User-supplied function to delay usec micro-seconds */
static void delay_us(unsigned int usec)
{
/* mxc_delay() takes unsigned long, so can't use it directly */
mxc_delay(usec);
}
static void device_deinit()
{
esb_cfg_handler deinit = s_device.deinit;
s_device.deinit = NULL;
s_device.configure = NULL;
s_device.deconfigure = NULL;
if (deinit) {
LOG_DEBUG("usb", "deinit");
deinit(&s_device);
}
}
//de-configure last device, if any
static volatile bool s_configured = false;
static bool device_deconfigure()
{
if (s_configured) {
s_configured = false;
if (s_device.deconfigure) {
LOG_DEBUG("usb", "deconfigure");
enum_clearconfig();
s_device.deconfigure(&s_device);
return true;
}
}
return false;
}
static int device_configure()
{
if (!s_configured && s_device.configure) {
s_configured = true;
LOG_DEBUG("usb", "configure");
return s_device.configure(&s_device);
}
return 0;
}
static volatile bool s_connected = false;
static void disconnect()
{
if (s_connected) {
LOG_DEBUG("usb", "disconnect");
s_connected = false;
usb_disconnect();
// SYS_Reset_Periph(SYS_RESET_USB);
mxc_delay(10000);
}
}
static void connect()
{
s_connected = true;
usb_connect();
}
static volatile bool s_initialized = false;
void esb_deinit(void)
{
if (s_initialized) {
s_initialized = false;
disconnect();
device_deconfigure();
do_usb_shutdown();
device_deinit();
}
}
int esb_init(struct esb_config *cfg)
{
esb_deinit();
if (cfg == NULL) {
return 0;
}
if (timerWakeup == NULL) {
timerWakeup = xTimerCreateStatic(
"timerWakeup", /* name */
pdMS_TO_TICKS(50), /* period/time */
pdFALSE, /* auto reload */
NULL, /* timer ID */
cb_timerReset,
&x);
}
maxusb_cfg_options_t usb_opts;
/* Initialize state */
suspended = 0;
#ifdef USE_REMOTE_WAKE_ENABLE
remote_wake_en = 0;
#endif
/* Start out in full speed */
usb_opts.enable_hs = 0;
usb_opts.delay_us = delay_us;
usb_opts.init_callback = cb_usb_init;
usb_opts.shutdown_callback = cb_usb_shutdown;
/* Initialize the usb module */
if (usb_init(&usb_opts) != 0) {
LOG_ERR("usb", "usb_init() failed");
return -EIO;
}
/* Initialize the enumeration module */
if (enum_init() != 0) {
do_usb_shutdown();
LOG_ERR("usb", "enum_init() failed");
return -EIO;
}
LOG_INFO("usb", "initializing device %s", cfg->name);
if (cfg->init(cfg)) {
enum_clearconfig();
do_usb_shutdown();
LOG_ERR("usb", "device init failed");
return -EIO;
}
s_initialized = true;
s_device = *cfg;
enum_register_descriptor(
ENUM_DESC_DEVICE, (uint8_t *)cfg->descriptors->device, 0
);
enum_register_descriptor(
ENUM_DESC_CONFIG, (uint8_t *)cfg->descriptors->config, 0
);
enum_register_descriptor(ENUM_DESC_STRING, lang_id_desc, 0);
enum_register_descriptor(ENUM_DESC_STRING, mfg_id_desc, 1);
enum_register_descriptor(ENUM_DESC_STRING, prod_id_desc, 2);
enum_register_descriptor(ENUM_DESC_STRING, serial_id_desc, 3);
//enum_register_descriptor(ENUM_DESC_STRING, cdcacm_func_desc, 4);
//enum_register_descriptor(ENUM_DESC_STRING, msc_func_desc, 5);
/* Handle configuration */
enum_register_callback(ENUM_SETCONFIG, cb_usb_setconfig, NULL);
#ifdef USE_REMOTE_WAKE_ENABLE
/* Handle feature set/clear */
enum_register_callback(ENUM_SETFEATURE, cb_usb_setfeature, NULL);
enum_register_callback(ENUM_CLRFEATURE, cb_usb_clrfeature, NULL);
#endif
/* Register callbacks */
usb_event_enable(MAXUSB_EVENT_NOVBUS, cb_usb_event, NULL);
usb_event_enable(MAXUSB_EVENT_VBUS, cb_usb_event, NULL);
/* Start with USB in low power mode */
usb_app_sleep();
/* TODO: Fix priority */
NVIC_SetPriority(USB_IRQn, 6);
NVIC_EnableIRQ(USB_IRQn);
return 0;
}
static int cb_usb_setconfig(usb_setup_pkt *sud, void *cbdata)
{
LOG_DEBUG("usb", "setconfig %d", sud->wValue);
if (sud->wValue == s_device.descriptors->config->bConfigurationValue) {
return device_configure();
} else if (sud->wValue == 0) {
device_deconfigure();
return 0;
}
return -1;
}
#ifdef USE_REMOTE_WAKE_ENABLE
static int cb_usb_setfeature(usb_setup_pkt *sud, void *cbdata)
{
if (sud->wValue == FEAT_REMOTE_WAKE) {
remote_wake_en = 1;
return 0;
}
return -1;
}
static int cb_usb_clrfeature(usb_setup_pkt *sud, void *cbdata)
{
if (sud->wValue == FEAT_REMOTE_WAKE) {
remote_wake_en = 0;
return 0;
}
return -1;
}
#endif
/******************************************************************************/
static void usb_app_sleep(void)
{
/* TODO: Place low-power code here */
suspended = 1;
}
/******************************************************************************/
static void usb_app_wakeup(void)
{
/* TODO: Place low-power code here */
suspended = 0;
}
static void cb_timerReset(TimerHandle_t t)
{
(void)t;
int s = usb_get_status();
LOG_DEBUG("usb", "cb_timerReset %08x", s);
LOG_DEBUG("usb", "SYS_USBHS_Shutdown");
SYS_USBHS_Shutdown();
LOG_DEBUG("usb", "SYS_Reset_Periph");
SYS_Reset_Periph(SYS_RESET_USB);
//copy-paste from esb_init(), need to refactor
maxusb_cfg_options_t usb_opts;
usb_opts.enable_hs = 0;
usb_opts.delay_us = delay_us;
usb_opts.init_callback = cb_usb_init;
usb_opts.shutdown_callback = cb_usb_shutdown;
/* Initialize the usb module */
if (usb_init(&usb_opts) != 0) {
LOG_ERR("usb", "usb_init() failed");
return;
}
usb_event_enable(MAXUSB_EVENT_NOVBUS, cb_usb_event, NULL);
usb_event_enable(MAXUSB_EVENT_VBUS, cb_usb_event, NULL);
}
static void scheduleReset()
{
LOG_DEBUG("usb", "scheduleReset");
xTimerChangePeriodFromISR(timerWakeup, pdMS_TO_TICKS(500), NULL);
}
#if LOG_ENABLE_DEBUG
static const char *maxusb_event_string(maxusb_event_t evt)
{
static const char *names[MAXUSB_NUM_EVENTS] = {
[MAXUSB_EVENT_DPACT] = "DPACT",
[MAXUSB_EVENT_RWUDN] = "RWUDN",
[MAXUSB_EVENT_BACT] = "BACT",
[MAXUSB_EVENT_BRST] = "BRST",
[MAXUSB_EVENT_SUSP] = "SUSP",
[MAXUSB_EVENT_NOVBUS] = "NOVBUS",
[MAXUSB_EVENT_VBUS] = "VBUS",
[MAXUSB_EVENT_BRSTDN] = "BRSTDN",
[MAXUSB_EVENT_SUDAV] = "SUDAV",
};
return evt < MAXUSB_NUM_EVENTS ? names[evt] : "<INVALID>";
}
#endif
/******************************************************************************/
static int cb_usb_event(maxusb_event_t evt, void *data)
{
static int s_VBUS_SUSP_sequence = 0;
LOG_DEBUG("usb", "event %s (%d)\n", maxusb_event_string(evt), evt);
switch (evt) {
case MAXUSB_EVENT_NOVBUS:
usb_event_disable(MAXUSB_EVENT_BRST);
usb_event_disable(MAXUSB_EVENT_SUSP);
usb_event_disable(MAXUSB_EVENT_DPACT);
usb_disconnect();
device_deconfigure();
usb_app_sleep();
break;
case MAXUSB_EVENT_VBUS:
s_VBUS_SUSP_sequence = 1;
usb_event_clear(MAXUSB_EVENT_BRST);
usb_event_enable(MAXUSB_EVENT_BRST, cb_usb_event, NULL);
usb_event_clear(MAXUSB_EVENT_SUSP);
usb_event_enable(MAXUSB_EVENT_SUSP, cb_usb_event, NULL);
connect();
usb_app_sleep();
break;
case MAXUSB_EVENT_BRST:
usb_app_wakeup();
device_deconfigure();
suspended = 0;
break;
case MAXUSB_EVENT_SUSP:
if (!s_VBUS_SUSP_sequence) {
scheduleReset();
}
s_VBUS_SUSP_sequence = 0;
//usb_app_sleep();
break;
case MAXUSB_EVENT_DPACT:
usb_app_wakeup();
break;
default:
break;
}
return 0;
}
#ifndef EPICARDIUM_USB_EPC_USB_H_INCLUDED
#define EPICARDIUM_USB_EPC_USB_H_INCLUDED
/**
*
* EPC - it's not just a Universal Serial Bus,
* it's an Epic Serial Bus!
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
struct esb_config;
typedef int (*esb_cfg_handler)(struct esb_config* self);
struct esb_config {
const char* name;
esb_cfg_handler init;
esb_cfg_handler configure;
esb_cfg_handler deconfigure;
esb_cfg_handler deinit;
struct esb_device_descriptors* descriptors;
void* deviceData;
};
int esb_init(struct esb_config* cfg);
void esb_deinit(void);
#endif//EPICARDIUM_USB_EPC_USB_H_INCLUDED
/**
* backend-independent implementation of the mass storage device
* services MSC API and esb_cfg API
*/
#include "usb/mass_storage.h"
#include "usb/epc_usb.h"
#include "usb/descriptors.h"
#include "modules/log.h"
#include "msc.h"
#include "usb.h"
#include "max32665.h"
#define VENDOR_STRING "CCC"
#define PRODUCT_STRING "card10"
#define VERSION_STRING "1.0"
static inline struct config_descriptor_msc *descriptors(struct esb_config *self)
{
return self->descriptors->msc;
}
int esb_msc_configure(struct esb_config *self)
{
LOG_DEBUG("msc", "configure");
struct config_descriptor_msc *dsc = descriptors(self);
const msc_cfg_t msc_cfg = {
dsc->endpoint_out.bEndpointAddress,
MXC_USBHS_MAX_PACKET, /* OUT max packet size */
dsc->endpoint_in.bEndpointAddress & 0x0f,
MXC_USBHS_MAX_PACKET, /* IN max packet size */
};
return msc_configure(&msc_cfg);
}
int esb_msc_deconfigure(struct esb_config *self)
{
LOG_DEBUG("msc", "deconfigure");
(void)self;
return msc_deconfigure();
}
int esb_msc_init(struct esb_config *self)
{
LOG_DEBUG("msc", "init");
static const msc_idstrings_t ids = { VENDOR_STRING,
PRODUCT_STRING,
VERSION_STRING };
msc_mem_t *mem = self->deviceData;
struct config_descriptor_msc *dsc = descriptors(self);
return msc_init(&dsc->msc_interface, &ids, mem);
}
#ifndef EPICARDIUM_USB_MSC_H_INCLUDED
#define EPICARDIUM_USB_MSC_H_INCLUDED
#include "usb/epc_usb.h"
int esb_msc_configure(struct esb_config* self);
int esb_msc_deconfigure(struct esb_config* self);
int esb_msc_init(struct esb_config* self);
#endif//EPICARDIUM_USB_MSC_H_INCLUDED