Merge branch 'arpruss-master'

This commit is contained in:
Roger Clark 2018-04-13 13:43:36 +10:00
commit 0e0370dfe9
62 changed files with 8676 additions and 0 deletions

View File

@ -0,0 +1,56 @@
#include "USBHID.h"
//================================================================================
//================================================================================
// Mouse
void HIDAbsMouse::begin(void){
}
void HIDAbsMouse::end(void){
}
void HIDAbsMouse::click(uint8_t b)
{
report.wheel = 0;
report.buttons = b;
sendReport();
report.buttons = 0;
sendReport();
}
void HIDAbsMouse::move(int16 x, int16 y, int8 wheel)
{
report.x = x;
report.y = y;
report.wheel = wheel;
sendReport();
}
void HIDAbsMouse::buttons(uint8_t b)
{
if (b != report.buttons)
{
report.wheel = 0;
report.buttons = b;
sendReport();
}
}
void HIDAbsMouse::press(uint8_t b)
{
buttons(report.buttons | b);
}
void HIDAbsMouse::release(uint8_t b)
{
buttons(report.buttons & ~b);
}
bool HIDAbsMouse::isPressed(uint8_t b)
{
if ((b & report.buttons) != 0)
return true;
return false;
}

View File

@ -0,0 +1,7 @@
#include "USBHID.h"
//================================================================================
//================================================================================
// Keyboard
HIDKeyboard BootKeyboard(0);

View File

@ -0,0 +1,13 @@
#include "USBHID.h"
void HIDConsumer::begin(void) {}
void HIDConsumer::end(void) {}
void HIDConsumer::press(uint16_t button) {
report.button = button;
sendReport();
}
void HIDConsumer::release() {
report.button = 0;
sendReport();
}

View File

@ -0,0 +1,14 @@
#include "USBHID.h"
#define REPORT(name, ...) \
static uint8_t raw_ ## name[] = { __VA_ARGS__ }; \
static const HIDReportDescriptor desc_ ## name = { raw_ ##name, sizeof(raw_ ##name) }; \
const HIDReportDescriptor* hidReport ## name = & desc_ ## name;
REPORT(KeyboardMouseJoystick, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR(), HID_JOYSTICK_REPORT_DESCRIPTOR());
REPORT(KeyboardMouse, HID_MOUSE_REPORT_DESCRIPTOR(), HID_KEYBOARD_REPORT_DESCRIPTOR());
REPORT(Keyboard, HID_KEYBOARD_REPORT_DESCRIPTOR());
REPORT(Mouse, HID_MOUSE_REPORT_DESCRIPTOR());
REPORT(KeyboardJoystick, HID_KEYBOARD_REPORT_DESCRIPTOR(), HID_JOYSTICK_REPORT_DESCRIPTOR());
REPORT(Joystick, HID_JOYSTICK_REPORT_DESCRIPTOR());
REPORT(BootKeyboard, HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR());

View File

@ -0,0 +1,118 @@
#include "USBHID.h"
// This code requires gcc on low-endian devices.
//================================================================================
//================================================================================
// Joystick
void HIDJoystick::begin(void){
}
void HIDJoystick::end(void){
}
void HIDJoystick::setManualReportMode(bool mode) {
manualReport = mode;
}
bool HIDJoystick::getManualReportMode() {
return manualReport;
}
void HIDJoystick::safeSendReport() {
if (!manualReport) {
sendReport();
}
}
void HIDJoystick::button(uint8_t button, bool val){
uint32_t mask = ((uint32_t)1 << (button-1));
if (val) {
joyReport.buttons |= mask;
} else {
joyReport.buttons &= ~mask;
}
safeSendReport();
}
void HIDJoystick::X(uint16_t val){
if (val > 1023) val = 1023;
joyReport.x = val;
safeSendReport();
}
void HIDJoystick::Y(uint16_t val){
if (val > 1023) val = 1023;
joyReport.y = val;
safeSendReport();
}
void HIDJoystick::position(uint16_t x, uint16_t y){
if (x > 1023) x = 1023;
if (y > 1023) y = 1023;
joyReport.x = x;
joyReport.y = y;
safeSendReport();
}
void HIDJoystick::Xrotate(uint16_t val){
if (val > 1023) val = 1023;
joyReport.rx = val;
safeSendReport();
}
void HIDJoystick::Yrotate(uint16_t val){
if (val > 1023) val = 1023;
joyReport.ry = val;
safeSendReport();
}
void HIDJoystick::sliderLeft(uint16_t val){
if (val > 1023) val = 1023;
joyReport.sliderLeft = val;
safeSendReport();
}
void HIDJoystick::sliderRight(uint16_t val){
if (val > 1023) val = 1023;
joyReport.sliderRight = val;
safeSendReport();
}
void HIDJoystick::slider(uint16_t val){
if (val > 1023) val = 1023;
joyReport.sliderLeft = val;
joyReport.sliderRight = val;
safeSendReport();
}
void HIDJoystick::hat(int16_t dir){
uint8_t val;
if (dir < 0) val = 15;
else if (dir < 23) val = 0;
else if (dir < 68) val = 1;
else if (dir < 113) val = 2;
else if (dir < 158) val = 3;
else if (dir < 203) val = 4;
else if (dir < 245) val = 5;
else if (dir < 293) val = 6;
else if (dir < 338) val = 7;
else val = 15;
joyReport.hat = val;
safeSendReport();
}
HIDJoystick Joystick;

View File

@ -0,0 +1,258 @@
#include "USBHID.h"
#include <string.h>
//================================================================================
//================================================================================
// Keyboard
#define SHIFT 0x80
static const uint8_t ascii_to_hid[128] =
{
0x00, // NUL
0x00, // SOH
0x00, // STX
0x00, // ETX
0x00, // EOT
0x00, // ENQ
0x00, // ACK
0x00, // BEL
0x2a, // BS Backspace
0x2b, // TAB Tab
0x28, // LF Enter
0x00, // VT
0x00, // FF
0x00, // CR
0x00, // SO
0x00, // SI
0x00, // DEL
0x00, // DC1
0x00, // DC2
0x00, // DC3
0x00, // DC4
0x00, // NAK
0x00, // SYN
0x00, // ETB
0x00, // CAN
0x00, // EM
0x00, // SUB
0x00, // ESC
0x00, // FS
0x00, // GS
0x00, // RS
0x00, // US
0x2c, // ' '
0x1e|SHIFT, // !
0x34|SHIFT, // "
0x20|SHIFT, // #
0x21|SHIFT, // $
0x22|SHIFT, // %
0x24|SHIFT, // &
0x34, // '
0x26|SHIFT, // (
0x27|SHIFT, // )
0x25|SHIFT, // *
0x2e|SHIFT, // +
0x36, // ,
0x2d, // -
0x37, // .
0x38, // /
0x27, // 0
0x1e, // 1
0x1f, // 2
0x20, // 3
0x21, // 4
0x22, // 5
0x23, // 6
0x24, // 7
0x25, // 8
0x26, // 9
0x33|SHIFT, // :
0x33, // ;
0x36|SHIFT, // <
0x2e, // =
0x37|SHIFT, // >
0x38|SHIFT, // ?
0x1f|SHIFT, // @
0x04|SHIFT, // A
0x05|SHIFT, // B
0x06|SHIFT, // C
0x07|SHIFT, // D
0x08|SHIFT, // E
0x09|SHIFT, // F
0x0a|SHIFT, // G
0x0b|SHIFT, // H
0x0c|SHIFT, // I
0x0d|SHIFT, // J
0x0e|SHIFT, // K
0x0f|SHIFT, // L
0x10|SHIFT, // M
0x11|SHIFT, // N
0x12|SHIFT, // O
0x13|SHIFT, // P
0x14|SHIFT, // Q
0x15|SHIFT, // R
0x16|SHIFT, // S
0x17|SHIFT, // T
0x18|SHIFT, // U
0x19|SHIFT, // V
0x1a|SHIFT, // W
0x1b|SHIFT, // X
0x1c|SHIFT, // Y
0x1d|SHIFT, // Z
0x2f, // [
0x31, // bslash
0x30, // ]
0x23|SHIFT, // ^
0x2d|SHIFT, // _
0x35, // `
0x04, // a
0x05, // b
0x06, // c
0x07, // d
0x08, // e
0x09, // f
0x0a, // g
0x0b, // h
0x0c, // i
0x0d, // j
0x0e, // k
0x0f, // l
0x10, // m
0x11, // n
0x12, // o
0x13, // p
0x14, // q
0x15, // r
0x16, // s
0x17, // t
0x18, // u
0x19, // v
0x1a, // w
0x1b, // x
0x1c, // y
0x1d, // z
0x2f|SHIFT, //
0x31|SHIFT, // |
0x30|SHIFT, // }
0x35|SHIFT, // ~
0 // DEL
};
void HIDKeyboard::begin(void){
USBHID.addOutputBuffer(&ledData);
}
void HIDKeyboard::end(void) {
}
// 136: non-printing key
// shift -> 0x02
// modifiers: 128 --> bit shift
uint8_t HIDKeyboard::getKeyCode(uint8_t k, uint8_t* modifiersP)
{
*modifiersP = 0;
if (adjustForHostCapsLock && (getLEDs() & 0x02)) { // capslock is down on host OS, so host will reverse
if ('a' <= k && k <= 'z')
k += 'A'-'a';
else if ('A' <= k && k <= 'Z')
k += 'a'-'A';
}
if (k < 0x80) {
k = ascii_to_hid[k];
if (k & SHIFT) {
k &= 0x7f;
*modifiersP = 0x02;
}
return k;
}
if (k >= 0x88) { // non-printing key, Arduino format
return k - 0x88;
}
else { // shift key
*modifiersP = 1<<(k-0x80);
return 0;
}
}
size_t HIDKeyboard::press(uint8_t k) {
uint8_t modifiers;
k = getKeyCode(k, &modifiers);
if (k == 0) {
if (modifiers == 0) {
return 0;
}
}
else {
for (unsigned i = 0; i<HID_KEYBOARD_ROLLOVER; i++) {
if (keyReport.keys[i] == k) {
goto SEND;
}
}
for (unsigned i = 0; i<HID_KEYBOARD_ROLLOVER; i++) {
if (keyReport.keys[i] == 0) {
keyReport.keys[i] = k;
goto SEND;
}
}
return 0;
}
SEND:
keyReport.modifiers |= modifiers;
sendReport();
return 1;
}
// release() takes the specified key out of the persistent key report and
// sends the report. This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t HIDKeyboard::release(uint8_t k)
{
uint8_t modifiers;
k = getKeyCode(k, &modifiers);
if (k != 0) {
for (unsigned i=0; i<HID_KEYBOARD_ROLLOVER; i++) {
if (keyReport.keys[i] == k) {
keyReport.keys[i] = 0;
break;
}
}
}
else {
if (modifiers == 0)
return 0;
}
keyReport.modifiers &= ~modifiers;
sendReport();
return 1;
}
void HIDKeyboard::releaseAll(void)
{
memset(keyReport.keys, 0, HID_KEYBOARD_ROLLOVER);
keyReport.modifiers = 0;
sendReport();
}
size_t HIDKeyboard::write(uint8_t c)
{
if (press(c)) {
release(c); // Keyup
return 1;
}
else {
return 0;
}
}
HIDKeyboard Keyboard;

View File

@ -0,0 +1,45 @@
Copyright (c) 2011, Peter Barrett
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 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, DIRECT, 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.
------------
The MIT License
Copyright (c) 2011 LeafLabs LLC.
Parts of composite HID+Serial code taken from https://github.com/libarra111/Arduino_STM32
USB Mass storage code based on Joe Ferner's code: https://github.com/joeferner/maple-usbMassStorage
MIDI code Copyright (c) 2010 Perry Hung, (c) 2013 Magnus Lundin, (c) 2013 Donald Delmar Davis, Suspect Devices,
(c) 2003-2008 Tymm Twillman <tymm@booyaka.com>.
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 THE AUTHORS OR COPYRIGHT HOLDERS
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.

View File

@ -0,0 +1,151 @@
/*--------------------------------------------------------------------------MidiSpecs.h
*
* These defines are based on specs created by the USB and MMA standards organizations.
* There are not a lot of other ways to code them so licensing this is rather ludicrous.
* However, in order to be able to embed this in client projects, and avoid the stupidity
* of enforced open everything I will declare the following about this file.
*
* Copyright (c) 2011 Donald Delmar Davis, Suspect Devices
*
* 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 THE AUTHORS OR COPYRIGHT
* HOLDERS 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.
*
*/
/*
* USB midi commands from
* MIDI10.pdf "Universal Serial Bus Device Class Definition for MIDI Devices"
* REV 1. (1999)
* http://www.usb.org/developers/devclass_docs/midi10.pdf
*
*/
#ifndef __LETS_MIDI_SPECS_H__
#define __LETS_MIDI_SPECS_H__
#include <stdint.h>
#include <stdbool.h>
// rework this for the different architectures....
#if defined(__GNUC__)
typedef struct
{
unsigned cin : 4; // this is the low nibble.
unsigned cable : 4;
// uint8_t cin;
uint8_t midi0;
uint8_t midi1;
uint8_t midi2;
} __attribute__ ((__packed__)) MIDI_EVENT_PACKET_t ;
#else
typedef struct // may need to be adjusted for other compilers and bitfield order...
{
unsigned cable : 4;
unsigned cin : 4;
uint8_t midi0;
uint8_t midi1;
uint8_t midi2;
} MIDI_EVENT_PACKET_t ;
#endif
#define CIN_MISC_FUNCTION 0x00 /* Reserved for future extension. */
#define CIN_CABLE_EVENT 0x01 /* Reserved for future extension. */
#define CIN_2BYTE_SYS_COMMON 0x02 /* 2Bytes -- MTC, SongSelect, etc. */
#define CIN_3BYTE_SYS_COMMON 0x03 /* 3Bytes -- SPP, etc. */
#define CIN_SYSEX 0x04 /* 3Bytes */
#define CIN_SYSEX_ENDS_IN_1 0x05 /* 1Bytes */
#define CIN_SYSEX_ENDS_IN_2 0x06 /* 2Bytes */
#define CIN_SYSEX_ENDS_IN_3 0x07 /* 3Bytes */
#define CIN_NOTE_OFF 0x08 /* 3Bytes */
#define CIN_NOTE_ON 0x09 /* 3Bytes */
#define CIN_AFTER_TOUCH 0x0A /* 3Bytes */
#define CIN_CONTROL_CHANGE 0x0B /* 3Bytes */
#define CIN_PROGRAM_CHANGE 0x0C /* 2Bytes */
#define CIN_CHANNEL_PRESSURE 0x0D /* 2Bytes */
#define CIN_PITCH_WHEEL 0x0E /* 3Bytes */
#define CIN_1BYTE 0x0F /* 1Bytes */
//#define CIN_IS_SYSEX(cin) ((cin == CIN_SYSEX)||(cin == CIN_SYSEX_ENDS_IN_1)||(cin == CIN_SYSEX_ENDS_IN_2)||(cin == CIN_SYSEX_ENDS_IN_3))
#define CIN_IS_SYSEX(cin) ( ((cin) & ~(0x08)) && ((cin) &0x04) )
/*
* MIDI V1 message definitions these are from the MMA document
* http://www.midi.org/techspecs/midimessages.php
*/
#define MIDIv1_BAUD_RATE 31250
/*
* parse midi (v1) message macros
*/
#define MIDIv1_IS_STATUS(b) ((b) & 0x80)
#define MIDIv1_IS_VOICE(b) ((b) <= 0xEF)
#define MIDIv1_VOICE_COMMAND(b) ((b) & 0xF0)
#define MIDIv1_VOICE_CHANNEL(b) ((b) & 0x0F)
#define MIDIv1_IS_SYSCOMMON(b) (((b) >= 0xF0) & ((b) < 0xF8))
#define MIDIv1_IS_REALTIME(b) ((b) >= 0xF8)
/*
* Voice category messages
*/
#define MIDIv1_NOTE_OFF 0x80 /* 2 bytes data -- CIN_NOTE_OFF */
#define MIDIv1_NOTE_ON 0x90 /* 2 bytes data -- CIN_NOTE_ON */
#define MIDIv1_AFTER_TOUCH 0xA0 /* 2 bytes data -- CIN_AFTER_TOUCH */
#define MIDIv1_CONTROL_CHANGE 0xB0 /* 2 bytes data -- CIN_CONTROL_CHANGE */
#define MIDIv1_PROGRAM_CHANGE 0xC0 /* 1 byte data -- CIN_PROGRAM_CHANGE */
#define MIDIv1_CHANNEL_PRESSURE 0xD0 /* 1 byte data -- CIN_CHANNEL_PRESSURE */
#define MIDIv1_PITCH_WHEEL 0xE0 /* 2 bytes data -- CIN_PITCH_WHEEL */
/*
* System common category messages
*/
#define MIDIv1_SYSEX_START 0xF0
#define MIDIv1_SYSEX_END 0xF7
#define MIDIv1_MTC_QUARTER_FRAME 0xF1 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */
#define MIDIv1_SONG_POSITION_PTR 0xF2 /* 2 bytes data -- CIN_3BYTE_SYS_COMMON */
#define MIDIv1_SONG_SELECT 0xF3 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */
#define MIDIv1_TUNE_REQUEST 0xF6 /* no data -- CIN_1BYTE */
/*
* Realtime category messages, can be sent anytime
*/
#define MIDIv1_CLOCK 0xF8 /* no data -- CIN_1BYTE */
#define MIDIv1_TICK 0xF9 /* no data -- CIN_1BYTE */
#define MIDIv1_START 0xFA /* no data -- CIN_1BYTE */
#define MIDIv1_CONTINUE 0xFB /* no data -- CIN_1BYTE */
#define MIDIv1_STOP 0xFC /* no data -- CIN_1BYTE */
#define MIDIv1_ACTIVE_SENSE 0xFE /* no data -- CIN_1BYTE */
#define MIDIv1_RESET 0xFF /* no data -- CIN_1BYTE */
/*
* sysex universal id's
*/
#define MIDIv1_UNIVERSAL_REALTIME_ID 0x7F
#define MIDIv1_UNIVERSAL_NON_REALTIME_ID 0x7E
#define MIDIv1_UNIVERSAL_ALL_CHANNELS 0x7F
/*
* Susbset of universal sysex (general info request)
* As described http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec.htm
*/
#define USYSEX_NON_REAL_TIME 0x7E
#define USYSEX_REAL_TIME 0x7F
#define USYSEX_ALL_CHANNELS 0x7F
#define USYSEX_GENERAL_INFO 0x06
#define USYSEX_GI_ID_REQUEST 0x01
#define USYSEX_GI_ID_RESPONSE 0x02
#endif

View File

@ -0,0 +1,306 @@
//
// MinSysex.c
// LibMaple4Midi
//
// Created by Donald D Davis on 4/11/13.
// Copyright (c) 2013 Suspect Devices. All rights reserved.
// Modified BSD Liscense
/*
0xF0 SysEx
0x7E Non-Realtime
0x7F The SysEx channel. Could be from 0x00 to 0x7F.
Here we set it to "disregard channel".
0x06 Sub-ID -- General Information
0x01 Sub-ID2 -- Identity Request
0xF7 End of SysEx
---- response
0xF0 SysEx
0x7E Non-Realtime
0x7F The SysEx channel. Could be from 0x00 to 0x7F.
Here we set it to "disregard channel".
0x06 Sub-ID -- General Information
0x02 Sub-ID2 -- Identity Reply
0xID Manufacturer's ID
0xf1 The f1 and f2 bytes make up the family code. Each
0xf2 manufacturer assigns different family codes to his products.
0xp1 The p1 and p2 bytes make up the model number. Each
0xp2 manufacturer assigns different model numbers to his products.
0xv1 The v1, v2, v3 and v4 bytes make up the version number.
0xv2
0xv3
0xv4
0xF7 End of SysEx
*/
#define USB_MIDI
#ifdef USB_MIDI
// change this to packets
#define STANDARD_ID_RESPONSE_LENGTH 7
#include "usb_midi_device.h"
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
#include <MinSysex.h>
//#include <wirish/wirish.h>
#define MAX_SYSEX_SIZE 256
/********************************* ACHTUNG! ignores usbmidi cable ********************************/
/*const MIDI_EVENT_PACKET_t standardIDResponse[]={
{ DEFAULT_MIDI_CABLE,
CIN_SYSEX,
MIDIv1_SYSEX_START,
USYSEX_NON_REAL_TIME,
USYSEX_ALL_CHANNELS},
{ DEFAULT_MIDI_CABLE,
CIN_SYSEX,
USYSEX_GENERAL_INFO,
USYSEX_GI_ID_RESPONSE,
LEAFLABS_MMA_VENDOR_1},
{ DEFAULT_MIDI_CABLE,
CIN_SYSEX,
LEAFLABS_MMA_VENDOR_2, // extended ID
LEAFLABS_MMA_VENDOR_3, // extended ID
1}, // family #1
{ DEFAULT_MIDI_CABLE,
CIN_SYSEX,
2, // family #2
1, // part #1
2}, // part #2
{ DEFAULT_MIDI_CABLE,
CIN_SYSEX,
0, // version 1
0, // version 2
1}, // version 3
{ DEFAULT_MIDI_CABLE,
CIN_SYSEX_ENDS_IN_2,
'!', // lgl compatible
MIDIv1_SYSEX_END,
0}
};
*/
const uint8 standardIDResponse[]={
CIN_SYSEX,
MIDIv1_SYSEX_START,
USYSEX_NON_REAL_TIME,
USYSEX_ALL_CHANNELS,
CIN_SYSEX,
USYSEX_GENERAL_INFO,
USYSEX_GI_ID_RESPONSE,
LEAFLABS_MMA_VENDOR_1,
CIN_SYSEX,
LEAFLABS_MMA_VENDOR_2, // extended ID
LEAFLABS_MMA_VENDOR_3, // extended ID
1, // family #1
CIN_SYSEX,
2, // family #2
1, // part #1
2, // part #2
CIN_SYSEX,
0, // version 1
0, // version 2
1, // version 3
CIN_SYSEX_ENDS_IN_2,
'!', // lgl compatible
MIDIv1_SYSEX_END,
0
};
//#define STANDARD_ID_RESPONSE_LENGTH (sizeof(standardIDResponse))
typedef enum {NOT_IN_SYSEX=0,COULD_BE_MY_SYSEX,YUP_ITS_MY_SYSEX,ITS_NOT_MY_SYSEX} sysexStates;
volatile uint8 sysexBuffer[MAX_SYSEX_SIZE];
volatile sysexStates sysexState;
volatile int sysexFinger=0;
/*
0xF0 SysEx
0x?? LEAFLABS_MMA_VENDOR_1
0x?? LEAFLABS_MMA_VENDOR_2
0x?? LEAFLABS_MMA_VENDOR_3
0x10 LGL_DEVICE_NUMBER
0xLE CMD: REBOOT
0xf7 EOSysEx
*/
#define STACK_TOP 0x20000800
#define EXC_RETURN 0xFFFFFFF9
#define DEFAULT_CPSR 0x61000000
#define RESET_DELAY 100000
#if 0
static void wait_reset(void) {
delay_us(RESET_DELAY);
nvic_sys_reset();
}
#endif
/* -----------------------------------------------------------------------------dealWithItQuickly()
* Note: at this point we have established that the sysex belongs to us.
* So we need to respond to any generic requests like information requests.
* We also need to handle requests which are meant for us. At the moment this is just the
* reset request.
*
*/
void dealWithItQuickly(){
switch (sysexBuffer[1]) {
case USYSEX_NON_REAL_TIME:
switch (sysexBuffer[3]) {
case USYSEX_GENERAL_INFO:
if (sysexBuffer[4]==USYSEX_GI_ID_REQUEST) {
usb_midi_tx((uint32 *) standardIDResponse, STANDARD_ID_RESPONSE_LENGTH);
}
}
case USYSEX_REAL_TIME:
break;
#if 0
case LEAFLABS_MMA_VENDOR_1:
if (sysexBuffer[5]==LGL_RESET_CMD) {
uintptr_t target = (uintptr_t)wait_reset | 0x1;
asm volatile("mov r0, %[stack_top] \n\t" // Reset stack
"mov sp, r0 \n\t"
"mov r0, #1 \n\t"
"mov r1, %[target_addr] \n\t"
"mov r2, %[cpsr] \n\t"
"push {r2} \n\t" // Fake xPSR
"push {r1} \n\t" // PC target addr
"push {r0} \n\t" // Fake LR
"push {r0} \n\t" // Fake R12
"push {r0} \n\t" // Fake R3
"push {r0} \n\t" // Fake R2
"push {r0} \n\t" // Fake R1
"push {r0} \n\t" // Fake R0
"mov lr, %[exc_return] \n\t"
"bx lr"
:
: [stack_top] "r" (STACK_TOP),
[target_addr] "r" (target),
[exc_return] "r" (EXC_RETURN),
[cpsr] "r" (DEFAULT_CPSR)
: "r0", "r1", "r2");
/* Can't happen. */
ASSERT_FAULT(0);
}
#endif
default:
break;
}
;//turn the led on?
}
/* -----------------------------------------------------------------------------LglSysexHandler()
* The idea here is to identify which Sysex's belong to us and deal with them.
*/
void LglSysexHandler(uint32 *midiBufferRx, uint32 *rx_offset, uint32 *n_unread_packets) {
MIDI_EVENT_PACKET_t * midiPackets = (MIDI_EVENT_PACKET_t *) (midiBufferRx+(*rx_offset));
uint8 nPackets=((*n_unread_packets)-(*rx_offset));
int cPacket;
uint8 soPackets=0;
/********************************* ACHTUNG! ignores usbmidi cable ********************************/
MIDI_EVENT_PACKET_t *packet;
for (cPacket=0;cPacket<nPackets;cPacket++){
packet=midiPackets+cPacket;
if (!CIN_IS_SYSEX(packet->cin)) {
continue;
} // else {
if (!soPackets) {
soPackets=cPacket*4;
}
if ((sysexState==YUP_ITS_MY_SYSEX) && ((sysexFinger+3)>=MAX_SYSEX_SIZE)){
sysexState=ITS_NOT_MY_SYSEX; //eisenhower policy. Even if its mine I cant deal with it.
}
switch (packet->cin) {
case CIN_SYSEX:
switch (sysexState) {
case NOT_IN_SYSEX : // new sysex.
sysexFinger=0;
if (packet->midi0 == MIDIv1_SYSEX_START) {
if (packet->midi1==USYSEX_REAL_TIME
||packet->midi1==USYSEX_NON_REAL_TIME) {
if ((packet->midi2==myMidiChannel)
||(packet->midi2==USYSEX_ALL_CHANNELS)
) {
sysexState=YUP_ITS_MY_SYSEX;
sysexBuffer[sysexFinger++]=MIDIv1_SYSEX_START;
sysexBuffer[sysexFinger++]=packet->midi1;
sysexBuffer[sysexFinger++]=packet->midi2;
break;
}
} else if ((packet->midi1==myMidiID[0])
&& (packet->midi2==myMidiID[1])
){
sysexState=COULD_BE_MY_SYSEX;
sysexBuffer[sysexFinger++]=MIDIv1_SYSEX_START;
sysexBuffer[sysexFinger++]=packet->midi1;
sysexBuffer[sysexFinger++]=packet->midi2;
break;
}
}
break;
case COULD_BE_MY_SYSEX:
if (packet->midi0==myMidiID[2]) {
sysexState=YUP_ITS_MY_SYSEX;
sysexBuffer[sysexFinger++]=packet->midi0;
sysexBuffer[sysexFinger++]=packet->midi1;
sysexBuffer[sysexFinger++]=packet->midi2;
} else {
sysexState=ITS_NOT_MY_SYSEX;
sysexFinger=0;
}
break;
default:
break;
}
break;
case CIN_SYSEX_ENDS_IN_1:
case CIN_SYSEX_ENDS_IN_2:
case CIN_SYSEX_ENDS_IN_3:
sysexBuffer[sysexFinger++]=packet->midi0;
sysexBuffer[sysexFinger++]=packet->midi1;
sysexBuffer[sysexFinger++]=packet->midi2;
if (sysexState==YUP_ITS_MY_SYSEX) {
if(cPacket>=(int32)(*n_unread_packets)){
*n_unread_packets = soPackets;
*rx_offset = soPackets;
} else {
uint8 c = cPacket;
uint32 *s;
uint32 *d = midiBufferRx + soPackets;
for (s = midiBufferRx+c;
((*n_unread_packets) && (s <= midiBufferRx+(USB_MIDI_RX_EPSIZE/4)));
d++,s++
) {
(*d)=(*s);
(*n_unread_packets)--;
(*rx_offset)++;
}
// we need to reset the for loop variables to re process remaining data.
nPackets=((*n_unread_packets)-(*rx_offset));
cPacket=(*rx_offset);
}
dealWithItQuickly();
}
sysexFinger=0;
sysexState=NOT_IN_SYSEX;
break;
default:
return;
}
//}
}
// its our sysex and we will cry if we want to
return;
}
#endif

View File

@ -0,0 +1,37 @@
//
// lgl_min_sysex.h
// LibMaple4Midi
//
// Created by Donald D Davis on 4/11/13.
// Copyright (c) 2013 Suspect Devices. All rights reserved.
//
#ifndef __LGL_MIN_SYSEX_H__
#define __LGL_MIN_SYSEX_H__ 1
#include "MidiSpecs.h"
//#include "LGL.h"
#define LEAFLABS_MMA_VENDOR_1 0x7D
#define LEAFLABS_MMA_VENDOR_2 0x1E
#define LEAFLABS_MMA_VENDOR_3 0x4F
// move to LGL.h
#define LGL_RESET_CMD 0x1e
#define DEFAULT_MIDI_CHANNEL 0x0A
#define DEFAULT_MIDI_DEVICE 0x0A
#define DEFAULT_MIDI_CABLE 0x00
// eventually all of this should be in a place for settings which can be written to flash.
extern volatile uint8 myMidiChannel;
extern volatile uint8 myMidiDevice;
extern volatile uint8 myMidiCable;
extern volatile uint8 myMidiID[];
void LglSysexHandler(uint32 *midiBufferRx,uint32 *rx_offset,uint32 *n_unread_bytes);
#endif

View File

@ -0,0 +1,57 @@
#include "USBHID.h"
//================================================================================
//================================================================================
// Mouse
void HIDMouse::begin(void){
}
void HIDMouse::end(void){
}
void HIDMouse::click(uint8_t b)
{
_buttons = b;
move(0,0,0);
_buttons = 0;
move(0,0,0);
}
void HIDMouse::move(signed char x, signed char y, signed char wheel)
{
reportBuffer[1] = _buttons;
reportBuffer[2] = x;
reportBuffer[3] = y;
reportBuffer[4] = wheel;
sendReport();
}
void HIDMouse::buttons(uint8_t b)
{
if (b != _buttons)
{
_buttons = b;
move(0,0,0);
}
}
void HIDMouse::press(uint8_t b)
{
buttons(_buttons | b);
}
void HIDMouse::release(uint8_t b)
{
buttons(_buttons & ~b);
}
bool HIDMouse::isPressed(uint8_t b)
{
if ((b & _buttons) > 0)
return true;
return false;
}
HIDMouse Mouse;

View File

@ -0,0 +1,88 @@
# USB Composite library for STM32F1
## Protocols supported
- standard USB HID, with many built-in profiles, and customizable with more
- MIDI over USB
- XBox360 controller (only controller-to-host is currently supported)
- Mass storage
## Basic concepts
Start with:
```
#include <USBComposite.h>
```
The library defines several crucial objects. The central object is:
```
extern USBCompositeDevice USBComposite;
```
This controls USB device identification as well as registers the plugins that are connected to it.
Plugin objects included in the library are:
```
extern USBHIDDevice USBHID;
extern USBMidi USBMIDI;
extern USBXBox360 XBox360;
extern USBMassStorageDevice MassStorage;
extern USBCompositeSerial CompositeSerial;
```
You can also create your own customized instances of these plugin classes or their subclasses.
If you want to make a simple (non-composite) USB device, you can just call the plugin's `begin()`
method, and it will take care of registering itself with `USBComposite` and starting up
`USBComposite`. If you want to make a composite USB device, however,
you need to control the device with `USBComposite`:
```
USBComposite.clear(); // clear any plugins previously registered
plugin1.registerComponent();
plugin2.registerComponent();
USBComposite.begin();
```
Of course, you may need to do some further configuring of the plugins or the `USBComposite` device
before the `USBComposite.begin()` call.
Finally, there are a number of objects that implement particular protocols for the `USBHID` plugin:
```
extern HIDMouse Mouse;
extern HIDKeyboard Keyboard;
extern HIDJoystick Joystick;
extern HIDKeyboard BootKeyboard;
```
And you can customize with more. Moreover, the `USBHID` plugin itself allows for compositing
multiple HID profiles, e.g., Mouse / Keyboard / three joysticks.
Not all combinations will fit within the constraints of the STM32F1 USB system, and not all
combinations will be supported by all operating systems.
## Simple USB device configuration
A simple USB device uses a single plugin. You just need to call any setup methods for the plugin
and the `begin()` method for the plugin. For instance, to inject keyboard data, you can do:
```
USBHID.begin(HID_KEYBOARD);
```
and then call `Keyboard.print("TextToInject")` to inject keyboard data. Some plugin configurations
may require further initialization code or further code that needs to be called inside the Arduino
`loop()` function.
See the `BootKeyboard`, `midiout` and `x360` example code for this procedure.
Additionally, for backwards compatibility reasons, the `USBHID` plugin has a convenience
`USBHID_begin_with_serial()` function which works just like `USBHID.begin()` except that it also
composites a `CompositeSerial` plugin.
However, if you want a USB device using more than one plugin, then you will NOT call the plugin's
`begin()` method.

View File

@ -0,0 +1,147 @@
#include "USBComposite.h"
#define DEFAULT_VENDOR_ID 0x1EAF
#define DEFAULT_PRODUCT_ID 0x0004
static char* putSerialNumber(char* out, int nibbles, uint32 id) {
for (int i=0; i<nibbles; i++, id >>= 4) {
uint8 nibble = id & 0xF;
if (nibble <= 9)
*out++ = nibble + '0';
else
*out++ = nibble - 10 + 'a';
}
return out;
}
const char* getDeviceIDString() {
static char string[80/4+1];
char* p = string;
uint32 id = (uint32) *(uint16*) (0x1FFFF7E8+0x02);
p = putSerialNumber(p, 4, id);
id = *(uint32*) (0x1FFFF7E8+0x04);
p = putSerialNumber(p, 8, id);
id = *(uint32*) (0x1FFFF7E8+0x08);
p = putSerialNumber(p, 8, id);
*p = 0;
return string;
}
USBCompositeDevice::USBCompositeDevice(void) {
vendorId = 0;
productId = 0;
numParts = 0;
setManufacturerString(NULL);
setProductString(NULL);
setSerialString(DEFAULT_SERIAL_STRING);
iManufacturer[0] = 0;
iProduct[0] = 0;
iSerialNumber[0] = 0;
}
void USBCompositeDevice::setVendorId(uint16 _vendorId) {
if (_vendorId != 0)
vendorId = _vendorId;
else
vendorId = DEFAULT_VENDOR_ID;
}
void USBCompositeDevice::setProductId(uint16 _productId) {
if (_productId != 0)
productId = _productId;
else
productId = DEFAULT_PRODUCT_ID;
}
void setString(uint8* out, const usb_descriptor_string* defaultDescriptor, const char* s, uint32 maxLength) {
if (s == NULL) {
uint8 n = defaultDescriptor->bLength;
uint8 m = USB_DESCRIPTOR_STRING_LEN(maxLength);
if (n > m)
n = m;
memcpy(out, defaultDescriptor, n);
out[0] = n;
}
else {
uint32 n = strlen(s);
if (n > maxLength)
n = maxLength;
out[0] = (uint8)USB_DESCRIPTOR_STRING_LEN(n);
out[1] = USB_DESCRIPTOR_TYPE_STRING;
for (uint32 i=0; i<n; i++) {
out[2 + 2*i] = (uint8)s[i];
out[2 + 1 + 2*i] = 0;
}
}
}
void USBCompositeDevice::setManufacturerString(const char* s) {
setString(iManufacturer, &usb_generic_default_iManufacturer, s, USB_MAX_MANUFACTURER_LENGTH);
}
void USBCompositeDevice::setProductString(const char* s) {
setString(iProduct, &usb_generic_default_iProduct, s, USB_MAX_PRODUCT_LENGTH);
}
void USBCompositeDevice::setSerialString(const char* s) {
if (s == NULL)
haveSerialNumber = false;
else {
haveSerialNumber = true;
setString(iSerialNumber, NULL, s, USB_MAX_SERIAL_NUMBER_LENGTH);
}
}
bool USBCompositeDevice::begin() {
if (enabled)
return true;
usb_generic_set_info(vendorId, productId, iManufacturer[0] ? iManufacturer : NULL, iProduct[0] ? iProduct : NULL,
haveSerialNumber ? iSerialNumber : NULL);
for (uint32 i = 0 ; i < numParts ; i++) {
if (init[i] != NULL && !init[i](plugin[i]))
return false;
}
if (! usb_generic_set_parts(parts, numParts))
return false;
usb_generic_enable();
enabled = true;
return true;
}
void USBCompositeDevice::end() {
if (!enabled)
return;
usb_generic_disable();
for (uint32 i = 0 ; i < numParts ; i++)
if (stop[i] != NULL)
stop[i](plugin[i]);
enabled = false;
}
void USBCompositeDevice::clear() {
numParts = 0;
}
bool USBCompositeDevice::add(USBCompositePart* part, void* _plugin, USBPartInitializer _init, USBPartStopper _stop) {
unsigned i;
for (i = 0; i<numParts; i++)
if (plugin[numParts] == _plugin && parts[i] == part)
break;
if (i >= USB_COMPOSITE_MAX_PARTS)
return false;
parts[i] = part;
init[i] = _init;
stop[i] = _stop;
plugin[i] = _plugin;
if (i >= numParts)
numParts++;
return true;
}
USBCompositeDevice USBComposite;

View File

@ -0,0 +1,64 @@
#ifndef _USBCOMPOSITE_H_
#define _USBCOMPOSITE_H_
#include <boards.h>
#include "Stream.h"
#include "usb_generic.h"
//#include <libmaple/usb.h>
#include <USBHID.h>
#include <USBXBox360.h>
#include <USBMassStorage.h>
#include <USBCompositeSerial.h>
#define USB_MAX_PRODUCT_LENGTH 32
#define USB_MAX_MANUFACTURER_LENGTH 32
#define USB_MAX_SERIAL_NUMBER_LENGTH 20
// You could use this for a serial number, but you'll be revealing the device ID to the host,
// and hence burning it for cryptographic purposes.
const char* getDeviceIDString();
#define USB_COMPOSITE_MAX_PARTS 6
class USBCompositeDevice;
#define DEFAULT_SERIAL_STRING "00000000000000000001"
typedef bool(*USBPartInitializer)(void*);
typedef void(*USBPartStopper)(void*);
class USBCompositeDevice {
private:
bool enabled = false;
bool haveSerialNumber = false;
uint8_t iManufacturer[USB_DESCRIPTOR_STRING_LEN(USB_MAX_MANUFACTURER_LENGTH)];
uint8_t iProduct[USB_DESCRIPTOR_STRING_LEN(USB_MAX_PRODUCT_LENGTH)];
uint8_t iSerialNumber[USB_DESCRIPTOR_STRING_LEN(USB_MAX_SERIAL_NUMBER_LENGTH)];
uint16 vendorId;
uint16 productId;
USBCompositePart* parts[USB_COMPOSITE_MAX_PARTS];
USBPartInitializer init[USB_COMPOSITE_MAX_PARTS];
USBPartStopper stop[USB_COMPOSITE_MAX_PARTS];
void* plugin[USB_COMPOSITE_MAX_PARTS];
uint32 numParts;
public:
USBCompositeDevice(void);
void setVendorId(uint16 vendor=0);
void setProductId(uint16 product=0);
void setManufacturerString(const char* manufacturer=NULL);
void setProductString(const char* product=NULL);
void setSerialString(const char* serialNumber=DEFAULT_SERIAL_STRING);
bool begin(void);
void end(void);
void clear();
bool isReady() {
return enabled && usb_is_connected(USBLIB) && usb_is_configured(USBLIB);
}
bool add(USBCompositePart* part, void* plugin, USBPartInitializer init = NULL, USBPartStopper stop = NULL);
};
extern USBCompositeDevice USBComposite;
#endif

View File

@ -0,0 +1,274 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 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, DIRECT, 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.
*/
#include <USBCompositeSerial.h>
#include <string.h>
#include <stdint.h>
#include <libmaple/nvic.h>
#include <libmaple/usb.h>
#include <string.h>
#include <libmaple/iwdg.h>
#include "usb_serial.h"
#define USB_TIMEOUT 50
#if defined(SERIAL_USB)
static void rxHook(unsigned, void*);
static void ifaceSetupHook(unsigned, void*);
#endif
bool USBCompositeSerial::init(USBCompositeSerial* me) {
(void)me;
#if defined(SERIAL_USB)
composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, rxHook);
composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook);
#endif
return true;
}
void USBCompositeSerial::begin(long speed) {
(void)speed;
if (!enabled) {
USBComposite.clear();
registerComponent();
USBComposite.begin();
enabled = true;
}
}
void USBCompositeSerial::end() {
if (enabled) {
USBComposite.end();
enabled = false;
}
}
size_t USBCompositeSerial::write(uint8 ch) {
size_t n = 0;
this->write(&ch, 1);
return n;
}
size_t USBCompositeSerial::write(const char *str) {
size_t n = 0;
this->write((const uint8*)str, strlen(str));
return n;
}
size_t USBCompositeSerial::write(const uint8 *buf, uint32 len)
{
size_t n = 0;
if (!this->isConnected() || !buf) {
return 0;
}
uint32 txed = 0;
while (txed < len) {
txed += composite_cdcacm_tx((const uint8*)buf + txed, len - txed);
}
return n;
}
int USBCompositeSerial::available(void) {
return composite_cdcacm_data_available();
}
int USBCompositeSerial::peek(void)
{
uint8 b;
if (composite_cdcacm_peek(&b, 1)==1)
{
return b;
}
else
{
return -1;
}
}
bool USBCompositeSerial::registerComponent() {
return USBComposite.add(&usbSerialPart, this, (USBPartInitializer)&USBCompositeSerial::init);
}
void USBCompositeSerial::flush(void)
{
/*Roger Clark. Rather slow method. Need to improve this */
uint8 b;
while(composite_cdcacm_data_available())
{
this->read(&b, 1);
}
return;
}
uint32 USBCompositeSerial::read(uint8 * buf, uint32 len) {
uint32 rxed = 0;
while (rxed < len) {
rxed += composite_cdcacm_rx(buf + rxed, len - rxed);
}
return rxed;
}
/* Blocks forever until 1 byte is received */
int USBCompositeSerial::read(void) {
uint8 b;
/*
this->read(&b, 1);
return b;
*/
if (composite_cdcacm_rx(&b, 1)==0)
{
return -1;
}
else
{
return b;
}
}
uint8 USBCompositeSerial::pending(void) {
return composite_cdcacm_get_pending();
}
uint8 USBCompositeSerial::isConnected(void) {
return usb_is_connected(USBLIB) && usb_is_configured(USBLIB) && composite_cdcacm_get_dtr();
}
uint8 USBCompositeSerial::getDTR(void) {
return composite_cdcacm_get_dtr();
}
uint8 USBCompositeSerial::getRTS(void) {
return composite_cdcacm_get_rts();
}
#if defined(SERIAL_USB)
enum reset_state_t {
DTR_UNSET,
DTR_HIGH,
DTR_NEGEDGE,
DTR_LOW
};
static reset_state_t reset_state = DTR_UNSET;
static void ifaceSetupHook(unsigned hook, void *requestvp) {
(void)hook;
uint8 request = *(uint8*)requestvp;
// Ignore requests we're not interested in.
if (request != USBHID_CDCACM_SET_CONTROL_LINE_STATE) {
return;
}
// We need to see a negative edge on DTR before we start looking
// for the in-band magic reset byte sequence.
uint8 dtr = composite_cdcacm_get_dtr();
switch (reset_state) {
case DTR_UNSET:
reset_state = dtr ? DTR_HIGH : DTR_LOW;
break;
case DTR_HIGH:
reset_state = dtr ? DTR_HIGH : DTR_NEGEDGE;
break;
case DTR_NEGEDGE:
reset_state = dtr ? DTR_HIGH : DTR_LOW;
break;
case DTR_LOW:
reset_state = dtr ? DTR_HIGH : DTR_LOW;
break;
}
if ((composite_cdcacm_get_baud() == 1200) && (reset_state == DTR_NEGEDGE)) {
iwdg_init(IWDG_PRE_4, 10);
while (1);
}
}
#define RESET_DELAY 100000
static void wait_reset(void) {
delay_us(RESET_DELAY);
nvic_sys_reset();
}
#define STACK_TOP 0x20000800
#define EXC_RETURN 0xFFFFFFF9
#define DEFAULT_CPSR 0x61000000
static void rxHook(unsigned hook, void *ignored) {
(void)hook;
(void)ignored;
/* FIXME this is mad buggy; we need a new reset sequence. E.g. NAK
* after each RX means you can't reset if any bytes are waiting. */
if (reset_state == DTR_NEGEDGE) {
reset_state = DTR_LOW;
if (composite_cdcacm_data_available() >= 4) {
// The magic reset sequence is "1EAF".
static const uint8 magic[4] = {'1', 'E', 'A', 'F'};
uint8 chkBuf[4];
// Peek at the waiting bytes, looking for reset sequence,
// bailing on mismatch.
composite_cdcacm_peek_ex(chkBuf, composite_cdcacm_data_available() - 4, 4);
for (unsigned i = 0; i < sizeof(magic); i++) {
if (chkBuf[i] != magic[i]) {
return;
}
}
// Got the magic sequence -> reset, presumably into the bootloader.
// Return address is wait_reset, but we must set the thumb bit.
uintptr_t target = (uintptr_t)wait_reset | 0x1;
asm volatile("mov r0, %[stack_top] \n\t" // Reset stack
"mov sp, r0 \n\t"
"mov r0, #1 \n\t"
"mov r1, %[target_addr] \n\t"
"mov r2, %[cpsr] \n\t"
"push {r2} \n\t" // Fake xPSR
"push {r1} \n\t" // PC target addr
"push {r0} \n\t" // Fake LR
"push {r0} \n\t" // Fake R12
"push {r0} \n\t" // Fake R3
"push {r0} \n\t" // Fake R2
"push {r0} \n\t" // Fake R1
"push {r0} \n\t" // Fake R0
"mov lr, %[exc_return] \n\t"
"bx lr"
:
: [stack_top] "r" (STACK_TOP),
[target_addr] "r" (target),
[exc_return] "r" (EXC_RETURN),
[cpsr] "r" (DEFAULT_CPSR)
: "r0", "r1", "r2");
/* Can't happen. */
ASSERT_FAULT(0);
}
}
}
#endif
USBCompositeSerial CompositeSerial;

View File

@ -0,0 +1,40 @@
#ifndef _COMPOSITE_SERIAL_H_
#define _COMPOSITE_SERIAL_H_
#include "USBComposite.h"
#include "usb_serial.h"
class USBCompositeSerial : public Stream {
private:
bool enabled = false;
public:
void begin(long speed=9600);
void end();
static bool init(USBCompositeSerial* me);
bool registerComponent();
operator bool() { return true; } // Roger Clark. This is needed because in cardinfo.ino it does if (!Serial) . It seems to be a work around for the Leonardo that we needed to implement just to be compliant with the API
virtual int available(void);// Changed to virtual
uint32 read(uint8 * buf, uint32 len);
// uint8 read(void);
// Roger Clark. added functions to support Arduino 1.0 API
virtual int peek(void);
virtual int read(void);
int availableForWrite(void);
virtual void flush(void);
size_t write(uint8);
size_t write(const char *str);
size_t write(const uint8*, uint32);
uint8 getRTS();
uint8 getDTR();
uint8 isConnected();
uint8 pending();
};
extern USBCompositeSerial CompositeSerial;
#endif

View File

@ -0,0 +1,180 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 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, DIRECT, 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.
*/
#include "USBHID.h"
#include "USBCompositeSerial.h"
#include <string.h>
#include <stdint.h>
#include <libmaple/nvic.h>
#include "usb_hid.h"
#include "usb_serial.h"
#include "usb_generic.h"
#include <libmaple/usb.h>
#include <string.h>
#include <libmaple/iwdg.h>
#include <wirish.h>
/*
* USB HID interface
*/
bool USBHIDDevice::registerComponent() {
return USBComposite.add(&usbHIDPart, this);
}
void USBHIDDevice::setReportDescriptor(const uint8_t* report_descriptor, uint16_t report_descriptor_length) {
usb_hid_set_report_descriptor(report_descriptor, report_descriptor_length);
}
void USBHIDDevice::setReportDescriptor(const HIDReportDescriptor* report) {
setReportDescriptor(report->descriptor, report->length);
}
void USBHIDDevice::begin(const uint8_t* report_descriptor, uint16_t report_descriptor_length, uint16_t idVendor, uint16_t idProduct,
const char* manufacturer, const char* product, const char* serialNumber) {
if (enabledHID)
return;
setReportDescriptor(report_descriptor, report_descriptor_length);
USBComposite.clear();
USBComposite.setVendorId(idVendor);
USBComposite.setProductId(idProduct);
USBComposite.setManufacturerString(manufacturer);
USBComposite.setProductString(product);
USBComposite.setSerialString(serialNumber);
registerComponent();
USBComposite.begin();
enabledHID = true;
}
void USBHIDDevice::begin(const HIDReportDescriptor* report, uint16_t idVendor, uint16_t idProduct,
const char* manufacturer, const char* product, const char* serialNumber) {
begin(report->descriptor, report->length, idVendor, idProduct, manufacturer, product, serialNumber);
}
void USBHIDDevice::setBuffers(uint8_t type, volatile HIDBuffer_t* fb, int count) {
usb_hid_set_buffers(type, fb, count);
}
bool USBHIDDevice::addBuffer(uint8_t type, volatile HIDBuffer_t* buffer) {
return 0 != usb_hid_add_buffer(type, buffer);
}
void USBHIDDevice::clearBuffers(uint8_t type) {
usb_hid_clear_buffers(type);
}
void USBHIDDevice::clearBuffers() {
clearBuffers(HID_REPORT_TYPE_OUTPUT);
clearBuffers(HID_REPORT_TYPE_FEATURE);
}
void USBHIDDevice::end(void){
if(enabledHID){
USBComposite.end();
enabledHID = false;
}
}
void HIDReporter::sendReport() {
// while (usb_is_transmitting() != 0) {
// }
unsigned toSend = bufferSize;
uint8* b = buffer;
while (toSend) {
unsigned delta = usb_hid_tx(b, toSend);
toSend -= delta;
b += delta;
}
// while (usb_is_transmitting() != 0) {
// }
/* flush out to avoid having the pc wait for more data */
usb_hid_tx(NULL, 0);
}
HIDReporter::HIDReporter(uint8_t* _buffer, unsigned _size, uint8_t _reportID) {
if (_reportID == 0) {
buffer = _buffer+1;
bufferSize = _size-1;
}
else {
buffer = _buffer;
bufferSize = _size;
}
memset(buffer, 0, bufferSize);
reportID = _reportID;
if (_size > 0 && reportID != 0)
buffer[0] = _reportID;
}
HIDReporter::HIDReporter(uint8_t* _buffer, unsigned _size) {
buffer = _buffer;
bufferSize = _size;
memset(buffer, 0, _size);
reportID = 0;
}
void HIDReporter::setFeature(uint8_t* in) {
return usb_hid_set_feature(reportID, in);
}
uint16_t HIDReporter::getData(uint8_t type, uint8_t* out, uint8_t poll) {
return usb_hid_get_data(type, reportID, out, poll);
}
uint16_t HIDReporter::getFeature(uint8_t* out, uint8_t poll) {
return usb_hid_get_data(HID_REPORT_TYPE_FEATURE, reportID, out, poll);
}
uint16_t HIDReporter::getOutput(uint8_t* out, uint8_t poll) {
return usb_hid_get_data(HID_REPORT_TYPE_OUTPUT, reportID, out, poll);
}
USBHIDDevice USBHID;
void USBHID_begin_with_serial(const uint8_t* report_descriptor, uint16_t report_descriptor_length, uint16_t idVendor, uint16_t idProduct,
const char* manufacturer, const char* product, const char* serialNumber) {
USBComposite.clear();
USBComposite.setVendorId(idVendor);
USBComposite.setProductId(idProduct);
USBComposite.setManufacturerString(manufacturer);
USBComposite.setProductString(product);
USBComposite.setSerialString(serialNumber);
USBHID.setReportDescriptor(report_descriptor, report_descriptor_length);
USBHID.registerComponent();
CompositeSerial.registerComponent();
USBComposite.begin();
}
void USBHID_begin_with_serial(const HIDReportDescriptor* report, uint16_t idVendor, uint16_t idProduct,
const char* manufacturer, const char* product, const char* serialNumber) {
USBHID_begin_with_serial(report->descriptor, report->length, idVendor, idProduct, manufacturer, product, serialNumber);
}

View File

@ -0,0 +1,608 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 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, DIRECT, 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.
*/
#ifndef _USBHID_H_
#define _USBHID_H_
#include <USBComposite.h>
#include <USBCompositeSerial.h>
#include <Print.h>
#include <boards.h>
#include "Stream.h"
#include "usb_hid.h"
#define USB_HID_MAX_PRODUCT_LENGTH 32
#define USB_HID_MAX_MANUFACTURER_LENGTH 32
#define USB_HID_MAX_SERIAL_NUMBER_LENGTH 20
#define HID_MOUSE_REPORT_ID 1
#define HID_KEYBOARD_REPORT_ID 2
#define HID_CONSUMER_REPORT_ID 3
#define HID_JOYSTICK_REPORT_ID 20
#define HID_KEYBOARD_ROLLOVER 6
#define MACRO_GET_ARGUMENT_2(x, y, ...) y
#define MACRO_GET_ARGUMENT_1_WITH_DEFAULT(default, ...) MACRO_GET_ARGUMENT_2(placeholder, ## __VA_ARGS__, default)
#define MACRO_ARGUMENT_2_TO_END(skip, ...) __VA_ARGS__
// HIDBuffer_t data buffers must have even memory length because of how PMA transfers work
#define HID_DATA_BUFFER_SIZE(n) (((n)+1)/2*2)
/* note that featureSize must be 1 less than the buffer size for the feature,
since the latter must include the reportId */
/* this only works in a collection with a report_id */
#define HID_FEATURE_REPORT_DESCRIPTOR(dataSize) \
0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 1) */ \
0x09, 0x01, /* USAGE (Vendor Usage 1) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x95, dataSize, /* REPORT_COUNT (xx) */ \
0xB1, 0x02, /* FEATURE (Data,Var,Abs) */ \
#define HID_OUTPUT_REPORT_DESCRIPTOR(dataSize) \
0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 1) */ \
0x09, 0x01, /* USAGE (Vendor Usage 1) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x95, dataSize, /* REPORT_COUNT (32) */ \
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \
#define HID_CONSUMER_REPORT_DESCRIPTOR(...) \
0x05, 0x0C, /* usage page (consumer device) */ \
0x09, 0x01, /* usage -- consumer control */ \
0xA1, 0x01, /* collection (application) */ \
0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_CONSUMER_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \
0x15, 0x00, /* logical minimum */ \
0x26, 0xFF, 0x03, /* logical maximum (3ff) */ \
0x19, 0x00, /* usage minimum (0) */ \
0x2A, 0xFF, 0x03, /* usage maximum (3ff) */ \
0x75, 0x10, /* report size (16) */ \
0x95, 0x01, /* report count (1) */ \
0x81, 0x00, /* input */ \
MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \
0xC0 /* end collection */
#define HID_MOUSE_REPORT_DESCRIPTOR(...) \
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 54 */ \
0x09, 0x02, /* USAGE (Mouse) */ \
0xa1, 0x01, /* COLLECTION (Application) */ \
0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_MOUSE_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \
0x09, 0x01, /* USAGE (Pointer) */ \
0xa1, 0x00, /* COLLECTION (Physical) */ \
0x05, 0x09, /* USAGE_PAGE (Button) */ \
0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \
0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x95, 0x08, /* REPORT_COUNT (8) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \
0x09, 0x30, /* USAGE (X) */ \
0x09, 0x31, /* USAGE (Y) */ \
0x09, 0x38, /* USAGE (Wheel) */ \
0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \
0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x95, 0x03, /* REPORT_COUNT (3) */ \
0x81, 0x06, /* INPUT (Data,Var,Rel) */ \
0xc0, /* END_COLLECTION */ \
MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \
0xc0 /* END_COLLECTION */
#define HID_ABS_MOUSE_REPORT_DESCRIPTOR(...) \
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 54 */ \
0x09, 0x02, /* USAGE (Mouse) */ \
0xa1, 0x01, /* COLLECTION (Application) */ \
0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_MOUSE_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \
0x09, 0x01, /* USAGE (Pointer) */ \
0xa1, 0x00, /* COLLECTION (Physical) */ \
0x05, 0x09, /* USAGE_PAGE (Button) */ \
0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \
0x29, 0x08, /* USAGE_MAXIMUM (Button 8) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x95, 0x08, /* REPORT_COUNT (8) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \
0x09, 0x30, /* USAGE (X) */ \
0x09, 0x31, /* USAGE (Y) */ \
0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32768) */ \
0x26, 0xFF, 0x7f, /* LOGICAL_MAXIMUM (32767) */ \
0x75, 0x10, /* REPORT_SIZE (16) */ \
0x95, 0x02, /* REPORT_COUNT (2) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x09, 0x38, /* USAGE (Wheel) */ \
0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \
0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x81, 0x06, /* INPUT (Data,Var,Rel) */ \
0xc0, /* END_COLLECTION */ \
MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \
0xc0 /* END_COLLECTION */
#define HID_KEYBOARD_REPORT_DESCRIPTOR(...) \
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 47 */ \
0x09, 0x06, /* USAGE (Keyboard) */ \
0xa1, 0x01, /* COLLECTION (Application) */ \
0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_KEYBOARD_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \
0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ \
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x95, 0x08, /* REPORT_COUNT (8) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
\
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \
\
0x95, HID_KEYBOARD_ROLLOVER, /* REPORT_COUNT (6) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \
0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \
\
0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \
0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \
\
0x05, 0x08, /* USAGE_PAGE (LEDs) */ \
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ \
0x29, 0x08, /* USAGE_MAXIMUM (Kana + 3 custom)*/ \
0x95, 0x08, /* REPORT_COUNT (8) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \
MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \
0xc0 /* END_COLLECTION */
#define HID_BOOT_KEYBOARD_REPORT_DESCRIPTOR(...) \
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) // 47 */ \
0x09, 0x06, /* USAGE (Keyboard) */ \
0xa1, 0x01, /* COLLECTION (Application) */ \
0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ \
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x95, 0x08, /* REPORT_COUNT (8) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
\
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \
\
0x95, 0x06, /* REPORT_COUNT (6) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ \
0x05, 0x07, /* USAGE_PAGE (Keyboard) */ \
\
0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */ \
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ \
0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \
\
0x05, 0x08, /* USAGE_PAGE (LEDs) */ \
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ \
0x29, 0x08, /* USAGE_MAXIMUM (Kana + 3 custom)*/ \
0x95, 0x08, /* REPORT_COUNT (8) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ \
__VA_ARGS__ \
0xc0 /* END_COLLECTION */
#define HID_JOYSTICK_REPORT_DESCRIPTOR(...) \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x04, /* Usage (Joystick) */ \
0xA1, 0x01, /* Collection (Application) */ \
0x85, MACRO_GET_ARGUMENT_1_WITH_DEFAULT(HID_JOYSTICK_REPORT_ID, ## __VA_ARGS__), /* REPORT_ID */ \
0x15, 0x00, /* Logical Minimum (0) */ \
0x25, 0x01, /* Logical Maximum (1) */ \
0x75, 0x01, /* Report Size (1) */ \
0x95, 0x20, /* Report Count (32) */ \
0x05, 0x09, /* Usage Page (Button) */ \
0x19, 0x01, /* Usage Minimum (Button #1) */ \
0x29, 0x20, /* Usage Maximum (Button #32) */ \
0x81, 0x02, /* Input (variable,absolute) */ \
0x15, 0x00, /* Logical Minimum (0) */ \
0x25, 0x07, /* Logical Maximum (7) */ \
0x35, 0x00, /* Physical Minimum (0) */ \
0x46, 0x3B, 0x01, /* Physical Maximum (315) */ \
0x75, 0x04, /* Report Size (4) */ \
0x95, 0x01, /* Report Count (1) */ \
0x65, 0x14, /* Unit (20) */ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x39, /* Usage (Hat switch) */ \
0x81, 0x42, /* Input (variable,absolute,null_state) */ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x01, /* Usage (Pointer) */ \
0xA1, 0x00, /* Collection () */ \
0x15, 0x00, /* Logical Minimum (0) */ \
0x26, 0xFF, 0x03, /* Logical Maximum (1023) */ \
0x75, 0x0A, /* Report Size (10) */ \
0x95, 0x04, /* Report Count (4) */ \
0x09, 0x30, /* Usage (X) */ \
0x09, 0x31, /* Usage (Y) */ \
0x09, 0x33, /* Usage (Rx) */ \
0x09, 0x34, /* Usage (Ry) */ \
0x81, 0x02, /* Input (variable,absolute) */ \
0xC0, /* End Collection */ \
0x15, 0x00, /* Logical Minimum (0) */ \
0x26, 0xFF, 0x03, /* Logical Maximum (1023) */ \
0x75, 0x0A, /* Report Size (10) */ \
0x95, 0x02, /* Report Count (2) */ \
0x09, 0x36, /* Usage (Slider) */ \
0x09, 0x36, /* Usage (Slider) */ \
0x81, 0x02, /* Input (variable,absolute) */ \
MACRO_ARGUMENT_2_TO_END(__VA_ARGS__) \
0xC0
#define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF
#define LSB(x) ((x) & 0xFF)
#define MSB(x) (((x) & 0xFF00) >> 8)
// TODO: make this work for txSize > 255
#define HID_RAW_REPORT_DESCRIPTOR(txSize, rxSize) \
0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), \
0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), \
0xA1, 0x01, /* Collection 0x01 */ \
/* 0x85, 10, */ /* REPORT_ID (1) */ \
0x75, 0x08, /* report size = 8 bits */ \
0x15, 0x00, /* logical minimum = 0 */ \
0x26, 0xFF, 0x00, /* logical maximum = 255 */ \
\
0x96, LSB(txSize), MSB(txSize), /* report count TX */ \
0x09, 0x01, /* usage */ \
0x81, 0x02, /* Input (array) */ \
\
0x75, 0x08, /* report size = 8 bits */ \
0x15, 0x00, /* logical minimum = 0 */ \
0x26, 0xFF, 0x00, /* logical maximum = 255 */ \
0x96, LSB(rxSize), MSB(rxSize), /* report count RX */ \
0x09, 0x02, /* usage */ \
0x91, 0x02, /* OUTPUT (0x91) */ \
0xC0 /* end collection */
typedef struct {
uint8_t* descriptor;
uint16_t length;
} HIDReportDescriptor;
class USBHIDDevice {
private:
bool enabledHID = false;
public:
bool registerComponent();
void setReportDescriptor(const uint8_t* report_descriptor, uint16_t report_descriptor_length);
void setReportDescriptor(const HIDReportDescriptor* reportDescriptor);
// All the strings are zero-terminated ASCII strings. Use NULL for defaults.
void begin(const uint8_t* report_descriptor, uint16_t length, uint16_t idVendor=0, uint16_t idProduct=0,
const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001");
void begin(const HIDReportDescriptor* reportDescriptor, uint16_t idVendor=0, uint16_t idProduct=0,
const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001");
void setSerial(uint8 serialSupport=true);
void setBuffers(uint8_t buffers, volatile HIDBuffer_t* fb=NULL, int count=0); // type = HID_REPORT_TYPE_FEATURE or HID_REPORT_TYPE_OUTPUT
bool addBuffer(uint8_t type, volatile HIDBuffer_t* buffer);
void clearBuffers(uint8_t type);
void clearBuffers();
inline bool addFeatureBuffer(volatile HIDBuffer_t* buffer) {
return addBuffer(HID_REPORT_TYPE_FEATURE, buffer);
}
inline bool addOutputBuffer(volatile HIDBuffer_t* buffer) {
return addBuffer(HID_REPORT_TYPE_OUTPUT, buffer);
}
inline void setFeatureBuffers(volatile HIDBuffer_t* fb=NULL, int count=0) {
setBuffers(HID_REPORT_TYPE_FEATURE, fb, count);
}
inline void setOutputBuffers(volatile HIDBuffer_t* fb=NULL, int count=0) {
setBuffers(HID_REPORT_TYPE_OUTPUT, fb, count);
}
void end(void);
};
void USBHID_begin_with_serial(const uint8_t* report_descriptor, uint16_t length, uint16_t idVendor=0, uint16_t idProduct=0,
const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001");
void USBHID_begin_with_serial(const HIDReportDescriptor* reportDescriptor, uint16_t idVendor=0, uint16_t idProduct=0,
const char* manufacturer=NULL, const char* product=NULL, const char* serialNumber="00000000000000000001");
class HIDReporter {
private:
uint8_t* buffer;
unsigned bufferSize;
uint8_t reportID;
public:
void sendReport();
public:
// if you use this init function, the buffer starts with a reportID, even if the reportID is zero,
// and bufferSize includes the reportID; if reportID is zero, sendReport() will skip the initial
// reportID byte
HIDReporter(uint8_t* _buffer, unsigned _size, uint8_t _reportID);
// if you use this init function, the buffer has no reportID byte in it
HIDReporter(uint8_t* _buffer, unsigned _size);
uint16_t getFeature(uint8_t* out=NULL, uint8_t poll=1);
uint16_t getOutput(uint8_t* out=NULL, uint8_t poll=1);
uint16_t getData(uint8_t type, uint8_t* out, uint8_t poll=1); // type = HID_REPORT_TYPE_FEATURE or HID_REPORT_TYPE_OUTPUT
void setFeature(uint8_t* feature);
};
//================================================================================
//================================================================================
// Mouse
#define MOUSE_LEFT 1
#define MOUSE_RIGHT 2
#define MOUSE_MIDDLE 4
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)
class HIDMouse : public HIDReporter {
protected:
uint8_t _buttons;
void buttons(uint8_t b);
uint8_t reportBuffer[5];
public:
HIDMouse(uint8_t reportID=HID_MOUSE_REPORT_ID) : HIDReporter(reportBuffer, sizeof(reportBuffer), reportID), _buttons(0) {}
void begin(void);
void end(void);
void click(uint8_t b = MOUSE_LEFT);
void move(signed char x, signed char y, signed char wheel = 0);
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default
};
typedef struct {
uint8_t reportID;
uint8_t buttons;
int16_t x;
int16_t y;
uint8_t wheel;
} __packed AbsMouseReport_t;
class HIDAbsMouse : public HIDReporter {
protected:
void buttons(uint8_t b);
AbsMouseReport_t report;
public:
HIDAbsMouse(uint8_t reportID=HID_MOUSE_REPORT_ID) : HIDReporter((uint8_t*)&report, sizeof(report), reportID) {
report.buttons = 0;
report.x = 0;
report.y = 0;
report.wheel = 0;
}
void begin(void);
void end(void);
void click(uint8_t b = MOUSE_LEFT);
void move(int16_t x, int16_t y, int8_t wheel = 0);
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default
};
typedef struct {
uint8_t reportID;
uint16_t button;
} __packed ConsumerReport_t;
class HIDConsumer : public HIDReporter {
protected:
ConsumerReport_t report;
public:
enum {
BRIGHTNESS_UP = 0x6F,
BRIGHTNESS_DOWN = 0x70,
VOLUME_UP = 0xE9,
VOLUME_DOWN = 0xEA,
MUTE = 0xE2,
PLAY_OR_PAUSE = 0xCD
// see pages 75ff of http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
};
HIDConsumer(uint8_t reportID=HID_CONSUMER_REPORT_ID) : HIDReporter((uint8_t*)&report, sizeof(report), reportID) {
report.button = 0;
}
void begin(void);
void end(void);
void press(uint16_t button);
void release();
};
#define KEY_LEFT_CTRL 0x80
#define KEY_LEFT_SHIFT 0x81
#define KEY_LEFT_ALT 0x82
#define KEY_LEFT_GUI 0x83
#define KEY_RIGHT_CTRL 0x84
#define KEY_RIGHT_SHIFT 0x85
#define KEY_RIGHT_ALT 0x86
#define KEY_RIGHT_GUI 0x87
#define KEY_UP_ARROW 0xDA
#define KEY_DOWN_ARROW 0xD9
#define KEY_LEFT_ARROW 0xD8
#define KEY_RIGHT_ARROW 0xD7
#define KEY_BACKSPACE 0xB2
#define KEY_TAB 0xB3
#define KEY_RETURN 0xB0
#define KEY_ESC 0xB1
#define KEY_INSERT 0xD1
#define KEY_DELETE 0xD4
#define KEY_PAGE_UP 0xD3
#define KEY_PAGE_DOWN 0xD6
#define KEY_HOME 0xD2
#define KEY_END 0xD5
#define KEY_CAPS_LOCK 0xC1
#define KEY_F1 0xC2
#define KEY_F2 0xC3
#define KEY_F3 0xC4
#define KEY_F4 0xC5
#define KEY_F5 0xC6
#define KEY_F6 0xC7
#define KEY_F7 0xC8
#define KEY_F8 0xC9
#define KEY_F9 0xCA
#define KEY_F10 0xCB
#define KEY_F11 0xCC
#define KEY_F12 0xCD
typedef struct{
uint8_t reportID;
uint8_t modifiers;
uint8_t reserved;
uint8_t keys[HID_KEYBOARD_ROLLOVER];
} __packed KeyReport_t;
class HIDKeyboard : public Print, public HIDReporter {
public:
KeyReport_t keyReport;
protected:
uint8_t leds[HID_BUFFER_ALLOCATE_SIZE(1,1)];
HIDBuffer_t ledData;
uint8_t reportID;
uint8_t getKeyCode(uint8_t k, uint8_t* modifiersP);
bool adjustForHostCapsLock = true;
public:
HIDKeyboard(uint8_t _reportID=HID_KEYBOARD_REPORT_ID) :
HIDReporter((uint8*)&keyReport, sizeof(KeyReport_t), _reportID),
ledData(leds, HID_BUFFER_SIZE(1,_reportID), _reportID, HID_BUFFER_MODE_NO_WAIT),
reportID(_reportID)
{}
void begin(void);
void end(void);
void setAdjustForHostCapsLock(bool state) {
adjustForHostCapsLock = state;
}
inline uint8 getLEDs(void) {
return leds[reportID != 0 ? 1 : 0];
}
virtual size_t write(uint8_t k);
virtual size_t press(uint8_t k);
virtual size_t release(uint8_t k);
virtual void releaseAll(void);
};
//================================================================================
//================================================================================
// Joystick
// only works for little-endian machines, but makes the code so much more
// readable
typedef struct {
uint8_t reportID;
uint32_t buttons;
unsigned hat:4;
unsigned x:10;
unsigned y:10;
unsigned rx:10;
unsigned ry:10;
unsigned sliderLeft:10;
unsigned sliderRight:10;
} __packed JoystickReport_t;
static_assert(sizeof(JoystickReport_t)==13, "Wrong endianness/packing!");
class HIDJoystick : public HIDReporter {
protected:
JoystickReport_t joyReport;
bool manualReport = false;
void safeSendReport(void);
public:
inline void send(void) {
sendReport();
}
void setManualReportMode(bool manualReport); // in manual report mode, reports only sent when send() is called
bool getManualReportMode();
void begin(void);
void end(void);
void button(uint8_t button, bool val);
void X(uint16_t val);
void Y(uint16_t val);
void position(uint16_t x, uint16_t y);
void Xrotate(uint16_t val);
void Yrotate(uint16_t val);
void sliderLeft(uint16_t val);
void sliderRight(uint16_t val);
void slider(uint16_t val);
void hat(int16_t dir);
HIDJoystick(uint8_t reportID=HID_JOYSTICK_REPORT_ID) : HIDReporter((uint8_t*)&joyReport, sizeof(joyReport), reportID) {
joyReport.buttons = 0;
joyReport.hat = 15;
joyReport.x = 512;
joyReport.y = 512;
joyReport.rx = 512;
joyReport.ry = 512;
joyReport.sliderLeft = 0;
joyReport.sliderRight = 0;
}
};
extern USBHIDDevice USBHID;
template<unsigned txSize,unsigned rxSize>class HIDRaw : public HIDReporter {
private:
uint8_t txBuffer[txSize];
uint8_t rxBuffer[HID_BUFFER_ALLOCATE_SIZE(rxSize,0)];
HIDBuffer_t buf;
public:
HIDRaw() : HIDReporter(txBuffer, sizeof(txBuffer)) {}
void begin(void) {
buf.buffer = rxBuffer;
buf.bufferSize = HID_BUFFER_SIZE(rxSize,0);
buf.reportID = 0;
USBHID.addOutputBuffer(&buf);
}
void end(void);
void send(const uint8_t* data, unsigned n=sizeof(txBuffer)) {
memset(txBuffer, 0, sizeof(txBuffer));
memcpy(txBuffer, data, n>sizeof(txBuffer)?sizeof(txBuffer):n);
sendReport();
}
};
extern HIDMouse Mouse;
extern HIDKeyboard Keyboard;
extern HIDJoystick Joystick;
extern HIDKeyboard BootKeyboard;
extern const HIDReportDescriptor* hidReportMouse;
extern const HIDReportDescriptor* hidReportKeyboard;
extern const HIDReportDescriptor* hidReportJoystick;
extern const HIDReportDescriptor* hidReportKeyboardMouse;
extern const HIDReportDescriptor* hidReportKeyboardJoystick;
extern const HIDReportDescriptor* hidReportKeyboardMouseJoystick;
extern const HIDReportDescriptor* hidReportBootKeyboard;
#define HID_MOUSE hidReportMouse
#define HID_KEYBOARD hidReportKeyboard
#define HID_JOYSTICK hidReportJoystick
#define HID_KEYBOARD_MOUSE hidReportKeyboardMouse
#define HID_KEYBOARD_JOYSTICK hidReportKeyboardJoystick
#define HID_KEYBOARD_MOUSE_JOYSTICK hidReportKeyboardMouseJoystick
#define HID_BOOT_KEYBOARD hidReportBootKeyboard
#endif

View File

@ -0,0 +1,469 @@
/******************************************************************************
* This started out as a munging of Tymm Twillman's arduino Midi Library into the Libusb class,
* though by now very little of the original code is left, except for the class API and
* comments. Tymm Twillman kindly gave Alexander Pruss permission to relicense his code under the MIT
* license, which fixed a nasty licensing mess.
*
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2013 Magnus Lundin.
* Copyright (c) 2013 Donald Delmar Davis, Suspect Devices.
* (c) 2003-2008 Tymm Twillman <tymm@booyaka.com>
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*
*
*****************************************************************************/
/**
* @brief USB MIDI device with a class compatible with maplemidi
*/
#include "USBMIDI.h"
#include <string.h>
#include <stdint.h>
#include <libmaple/nvic.h>
#include <wirish.h>
#include "usb_midi_device.h"
#include <libmaple/usb.h>
#include "usb_generic.h"
/*
* USBMidi interface
*/
#define USB_TIMEOUT 50
void USBMidi::setChannel(unsigned int channel) {
channelIn_ = channel;
}
/*bool USBMidi::init(USBMidi* me) {
return true;
}*/
bool USBMidi::registerComponent() {
return USBComposite.add(&usbMIDIPart, this);
}
void USBMidi::begin(unsigned channel) {
setChannel(channel);
if (enabled)
return;
USBComposite.clear();
registerComponent();
USBComposite.begin();
enabled = true;
}
void USBMidi::end(void) {
if (enabled) {
USBComposite.end();
enabled = false;
}
}
void USBMidi::writePacket(uint32 p) {
this->writePackets(&p, 1);
}
void USBMidi::writePackets(const void *buf, uint32 len) {
if (!this->isConnected() || !buf) {
return;
}
uint32 txed = 0;
uint32 old_txed = 0;
uint32 start = millis();
uint32 sent = 0;
while (txed < len && (millis() - start < USB_TIMEOUT)) {
sent = usb_midi_tx((const uint32*)buf + txed, len - txed);
txed += sent;
if (old_txed != txed) {
start = millis();
}
old_txed = txed;
}
if (sent == USB_MIDI_TX_EPSIZE) {
while (usb_midi_is_transmitting() != 0) {
}
/* flush out to avoid having the pc wait for more data */
usb_midi_tx(NULL, 0);
}
}
uint32 USBMidi::available(void) {
return usb_midi_data_available();
}
uint32 USBMidi::readPackets(void *buf, uint32 len) {
if (!buf) {
return 0;
}
uint32 rxed = 0;
while (rxed < len) {
rxed += usb_midi_rx((uint32*)buf + rxed, len - rxed);
}
return rxed;
}
/* Blocks forever until 1 byte is received */
uint32 USBMidi::readPacket(void) {
uint32 p;
this->readPackets(&p, 1);
return p;
}
uint8 USBMidi::pending(void) {
return usb_midi_get_pending();
}
uint8 USBMidi::isConnected(void) {
return usb_is_connected(USBLIB) && usb_is_configured(USBLIB);
}
USBMidi USBMIDI;
// These are midi status message types are defined in MidiSpec.h
union EVENT_t {
uint32 i;
uint8 b[4];
MIDI_EVENT_PACKET_t p;
};
// Handle decoding incoming MIDI traffic a word at a time -- remembers
// what it needs to from one call to the next.
//
// This is a private function & not meant to be called from outside this class.
// It's used whenever data is available from the USB port.
//
void USBMidi::dispatchPacket(uint32 p)
{
union EVENT_t e;
e.i=p;
switch (e.p.cin) {
case CIN_3BYTE_SYS_COMMON:
if (e.p.midi0 == MIDIv1_SONG_POSITION_PTR) {
handleSongPosition(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1));
}
break;
case CIN_2BYTE_SYS_COMMON:
switch (e.p.midi0) {
case MIDIv1_SONG_SELECT:
handleSongSelect(e.p.midi1);
break;
case MIDIv1_MTC_QUARTER_FRAME:
// reference library doesnt handle quarter frame.
break;
}
break;
case CIN_NOTE_OFF:
handleNoteOff(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2);
break;
case CIN_NOTE_ON:
handleNoteOn(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2);
break;
case CIN_AFTER_TOUCH:
handleVelocityChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2);
break;
case CIN_CONTROL_CHANGE:
handleControlChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1, e.p.midi2);
break;
case CIN_PROGRAM_CHANGE:
handleProgramChange(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1);
break;
case CIN_CHANNEL_PRESSURE:
handleAfterTouch(MIDIv1_VOICE_CHANNEL(e.p.midi0), e.p.midi1);
break;
case CIN_PITCH_WHEEL:
handlePitchChange(((uint16)e.p.midi2)<<7|((uint16)e.p.midi1));
break;
case CIN_1BYTE:
switch (e.p.midi0) {
case MIDIv1_CLOCK:
handleSync();
break;
case MIDIv1_TICK:
break;
case MIDIv1_START:
handleStart();
break;
case MIDIv1_CONTINUE:
handleContinue();
break;
case MIDIv1_STOP:
handleStop();
break;
case MIDIv1_ACTIVE_SENSE:
handleActiveSense();
break;
case MIDIv1_RESET:
handleReset();
break;
case MIDIv1_TUNE_REQUEST:
handleTuneRequest();
break;
default:
break;
}
break;
}
}
// Try to read data from USB port & pass anything read to processing function
void USBMidi::poll(void)
{ while(available()) {
dispatchPacket(readPacket());
}
}
static union EVENT_t outPacket; // since we only use one at a time no point in reallocating it
// Send Midi NOTE OFF message to a given channel, with note 0-127 and velocity 0-127
void USBMidi::sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_NOTE_OFF;
outPacket.p.midi0=MIDIv1_NOTE_OFF|(channel & 0x0f);
outPacket.p.midi1=note;
outPacket.p.midi2=velocity;
writePacket(outPacket.i);
}
// Send Midi NOTE ON message to a given channel, with note 0-127 and velocity 0-127
void USBMidi::sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_NOTE_ON;
outPacket.p.midi0=MIDIv1_NOTE_ON|(channel & 0x0f);
outPacket.p.midi1=note;
outPacket.p.midi2=velocity;
writePacket(outPacket.i);
}
// Send a Midi VELOCITY CHANGE message to a given channel, with given note 0-127,
// and new velocity 0-127
// Note velocity change == polyphonic aftertouch.
// Note aftertouch == channel pressure.
void USBMidi::sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_AFTER_TOUCH;
outPacket.p.midi0=MIDIv1_AFTER_TOUCH |(channel & 0x0f);
outPacket.p.midi1=note;
outPacket.p.midi2=velocity;
writePacket(outPacket.i);
}
// Send a Midi CC message to a given channel, as a given controller 0-127, with given
// value 0-127
void USBMidi::sendControlChange(unsigned int channel, unsigned int controller, unsigned int value)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_CONTROL_CHANGE;
outPacket.p.midi0=MIDIv1_CONTROL_CHANGE |(channel & 0x0f);
outPacket.p.midi1=controller;
outPacket.p.midi2=value;
writePacket(outPacket.i);
}
// Send a Midi PROGRAM CHANGE message to given channel, with program ID 0-127
void USBMidi::sendProgramChange(unsigned int channel, unsigned int program)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_PROGRAM_CHANGE;
outPacket.p.midi0=MIDIv1_PROGRAM_CHANGE |(channel & 0x0f);
outPacket.p.midi1=program;
writePacket(outPacket.i);
}
// Send a Midi AFTER TOUCH message to given channel, with velocity 0-127
void USBMidi::sendAfterTouch(unsigned int channel, unsigned int velocity)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_CHANNEL_PRESSURE;
outPacket.p.midi0=MIDIv1_CHANNEL_PRESSURE |(channel & 0x0f);
outPacket.p.midi1=velocity;
writePacket(outPacket.i);
}
// Send a Midi PITCH CHANGE message, with a 14-bit pitch (always for all channels)
void USBMidi::sendPitchChange(unsigned int pitch)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_PITCH_WHEEL;
outPacket.p.midi0=MIDIv1_PITCH_WHEEL;
outPacket.p.midi1= (uint8) pitch & 0x07F;
outPacket.p.midi2= (uint8) (pitch>>7) & 0x7f;
writePacket(outPacket.i);
}
// Send a Midi SONG POSITION message, with a 14-bit position (always for all channels)
void USBMidi::sendSongPosition(unsigned int position)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_3BYTE_SYS_COMMON;
outPacket.p.midi0=MIDIv1_SONG_POSITION_PTR;
outPacket.p.midi1= (uint8) position & 0x07F;
outPacket.p.midi2= (uint8) (position>>7) & 0x7f;
writePacket(outPacket.i);
}
// Send a Midi SONG SELECT message, with a song ID of 0-127 (always for all channels)
void USBMidi::sendSongSelect(unsigned int song)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_2BYTE_SYS_COMMON;
outPacket.p.midi0=MIDIv1_SONG_SELECT;
outPacket.p.midi1= (uint8) song & 0x07F;
writePacket(outPacket.i);
}
// Send a Midi TUNE REQUEST message (TUNE REQUEST is always for all channels)
void USBMidi::sendTuneRequest(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_TUNE_REQUEST;
writePacket(outPacket.i);
}
// Send a Midi SYNC message (SYNC is always for all channels)
void USBMidi::sendSync(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_CLOCK;
writePacket(outPacket.i);
}
// Send a Midi START message (START is always for all channels)
void USBMidi::sendStart(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_START ;
writePacket(outPacket.i);
}
// Send a Midi CONTINUE message (CONTINUE is always for all channels)
void USBMidi::sendContinue(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_CONTINUE ;
writePacket(outPacket.i);
}
// Send a Midi STOP message (STOP is always for all channels)
void USBMidi::sendStop(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_STOP ;
writePacket(outPacket.i);
}
// Send a Midi ACTIVE SENSE message (ACTIVE SENSE is always for all channels)
void USBMidi::sendActiveSense(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_ACTIVE_SENSE ;
writePacket(outPacket.i);
}
// Send a Midi RESET message (RESET is always for all channels)
void USBMidi::sendReset(void)
{
outPacket.p.cable=DEFAULT_MIDI_CABLE;
outPacket.p.cin=CIN_1BYTE;
outPacket.p.midi0=MIDIv1_RESET ;
writePacket(outPacket.i);
}
const uint32 midiNoteFrequency_10ths[128] = {
82, 87, 92, 97, 103, 109, 116, 122, 130, 138, 146, 154, 164, 173, 184, 194,
206, 218, 231, 245, 260, 275, 291, 309, 327, 346, 367, 389, 412, 437, 462, 490,
519, 550, 583, 617, 654, 693, 734, 778, 824, 873, 925, 980, 1038, 1100, 1165, 1235,
1308, 1386, 1468, 1556, 1648, 1746, 1850, 1960, 2077, 2200, 2331, 2469, 2616, 2772, 2937, 3111,
3296, 3492, 3700, 3920, 4153, 4400, 4662, 4939, 5233, 5544, 5873, 6223, 6593, 6985, 7400, 7840,
8306, 8800, 9323, 9878, 10465, 11087, 11747, 12445, 13185, 13969, 14800, 15680, 16612, 17600, 18647, 19755,
20930, 22175, 23493, 24890, 26370, 27938, 29600, 31360, 33224, 35200, 37293, 39511, 41860, 44349, 46986, 49780,
52740, 55877, 59199, 62719, 66449, 70400, 74586, 79021, 83720, 88698, 93973, 99561, 105481, 111753, 118398, 125439 };
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
// Placeholders. You should subclass the Midi base class and define these to have your
// version called.
void USBMidi::handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {}
void USBMidi::handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {}
void USBMidi::handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity) {}
void USBMidi::handleControlChange(unsigned int channel, unsigned int controller, unsigned int value) {}
void USBMidi::handleProgramChange(unsigned int channel, unsigned int program) {}
void USBMidi::handleAfterTouch(unsigned int channel, unsigned int velocity) {}
void USBMidi::handlePitchChange(unsigned int pitch) {}
void USBMidi::handleSongPosition(unsigned int position) {}
void USBMidi::handleSongSelect(unsigned int song) {}
void USBMidi::handleTuneRequest(void) {}
void USBMidi::handleSync(void) {}
void USBMidi::handleStart(void) {}
void USBMidi::handleContinue(void) {}
void USBMidi::handleStop(void) {}
void USBMidi::handleActiveSense(void) {}
void USBMidi::handleReset(void) {}
#pragma GCC diagnostic pop

View File

@ -0,0 +1,186 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2013 Magnus Lundin.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @brief Wirish USB MIDI port (MidiUSB).
*/
#ifndef _USBMIDI_H_
#define _USBMIDI_H_
//#include <Print.h>
#include <boards.h>
#include <USBComposite.h>
#include "usb_generic.h"
/*
* This is the Midi class. If you are just sending Midi data, you only need to make an
* instance of the class, passing it your USB port -- in most cases it looks like
*
* USBMidi midi;
*
* then you don't need to do anything else; you can start using it to send Midi messages,
* e.g.
*
* midi.sendNoteOn(1, note, velocity);
*
* If you are using it to receive Midi data, it's a little more complex & you will need
* to subclass the Midi class.
*
* For people not used to C++ this may look confusing, but it's actually pretty easy.
* Note that you only need to write the functions for event types you want to handle.
* They should match the names & prototypes of the functions in the class; look at
* the functions in the Midi class below that have the keyword "virtual" to see which
* ones you can use.
*
* Here's an example of one that takes NOTE ON, NOTE OFF, and CONTROL CHANGE:
*
* class MyMidi : public USBMidi {
* public:
*
* // Need this to compile; it just hands things off to the Midi class.
* MyMidi() : USBMidi(s) {}
*
* void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity)
* {
* if (note == 40) {digitalWrite(13, HIGH); }
* }
*
* void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity)
* {
* if (note == 40) { digitalWrite(13, LOW); }
* }
*
* void handleControlChange(unsigned int channel, unsigned int controller,
* unsigned int value)
* {
* analogWrite(6, value * 2);
* }
*
* Then you need to make an instance of this class:
*
* MyMidi midi();
*
* If receiving Midi data, you also need to call the poll function every time through
* loop(); e.g.
*
* void loop() {
* midi.poll();
* }
*
* This causes the Midi class to read data from the USB port and process it.
*/
class USBMidi {
private:
bool enabled = false;
/* Private Receive Parameters */
// The channel this Midi instance receives data for (0 means all channels)
int channelIn_;
/* Internal functions */
// Called whenever data is read from the USB port
void dispatchPacket(uint32 packet);
public:
//static bool init(USBMidi* me);
// This registers this USB composite device component with the USBComposite class instance.
bool registerComponent();
void setChannel(unsigned channel=0);
unsigned getChannel() {
return channelIn_;
}
// Call to start the USB port, at given baud. For many applications
// the default parameters are just fine (which will cause messages for all
// MIDI channels to be delivered)
void begin(unsigned int channel = 0);
//void begin();
void end();
uint32 available(void);
uint32 readPackets(void *buf, uint32 len);
uint32 readPacket(void);
void writePacket(uint32);
// void write(const char *str);
void writePackets(const void*, uint32);
uint8 isConnected();
uint8 pending();
// poll() should be called every time through loop() IF dealing with incoming MIDI
// (if you're only SENDING MIDI events from the Arduino, you don't need to call
// poll); it causes data to be read from the USB port and processed.
void poll();
// Call these to send MIDI messages of the given types
void sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity);
void sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity);
void sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity);
void sendControlChange(unsigned int channel, unsigned int controller, unsigned int value);
void sendProgramChange(unsigned int channel, unsigned int program);
void sendAfterTouch(unsigned int channel, unsigned int velocity);
void sendPitchChange(unsigned int pitch);
void sendSongPosition(unsigned int position);
void sendSongSelect(unsigned int song);
void sendTuneRequest(void);
void sendSync(void);
void sendStart(void);
void sendContinue(void);
void sendStop(void);
void sendActiveSense(void);
void sendReset(void);
// Overload these in a subclass to get MIDI messages when they come in
virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity);
virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity);
virtual void handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity);
virtual void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value);
virtual void handleProgramChange(unsigned int channel, unsigned int program);
virtual void handleAfterTouch(unsigned int channel, unsigned int velocity);
virtual void handlePitchChange(unsigned int pitch);
virtual void handleSongPosition(unsigned int position);
virtual void handleSongSelect(unsigned int song);
virtual void handleTuneRequest(void);
virtual void handleSync(void);
virtual void handleStart(void);
virtual void handleContinue(void);
virtual void handleStop(void);
virtual void handleActiveSense(void);
virtual void handleReset(void);
};
extern USBMidi USBMIDI;
extern const uint32 midiNoteFrequency_10ths[128];
#endif

View File

@ -0,0 +1,45 @@
#include "USBMassStorage.h"
#include "usb_mass.h"
#include "usb_mass_mal.h"
#include "usb_serial.h"
#include <string.h>
void USBMassStorageDevice::begin() {
if(!enabled) {
USBComposite.clear();
registerComponent();
USBComposite.begin();
enabled = true;
}
}
void USBMassStorageDevice::end() {
USBComposite.end();
}
void USBMassStorageDevice::loop() {
usb_mass_loop();
}
bool USBMassStorageDevice::registerComponent() {
return USBComposite.add(&usbMassPart, this);
}
void USBMassStorageDevice::setDrive(uint32 driveNumber, uint32 byteSize, MassStorageReader reader,
MassStorageWriter writer, MassStorageStatuser statuser, MassStorageInitializer initializer) {
if (driveNumber >= USB_MASS_MAX_DRIVES)
return;
usb_mass_drives[driveNumber].blockCount = byteSize/512;
usb_mass_drives[driveNumber].read = reader;
usb_mass_drives[driveNumber].write = writer;
usb_mass_drives[driveNumber].status = statuser;
usb_mass_drives[driveNumber].init = initializer;
usb_mass_drives[driveNumber].format = initializer;
}
void USBMassStorageDevice::clearDrives() {
memset(usb_mass_drives, 0, sizeof(usb_mass_drives));
}
USBMassStorageDevice MassStorage;

View File

@ -0,0 +1,25 @@
#ifndef USBMASSSTORAGE_H
#define USBMASSSTORAGE_H
#include <boards.h>
#include "USBComposite.h"
#include "usb_generic.h"
#include "usb_mass_mal.h"
class USBMassStorageDevice {
private:
bool enabled = false;
public:
void begin();
void end();
void loop();
void clearDrives(void);
bool registerComponent();
void setDrive(uint32 driveNumber, uint32 byteSize, MassStorageReader reader,
MassStorageWriter writer = NULL, MassStorageStatuser = NULL, MassStorageInitializer = NULL);
};
extern USBMassStorageDevice MassStorage;
#endif /* USBMASSSTORAGE_H */

View File

@ -0,0 +1,173 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 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, DIRECT, 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.
*/
/**
* @brief USB HID Keyboard device
*/
#include <string.h>
#include <stdint.h>
#include <libmaple/nvic.h>
#include <libmaple/usb.h>
#include "USBXBox360.h"
#include "usb_x360.h"
void USBXBox360::sendReport(void){
x360_tx(xbox360_Report, sizeof(xbox360_Report));
while (x360_is_transmitting() != 0) {
}
/* flush out to avoid having the pc wait for more data */
x360_tx(NULL, 0);
}
void USBXBox360::setRumbleCallback(void (*callback)(uint8 left, uint8 right)) {
x360_set_rumble_callback(callback);
}
void USBXBox360::setLEDCallback(void (*callback)(uint8 pattern)) {
x360_set_led_callback(callback);
}
bool USBXBox360::init(void* ignore) {
(void)ignore;
usb_generic_set_info(0x045e, 0x028e, NULL, NULL, NULL);
return true;
}
bool USBXBox360::registerComponent() {
return USBComposite.add(&usbX360Part, this, init);
}
void USBXBox360::begin(void){
if(!enabled){
USBComposite.clear();
registerComponent();
USBComposite.begin();
enabled = true;
}
}
void USBXBox360::end() {
if (enabled) {
enabled = false;
USBComposite.end();
}
}
void USBXBox360::stop(void){
setRumbleCallback(NULL);
setLEDCallback(NULL);
}
void USBXBox360::setManualReportMode(bool mode) {
manualReport = mode;
}
bool USBXBox360::getManualReportMode() {
return manualReport;
}
void USBXBox360::safeSendReport() {
if (!manualReport) {
while (x360_is_transmitting() != 0) {
}
sendReport();
}
}
void USBXBox360::send() {
while (x360_is_transmitting() != 0) {
}
sendReport();
}
void USBXBox360::button(uint8_t button, bool val){
button--;
uint8_t mask = (1 << (button & 7));
if (val) {
if (button < 8) xbox360_Report[2] |= mask;
else if (button < 16) xbox360_Report[3] |= mask;
} else {
mask = ~mask;
if (button < 8) xbox360_Report[2] &= mask;
else if (button < 16) xbox360_Report[3] &= mask;
}
safeSendReport();
}
void USBXBox360::X(int16_t val){
xbox360_Report[6] = val;
xbox360_Report[7] = (uint16)val >> 8;
safeSendReport();
}
void USBXBox360::Y(int16_t val){
xbox360_Report[8] = val;
xbox360_Report[9] = (uint16)val >> 8;
safeSendReport();
}
void USBXBox360::XRight(int16_t val){
xbox360_Report[0xA] = val;
xbox360_Report[0xB] = (uint16)val >> 8;
safeSendReport();
}
void USBXBox360::YRight(int16_t val){
xbox360_Report[0xC] = val;
xbox360_Report[0xD] = (uint16)val >> 8;
safeSendReport();
}
void USBXBox360::position(int16_t x, int16_t y){
xbox360_Report[6] = x;
xbox360_Report[7] = (uint16)x >> 8;
xbox360_Report[8] = y;
xbox360_Report[9] = (uint16)y >> 8;
safeSendReport();
}
void USBXBox360::positionRight(int16_t x, int16_t y){
xbox360_Report[0xA] = x;
xbox360_Report[0xB] = (uint16)x >> 8;
xbox360_Report[0xC] = y;
xbox360_Report[0xD] = (uint16)y >> 8;
safeSendReport();
}
void USBXBox360::sliderLeft(uint8_t val){
xbox360_Report[4] = val;
safeSendReport();
}
void USBXBox360::sliderRight(uint8_t val){
xbox360_Report[5] = val;
safeSendReport();
}
USBXBox360 XBox360;

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 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, DIRECT, 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.
*/
#ifndef _USBXBox360_H
#define _USBXBox360_H
#include <Print.h>
#include <boards.h>
#include "USBComposite.h"
#include "usb_generic.h"
class USBXBox360 {
private:
uint8_t xbox360_Report[20] = {0,0x14};// 3,0,0,0,0,0x0F,0x20,0x80,0x00,0x02,0x08,0x20,0x80};
bool manualReport = false;
bool enabled;
void safeSendReport(void);
void sendReport(void);
public:
void send(void);
static bool init(void* ignore);
bool registerComponent();
void stop();
void setManualReportMode(bool manualReport);
bool getManualReportMode();
void begin(void);
void end(void);
void button(uint8_t button, bool val);
void X(int16_t val);
void Y(int16_t val);
void position(int16_t x, int16_t y);
void positionRight(int16_t x, int16_t y);
void XRight(int16_t val);
void YRight(int16_t val);
void sliderLeft(uint8_t val);
void sliderRight(uint8_t val);
void hat(int16_t dir);
void setLEDCallback(void (*callback)(uint8 pattern));
void setRumbleCallback(void (*callback)(uint8 left, uint8 right));
};
extern USBXBox360 XBox360;
#endif

View File

@ -0,0 +1,15 @@
#include <USBHID.h>
void setup()
{
USBHID_begin_with_serial(HID_BOOT_KEYBOARD);
BootKeyboard.begin(); // needed just in case you need LED support
}
void loop()
{
BootKeyboard.press(KEY_F12);
delay(100);
BootKeyboard.release(KEY_F12);
delay(1000);
}

View File

@ -0,0 +1,25 @@
#include <USBHID.h>
const uint8_t reportDescription[] = {
HID_ABS_MOUSE_REPORT_DESCRIPTOR(HID_MOUSE_REPORT_ID)
};
HIDAbsMouse mouse;
void setup(){
USBHID_begin_with_serial(reportDescription, sizeof(reportDescription));
delay(1000);
mouse.move(0,0);
delay(1000);
mouse.press(MOUSE_LEFT);
mouse.move(500,500);
mouse.release(MOUSE_ALL);
mouse.click(MOUSE_RIGHT);
}
void loop(){
mouse.move(0,0);
delay(1000);
mouse.move(16384,16384);
delay(1000);
}

View File

@ -0,0 +1,18 @@
#include <USBComposite.h>
const uint8_t reportDescription[] = {
HID_CONSUMER_REPORT_DESCRIPTOR()
};
HIDConsumer Consumer;
void setup(){
USBHID_begin_with_serial(reportDescription, sizeof(reportDescription));
}
void loop() {
Consumer.press(HIDConsumer::BRIGHTNESS_DOWN);
Consumer.release();
delay(500);
}

View File

@ -0,0 +1,14 @@
#include <USBComposite.h>
void setup() {
USBHID_begin_with_serial(HID_KEYBOARD);
Keyboard.begin(); // needed for LED support
delay(1000);
}
void loop() {
CompositeSerial.println(Keyboard.getLEDs());
}

View File

@ -0,0 +1,67 @@
uint8 image[11776] = {
0xEB,0x3C,0x90,0x6D,0x6B,0x64,0x6F,0x73,0x66,0x73,0x00,0x00,0x02,0x04,0x01,0x00,
0x02,0x10,0x00,0x17,0x00,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xDB,0x32,0x73,0x5A,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x32,0x20,0x20,0x20,0x0E,0x1F,
0xBE,0x5B,0x7C,0xAC,0x22,0xC0,0x74,0x0B,0x56,0xB4,0x0E,0xBB,0x07,0x00,0xCD,0x10,
0x5E,0xEB,0xF0,0x32,0xE4,0xCD,0x16,0xCD,0x19,0xEB,0xFE,0x54,0x68,0x69,0x73,0x20,
0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C,
0x65,0x20,0x64,0x69,0x73,0x6B,0x2E,0x20,0x20,0x50,0x6C,0x65,0x61,0x73,0x65,0x20,
0x69,0x6E,0x73,0x65,0x72,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C,
0x65,0x20,0x66,0x6C,0x6F,0x70,0x70,0x79,0x20,0x61,0x6E,0x64,0x0D,0x0A,0x70,0x72,
0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x74,
0x72,0x79,0x20,0x61,0x67,0x61,0x69,0x6E,0x20,0x2E,0x2E,0x2E,0x20,0x0D,0x0A,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA,
0xF8,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xF8,0xFF,0xFF,
};

View File

@ -0,0 +1,65 @@
#include <USBComposite.h>
#include "image.h"
bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) {
memcpy(image+memoryOffset, writebuff, transferLength);
return true;
}
bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) {
memcpy(readbuff, image+memoryOffset, transferLength);
return true;
}
char hexNibble(uint8 x) {
return x < 10 ? x + '0' : x + 'A' - 10;
}
char* format16(uint16 c) {
static char str[6];
str[5] = 0;
char *p = str+5;
do {
*--p = (c % 10) + '0';
c /= 10;
} while(c);
return p;
}
void dumpDrive() {
char hex[7] = "0x11,";
CompositeSerial.print("uint8 image[");
CompositeSerial.print(format16(sizeof(image)));
CompositeSerial.println("] = {");
int last;
for (last=sizeof(image)-1;last>=0 && image[last] == 0;last--);
if (last<0) last=0;
for (int i=0; i<=last; i++) {
if (i && i % 16 == 0)
CompositeSerial.println("");
hex[2] = hexNibble(image[i]>>4);
hex[3] = hexNibble(image[i]&0xF);
CompositeSerial.print(hex);
}
CompositeSerial.println("\n};\n");
}
void setup() {
MassStorage.setDrive(0, sizeof(image), read, write);
MassStorage.registerComponent();
CompositeSerial.registerComponent();
USBComposite.begin();
delay(2000);
}
void loop() {
MassStorage.loop();
if (CompositeSerial.available() && 'd' == CompositeSerial.read()) {
dumpDrive();
}
}

View File

@ -0,0 +1,27 @@
#include <USBMIDI.h>
#define SPEAKER_PIN PA0
class myMidi : public USBMidi {
virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {
noTone(SPEAKER_PIN);
}
virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {
tone(SPEAKER_PIN, (midiNoteFrequency_10ths[note]+5)/10);
}
};
myMidi midi;
void setup() {
pinMode(SPEAKER_PIN, OUTPUT);
midi.registerComponent();
CompositeSerial.registerComponent();
USBComposite.begin();
}
void loop() {
midi.poll();
}

View File

@ -0,0 +1,17 @@
#include <USBMIDI.h>
const uint8_t notes[] = {60, 62, 64, 65, 67, 69, 71, 72, 61, 63, 66, 68, 70};
const int numNotes = sizeof(notes)/sizeof(*notes);
void setup() {
USBMIDI.begin();
delay(1000);
}
void loop() {
for (int i=0;i<numNotes;i++) {
USBMIDI.sendNoteOn(0, notes[i], 127);
delay(200);
USBMIDI.sendNoteOff(0, notes[i], 127);
}
}

View File

@ -0,0 +1,24 @@
#include <USBComposite.h>
#define TXSIZE 256
#define RXSIZE 300
HIDRaw<TXSIZE,RXSIZE> raw;
uint8 buf[RXSIZE];
const uint8_t reportDescription[] = {
HID_RAW_REPORT_DESCRIPTOR(TXSIZE,RXSIZE)
};
void setup(){
USBHID_begin_with_serial(reportDescription, sizeof(reportDescription));
raw.begin();
}
void loop() {
if (raw.getOutput(buf)) {
for (int i=0;i<RXSIZE;i++) buf[i]++;
raw.send(buf+RXSIZE-min(RXSIZE,TXSIZE),min(RXSIZE,TXSIZE));
}
}

View File

@ -0,0 +1,26 @@
from pywinusb import hid
from time import sleep
SIZE=300
def sample_handler(data):
print("Raw data: {0}".format(data))
device = hid.HidDeviceFilter(vendor_id = 0x1EAF, product_id = 0x0004).get_devices()[0]
print(device)
device.open()
device.set_raw_data_handler(sample_handler)
n = 0
while True:
for out_report in device.find_output_reports():
buffer=[i for i in range(SIZE+1)]
buffer[0]=0x0 # report id
buffer[-1] = n
out_report.set_raw_data(buffer)
print("sending")
if out_report.send():
n = (n+1)&0xFF
sleep(0.1)
#sleep(0.005)

View File

@ -0,0 +1,52 @@
// This uses the greiman sdfat library.
// To use SdFatEX, set ENABLE_EXTENDED_TRANSFER_CLASS to 1 in the library's
// src/SdFatConfig.h
#include <USBComposite.h>
#include <SPI.h>
#include "SdFat.h"
#define LED_PIN PB12
SdFatEX sd;
const uint32_t speed = SPI_CLOCK_DIV2 ;
const uint8_t SD_CHIP_SELECT = SS;
bool enabled = false;
uint32 cardSize;
bool write(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength) {
return sd.card()->writeBlocks(memoryOffset/512, writebuff, transferLength/512);
}
bool read(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) {
return sd.card()->readBlocks(memoryOffset/512, readbuff, transferLength/512);
}
void setup() {
pinMode(LED_PIN,OUTPUT);
digitalWrite(LED_PIN,1);
}
void initReader() {
digitalWrite(LED_PIN,0);
cardSize = sd.card()->cardSize();
MassStorage.setDrive(0, cardSize*512, read, write);
MassStorage.registerComponent();
CompositeSerial.registerComponent();
USBComposite.begin();
enabled=true;
}
void loop() {
if (!enabled) {
if (sd.begin(SD_CHIP_SELECT)) {
initReader();
}
else {
delay(50);
}
}
else {
MassStorage.loop();
}
}

View File

@ -0,0 +1,13 @@
#include <USBComposite.h>
void setup() {
USBHID_begin_with_serial(HID_JOYSTICK);
}
void loop() {
Joystick.X(0);
delay(500);
Joystick.X(1023);
delay(500);
}

View File

@ -0,0 +1,13 @@
#include <USBComposite.h>
void setup() {
USBHID_begin_with_serial(HID_KEYBOARD);
Keyboard.begin(); // useful to detect host capslock state and LEDs
delay(1000);
}
void loop() {
Keyboard.println("Hello world");
delay(10000);
}

View File

@ -0,0 +1,60 @@
from pywinusb import hid
from time import sleep
REPORT_ID = 20
HID_REPORT_FEATURE = 3
device = hid.HidDeviceFilter(vendor_id = 0x1EAF).get_devices()[0] # , product_id = 0x0024
print(device)
device.open()
"""
uint8_t reportID;
uint32_t buttons;
unsigned hat:4;
unsigned x:10;
unsigned y:10;
unsigned rx:10;
unsigned ry:10;
unsigned sliderLeft:10;
unsigned sliderRight:10;
"""
def toBits(n,bits):
return tuple((n>>i)&1 for i in range(bits))
def getByteFromBits(bits,n):
out = 0
for i in range(8):
out += bits[8*n+i] << i
return out
def joystickData(reportID=REPORT_ID, buttons=0, hat=15, x=512, y=512, rx=512, ry=512, sliderLeft=512, sliderRight=512):
joyData = ( toBits(reportID,8) + toBits(buttons,32) + toBits(hat,4) + toBits(x,10) + toBits(y,10) +
toBits(rx,10) + toBits(ry,10) + toBits(sliderLeft,10) + toBits(sliderRight,10) )
out = [getByteFromBits(joyData,n) for n in range(13)]
print(out)
return out
myReport = None
for report in device.find_feature_reports():
if report.report_id == REPORT_ID and report.report_type == "Feature":
myReport = report
break
if myReport is None:
for report in device.find_output_reports():
if report.report_id == REPORT_ID and report.report_type == "Output":
myReport = report
break
assert myReport is not None
while True:
myReport.set_raw_data(joystickData(buttons=7,x=0,y=0))
myReport.send()
sleep(0.5)
myReport.set_raw_data(joystickData(buttons=0,x=1023,y=1023))
myReport.send()
sleep(0.5)

View File

@ -0,0 +1,47 @@
// This is a silly project: you send a feature
// report from the PC, and it becomes a joystick setting.
// I guess it's not completely useless as it lets you
// get vJoy functionality without special vJoy drivers.
#include <USBComposite.h>
#define DATA_SIZE (sizeof(JoystickReport_t)-1)
class HIDJoystickRawData : public HIDJoystick {
private:
uint8_t featureData[HID_BUFFER_ALLOCATE_SIZE(DATA_SIZE,1)];
HIDBuffer_t fb { featureData, HID_BUFFER_SIZE(DATA_SIZE,1), HID_JOYSTICK_REPORT_ID };
public:
HIDJoystickRawData(uint8_t reportID=HID_JOYSTICK_REPORT_ID) : HIDJoystick(reportID) {}
void begin() {
USBHID.setFeatureBuffers(&fb, 1);
}
void setRawData(JoystickReport_t* p) {
joyReport = *p;
send();
}
};
HIDJoystickRawData joy;
JoystickReport_t report = {HID_JOYSTICK_REPORT_ID};
const uint8_t reportDescription[] = {
HID_JOYSTICK_REPORT_DESCRIPTOR(HID_JOYSTICK_REPORT_ID,
HID_FEATURE_REPORT_DESCRIPTOR(DATA_SIZE))
};
void setup() {
USBHID_begin_with_serial(reportDescription, sizeof(reportDescription));
joy.begin();
}
void loop() {
if (joy.getFeature(1+(uint8_t*)&report)) {
joy.setRawData(&report);
}
delay(5);
}

View File

@ -0,0 +1,40 @@
#include <USBComposite.h>
const uint8_t reportDescription[] = {
HID_MOUSE_REPORT_DESCRIPTOR(),
HID_KEYBOARD_REPORT_DESCRIPTOR(),
HID_JOYSTICK_REPORT_DESCRIPTOR(),
HID_JOYSTICK_REPORT_DESCRIPTOR(HID_JOYSTICK_REPORT_ID+1),
};
HIDJoystick Joystick2(HID_JOYSTICK_REPORT_ID+1);
void setup(){
USBHID_begin_with_serial(reportDescription, sizeof(reportDescription));
Joystick.setManualReportMode(true);
Joystick2.setManualReportMode(true);
}
void loop(){
Joystick.X(0);
Joystick.Y(0);
Joystick.sliderRight(1023);
Joystick.send();
delay(400);
Joystick.X(1023);
Joystick.Y(1023);
Joystick.sliderRight(0);
Joystick.send();
delay(400);
Joystick2.X(0);
Joystick2.Y(0);
Joystick2.sliderRight(1023);
Joystick2.send();
delay(400);
Joystick2.X(1023);
Joystick2.Y(1023);
Joystick2.sliderRight(0);
Joystick2.send();
delay(400);
}

View File

@ -0,0 +1,15 @@
#include <USBComposite.h>
void setup() {
XBox360.begin();
delay(1000);
}
void loop() {
XBox360.X(-32767);
XBox360.Y(-32767);
delay(1000);
XBox360.X(32767);
XBox360.Y(32767);
delay(1000);
}

View File

@ -0,0 +1,89 @@
#######################################
# Syntax Coloring Map USBHID
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
HID KEYWORD1
Joystick KEYWORD1
Keyboard KEYWORD1
Mouse KEYWORD1
CompositeSerial KEYWORD1
XBox360 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
XRight KEYWORD2
YRight KEYWORD2
Yrotate KEYWORD2
Y KEYWORD2
Xrotate KEYWORD2
X KEYWORD2
sliderLeft KEYWORD2
sliderRight KEYWORD2
button KEYWORD2
hat KEYWORD2
setManualReportMode KEYWORD2
getManualReportMode KEYWORD2
release KEYWORD2
press KEYWORD2
releaseAll KEYWORD2
move KEYWORD2
send KEYWORD2
click KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
USB_HID_MOUSE LITERAL1
USB_HID_KEYBOARD LITERAL1
USB_HID_JOYSTICK LITERAL1
USB_HID_KEYBOARD_MOUSE LITERAL1
USB_HID_KEYBOARD_MOUSE_JOYSTICK LITERAL1
USB_HID_KEYBOARD_JOYSTICK LITERAL1
KEY_LEFT_CTRL LITERAL1
KEY_LEFT_SHIFT LITERAL1
KEY_LEFT_ALT LITERAL1
KEY_LEFT_GUI LITERAL1
KEY_RIGHT_CTRL LITERAL1
KEY_RIGHT_SHIFT LITERAL1
KEY_RIGHT_ALT LITERAL1
KEY_RIGHT_GUI LITERAL1
KEY_UP_ARROW LITERAL1
KEY_DOWN_ARROW LITERAL1
KEY_LEFT_ARROW LITERAL1
KEY_RIGHT_ARROW LITERAL1
KEY_BACKSPACE LITERAL1
KEY_TAB LITERAL1
KEY_RETURN LITERAL1
KEY_ESC LITERAL1
KEY_INSERT LITERAL1
KEY_DELETE LITERAL1
KEY_PAGE_UP LITERAL1
KEY_PAGE_DOWN LITERAL1
KEY_HOME LITERAL1
KEY_END LITERAL1
KEY_CAPS_LOCK LITERAL1
KEY_F1 LITERAL1
KEY_F2 LITERAL1
KEY_F3 LITERAL1
KEY_F4 LITERAL1
KEY_F5 LITERAL1
KEY_F6 LITERAL1
KEY_F7 LITERAL1
KEY_F8 LITERAL1
KEY_F9 LITERAL1
KEY_F10 LITERAL1
KEY_F11 LITERAL1
KEY_F12 LITERAL1
MOUSE_LEFT LITERAL1
MOUSE_MIDDLE LITERAL1
MOUSE_RIGHT LITERAL1
MOUSE_ALL LITERAL1
HIDConsumer LITERAL1

View File

@ -0,0 +1,10 @@
name=USBComposite for STM32F1
version=0.64
author=Various
email=arpruss@gmail.com
sentence=USB HID / MIDI / mass storage library for STM32F1
paragraph=USB HID / MIDI / mass storage library for STM32F1
url=https://github.com/arpruss/USBHID_stm32f1
architectures=STM32F1
maintainer=arpruss@gmail.com
category=Communication

View File

@ -0,0 +1,531 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file libmaple/usb/stm32f1/usb_hid.c
* @brief USB HID (human interface device) support
*
* FIXME: this works on the STM32F1 USB peripherals, and probably no
* place else. Nonportable bits really need to be factored out, and
* the result made cleaner.
*/
#include <string.h>
#include <libmaple/libmaple_types.h>
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
#include <libmaple/gpio.h>
#include <usb_lib_globals.h>
#include <usb_reg_map.h>
//#include <usb_core.h>
#include <board/board.h>
//uint16 GetEPTxAddr(uint8 /*bEpNum*/);
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
#include "usb_generic.h"
// Are we currently sending an IN packet?
volatile int8 usbGenericTransmitting = -1;
static uint8* usbGetConfigDescriptor(uint16 length);
static void usbInit(void);
static void usbReset(void);
static void usbClearFeature(void);
static void usbSetConfiguration(void);
static RESULT usbDataSetup(uint8 request);
static RESULT usbNoDataSetup(uint8 request);
static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting);
static uint8* usbGetStringDescriptor(uint16 length);
static uint8* usbGetConfigDescriptor(uint16 length);
static uint8* usbGetDeviceDescriptor(uint16 length);
static void usbSetConfiguration(void);
static void usbSetDeviceAddress(void);
#define LEAFLABS_ID_VENDOR 0x1EAF
#define MAPLE_ID_PRODUCT 0x0004 // was 0x0024
#define USB_DEVICE_CLASS 0x00
#define USB_DEVICE_SUBCLASS 0x00
#define DEVICE_PROTOCOL 0x01
#define HID_DESCRIPTOR_TYPE 0x21
static usb_descriptor_device usbGenericDescriptor_Device =
{
.bLength = sizeof(usb_descriptor_device),
.bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = USB_DEVICE_CLASS,
.bDeviceSubClass = USB_DEVICE_SUBCLASS,
.bDeviceProtocol = DEVICE_PROTOCOL,
.bMaxPacketSize0 = 0x40,
.idVendor = LEAFLABS_ID_VENDOR,
.idProduct = MAPLE_ID_PRODUCT,
.bcdDevice = 0x0200,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x00,
.bNumConfigurations = 0x01,
};
typedef struct {
usb_descriptor_config_header Config_Header;
uint8 descriptorData[MAX_USB_DESCRIPTOR_DATA_SIZE];
} __packed usb_descriptor_config;
static usb_descriptor_config usbConfig;
#define MAX_POWER (100 >> 1)
static const usb_descriptor_config_header Base_Header = {
.bLength = sizeof(usb_descriptor_config_header),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
.wTotalLength = 0,
.bNumInterfaces = 0,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED |
USB_CONFIG_ATTR_SELF_POWERED),
.bMaxPower = MAX_POWER,
};
static ONE_DESCRIPTOR Device_Descriptor = {
(uint8*)&usbGenericDescriptor_Device,
sizeof(usb_descriptor_device)
};
static ONE_DESCRIPTOR Config_Descriptor = {
(uint8*)&usbConfig,
0
};
static DEVICE my_Device_Table = {
.Total_Endpoint = 0,
.Total_Configuration = 1
};
/* Unicode language identifier: 0x0409 is US English */
/* FIXME move to Wirish */
static const usb_descriptor_string usbHIDDescriptor_LangID = {
.bLength = USB_DESCRIPTOR_STRING_LEN(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
.bString = {0x09, 0x04},
};
#define default_iManufacturer_length 8
const usb_descriptor_string usb_generic_default_iManufacturer = {
.bLength = USB_DESCRIPTOR_STRING_LEN(default_iManufacturer_length),
.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
.bString = {'L', 0, 'e', 0, 'a', 0, 'f', 0, 'L', 0, 'a', 0, 'b', 0, 's', 0},
};
#define default_iProduct_length 5
const usb_descriptor_string usb_generic_default_iProduct = {
.bLength = USB_DESCRIPTOR_STRING_LEN(default_iProduct_length),
.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
.bString = {'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0},
};
#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */
static DEVICE_PROP my_Device_Property = {
.Init = usbInit,
.Reset = usbReset,
.Process_Status_IN = NOP_Process,
.Process_Status_OUT = NOP_Process,
.Class_Data_Setup = usbDataSetup,
.Class_NoData_Setup = usbNoDataSetup,
.Class_Get_Interface_Setting = usbGetInterfaceSetting,
.GetDeviceDescriptor = usbGetDeviceDescriptor,
.GetConfigDescriptor = usbGetConfigDescriptor,
.GetStringDescriptor = usbGetStringDescriptor,
.RxEP_buffer = NULL,
.MaxPacketSize = MAX_PACKET_SIZE
};
static const USER_STANDARD_REQUESTS my_User_Standard_Requests = {
.User_GetConfiguration = NOP_Process,
.User_SetConfiguration = usbSetConfiguration,
.User_GetInterface = NOP_Process,
.User_SetInterface = NOP_Process,
.User_GetStatus = NOP_Process,
.User_ClearFeature = usbClearFeature,
.User_SetEndPointFeature = NOP_Process,
.User_SetDeviceFeature = NOP_Process,
.User_SetDeviceAddress = usbSetDeviceAddress
};
static uint8 numStringDescriptors = 3;
#define MAX_STRING_DESCRIPTORS 4
static ONE_DESCRIPTOR String_Descriptor[MAX_STRING_DESCRIPTORS] = {
{(uint8*)&usbHIDDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)},
{(uint8*)&usb_generic_default_iManufacturer, USB_DESCRIPTOR_STRING_LEN(default_iManufacturer_length)},
{(uint8*)&usb_generic_default_iProduct, USB_DESCRIPTOR_STRING_LEN(default_iProduct_length)},
{NULL, 0},
};
static USBCompositePart** parts;
static uint32 numParts;
static DEVICE saved_Device_Table;
static DEVICE_PROP saved_Device_Property;
static USER_STANDARD_REQUESTS saved_User_Standard_Requests;
static void (*ep_int_in[7])(void);
static void (*ep_int_out[7])(void);
uint8 usb_generic_set_parts(USBCompositePart** _parts, unsigned _numParts) {
parts = _parts;
numParts = _numParts;
unsigned numInterfaces = 0;
unsigned numEndpoints = 1;
uint16 usbDescriptorSize = 0;
uint16 pmaOffset = USB_EP0_RX_BUFFER_ADDRESS + USB_EP0_BUFFER_SIZE;
for (unsigned i = 0 ; i < 7 ; i++) {
ep_int_in[i] = NOP_Process;
ep_int_out[i] = NOP_Process;
}
usbDescriptorSize = 0;
for (unsigned i = 0 ; i < _numParts ; i++ ) {
parts[i]->startInterface = numInterfaces;
numInterfaces += parts[i]->numInterfaces;
if (numEndpoints + parts[i]->numEndpoints > 8) {
return 0;
}
if (usbDescriptorSize + parts[i]->descriptorSize > MAX_USB_DESCRIPTOR_DATA_SIZE) {
return 0;
}
parts[i]->startEndpoint = numEndpoints;
USBEndpointInfo* ep = parts[i]->endpoints;
for (unsigned j = 0 ; j < parts[i]->numEndpoints ; j++) {
if (ep[j].bufferSize + pmaOffset > PMA_MEMORY_SIZE) {
return 0;
}
ep[j].pmaAddress = pmaOffset;
pmaOffset += ep[j].bufferSize;
ep[j].address = numEndpoints;
if (ep[j].callback == NULL)
ep[j].callback = NOP_Process;
if (ep[j].tx) {
ep_int_in[numEndpoints - 1] = ep[j].callback;
}
else {
ep_int_out[numEndpoints - 1] = ep[j].callback;
}
numEndpoints++;
}
parts[i]->getPartDescriptor(usbConfig.descriptorData + usbDescriptorSize);
usbDescriptorSize += parts[i]->descriptorSize;
}
usbConfig.Config_Header = Base_Header;
usbConfig.Config_Header.bNumInterfaces = numInterfaces;
usbConfig.Config_Header.wTotalLength = usbDescriptorSize + sizeof(Base_Header);
Config_Descriptor.Descriptor_Size = usbConfig.Config_Header.wTotalLength;
my_Device_Table.Total_Endpoint = numEndpoints;
return 1;
}
void usb_generic_set_info( uint16 idVendor, uint16 idProduct, const uint8* iManufacturer, const uint8* iProduct, const uint8* iSerialNumber) {
if (idVendor != 0)
usbGenericDescriptor_Device.idVendor = idVendor;
else
usbGenericDescriptor_Device.idVendor = LEAFLABS_ID_VENDOR;
if (idProduct != 0)
usbGenericDescriptor_Device.idProduct = idProduct;
else
usbGenericDescriptor_Device.idProduct = MAPLE_ID_PRODUCT;
if (iManufacturer == NULL) {
iManufacturer = (uint8*)&usb_generic_default_iManufacturer;
}
String_Descriptor[1].Descriptor = (uint8*)iManufacturer;
String_Descriptor[1].Descriptor_Size = iManufacturer[0];
if (iProduct == NULL) {
iProduct = (uint8*)&usb_generic_default_iProduct;
}
String_Descriptor[2].Descriptor = (uint8*)iProduct;
String_Descriptor[2].Descriptor_Size = iProduct[0];
if (iSerialNumber == NULL) {
numStringDescriptors = 3;
usbGenericDescriptor_Device.iSerialNumber = 0;
}
else {
String_Descriptor[3].Descriptor = (uint8*)iSerialNumber;
String_Descriptor[3].Descriptor_Size = iSerialNumber[0];
numStringDescriptors = 4;
usbGenericDescriptor_Device.iSerialNumber = 3;
}
}
void usb_generic_enable(void) {
/* Present ourselves to the host. Writing 0 to "disc" pin must
* pull USB_DP pin up while leaving USB_DM pulled down by the
* transceiver. See USB 2.0 spec, section 7.1.7.3. */
#ifdef GENERIC_BOOTLOADER
//Reset the USB interface on generic boards - developed by Victor PV
gpio_set_mode(GPIOA, 12, GPIO_OUTPUT_PP);
gpio_write_bit(GPIOA, 12, 0);
for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed
gpio_set_mode(GPIOA, 12, GPIO_INPUT_FLOATING);
#endif
if (BOARD_USB_DISC_DEV != NULL) {
gpio_set_mode(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, GPIO_OUTPUT_PP);
gpio_write_bit(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, 0);
}
saved_Device_Table = Device_Table;
saved_Device_Property = Device_Property;
saved_User_Standard_Requests = User_Standard_Requests;
Device_Table = my_Device_Table;
Device_Property = my_Device_Property;
User_Standard_Requests = my_User_Standard_Requests;
/* Initialize the USB peripheral. */
usb_init_usblib(USBLIB, ep_int_in, ep_int_out);
}
static void usbInit(void) {
pInformation->Current_Configuration = 0;
USB_BASE->CNTR = USB_CNTR_FRES;
USBLIB->irq_mask = 0;
USB_BASE->CNTR = USBLIB->irq_mask;
USB_BASE->ISTR = 0;
USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
USB_BASE->CNTR = USBLIB->irq_mask;
USB_BASE->ISTR = 0;
USBLIB->irq_mask = USB_ISR_MSK;
USB_BASE->CNTR = USBLIB->irq_mask;
nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
for (unsigned i = 0 ; i < numParts ; i++)
if(parts[i]->usbInit != NULL)
parts[i]->usbInit();
USBLIB->state = USB_UNCONNECTED;
}
#define BTABLE_ADDRESS 0x00
static void usbReset(void) {
pInformation->Current_Configuration = 0;
/* current feature is current bmAttributes */
pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED |
USB_CONFIG_ATTR_SELF_POWERED);
USB_BASE->BTABLE = BTABLE_ADDRESS;
/* setup control endpoint 0 */
usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL);
usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL);
usb_set_ep_rx_addr(USB_EP0, USB_EP0_RX_BUFFER_ADDRESS);
usb_set_ep_tx_addr(USB_EP0, USB_EP0_TX_BUFFER_ADDRESS);
usb_clear_status_out(USB_EP0);
usb_set_ep_rx_count(USB_EP0, USB_EP0_BUFFER_SIZE);
usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID);
for (unsigned i = 0 ; i < numParts ; i++) {
for (unsigned j = 0 ; j < parts[i]->numEndpoints ; j++) {
USBEndpointInfo* e = &(parts[i]->endpoints[j]);
uint8 address = e->address;
usb_set_ep_type(address, e->type);
if (parts[i]->endpoints[j].tx) {
usb_set_ep_tx_addr(address, e->pmaAddress);
usb_set_ep_tx_stat(address, USB_EP_STAT_TX_NAK);
usb_set_ep_rx_stat(address, USB_EP_STAT_RX_DISABLED);
}
else {
usb_set_ep_rx_addr(address, e->pmaAddress);
usb_set_ep_rx_count(address, e->bufferSize);
usb_set_ep_rx_stat(address, USB_EP_STAT_RX_VALID);
}
}
if (parts[i]->usbReset != NULL)
parts[i]->usbReset();
}
usbGenericTransmitting = -1;
USBLIB->state = USB_ATTACHED;
SetDeviceAddress(0);
}
static void usb_power_down(void) {
USB_BASE->CNTR = USB_CNTR_FRES;
USB_BASE->ISTR = 0;
USB_BASE->CNTR = USB_CNTR_FRES + USB_CNTR_PDWN;
}
void usb_generic_disable(void) {
/* Turn off the interrupt and signal disconnect (see e.g. USB 2.0
* spec, section 7.1.7.3). */
nvic_irq_disable(NVIC_USB_LP_CAN_RX0);
if (BOARD_USB_DISC_DEV != NULL) {
gpio_write_bit(BOARD_USB_DISC_DEV, (uint8)(uint32)BOARD_USB_DISC_BIT, 1);
}
usb_power_down();
Device_Table = saved_Device_Table;
Device_Property = saved_Device_Property;
User_Standard_Requests = saved_User_Standard_Requests;
}
static RESULT usbDataSetup(uint8 request) {
uint8* (*CopyRoutine)(uint16) = 0;
if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT) && request == GET_DESCRIPTOR &&
pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){
CopyRoutine = usbGetConfigDescriptor;
}
if (CopyRoutine == NULL){
for (unsigned i = 0 ; i < numParts ; i++) {
RESULT r = parts[i]->usbDataSetup(request);
if (USB_UNSUPPORT != r)
return r;
}
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
static RESULT usbNoDataSetup(uint8 request) {
for (unsigned i = 0 ; i < numParts ; i++) {
RESULT r = parts[i]->usbNoDataSetup(request);
if (USB_UNSUPPORT != r)
return r;
}
return USB_UNSUPPORT;
}
static void usbSetConfiguration(void) {
if (pInformation->Current_Configuration != 0) {
USBLIB->state = USB_CONFIGURED;
}
for (unsigned i = 0 ; i < numParts ; i++) {
if (parts[i]->usbSetConfiguration != NULL)
parts[i]->usbSetConfiguration();
}
}
static void usbClearFeature(void) {
for (unsigned i = 0 ; i < numParts ; i++) {
if (parts[i]->usbClearFeature != NULL)
parts[i]->usbClearFeature();
}
}
static void usbSetDeviceAddress(void) {
USBLIB->state = USB_ADDRESSED;
}
static uint8* usbGetDeviceDescriptor(uint16 length) {
return Standard_GetDescriptorData(length, &Device_Descriptor);
}
static uint8* usbGetConfigDescriptor(uint16 length) {
return Standard_GetDescriptorData(length, &Config_Descriptor);
}
static uint8* usbGetStringDescriptor(uint16 length) {
uint8 wValue0 = pInformation->USBwValue0;
if (wValue0 >= numStringDescriptors) {
return NULL;
}
return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]);
}
static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) {
if (alt_setting > 0) {
return USB_UNSUPPORT;
} else if (interface >= usbConfig.Config_Header.bNumInterfaces) {
return USB_UNSUPPORT;
}
return USB_SUCCESS;
}
void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) {
uint16 *dst = (uint16*)usb_pma_ptr(pma_offset);
uint16 n = len >> 1;
uint16 i;
for (i = 0; i < n; i++) {
*dst = (uint16)(*buf) | *(buf + 1) << 8;
buf += 2;
dst += 2;
}
if (len & 1) {
*dst = *buf;
}
}
void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) {
uint32 *src = (uint32*)usb_pma_ptr(pma_offset);
uint16 *dst = (uint16*)buf;
uint16 n = len >> 1;
uint16 i;
for (i = 0; i < n; i++) {
*dst++ = *src++;
}
if (len & 1) {
*dst = *src & 0xFF;
}
}

View File

@ -0,0 +1,60 @@
#ifndef _USB_GENERIC_H
#define _USB_GENERIC_H
#include <libmaple/libmaple_types.h>
typedef unsigned short u16;
typedef unsigned char u8;
#include <usb_core.h>
#include <libmaple/usb.h>
#define PMA_MEMORY_SIZE 512
#define MAX_USB_DESCRIPTOR_DATA_SIZE 200
#define USB_EP0_BUFFER_SIZE 0x40
#define USB_EP0_TX_BUFFER_ADDRESS 0x40
#define USB_EP0_RX_BUFFER_ADDRESS (USB_EP0_TX_BUFFER_ADDRESS+USB_EP0_BUFFER_SIZE)
#ifdef __cplusplus
extern "C" {
#endif
extern const usb_descriptor_string usb_generic_default_iManufacturer;
extern const usb_descriptor_string usb_generic_default_iProduct;
typedef struct USBEndpointInfo {
void (*callback)(void);
uint16 bufferSize;
uint16 type; // bulk, interrupt, etc.
uint8 tx; // 1 if TX, 0 if RX
uint8 address;
uint16 pmaAddress;
} USBEndpointInfo;
typedef struct USBCompositePart {
uint8 numInterfaces;
uint8 numEndpoints;
uint8 startInterface;
uint8 startEndpoint;
uint16 descriptorSize;
void (*getPartDescriptor)(uint8* out);
void (*usbInit)(void);
void (*usbReset)(void);
void (*usbSetConfiguration)(void);
void (*usbClearFeature)(void);
RESULT (*usbDataSetup)(uint8 request);
RESULT (*usbNoDataSetup)(uint8 request);
USBEndpointInfo* endpoints;
} USBCompositePart;
void usb_generic_set_info(uint16 idVendor, uint16 idProduct, const uint8* iManufacturer, const uint8* iProduct, const uint8* iSerialNumber);
uint8 usb_generic_set_parts(USBCompositePart** _parts, unsigned _numParts);
void usb_generic_disable(void);
void usb_generic_enable(void);
extern volatile int8 usbGenericTransmitting;
void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset);
void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,578 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file libmaple/usb/stm32f1/usb_hid.c
* @brief USB HID (human interface device) support
*
* FIXME: this works on the STM32F1 USB peripherals, and probably no
* place else. Nonportable bits really need to be factored out, and
* the result made cleaner.
*/
#include "usb_hid.h"
#include <string.h>
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
uint16 GetEPTxAddr(uint8 /*bEpNum*/);
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
static uint32 ProtocolValue = 0;
static void hidDataTxCb(void);
static void hidUSBReset(void);
static RESULT hidUSBDataSetup(uint8 request);
static RESULT hidUSBNoDataSetup(uint8 request);
//static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting);
static uint8* HID_GetReportDescriptor(uint16 Length);
static uint8* HID_GetProtocolValue(uint16 Length);
static volatile HIDBuffer_t hidBuffers[MAX_HID_BUFFERS] = {{ 0 }};
static volatile HIDBuffer_t* currentHIDBuffer = NULL;
//#define DUMMY_BUFFER_SIZE 0x40 // at least as big as a buffer size
#define HID_INTERFACE_OFFSET 0x00
#define NUM_HID_ENDPOINTS 1
#define HID_INTERFACE_NUMBER (HID_INTERFACE_OFFSET+usbHIDPart.startInterface)
/*
* Descriptors
*/
static ONE_DESCRIPTOR HID_Report_Descriptor = {
(uint8*)NULL,
0
};
#define HID_ENDPOINT_TX 0
typedef struct {
//HID
usb_descriptor_interface HID_Interface;
HIDDescriptor HID_Descriptor;
usb_descriptor_endpoint HIDDataInEndpoint;
} __packed hid_part_config;
static const hid_part_config hidPartConfigData = {
.HID_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = HID_INTERFACE_OFFSET, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = NUM_HID_ENDPOINTS,
.bInterfaceClass = USB_INTERFACE_CLASS_HID,
.bInterfaceSubClass = USB_INTERFACE_SUBCLASS_HID,
.bInterfaceProtocol = 0x00, /* Common AT Commands */
.iInterface = 0x00,
},
.HID_Descriptor = {
.len = 9,//sizeof(HIDDescDescriptor),
.dtype = HID_DESCRIPTOR_TYPE,
.versionL = 0x10,
.versionH = 0x01,
.country = 0x00,
.numDesc = 0x01,
.desctype = REPORT_DESCRIPTOR,//0x22,
.descLenL = 0x00, //PATCH
.descLenH = 0x00, //PATCH
},
.HIDDataInEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = USB_DESCRIPTOR_ENDPOINT_IN | HID_ENDPOINT_TX, // PATCH
.bmAttributes = USB_ENDPOINT_TYPE_INTERRUPT,
.wMaxPacketSize = USB_HID_TX_EPSIZE,//0x40,//big enough for a keyboard 9 byte packet and for a mouse 5 byte packet
.bInterval = 0x0A,
}
};
static USBEndpointInfo hidEndpoints[1] = {
{
.callback = hidDataTxCb,
.bufferSize = USB_HID_TX_EPSIZE,
.type = USB_EP_EP_TYPE_INTERRUPT, // TODO: interrupt???
.tx = 1,
}
};
#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s]
static void getHIDPartDescriptor(uint8* out) {
memcpy(out, &hidPartConfigData, sizeof(hid_part_config));
// patch to reflect where the part goes in the descriptor
OUT_BYTE(hidPartConfigData, HID_Interface.bInterfaceNumber) += usbHIDPart.startInterface;
OUT_BYTE(hidPartConfigData, HIDDataInEndpoint.bEndpointAddress) += usbHIDPart.startEndpoint;
OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenL) = (uint8)HID_Report_Descriptor.Descriptor_Size;
OUT_BYTE(hidPartConfigData, HID_Descriptor.descLenH) = (uint8)(HID_Report_Descriptor.Descriptor_Size>>8);
}
USBCompositePart usbHIDPart = {
.numInterfaces = 1,
.numEndpoints = sizeof(hidEndpoints)/sizeof(*hidEndpoints),
.descriptorSize = sizeof(hid_part_config),
.getPartDescriptor = getHIDPartDescriptor,
.usbInit = NULL,
.usbReset = hidUSBReset,
.usbDataSetup = hidUSBDataSetup,
.usbNoDataSetup = hidUSBNoDataSetup,
.usbClearFeature = NULL,
.usbSetConfiguration = NULL,
.endpoints = hidEndpoints
};
#define HID_TX_BUFFER_SIZE 256 // must be power of 2
#define HID_TX_BUFFER_SIZE_MASK (HID_TX_BUFFER_SIZE-1)
// Tx data
static volatile uint8 hidBufferTx[HID_TX_BUFFER_SIZE];
// Write index to hidBufferTx
static volatile uint32 hid_tx_head = 0;
// Read index from hidBufferTx
static volatile uint32 hid_tx_tail = 0;
#define CDC_SERIAL_RX_BUFFER_SIZE 256 // must be power of 2
#define CDC_SERIAL_RX_BUFFER_SIZE_MASK (CDC_SERIAL_RX_BUFFER_SIZE-1)
void usb_hid_putc(char ch) {
while (!usb_hid_tx((uint8*)&ch, 1))
;
}
/*
static void hidStatusIn() {
if (pInformation->ControlState == WAIT_STATUS_IN) {
if (currentInFeature >= 0) {
if (featureBuffers[currentInFeature].bufferSize == featureBuffers[currentInFeature].currentDataSize)
featureBuffers[currentInFeature].state = HID_BUFFER_UNREAD;
currentInFeature = -1;
}
if (currentOutput >= 0) {
if (outputBuffers[currentOutput].bufferSize == outputBuffers[currentOutput].currentDataSize)
outputBuffers[currentOutput].state = HID_BUFFER_UNREAD;
currentOutput = -1;
}
}
}
*/
void usb_hid_set_report_descriptor(const uint8* report_descriptor, uint16 report_descriptor_length) {
HID_Report_Descriptor.Descriptor = (uint8*)report_descriptor;
HID_Report_Descriptor.Descriptor_Size = report_descriptor_length;
}
static volatile HIDBuffer_t* usb_hid_find_buffer(uint8 type, uint8 reportID) {
uint8 typeTest = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0;
for (int i=0; i<MAX_HID_BUFFERS; i++) {
if ( hidBuffers[i].buffer != NULL &&
( hidBuffers[i].mode & HID_BUFFER_MODE_OUTPUT ) == typeTest &&
hidBuffers[i].reportID == reportID) {
return hidBuffers+i;
}
}
return NULL;
}
void usb_hid_set_feature(uint8 reportID, uint8* data) {
volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, reportID);
if (buffer != NULL) {
usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_NAK);
unsigned delta = reportID != 0;
memcpy((uint8*)buffer->buffer+delta, data, buffer->bufferSize-delta);
if (reportID)
buffer->buffer[0] = reportID;
buffer->currentDataSize = buffer->bufferSize;
buffer->state = HID_BUFFER_READ;
usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID);
return;
}
}
static uint8 have_unread_data_in_hid_buffer() {
for (int i=0;i<MAX_HID_BUFFERS; i++) {
if (hidBuffers[i].buffer != NULL && hidBuffers[i].state == HID_BUFFER_UNREAD)
return 1;
}
return 0;
}
uint16_t usb_hid_get_data(uint8 type, uint8 reportID, uint8* out, uint8 poll) {
volatile HIDBuffer_t* buffer;
unsigned ret = 0;
buffer = usb_hid_find_buffer(type, reportID);
if (buffer == NULL)
return 0;
nvic_irq_disable(NVIC_USB_LP_CAN_RX0);
if (buffer->reportID == reportID && buffer->state != HID_BUFFER_EMPTY && !(poll && buffer->state == HID_BUFFER_READ)) {
if (buffer->bufferSize != buffer->currentDataSize) {
buffer->state = HID_BUFFER_EMPTY;
ret = 0;
}
else {
unsigned delta = reportID != 0;
if (out != NULL)
memcpy(out, (uint8*)buffer->buffer+delta, buffer->bufferSize-delta);
if (poll) {
buffer->state = HID_BUFFER_READ;
}
ret = buffer->bufferSize-delta;
}
}
if (! have_unread_data_in_hid_buffer() ) {
usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID);
}
nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
return ret;
}
void usb_hid_clear_buffers(uint8 type) {
uint8 typeTest = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0;
for (int i=0; i<MAX_HID_BUFFERS; i++) {
if (( hidBuffers[i].mode & HID_BUFFER_MODE_OUTPUT ) == typeTest) {
hidBuffers[i].buffer = NULL;
}
}
}
uint8 usb_hid_add_buffer(uint8 type, volatile HIDBuffer_t* buf) {
if (type == HID_BUFFER_MODE_OUTPUT)
buf->mode |= HID_BUFFER_MODE_OUTPUT;
else
buf->mode &= ~HID_BUFFER_MODE_OUTPUT;
memset((void*)buf->buffer, 0, buf->bufferSize);
buf->buffer[0] = buf->reportID;
volatile HIDBuffer_t* buffer = usb_hid_find_buffer(type, buf->reportID);
if (buffer != NULL) {
*buffer = *buf;
return 1;
}
else {
for (int i=0; i<MAX_HID_BUFFERS; i++) {
if (hidBuffers[i].buffer == NULL) {
hidBuffers[i] = *buf;
return 1;
}
}
return 0;
}
}
void usb_hid_set_buffers(uint8 type, volatile HIDBuffer_t* bufs, int n) {
uint8 typeMask = type == HID_REPORT_TYPE_OUTPUT ? HID_BUFFER_MODE_OUTPUT : 0;
usb_hid_clear_buffers(type);
for (int i=0; i<n; i++) {
bufs[i].mode &= ~HID_REPORT_TYPE_OUTPUT;
bufs[i].mode |= typeMask;
usb_hid_add_buffer(type, bufs+i);
}
currentHIDBuffer = NULL;
}
/* This function is non-blocking.
*
* It copies data from a user buffer into the USB peripheral TX
* buffer, and returns the number of bytes copied. */
uint32 usb_hid_tx(const uint8* buf, uint32 len)
{
if (len==0) return 0; // no data to send
uint32 head = hid_tx_head; // load volatile variable
uint32 tx_unsent = (head - hid_tx_tail) & HID_TX_BUFFER_SIZE_MASK;
// We can only put bytes in the buffer if there is place
if (len > (HID_TX_BUFFER_SIZE-tx_unsent-1) ) {
len = (HID_TX_BUFFER_SIZE-tx_unsent-1);
}
if (len==0) return 0; // buffer full
uint16 i;
// copy data from user buffer to USB Tx buffer
for (i=0; i<len; i++) {
hidBufferTx[head] = buf[i];
head = (head+1) & HID_TX_BUFFER_SIZE_MASK;
}
hid_tx_head = head; // store volatile variable
while(usbGenericTransmitting >= 0);
if (usbGenericTransmitting<0) {
hidDataTxCb(); // initiate data transmission
}
return len;
}
uint16 usb_hid_get_pending(void) {
return (hid_tx_head - hid_tx_tail) & HID_TX_BUFFER_SIZE_MASK;
}
static void hidDataTxCb(void)
{
uint32 tail = hid_tx_tail; // load volatile variable
uint32 tx_unsent = (hid_tx_head - tail) & HID_TX_BUFFER_SIZE_MASK;
if (tx_unsent==0) {
if ( (--usbGenericTransmitting)==0) goto flush_hid; // no more data to send
return; // it was already flushed, keep Tx endpoint disabled
}
usbGenericTransmitting = 1;
// We can only send up to USBHID_CDCACM_TX_EPSIZE bytes in the endpoint.
if (tx_unsent > USB_HID_TX_EPSIZE) {
tx_unsent = USB_HID_TX_EPSIZE;
}
// copy the bytes from USB Tx buffer to PMA buffer
uint32 *dst = usb_pma_ptr(usbHIDPart.endpoints[HID_ENDPOINT_TX].pmaAddress);
uint16 tmp = 0;
uint16 val;
unsigned i;
for (i = 0; i < tx_unsent; i++) {
val = hidBufferTx[tail];
tail = (tail + 1) & HID_TX_BUFFER_SIZE_MASK;
if (i&1) {
*dst++ = tmp | (val<<8);
} else {
tmp = val;
}
}
if ( tx_unsent&1 ) {
*dst = tmp;
}
hid_tx_tail = tail; // store volatile variable
flush_hid:
// enable Tx endpoint
usb_set_ep_tx_count(usbHIDPart.endpoints[HID_ENDPOINT_TX].address, tx_unsent);
usb_set_ep_tx_stat(usbHIDPart.endpoints[HID_ENDPOINT_TX].address, USB_EP_STAT_TX_VALID);
}
static void hidUSBReset(void) {
/* Reset the RX/TX state */
hid_tx_head = 0;
hid_tx_tail = 0;
currentHIDBuffer = NULL;
}
static uint8* HID_Set(uint16 length) {
if (currentHIDBuffer == NULL)
return NULL;
if (length ==0) {
if ( (0 == (currentHIDBuffer->mode & HID_BUFFER_MODE_NO_WAIT)) &&
currentHIDBuffer->state == HID_BUFFER_UNREAD &&
pInformation->Ctrl_Info.Usb_wOffset < pInformation->USBwLengths.w) {
pInformation->Ctrl_Info.Usb_wLength = 0xFFFF;
return NULL;
}
uint16 len = pInformation->USBwLengths.w;
if (len > currentHIDBuffer->bufferSize)
len = currentHIDBuffer->bufferSize;
currentHIDBuffer->currentDataSize = len;
currentHIDBuffer->state = HID_BUFFER_EMPTY;
if (pInformation->Ctrl_Info.Usb_wOffset < len) {
pInformation->Ctrl_Info.Usb_wLength = len - pInformation->Ctrl_Info.Usb_wOffset;
}
else {
pInformation->Ctrl_Info.Usb_wLength = 0;
}
return NULL;
}
if (pInformation->USBwLengths.w <= pInformation->Ctrl_Info.Usb_wOffset + pInformation->Ctrl_Info.PacketSize) {
currentHIDBuffer->state = HID_BUFFER_UNREAD;
}
return (uint8*)currentHIDBuffer->buffer + pInformation->Ctrl_Info.Usb_wOffset;
}
static uint8* HID_GetFeature(uint16 length) {
if (currentHIDBuffer == NULL)
return NULL;
unsigned wOffset = pInformation->Ctrl_Info.Usb_wOffset;
if (length == 0)
{
pInformation->Ctrl_Info.Usb_wLength = currentHIDBuffer->bufferSize - wOffset;
return NULL;
}
return (uint8*)currentHIDBuffer->buffer + wOffset;
}
static RESULT hidUSBDataSetup(uint8 request) {
uint8* (*CopyRoutine)(uint16) = 0;
if (pInformation->USBwIndex0 != HID_INTERFACE_NUMBER)
return USB_UNSUPPORT;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
switch (request) {
case SET_REPORT:
if (pInformation->USBwValue1 == HID_REPORT_TYPE_FEATURE) {
volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, pInformation->USBwValue0);
if (buffer == NULL) {
return USB_UNSUPPORT;
}
if (0 == (buffer->mode & HID_BUFFER_MODE_NO_WAIT) && buffer->state == HID_BUFFER_UNREAD) {
return USB_NOT_READY;
}
else
{
currentHIDBuffer = buffer;
CopyRoutine = HID_Set;
}
}
else if (pInformation->USBwValue1 == HID_REPORT_TYPE_OUTPUT) {
volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_OUTPUT, pInformation->USBwValue0);
if (buffer == NULL) {
return USB_UNSUPPORT;
}
if (0 == (buffer->mode & HID_BUFFER_MODE_NO_WAIT) && buffer->state == HID_BUFFER_UNREAD) {
return USB_NOT_READY;
}
else
{
currentHIDBuffer = buffer;
CopyRoutine = HID_Set;
}
}
break;
case GET_REPORT:
if (pInformation->USBwValue1 == HID_REPORT_TYPE_FEATURE) {
volatile HIDBuffer_t* buffer = usb_hid_find_buffer(HID_REPORT_TYPE_FEATURE, pInformation->USBwValue0);
if (buffer == NULL || buffer->state == HID_BUFFER_EMPTY) {
return USB_UNSUPPORT;
}
currentHIDBuffer = buffer;
CopyRoutine = HID_GetFeature;
break;
}
default:
break;
}
}
if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)){
switch (request){
case GET_DESCRIPTOR:
if (pInformation->USBwValue1 == REPORT_DESCRIPTOR){
CopyRoutine = HID_GetReportDescriptor;
}
break;
case GET_PROTOCOL: // TODO: check for interface number?
CopyRoutine = HID_GetProtocolValue;
break;
}
}
if (CopyRoutine == NULL){
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
static RESULT hidUSBNoDataSetup(uint8 request) {
if (pInformation->USBwIndex0 != HID_INTERFACE_NUMBER)
return USB_UNSUPPORT;
RESULT ret = USB_UNSUPPORT;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
switch(request) {
case SET_PROTOCOL:
ProtocolValue = pInformation->USBwValue0;
ret = USB_SUCCESS;
break;
}
}
return ret;
}
/*
static RESULT HID_SetProtocol(void){
uint8 wValue0 = pInformation->USBwValue0;
ProtocolValue = wValue0;
return USB_SUCCESS;
}
*/
static uint8* HID_GetProtocolValue(uint16 Length){
if (Length == 0){
pInformation->Ctrl_Info.Usb_wLength = 1;
return NULL;
} else {
return (uint8 *)(&ProtocolValue);
}
}
static uint8* HID_GetReportDescriptor(uint16 Length){
return Standard_GetDescriptorData(Length, &HID_Report_Descriptor);
}

View File

@ -0,0 +1,153 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file libmaple/include/libmaple/usb_device.h
* @brief USB Composite with CDC ACM and HID support
*
* IMPORTANT: this API is unstable, and may change without notice.
*/
#ifndef _USB_HID_H_
#define _USB_HID_H_
#include <libmaple/libmaple_types.h>
#include <libmaple/usb.h>
#include "usb_generic.h"
#define MAX_HID_BUFFERS 8
#define HID_BUFFER_SIZE(n,reportID) ((n)+((reportID)!=0))
#define HID_BUFFER_ALLOCATE_SIZE(n,reportID) ((HID_BUFFER_SIZE((n),(reportID))+1)/2*2)
#define HID_BUFFER_MODE_NO_WAIT 1
#define HID_BUFFER_MODE_OUTPUT 2
#define HID_BUFFER_EMPTY 0
#define HID_BUFFER_UNREAD 1
#define HID_BUFFER_READ 2
extern USBCompositePart usbHIDPart;
typedef struct HIDBuffer_t {
volatile uint8_t* buffer; // use HID_BUFFER_ALLOCATE_SIZE() to calculate amount of memory to allocate
uint16_t bufferSize; // this should match HID_BUFFER_SIZE
uint8_t reportID;
uint8_t mode;
uint16_t currentDataSize;
uint8_t state; // HID_BUFFER_EMPTY, etc.
#ifdef __cplusplus
inline HIDBuffer_t(volatile uint8_t* _buffer=NULL, uint16_t _bufferSize=0, uint8_t _reportID=0, uint8_t _mode=0) {
reportID = _reportID;
buffer = _buffer;
bufferSize = _bufferSize;
mode = _mode;
}
#endif
} HIDBuffer_t;
#ifdef __cplusplus
extern "C" {
#endif
#define USB_HID_TX_EPSIZE 0x40
void usb_hid_set_report_descriptor(const uint8* report_descriptor, uint16 report_descriptor_length);
void usb_hid_clear_buffers(uint8_t type);
uint8_t usb_hid_add_buffer(uint8_t type, volatile HIDBuffer_t* buf);
void usb_hid_set_buffers(uint8_t type, volatile HIDBuffer_t* featureBuffers, int count);
uint16_t usb_hid_get_data(uint8_t type, uint8_t reportID, uint8_t* out, uint8_t poll);
void usb_hid_set_feature(uint8_t reportID, uint8_t* data);
/*
* HID Requests
*/
typedef enum _HID_REQUESTS
{
GET_REPORT = 1,
GET_IDLE,
GET_PROTOCOL,
SET_REPORT = 9,
SET_IDLE,
SET_PROTOCOL
} HID_REQUESTS;
#define HID_REPORT_TYPE_INPUT 0x01
#define HID_REPORT_TYPE_OUTPUT 0x02
#define HID_REPORT_TYPE_FEATURE 0x03
/*
* HID Descriptors, etc.
*/
#define HID_ENDPOINT_INT 1
#define HID_DESCRIPTOR_TYPE 0x21
#define REPORT_DESCRIPTOR 0x22
typedef struct
{
uint8_t len; // 9
uint8_t dtype; // 0x21
uint8_t versionL; // 0x101
uint8_t versionH; // 0x101
uint8_t country;
uint8_t numDesc;
uint8_t desctype; // 0x22 report
uint8_t descLenL;
uint8_t descLenH;
} HIDDescriptor;
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
#define USB_INTERFACE_CLASS_HID 0x03
#define USB_INTERFACE_SUBCLASS_HID 0x01
/*
* HID interface
*/
void usb_hid_putc(char ch);
uint32 usb_hid_tx(const uint8* buf, uint32 len);
uint32 usb_hid_tx_mod(const uint8* buf, uint32 len);
uint32 usb_hid_data_available(void); /* in RX buffer */
uint16 usb_hid_get_pending(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,464 @@
#include <string.h>
#include "usb_generic.h"
#include "usb_mass.h"
#include "usb_scsi.h"
#include "usb_mass_internal.h"
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
#include "usb_regs.h"
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
static void usb_mass_bot_cbw_decode();
static void usb_mass_set_configuration();
static void usb_mass_clear_feature();
static RESULT usb_mass_data_setup(uint8 request);
static RESULT usb_mass_no_data_setup(uint8 request);
static void usb_mass_reset();
static uint8_t* usb_mass_get_max_lun(uint16_t Length);
static void usb_mass_in(void);
static void usb_mass_out(void);
uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize);
uint32_t usb_mass_sil_read(uint8_t* pBufferPointer);
#define MASS_INTERFACE_OFFSET 0x00
#define MASS_INTERFACE_NUMBER (MASS_INTERFACE_OFFSET+usbMassPart.startInterface)
#define LUN_DATA_LENGTH 1
static uint32_t maxLun = 0;
static uint32_t deviceState = DEVICE_STATE_UNCONNECTED;
uint8_t usb_mass_botState = BOT_STATE_IDLE;
BulkOnlyCBW usb_mass_CBW;
BulkOnlyCSW usb_mass_CSW;
uint8_t usb_mass_bulkDataBuff[MAX_BULK_PACKET_SIZE];
uint16_t usb_mass_dataLength;
static uint8_t inRequestPending;
static uint8_t outRequestPending;
typedef struct mass_descriptor_config {
// usb_descriptor_config_header Config_Header;
usb_descriptor_interface MASS_Interface;
usb_descriptor_endpoint DataInEndpoint;
usb_descriptor_endpoint DataOutEndpoint;
} __packed mass_descriptor_config;
#define MAX_POWER (500 >> 1)
const mass_descriptor_config usbMassConfigDescriptor = {
/*.Config_Header =
{
.bLength = sizeof (usb_descriptor_config_header),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
.wTotalLength = sizeof (usb_descriptor_config),
.bNumInterfaces = 0x01,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED),
.bMaxPower = MAX_POWER,
}, */
.MASS_Interface =
{
.bLength = sizeof (usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = 0x00, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = 8, // mass storage
.bInterfaceSubClass = 6, // SCSI
.bInterfaceProtocol = 0x50, // Bulk-Only
.iInterface = 0,
},
.DataInEndpoint =
{
.bLength = sizeof (usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | MASS_ENDPOINT_TX), // PATCH
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = MAX_BULK_PACKET_SIZE,
.bInterval = 0,
},
.DataOutEndpoint =
{
.bLength = sizeof (usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | MASS_ENDPOINT_RX), // PATCH
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = MAX_BULK_PACKET_SIZE,
.bInterval = 1,
}
};
USBEndpointInfo usbMassEndpoints[2] = {
{
.callback = usb_mass_in,
.bufferSize = MAX_BULK_PACKET_SIZE,
.type = USB_EP_EP_TYPE_BULK,
.tx = 1,
},
{
.callback = usb_mass_out,
.bufferSize = MAX_BULK_PACKET_SIZE,
.type = USB_EP_EP_TYPE_BULK,
.tx = 0,
},
};
#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s]
static void getMassPartDescriptor(uint8* out) {
memcpy(out, &usbMassConfigDescriptor, sizeof(mass_descriptor_config));
// patch to reflect where the part goes in the descriptor
OUT_BYTE(usbMassConfigDescriptor, MASS_Interface.bInterfaceNumber) += usbMassPart.startInterface;
OUT_BYTE(usbMassConfigDescriptor, DataInEndpoint.bEndpointAddress) += usbMassPart.startEndpoint;
OUT_BYTE(usbMassConfigDescriptor, DataOutEndpoint.bEndpointAddress) += usbMassPart.startEndpoint;
}
USBCompositePart usbMassPart = {
.numInterfaces = 1,
.numEndpoints = sizeof(usbMassEndpoints)/sizeof(*usbMassEndpoints),
.descriptorSize = sizeof(mass_descriptor_config),
.getPartDescriptor = getMassPartDescriptor,
.usbInit = NULL,
.usbReset = usb_mass_reset,
.usbDataSetup = usb_mass_data_setup,
.usbNoDataSetup = usb_mass_no_data_setup,
.usbClearFeature = usb_mass_clear_feature,
.usbSetConfiguration = usb_mass_set_configuration,
.endpoints = usbMassEndpoints
};
static void usb_mass_reset(void) {
usb_mass_mal_init(0);
pInformation->Current_Configuration = 0; // TODO: remove?
/* current feature is current bmAttributes */
pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED); // usbMassConfigDescriptor.Config_Header.bmAttributes; // TODO: remove?
deviceState = DEVICE_STATE_ATTACHED;
usb_mass_CBW.dSignature = BOT_CBW_SIGNATURE;
usb_mass_botState = BOT_STATE_IDLE;
}
static void usb_mass_set_configuration(void) {
if (pInformation->Current_Configuration != 0) {
deviceState = USB_CONFIGURED;
ClearDTOG_TX(USB_MASS_TX_ENDP);
ClearDTOG_RX(USB_MASS_RX_ENDP);
usb_mass_botState = BOT_STATE_IDLE;
}
}
static void usb_mass_clear_feature(void) {
/* when the host send a usb_mass_CBW with invalid signature or invalid length the two
Endpoints (IN & OUT) shall stall until receiving a Mass Storage Reset */
if (usb_mass_CBW.dSignature != BOT_CBW_SIGNATURE) {
usb_mass_bot_abort(BOT_DIR_BOTH);
}
}
static RESULT usb_mass_data_setup(uint8 request) {
uint8_t * (*copy_routine)(uint16_t);
copy_routine = NULL;
if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& (request == REQUEST_GET_MAX_LUN) && (pInformation->USBwValue == 0)
&& (pInformation->USBwIndex == MASS_INTERFACE_NUMBER) && (pInformation->USBwLength == 0x01)) {
copy_routine = usb_mass_get_max_lun;
} else {
return USB_UNSUPPORT;
}
if (copy_routine == NULL) {
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = copy_routine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*copy_routine)(0);
return USB_SUCCESS;
}
static uint8_t* usb_mass_get_max_lun(uint16_t length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = LUN_DATA_LENGTH;
return 0;
} else {
return ((uint8_t*) (&maxLun));
}
}
static RESULT usb_mass_no_data_setup(uint8 request) {
if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& (request == REQUEST_MASS_STORAGE_RESET) && (pInformation->USBwValue == 0)
&& (pInformation->USBwIndex == MASS_INTERFACE_NUMBER) && (pInformation->USBwLength == 0x00)) {
/* Initialize Endpoint 1 */
ClearDTOG_TX(USB_MASS_TX_ENDP);
/* Initialize Endpoint 2 */
ClearDTOG_RX(USB_MASS_RX_ENDP);
/*initialize the usb_mass_CBW signature to enable the clear feature*/
usb_mass_CBW.dSignature = BOT_CBW_SIGNATURE;
usb_mass_botState = BOT_STATE_IDLE;
return USB_SUCCESS;
}
return USB_UNSUPPORT;
}
void usb_mass_loop() {
if (inRequestPending) {
inRequestPending = 0;
switch (usb_mass_botState) {
case BOT_STATE_CSW_Send:
case BOT_STATE_ERROR:
usb_mass_botState = BOT_STATE_IDLE;
SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); /* enable the Endpoint to receive the next cmd*/
break;
case BOT_STATE_DATA_IN:
switch (usb_mass_CBW.CB[0]) {
case SCSI_READ10:
scsi_read10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen);
break;
}
break;
case BOT_STATE_DATA_IN_LAST:
usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE);
SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL);
break;
default:
break;
}
}
if (outRequestPending) {
outRequestPending = 0;
uint8_t CMD;
CMD = usb_mass_CBW.CB[0];
switch (usb_mass_botState) {
case BOT_STATE_IDLE:
usb_mass_bot_cbw_decode();
break;
case BOT_STATE_DATA_OUT:
if (CMD == SCSI_WRITE10) {
scsi_write10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen);
break;
}
usb_mass_bot_abort(BOT_DIR_OUT);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_PHASE_ERROR, BOT_SEND_CSW_DISABLE);
break;
default:
usb_mass_bot_abort(BOT_DIR_BOTH);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_PHASE_ERROR, BOT_SEND_CSW_DISABLE);
break;
}
}
}
/*
* IN
*/
static void usb_mass_in(void) {
inRequestPending = 1;
}
/*
* OUT
*/
static void usb_mass_out(void) {
usb_mass_dataLength = usb_mass_sil_read(usb_mass_bulkDataBuff);
outRequestPending = 1;
}
static void usb_mass_bot_cbw_decode() {
uint32_t counter;
for (counter = 0; counter < usb_mass_dataLength; counter++) {
*((uint8_t *) & usb_mass_CBW + counter) = usb_mass_bulkDataBuff[counter];
}
usb_mass_CSW.dTag = usb_mass_CBW.dTag;
usb_mass_CSW.dDataResidue = usb_mass_CBW.dDataLength;
if (usb_mass_dataLength != BOT_CBW_PACKET_LENGTH) {
usb_mass_bot_abort(BOT_DIR_BOTH);
/* reset the usb_mass_CBW.dSignature to disable the clear feature until receiving a Mass storage reset*/
usb_mass_CBW.dSignature = 0;
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_PARAMETER_LIST_LENGTH_ERROR);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
return;
}
if ((usb_mass_CBW.CB[0] == SCSI_READ10) || (usb_mass_CBW.CB[0] == SCSI_WRITE10)) {
/* Calculate Logical Block Address */
SCSI_lba = (usb_mass_CBW.CB[2] << 24) | (usb_mass_CBW.CB[3] << 16) | (usb_mass_CBW.CB[4] << 8) | usb_mass_CBW.CB[5];
/* Calculate the Number of Blocks to transfer */
SCSI_blkLen = (usb_mass_CBW.CB[7] << 8) | usb_mass_CBW.CB[8];
}
if (usb_mass_CBW.dSignature == BOT_CBW_SIGNATURE) {
/* Valid usb_mass_CBW */
if ((usb_mass_CBW.bLUN > maxLun) || (usb_mass_CBW.bCBLength < 1) || (usb_mass_CBW.bCBLength > 16)) {
usb_mass_bot_abort(BOT_DIR_BOTH);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
} else {
switch (usb_mass_CBW.CB[0]) {
case SCSI_REQUEST_SENSE:
scsi_request_sense_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_INQUIRY:
scsi_inquiry_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_START_STOP_UNIT:
scsi_start_stop_unit_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_ALLOW_MEDIUM_REMOVAL:
scsi_start_stop_unit_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_MODE_SENSE6:
scsi_mode_sense6_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_MODE_SENSE10:
scsi_mode_sense10_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_READ_FORMAT_CAPACITIES:
scsi_read_format_capacity_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_READ_CAPACITY10:
scsi_read_capacity10_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_TEST_UNIT_READY:
scsi_test_unit_ready_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_READ10:
scsi_read10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen);
break;
case SCSI_WRITE10:
scsi_write10_cmd(usb_mass_CBW.bLUN, SCSI_lba, SCSI_blkLen);
break;
case SCSI_VERIFY10:
scsi_verify10_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_FORMAT_UNIT:
scsi_format_cmd(usb_mass_CBW.bLUN);
break;
case SCSI_MODE_SELECT10:
case SCSI_MODE_SELECT6:
case SCSI_SEND_DIAGNOSTIC:
case SCSI_READ6:
case SCSI_READ12:
case SCSI_READ16:
case SCSI_READ_CAPACITY16:
case SCSI_WRITE6:
case SCSI_WRITE12:
case SCSI_VERIFY12:
case SCSI_VERIFY16:
case SCSI_WRITE16:
scsi_invalid_cmd(usb_mass_CBW.bLUN);
break;
default:
{
usb_mass_bot_abort(BOT_DIR_BOTH);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
}
}
}
} else {
/* Invalid usb_mass_CBW */
usb_mass_bot_abort(BOT_DIR_BOTH);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
}
}
void usb_mass_bot_abort(uint8_t direction) {
switch (direction) {
case BOT_DIR_IN:
SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_STL);
break;
case BOT_DIR_OUT:
SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_STL);
break;
case BOT_DIR_BOTH:
SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_STL);
SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_STL);
break;
default:
break;
}
}
void usb_mass_transfer_data_request(uint8_t* dataPointer, uint16_t dataLen) {
usb_mass_sil_write(dataPointer, dataLen);
SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL);
usb_mass_botState = BOT_STATE_DATA_IN_LAST;
usb_mass_CSW.dDataResidue -= dataLen;
usb_mass_CSW.bStatus = BOT_CSW_CMD_PASSED;
}
void usb_mass_bot_set_csw(uint8_t status, uint8_t sendPermission) {
usb_mass_CSW.dSignature = BOT_CSW_SIGNATURE;
usb_mass_CSW.bStatus = status;
usb_mass_sil_write(((uint8_t *) & usb_mass_CSW), BOT_CSW_DATA_LENGTH);
usb_mass_botState = BOT_STATE_ERROR;
if (sendPermission) {
usb_mass_botState = BOT_STATE_CSW_Send;
SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL);
}
}
uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize) {
/* Use the memory interface function to write to the selected endpoint */
usb_copy_to_pma(pBufferPointer, wBufferSize, USB_MASS_TX_ADDR);
/* Update the data length in the control register */
SetEPTxCount(USB_MASS_TX_ENDP, wBufferSize);
return 0;
}
uint32_t usb_mass_sil_read(uint8_t* pBufferPointer) {
uint32_t usb_mass_dataLength = 0;
/* Get the number of received data on the selected Endpoint */
usb_mass_dataLength = GetEPRxCount(USB_MASS_RX_ENDP);
/* Use the memory interface function to write to the selected endpoint */
usb_copy_from_pma(pBufferPointer, usb_mass_dataLength, USB_MASS_RX_ADDR);
/* Return the number of received data */
return usb_mass_dataLength;
}

View File

@ -0,0 +1,112 @@
#ifndef _LIBMAPLE_USB_MASS_H_
#define _LIBMAPLE_USB_MASS_H_
#include <libmaple/libmaple_types.h>
#include <libmaple/gpio.h>
#include <libmaple/usb.h>
#include <inttypes.h>
#include "usb_generic.h"
#include "usb_mass_mal.h"
#ifdef __cplusplus
extern "C" {
#endif
#define N_STRING_DESCRIPTORS 4
#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */
#define MAX_BULK_PACKET_SIZE 0x40 /* 64B, max bulk Can't use 512 because the internal buffers for USB is only 512B */
/* MASS Storage Requests */
#define REQUEST_GET_MAX_LUN 0xFE
#define REQUEST_MASS_STORAGE_RESET 0xFF
/* USB device state */
typedef enum _DEVICE_STATE {
DEVICE_STATE_UNCONNECTED,
DEVICE_STATE_ATTACHED,
DEVICE_STATE_POWERED,
DEVICE_STATE_SUSPENDED,
DEVICE_STATE_ADDRESSED,
DEVICE_STATE_CONFIGURED
} DEVICE_STATE;
#define BOT_DIR_IN 0
#define BOT_DIR_OUT 1
#define BOT_DIR_BOTH 2
/*****************************************************************************/
/*********************** Bulk-Only Transfer State machine ********************/
/*****************************************************************************/
#define BOT_STATE_IDLE 0 /* Idle state */
#define BOT_STATE_DATA_OUT 1 /* Data Out state */
#define BOT_STATE_DATA_IN 2 /* Data In state */
#define BOT_STATE_DATA_IN_LAST 3 /* Last Data In Last */
#define BOT_STATE_CSW_Send 4 /* Command Status Wrapper */
#define BOT_STATE_ERROR 5 /* error state */
#define BOT_CBW_SIGNATURE 0x43425355
#define BOT_CSW_SIGNATURE 0x53425355
#define BOT_CBW_PACKET_LENGTH 31
#define BOT_CSW_DATA_LENGTH 0x000D
/* CSW Status Definitions */
#define BOT_CSW_CMD_PASSED 0x00
#define BOT_CSW_CMD_FAILED 0x01
#define BOT_CSW_PHASE_ERROR 0x02
#define BOT_SEND_CSW_DISABLE 0
#define BOT_SEND_CSW_ENABLE 1
#define USB_EP1_IN 0x81
/* Bulk-only Command Block Wrapper */
typedef struct _BulkOnlyCBW {
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataLength;
uint8_t bmFlags;
uint8_t bLUN;
uint8_t bCBLength;
uint8_t CB[16];
} BulkOnlyCBW;
/* Bulk-only Command Status Wrapper */
typedef struct _BulkOnlyCSW {
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataResidue;
uint8_t bStatus;
} BulkOnlyCSW;
typedef struct _usb_descriptor_config {
usb_descriptor_config_header Config_Header;
usb_descriptor_interface MASS_Interface;
usb_descriptor_endpoint DataInEndpoint;
usb_descriptor_endpoint DataOutEndpoint;
} __packed usb_descriptor_config;
void usb_mass_enable(gpio_dev *disc_dev, uint8 disc_bit);
void usb_mass_disable(gpio_dev *disc_dev, uint8 disc_bit);
void usb_mass_loop();
void usb_mass_bot_set_csw(uint8_t cswStatus, uint8_t sendPermission);
void usb_mass_transfer_data_request(uint8_t* dataPointer, uint16_t dataLen);
void usb_mass_bot_abort(uint8_t direction);
extern USBCompositePart usbMassPart;
extern uint8_t usb_mass_botState;
extern BulkOnlyCBW usb_mass_CBW;
extern BulkOnlyCSW usb_mass_CSW;
extern uint8_t usb_mass_bulkDataBuff[MAX_BULK_PACKET_SIZE];
extern uint16_t usb_mass_dataLength;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,12 @@
#ifndef _USB_MASS_INTERNAL_H_
#define _USB_MASS_INTERNAL_H_
extern USBEndpointInfo usbMassEndpoints[];
#define MASS_ENDPOINT_TX 0
#define MASS_ENDPOINT_RX 1
#define USB_MASS_RX_ENDP (usbMassEndpoints[MASS_ENDPOINT_RX].address)
#define USB_MASS_TX_ENDP (usbMassEndpoints[MASS_ENDPOINT_TX].address)
#define USB_MASS_RX_ADDR (usbMassEndpoints[MASS_ENDPOINT_RX].pmaAddress)
#define USB_MASS_TX_ADDR (usbMassEndpoints[MASS_ENDPOINT_TX].pmaAddress)
#endif

View File

@ -0,0 +1,42 @@
#include <stdlib.h>
#include "usb_mass_mal.h"
#define USB_MASS_MAL_FAIL 1
#define USB_MASS_MAL_SUCCESS 0
MassStorageDriveInfo usb_mass_drives[USB_MASS_MAX_DRIVES] = { { 0 } };
uint16_t usb_mass_mal_init(uint8_t lun) {
if (lun >= USB_MASS_MAX_DRIVES || (usb_mass_drives[lun].init != NULL && ! usb_mass_drives[lun].init()))
return USB_MASS_MAL_FAIL;
else
return USB_MASS_MAL_SUCCESS;
}
void usb_mass_mal_format(uint8_t lun) {
if (lun < USB_MASS_MAX_DRIVES && usb_mass_drives[lun].format != NULL)
usb_mass_drives[lun].format();
}
uint16_t usb_mass_mal_get_status(uint8_t lun) {
if (lun >= USB_MASS_MAX_DRIVES || (usb_mass_drives[lun].status != NULL && ! usb_mass_drives[lun].status()))
return USB_MASS_MAL_FAIL;
else
return USB_MASS_MAL_SUCCESS;
}
uint16_t usb_mass_mal_read_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength) {
if (lun >= USB_MASS_MAX_DRIVES || ! usb_mass_drives[lun].read(memoryOffset, readbuff, transferLength))
return USB_MASS_MAL_FAIL;
else
return USB_MASS_MAL_SUCCESS;
}
uint16_t usb_mass_mal_write_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *writebuff, uint16_t transferLength) {
if (lun >= USB_MASS_MAX_DRIVES || usb_mass_drives[lun].write == NULL
|| ! usb_mass_drives[lun].write(memoryOffset, writebuff, transferLength))
return USB_MASS_MAL_FAIL;
else
return USB_MASS_MAL_SUCCESS;
}

View File

@ -0,0 +1,39 @@
#ifndef __USB_MASS_MAL_H
#define __USB_MASS_MAL_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define USB_MASS_MAX_DRIVES 2
typedef bool (*MassStorageWriter)(uint32_t memoryOffset, const uint8_t *writebuff, uint16_t transferLength);
typedef bool (*MassStorageReader)(uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength);
typedef bool (*MassStorageStatuser)(void);
typedef bool (*MassStorageInitializer)(void);
typedef bool (*MassStorageFormatter)(void);
typedef struct {
uint32_t blockCount;
MassStorageReader read;
MassStorageWriter write;
MassStorageStatuser status;
MassStorageInitializer init;
MassStorageFormatter format;
} MassStorageDriveInfo;
extern MassStorageDriveInfo usb_mass_drives[USB_MASS_MAX_DRIVES];
uint16_t usb_mass_mal_init(uint8_t lun);
uint16_t usb_mass_mal_get_status(uint8_t lun);
uint16_t usb_mass_mal_read_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *readbuff, uint16_t transferLength);
uint16_t usb_mass_mal_write_memory(uint8_t lun, uint32_t memoryOffset, uint8_t *writebuff, uint16_t transferLength);
void usb_mass_mal_format(uint8_t lun);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,532 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
* Copyright (c) 2013 Magnus Lundin.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file libmaple/usb/stm32f1/usb_midi_device.c
* @brief USB MIDI.
*
* FIXME: this works on the STM32F1 USB peripherals, and probably no
* place else. Nonportable bits really need to be factored out, and
* the result made cleaner.
*/
#include <string.h>
#include "usb_generic.h"
#include "usb_midi_device.h"
#include <MidiSpecs.h>
#include <MinSysex.h>
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
static void midiDataTxCb(void);
static void midiDataRxCb(void);
static void usbMIDIReset(void);
static RESULT usbMIDIDataSetup(uint8 request);
static RESULT usbMIDINoDataSetup(uint8 request);
#define MIDI_ENDPOINT_RX 0
#define MIDI_ENDPOINT_TX 1
#define USB_MIDI_RX_ENDP (midiEndpoints[MIDI_ENDPOINT_RX].address)
#define USB_MIDI_TX_ENDP (midiEndpoints[MIDI_ENDPOINT_TX].address)
#define USB_MIDI_RX_ADDR (midiEndpoints[MIDI_ENDPOINT_RX].pmaAddress)
#define USB_MIDI_TX_ADDR (midiEndpoints[MIDI_ENDPOINT_TX].pmaAddress)
/*
* Descriptors
*/
typedef struct {
// usb_descriptor_config_header Config_Header;
/* Control Interface */
usb_descriptor_interface AC_Interface;
AC_CS_INTERFACE_DESCRIPTOR(1) AC_CS_Interface;
/* Control Interface */
usb_descriptor_interface MS_Interface;
MS_CS_INTERFACE_DESCRIPTOR MS_CS_Interface;
MIDI_IN_JACK_DESCRIPTOR MIDI_IN_JACK_1;
MIDI_IN_JACK_DESCRIPTOR MIDI_IN_JACK_2;
MIDI_OUT_JACK_DESCRIPTOR(1) MIDI_OUT_JACK_3;
MIDI_OUT_JACK_DESCRIPTOR(1) MIDI_OUT_JACK_4;
usb_descriptor_endpoint DataOutEndpoint;
MS_CS_BULK_ENDPOINT_DESCRIPTOR(1) MS_CS_DataOutEndpoint;
usb_descriptor_endpoint DataInEndpoint;
MS_CS_BULK_ENDPOINT_DESCRIPTOR(1) MS_CS_DataInEndpoint;
} __packed usb_descriptor_config;
static const usb_descriptor_config usbMIDIDescriptor_Config = {
/* .Config_Header = {
.bLength = sizeof(usb_descriptor_config_header),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
.wTotalLength = sizeof(usb_descriptor_config),
.bNumInterfaces = 0x02,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED |
USB_CONFIG_ATTR_SELF_POWERED),
.bMaxPower = MAX_POWER,
}, */
.AC_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = 0x00, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x00,
.bInterfaceClass = USB_INTERFACE_CLASS_AUDIO,
.bInterfaceSubClass = USB_INTERFACE_AUDIOCONTROL,
.bInterfaceProtocol = 0x00,
.iInterface = 0x00,
},
.AC_CS_Interface = {
.bLength = AC_CS_INTERFACE_DESCRIPTOR_SIZE(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE,
.SubType = 0x01,
.bcdADC = 0x0100,
.wTotalLength = AC_CS_INTERFACE_DESCRIPTOR_SIZE(1),
.bInCollection = 0x01,
.baInterfaceNr = {0x01},
},
.MS_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = 0x01, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = USB_INTERFACE_CLASS_AUDIO,
.bInterfaceSubClass = USB_INTERFACE_MIDISTREAMING,
.bInterfaceProtocol = 0x00,
.iInterface = 0, // was 0x04
},
.MS_CS_Interface = {
.bLength = sizeof(MS_CS_INTERFACE_DESCRIPTOR),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE,
.SubType = 0x01,
.bcdADC = 0x0100,
.wTotalLength = sizeof(MS_CS_INTERFACE_DESCRIPTOR)
+sizeof(MIDI_IN_JACK_DESCRIPTOR)
+sizeof(MIDI_IN_JACK_DESCRIPTOR)
+MIDI_OUT_JACK_DESCRIPTOR_SIZE(1)
+MIDI_OUT_JACK_DESCRIPTOR_SIZE(1)
+sizeof(usb_descriptor_endpoint)
+MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1)
+sizeof(usb_descriptor_endpoint)
+MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1)
/* 0x41-4 */,
},
.MIDI_IN_JACK_1 = {
.bLength = sizeof(MIDI_IN_JACK_DESCRIPTOR),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE,
.SubType = MIDI_IN_JACK,
.bJackType = MIDI_JACK_EMBEDDED,
.bJackId = 0x01,
.iJack = 0x05,
},
.MIDI_IN_JACK_2 = {
.bLength = sizeof(MIDI_IN_JACK_DESCRIPTOR),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE,
.SubType = MIDI_IN_JACK,
.bJackType = MIDI_JACK_EXTERNAL,
.bJackId = 0x02,
.iJack = 0x00,
},
.MIDI_OUT_JACK_3 = {
.bLength = MIDI_OUT_JACK_DESCRIPTOR_SIZE(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE,
.SubType = MIDI_OUT_JACK,
.bJackType = MIDI_JACK_EMBEDDED,
.bJackId = 0x03,
.bNrInputPins = 0x01,
.baSourceId = {0x02},
.baSourcePin = {0x01},
.iJack = 0x00,
},
.MIDI_OUT_JACK_4 = {
.bLength = MIDI_OUT_JACK_DESCRIPTOR_SIZE(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_INTERFACE,
.SubType = MIDI_OUT_JACK,
.bJackType = MIDI_JACK_EXTERNAL,
// .bJackId = 0x04,
.bJackId = 0x03,
.bNrInputPins = 0x01,
.baSourceId = {0x01},
.baSourcePin = {0x01},
.iJack = 0x00,
},
.DataOutEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT |
MIDI_ENDPOINT_RX), // PATCH
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = USB_MIDI_RX_EPSIZE,
.bInterval = 0x00,
},
.MS_CS_DataOutEndpoint = {
.bLength = MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_ENDPOINT,
.SubType = 0x01,
.bNumEmbMIDIJack = 0x01,
.baAssocJackID = {0x01},
},
.DataInEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | MIDI_ENDPOINT_TX), // PATCH
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = USB_MIDI_TX_EPSIZE,
.bInterval = 0x00,
},
.MS_CS_DataInEndpoint = {
.bLength = MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CS_ENDPOINT,
.SubType = 0x01,
.bNumEmbMIDIJack = 0x01,
.baAssocJackID = {0x03},
},
};
/* I/O state */
/* Received data */
static volatile uint32 midiBufferRx[USB_MIDI_RX_EPSIZE/4];
/* Read index into midiBufferRx */
static volatile uint32 rx_offset = 0;
/* Transmit data */
static volatile uint32 midiBufferTx[USB_MIDI_TX_EPSIZE/4];
/* Write index into midiBufferTx */
static volatile uint32 tx_offset = 0;
/* Number of bytes left to transmit */
static volatile uint32 n_unsent_packets = 0;
/* Are we currently sending an IN packet? */
static volatile uint8 transmitting = 0;
/* Number of unread bytes */
static volatile uint32 n_unread_packets = 0;
// eventually all of this should be in a place for settings which can be written to flash.
volatile uint8 myMidiChannel = DEFAULT_MIDI_CHANNEL;
volatile uint8 myMidiDevice = DEFAULT_MIDI_DEVICE;
volatile uint8 myMidiCable = DEFAULT_MIDI_CABLE;
volatile uint8 myMidiID[] = { LEAFLABS_MMA_VENDOR_1,LEAFLABS_MMA_VENDOR_2,LEAFLABS_MMA_VENDOR_3,0};
#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s]
static void getMIDIPartDescriptor(uint8* out) {
memcpy(out, &usbMIDIDescriptor_Config, sizeof(usbMIDIDescriptor_Config));
// patch to reflect where the part goes in the descriptor
OUT_BYTE(usbMIDIDescriptor_Config, AC_Interface.bInterfaceNumber) += usbMIDIPart.startInterface;
OUT_BYTE(usbMIDIDescriptor_Config, MS_Interface.bInterfaceNumber) += usbMIDIPart.startInterface;
OUT_BYTE(usbMIDIDescriptor_Config, DataOutEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint;
OUT_BYTE(usbMIDIDescriptor_Config, DataInEndpoint.bEndpointAddress) += usbMIDIPart.startEndpoint;
}
static USBEndpointInfo midiEndpoints[2] = {
{
.callback = midiDataRxCb,
.bufferSize = USB_MIDI_RX_EPSIZE,
.type = USB_EP_EP_TYPE_BULK,
.tx = 0
},
{
.callback = midiDataTxCb,
.bufferSize = USB_MIDI_TX_EPSIZE,
.type = USB_EP_EP_TYPE_BULK,
.tx = 1,
}
};
USBCompositePart usbMIDIPart = {
.numInterfaces = 2,
.numEndpoints = sizeof(midiEndpoints)/sizeof(*midiEndpoints),
.descriptorSize = sizeof(usbMIDIDescriptor_Config),
.getPartDescriptor = getMIDIPartDescriptor,
.usbInit = NULL,
.usbReset = usbMIDIReset,
.usbDataSetup = usbMIDIDataSetup,
.usbNoDataSetup = usbMIDINoDataSetup,
.endpoints = midiEndpoints
};
/*
* MIDI interface
*/
/* This function is non-blocking.
*
* It copies data from a usercode buffer into the USB peripheral TX
* buffer, and returns the number of bytes copied. */
uint32 usb_midi_tx(const uint32* buf, uint32 packets) {
uint32 bytes=packets*4;
/* Last transmission hasn't finished, so abort. */
if (usb_midi_is_transmitting()) {
/* Copy to TxBuffer */
return 0; /* return len */
}
/* We can only put USB_MIDI_TX_EPSIZE bytes in the buffer. */
if (bytes > USB_MIDI_TX_EPSIZE) {
bytes = USB_MIDI_TX_EPSIZE;
packets=bytes/4;
}
/* Queue bytes for sending. */
if (packets) {
usb_copy_to_pma((uint8 *)buf, bytes, USB_MIDI_TX_ADDR);
}
// We still need to wait for the interrupt, even if we're sending
// zero bytes. (Sending zero-size packets is useful for flushing
// host-side buffers.)
usb_set_ep_tx_count(USB_MIDI_TX_ENDP, bytes);
n_unsent_packets = packets;
transmitting = 1;
usb_set_ep_tx_stat(USB_MIDI_TX_ENDP, USB_EP_STAT_TX_VALID);
return packets;
}
uint32 usb_midi_data_available(void) {
return n_unread_packets;
}
uint8 usb_midi_is_transmitting(void) {
return transmitting;
}
uint16 usb_midi_get_pending(void) {
return n_unsent_packets;
}
/* Nonblocking byte receive.
*
* Copies up to len bytes from our private data buffer (*NOT* the PMA)
* into buf and deq's the FIFO. */
uint32 usb_midi_rx(uint32* buf, uint32 packets) {
/* Copy bytes to buffer. */
uint32 n_copied = usb_midi_peek(buf, packets);
/* Mark bytes as read. */
n_unread_packets -= n_copied;
rx_offset += n_copied;
/* If all bytes have been read, re-enable the RX endpoint, which
* was set to NAK when the current batch of bytes was received. */
if (n_unread_packets == 0) {
usb_set_ep_rx_count(USB_MIDI_RX_ENDP, USB_MIDI_RX_EPSIZE);
usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_VALID);
rx_offset = 0;
}
return n_copied;
}
/* Nonblocking byte lookahead.
*
* Looks at unread bytes without marking them as read. */
uint32 usb_midi_peek(uint32* buf, uint32 packets) {
uint32 i;
if (packets > n_unread_packets) {
packets = n_unread_packets;
}
for (i = 0; i < packets; i++) {
buf[i] = midiBufferRx[i + rx_offset];
}
return packets;
}
/*
* Callbacks
*/
static void midiDataTxCb(void) {
n_unsent_packets = 0;
transmitting = 0;
}
static void midiDataRxCb(void) {
usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_NAK);
n_unread_packets = usb_get_ep_rx_count(USB_MIDI_RX_ENDP) / 4;
/* This copy won't overwrite unread bytes, since we've set the RX
* endpoint to NAK, and will only set it to VALID when all bytes
* have been read. */
usb_copy_from_pma((uint8*)midiBufferRx, n_unread_packets * 4,
USB_MIDI_RX_ADDR);
// discard volatile
LglSysexHandler((uint32*)midiBufferRx,(uint32*)&rx_offset,(uint32*)&n_unread_packets);
if (n_unread_packets == 0) {
usb_set_ep_rx_count(USB_MIDI_RX_ENDP, USB_MIDI_RX_EPSIZE);
usb_set_ep_rx_stat(USB_MIDI_RX_ENDP, USB_EP_STAT_RX_VALID);
rx_offset = 0;
}
}
static void usbMIDIReset(void) {
/* Reset the RX/TX state */
n_unread_packets = 0;
n_unsent_packets = 0;
rx_offset = 0;
}
static RESULT usbMIDIDataSetup(uint8 request) {
(void)request;//unused
#if 0
uint8* (*CopyRoutine)(uint16) = 0;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
}
if (CopyRoutine == NULL) {
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
#endif
return USB_UNSUPPORT;
}
static RESULT usbMIDINoDataSetup(uint8 request) {
(void)request;//unused
#if 0
RESULT ret = USB_UNSUPPORT;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
}
return ret;
#endif
return USB_UNSUPPORT;
}
// .............THIS IS NOT WORKING YET................
// send debugging information to
static uint8_t sysexbuffer[80]={CIN_SYSEX,0xF0,0x7D,0x33,CIN_SYSEX,0x33,0x00,0xf7}; // !!!bad hardcoded number foo !!!
uint8_t iSysHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer);
void sendThroughSysex(char *printbuffer, int bufferlength) {
int n;
n = iSysHexLine(1, 0 , (uint8_t *) printbuffer, (uint8_t) bufferlength , sysexbuffer+6);
usb_midi_tx((uint32*)sysexbuffer,n/4);
}
#define HIGHBYTE(x) ((uint8_t) (((x) >> 8) & 0x00ff) )
#define LOWBYTE(x) ((uint8_t) ((x) & 0x00ff) )
#define HIGHNIBBLE(x) ((((uint8_t)(x)) & 0xF0) >> 4)
#define LOWNIBBLE(x) (((uint8_t)(x)) & 0x0F)
#define HEXCHAR(c) ((c>9)?55+c:48+c)
uint8_t iSysHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer) {
int i=0; int j; int thirdone;
uint8_t n=0;
uint16_t checksum=0;
//uint16_t length=0;
buffer[i++]=':';
checksum+=payloadlength;
buffer[i++]=HEXCHAR(HIGHNIBBLE(payloadlength));
buffer[i++]=HEXCHAR(LOWNIBBLE(payloadlength));
buffer[i++]=CIN_SYSEX;
n=HIGHBYTE(address);
checksum+=n;
buffer[i++]=HEXCHAR(HIGHNIBBLE(n));
buffer[i++]=HEXCHAR(LOWNIBBLE(n));
n=LOWBYTE(address);
checksum+=n;
buffer[i++]=HEXCHAR(HIGHNIBBLE(n));
buffer[i++]=CIN_SYSEX;
buffer[i++]=HEXCHAR(LOWNIBBLE(n));
n=rectype;
checksum+=n;
buffer[i++]=HEXCHAR(HIGHNIBBLE(n));
buffer[i++]=HEXCHAR(LOWNIBBLE(n));
buffer[i++]=CIN_SYSEX;
thirdone=0;
for (j=0; j<payloadlength ; j++) {
n=payload[j];
checksum+=n;
buffer[i++]=HEXCHAR(HIGHNIBBLE(n));
if (++thirdone==3) {
buffer[i++]=CIN_SYSEX;
thirdone=0;
}
buffer[i++]=HEXCHAR(LOWNIBBLE(n));
if (++thirdone==3) {
buffer[i++]=CIN_SYSEX;
thirdone=0;
}
}
if (thirdone==0) {
buffer[i-1]=CIN_SYSEX_ENDS_IN_3;
}
n=~((uint8_t) checksum&0x00ff)+1;
buffer[i++]=HEXCHAR(HIGHNIBBLE(n));
if (thirdone==1) {
buffer[i++]=CIN_SYSEX_ENDS_IN_2;
}
buffer[i++]=HEXCHAR(LOWNIBBLE(n));
if (thirdone==2) {
buffer[i++]=CIN_SYSEX_ENDS_IN_1;
}
buffer[i++]=0xf7;
return i+thirdone;
}

View File

@ -0,0 +1,189 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
* Copyright (c) 2013 Magnus Lundin.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* IMPORTANT: this API is unstable, and may change without notice.
*/
#ifndef _LIBMAPLE_USB_MIDI_H_
#define _LIBMAPLE_USB_MIDI_H_
#include <libmaple/libmaple_types.h>
#include <libmaple/gpio.h>
#include <libmaple/usb.h>
#include <MinSysex.h>
#include "usb_generic.h"
#ifdef __cplusplus
extern "C" {
#endif
extern USBCompositePart usbMIDIPart;
typedef union {
uint8 byte[4];
uint32 data;
} USB_MIDI_Event_Packet;
/*
* USB MIDI Requests
*/
/*
* Descriptors, etc.
*/
#define USB_DESCRIPTOR_TYPE_CS_INTERFACE 0x24
#define USB_DESCRIPTOR_TYPE_CS_ENDPOINT 0x25
#define USB_DEVICE_CLASS_UNDEFINED 0x00
#define USB_DEVICE_CLASS_CDC 0x02
#define USB_DEVICE_SUBCLASS_UNDEFINED 0x00
#define USB_INTERFACE_CLASS_AUDIO 0x01
#define USB_INTERFACE_SUBCLASS_UNDEFINED 0x00
#define USB_INTERFACE_AUDIOCONTROL 0x01
#define USB_INTERFACE_AUDIOSTREAMING 0x02
#define USB_INTERFACE_MIDISTREAMING 0x03
/* MIDI Streaming class specific interfaces */
#define MIDI_IN_JACK 0x02
#define MIDI_OUT_JACK 0x03
#define MIDI_JACK_EMBEDDED 0x01
#define MIDI_JACK_EXTERNAL 0x02
#define AC_CS_INTERFACE_DESCRIPTOR_SIZE(DataSize) (8 + DataSize)
#define AC_CS_INTERFACE_DESCRIPTOR(DataSize) \
struct { \
uint8 bLength; \
uint8 bDescriptorType; \
uint8 SubType; \
uint16 bcdADC; \
uint16 wTotalLength; \
uint8 bInCollection; \
uint8 baInterfaceNr[DataSize]; \
} __packed
typedef struct {
uint8 bLength;
uint8 bDescriptorType;
uint8 SubType;
uint16 bcdADC;
uint16 wTotalLength;
} __packed MS_CS_INTERFACE_DESCRIPTOR;
typedef struct {
uint8 bLength;
uint8 bDescriptorType;
uint8 SubType;
uint8 bJackType;
uint8 bJackId;
uint8 iJack;
} __packed MIDI_IN_JACK_DESCRIPTOR;
#define MIDI_OUT_JACK_DESCRIPTOR_SIZE(DataSize) (7 + 2*DataSize)
#define MIDI_OUT_JACK_DESCRIPTOR(DataSize) \
struct { \
uint8 bLength; \
uint8 bDescriptorType; \
uint8 SubType; \
uint8 bJackType; \
uint8 bJackId; \
uint8 bNrInputPins; \
uint8 baSourceId[DataSize]; \
uint8 baSourcePin[DataSize]; \
uint8 iJack; \
} __packed
#define MS_CS_BULK_ENDPOINT_DESCRIPTOR_SIZE(DataSize) (4 + DataSize)
#define MS_CS_BULK_ENDPOINT_DESCRIPTOR(DataSize) \
struct { \
uint8 bLength; \
uint8 bDescriptorType; \
uint8 SubType; \
uint8 bNumEmbMIDIJack; \
uint8 baAssocJackID[DataSize]; \
} __packed
/*
* Endpoint configuration
*/
#define USB_MIDI_TX_EPSIZE 0x40
#define USB_MIDI_RX_EPSIZE 0x40
#ifndef __cplusplus
#define USB_MIDI_DECLARE_DEV_DESC(vid, pid) \
{ \
.bLength = sizeof(usb_descriptor_device), \
.bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, \
.bcdUSB = 0x0110, \
.bDeviceClass = USB_DEVICE_CLASS_UNDEFINED, \
.bDeviceSubClass = USB_DEVICE_SUBCLASS_UNDEFINED, \
.bDeviceProtocol = 0x00, \
.bMaxPacketSize0 = 0x40, \
.idVendor = vid, \
.idProduct = pid, \
.bcdDevice = 0x0200, \
.iManufacturer = 0x01, \
.iProduct = 0x02, \
.iSerialNumber = 0x00, \
.bNumConfigurations = 0x01, \
}
#endif
/*
* Sysex Stuff.
*/
#define SYSEX_BUFFER_LENGTH 256
/*
* MIDI interface
*/
void usb_midi_putc(char ch);
uint32 usb_midi_tx(const uint32* buf, uint32 len);
uint32 usb_midi_rx(uint32* buf, uint32 len);
uint32 usb_midi_peek(uint32* buf, uint32 len);
uint32 usb_midi_data_available(void); /* in RX buffer */
uint16 usb_midi_get_pending(void);
uint8 usb_midi_is_transmitting(void);
void sendThroughSysex(char *printbuffer, int bufferlength);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,333 @@
#include "usb_mass.h"
#include "usb_mass_mal.h"
#include "usb_mass_internal.h"
#include "usb_scsi.h"
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
#include "usb_regs.h"
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C
#define SCSI_READ_FORMAT_CAPACITY10_DATA_LEN 0x08
#define SCSI_MODE_SENSE6_DATA_LEN 0x04
#define SCSI_MODE_SENSE10_DATA_LEN 0x08
#define SCSI_TXFR_IDLE 0
#define SCSI_TXFR_ONGOING 1
extern uint32_t usb_mass_sil_write(uint8_t* pBufferPointer, uint32_t wBufferSize);
/* See usb_scsi_data.c */
extern uint8_t SCSI_page00InquiryData[];
extern uint8_t SCSI_standardInquiryData[];
extern uint8_t SCSI_standardInquiryData2[];
extern uint8_t SCSI_senseData[];
extern uint8_t SCSI_modeSense6Data[];
extern uint8_t SCSI_modeSense10Data[];
extern uint8_t SCSI_readFormatCapacityData[];
extern uint8_t SCSI_readFormatCapacity10Data[];
uint32_t SCSI_lba;
uint32_t SCSI_blkLen;
uint8_t SCSI_transferState = SCSI_TXFR_IDLE;
uint32_t SCSI_blockReadCount = 0;
uint32_t SCSI_blockOffset;
uint32_t SCSI_counter = 0;
uint8_t SCSI_dataBuffer[512]; /* 512 bytes (SDCard block size) */
uint8_t scsi_address_management(uint8_t lun, uint8_t cmd, uint32_t lba, uint32_t blockNbr);
void scsi_read_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength);
void scsi_write_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength);
void scsi_inquiry_cmd(uint8_t lun) {
uint8_t* inquiryData;
uint16_t inquiryDataLength;
if (usb_mass_CBW.CB[1] & 0x01) /*Evpd is set*/ {
inquiryData = SCSI_page00InquiryData;
inquiryDataLength = 5;
} else {
if (lun == 0) {
inquiryData = SCSI_standardInquiryData;
} else {
inquiryData = SCSI_standardInquiryData2;
}
if (usb_mass_CBW.CB[4] <= SCSI_STANDARD_INQUIRY_DATA_LEN) {
inquiryDataLength = usb_mass_CBW.CB[4];
} else {
inquiryDataLength = SCSI_STANDARD_INQUIRY_DATA_LEN;
}
}
usb_mass_transfer_data_request(inquiryData, inquiryDataLength);
}
void scsi_request_sense_cmd(uint8_t lun) {
uint8_t requestSenseDataLength;
if (usb_mass_CBW.CB[4] <= SCSI_REQUEST_SENSE_DATA_LEN) {
requestSenseDataLength = usb_mass_CBW.CB[4];
} else {
requestSenseDataLength = SCSI_REQUEST_SENSE_DATA_LEN;
}
usb_mass_transfer_data_request(SCSI_senseData, requestSenseDataLength);
}
void scsi_start_stop_unit_cmd(uint8_t lun) {
usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE);
}
void scsi_mode_sense6_cmd(uint8_t lun) {
usb_mass_transfer_data_request(SCSI_modeSense6Data, SCSI_MODE_SENSE6_DATA_LEN);
}
void scsi_mode_sense10_cmd(uint8_t lun) {
usb_mass_transfer_data_request(SCSI_modeSense10Data, SCSI_MODE_SENSE10_DATA_LEN);
}
void scsi_read_format_capacity_cmd(uint8_t lun) {
if (usb_mass_mal_get_status(lun)) {
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE);
usb_mass_bot_abort(BOT_DIR_IN);
return;
}
SCSI_readFormatCapacityData[4] = (uint8_t) (usb_mass_drives[lun].blockCount >> 24);
SCSI_readFormatCapacityData[5] = (uint8_t) (usb_mass_drives[lun].blockCount >> 16);
SCSI_readFormatCapacityData[6] = (uint8_t) (usb_mass_drives[lun].blockCount >> 8);
SCSI_readFormatCapacityData[7] = (uint8_t) (usb_mass_drives[lun].blockCount);
SCSI_readFormatCapacityData[9] = (uint8_t) (SCSI_BLOCK_SIZE >> 16);
SCSI_readFormatCapacityData[10] = (uint8_t) (SCSI_BLOCK_SIZE >> 8);
SCSI_readFormatCapacityData[11] = (uint8_t) (SCSI_BLOCK_SIZE);
usb_mass_transfer_data_request(SCSI_readFormatCapacityData, SCSI_READ_FORMAT_CAPACITY_DATA_LEN);
}
void scsi_read_capacity10_cmd(uint8_t lun) {
if (usb_mass_mal_get_status(lun)) {
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE);
usb_mass_bot_abort(BOT_DIR_IN);
return;
}
SCSI_readFormatCapacity10Data[0] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 24);
SCSI_readFormatCapacity10Data[1] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 16);
SCSI_readFormatCapacity10Data[2] = (uint8_t) ((usb_mass_drives[lun].blockCount - 1) >> 8);
SCSI_readFormatCapacity10Data[3] = (uint8_t) (usb_mass_drives[lun].blockCount - 1);
SCSI_readFormatCapacity10Data[4] = (uint8_t) (SCSI_BLOCK_SIZE >> 24);
SCSI_readFormatCapacity10Data[5] = (uint8_t) (SCSI_BLOCK_SIZE >> 16);
SCSI_readFormatCapacity10Data[6] = (uint8_t) (SCSI_BLOCK_SIZE >> 8);
SCSI_readFormatCapacity10Data[7] = (uint8_t) (SCSI_BLOCK_SIZE);
usb_mass_transfer_data_request(SCSI_readFormatCapacity10Data, SCSI_READ_FORMAT_CAPACITY10_DATA_LEN);
}
void scsi_read10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr) {
if (usb_mass_botState == BOT_STATE_IDLE) {
if (!(scsi_address_management(usb_mass_CBW.bLUN, SCSI_READ10, lba, blockNbr))) /*address out of range*/ {
return;
}
if ((usb_mass_CBW.bmFlags & 0x80) != 0) {
usb_mass_botState = BOT_STATE_DATA_IN;
scsi_read_memory(lun, lba, blockNbr);
} else {
usb_mass_bot_abort(BOT_DIR_BOTH);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE);
}
return;
} else if (usb_mass_botState == BOT_STATE_DATA_IN) {
scsi_read_memory(lun, lba, blockNbr);
}
}
void scsi_write10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr) {
if (usb_mass_botState == BOT_STATE_IDLE) {
if (!(scsi_address_management(usb_mass_CBW.bLUN, SCSI_WRITE10, lba, blockNbr)))/*address out of range*/ {
return;
}
if ((usb_mass_CBW.bmFlags & 0x80) == 0) {
usb_mass_botState = BOT_STATE_DATA_OUT;
SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL);
} else {
usb_mass_bot_abort(BOT_DIR_IN);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
}
return;
} else if (usb_mass_botState == BOT_STATE_DATA_OUT) {
scsi_write_memory(lun, lba, blockNbr);
}
}
void scsi_test_unit_ready_cmd(uint8_t lun) {
if (usb_mass_mal_get_status(lun)) {
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE);
usb_mass_bot_abort(BOT_DIR_IN);
return;
} else {
usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE);
}
}
void scsi_verify10_cmd(uint8_t lun) {
if ((usb_mass_CBW.dDataLength == 0) && !(usb_mass_CBW.CB[1] & SCSI_BLKVFY))/* BLKVFY not set*/ {
usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE);
} else {
usb_mass_bot_abort(BOT_DIR_BOTH);
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
}
}
void scsi_format_cmd(uint8_t lun) {
if (usb_mass_mal_get_status(lun)) {
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_NOT_READY, SCSI_MEDIUM_NOT_PRESENT);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_ENABLE);
usb_mass_bot_abort(BOT_DIR_IN);
return;
}
usb_mass_mal_format(lun);
usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE);
}
void scsi_set_sense_data(uint8_t lun, uint8_t sensKey, uint8_t asc) {
SCSI_senseData[2] = sensKey;
SCSI_senseData[12] = asc;
}
void scsi_invalid_cmd(uint8_t lun) {
if (usb_mass_CBW.dDataLength == 0) {
usb_mass_bot_abort(BOT_DIR_IN);
} else {
if ((usb_mass_CBW.bmFlags & 0x80) != 0) {
usb_mass_bot_abort(BOT_DIR_IN);
} else {
usb_mass_bot_abort(BOT_DIR_BOTH);
}
}
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
}
uint8_t scsi_address_management(uint8_t lun, uint8_t cmd, uint32_t lba, uint32_t blockNbr) {
if ((lba + blockNbr) > usb_mass_drives[lun].blockCount) {
if (cmd == SCSI_WRITE10) {
usb_mass_bot_abort(BOT_DIR_BOTH);
}
usb_mass_bot_abort(BOT_DIR_IN);
scsi_set_sense_data(lun, SCSI_ILLEGAL_REQUEST, SCSI_ADDRESS_OUT_OF_RANGE);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
return (FALSE);
}
if (usb_mass_CBW.dDataLength != blockNbr * SCSI_BLOCK_SIZE) {
if (cmd == SCSI_WRITE10) {
usb_mass_bot_abort(BOT_DIR_BOTH);
} else {
usb_mass_bot_abort(BOT_DIR_IN);
}
scsi_set_sense_data(usb_mass_CBW.bLUN, SCSI_ILLEGAL_REQUEST, SCSI_INVALID_FIELED_IN_COMMAND);
usb_mass_bot_set_csw(BOT_CSW_CMD_FAILED, BOT_SEND_CSW_DISABLE);
return (FALSE);
}
return (TRUE);
}
void scsi_read_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength) {
static uint32_t offset, length;
if (SCSI_transferState == SCSI_TXFR_IDLE) {
offset = memoryOffset * SCSI_BLOCK_SIZE;
length = transferLength * SCSI_BLOCK_SIZE;
SCSI_transferState = SCSI_TXFR_ONGOING;
}
if (SCSI_transferState == SCSI_TXFR_ONGOING) {
if (SCSI_blockReadCount == 0) {
usb_mass_mal_read_memory(lun, offset, SCSI_dataBuffer, SCSI_BLOCK_SIZE);
usb_mass_sil_write(SCSI_dataBuffer, MAX_BULK_PACKET_SIZE);
SCSI_blockReadCount = SCSI_BLOCK_SIZE - MAX_BULK_PACKET_SIZE;
SCSI_blockOffset = MAX_BULK_PACKET_SIZE;
} else {
usb_mass_sil_write(SCSI_dataBuffer + SCSI_blockOffset, MAX_BULK_PACKET_SIZE);
SCSI_blockReadCount -= MAX_BULK_PACKET_SIZE;
SCSI_blockOffset += MAX_BULK_PACKET_SIZE;
}
SetEPTxStatus(USB_MASS_TX_ENDP, USB_EP_ST_TX_VAL);
offset += MAX_BULK_PACKET_SIZE;
length -= MAX_BULK_PACKET_SIZE;
usb_mass_CSW.dDataResidue -= MAX_BULK_PACKET_SIZE;
usb_mass_CSW.bStatus = BOT_CSW_CMD_PASSED;
// TODO: Led_RW_ON();
}
if (length == 0) {
SCSI_blockReadCount = 0;
SCSI_blockOffset = 0;
offset = 0;
usb_mass_botState = BOT_STATE_DATA_IN_LAST;
SCSI_transferState = SCSI_TXFR_IDLE;
// TODO: Led_RW_OFF();
}
}
void scsi_write_memory(uint8_t lun, uint32_t memoryOffset, uint32_t transferLength) {
static uint32_t offset, length;
uint32_t idx;
uint32_t temp = SCSI_counter + 64;
if (SCSI_transferState == SCSI_TXFR_IDLE) {
offset = memoryOffset * SCSI_BLOCK_SIZE;
length = transferLength * SCSI_BLOCK_SIZE;
SCSI_transferState = SCSI_TXFR_ONGOING;
}
if (SCSI_transferState == SCSI_TXFR_ONGOING) {
for (idx = 0; SCSI_counter < temp; SCSI_counter++) {
*((uint8_t *) SCSI_dataBuffer + SCSI_counter) = usb_mass_bulkDataBuff[idx++];
}
offset += usb_mass_dataLength;
length -= usb_mass_dataLength;
if (!(length % SCSI_BLOCK_SIZE)) {
SCSI_counter = 0;
usb_mass_mal_write_memory(lun, offset - SCSI_BLOCK_SIZE, SCSI_dataBuffer, SCSI_BLOCK_SIZE);
}
usb_mass_CSW.dDataResidue -= usb_mass_dataLength;
SetEPRxStatus(USB_MASS_RX_ENDP, USB_EP_ST_RX_VAL); /* enable the next transaction*/
// TODO: Led_RW_ON();
}
if ((length == 0) || (usb_mass_botState == BOT_STATE_CSW_Send)) {
SCSI_counter = 0;
usb_mass_bot_set_csw(BOT_CSW_CMD_PASSED, BOT_SEND_CSW_ENABLE);
SCSI_transferState = SCSI_TXFR_IDLE;
// TODO: Led_RW_OFF();
}
}

View File

@ -0,0 +1,96 @@
#ifndef __USB_SCSI_H
#define __USB_SCSI_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SCSI_BLOCK_SIZE 512
/* SCSI Commands */
#define SCSI_FORMAT_UNIT 0x04
#define SCSI_INQUIRY 0x12
#define SCSI_MODE_SELECT6 0x15
#define SCSI_MODE_SELECT10 0x55
#define SCSI_MODE_SENSE6 0x1A
#define SCSI_MODE_SENSE10 0x5A
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
#define SCSI_READ6 0x08
#define SCSI_READ10 0x28
#define SCSI_READ12 0xA8
#define SCSI_READ16 0x88
#define SCSI_READ_CAPACITY10 0x25
#define SCSI_READ_CAPACITY16 0x9E
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_START_STOP_UNIT 0x1B
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_WRITE6 0x0A
#define SCSI_WRITE10 0x2A
#define SCSI_WRITE12 0xAA
#define SCSI_WRITE16 0x8A
#define SCSI_VERIFY10 0x2F
#define SCSI_VERIFY12 0xAF
#define SCSI_VERIFY16 0x8F
#define SCSI_SEND_DIAGNOSTIC 0x1D
#define SCSI_READ_FORMAT_CAPACITIES 0x23
#define SCSI_NO_SENSE 0
#define SCSI_RECOVERED_ERROR 1
#define SCSI_NOT_READY 2
#define SCSI_MEDIUM_ERROR 3
#define SCSI_HARDWARE_ERROR 4
#define SCSI_ILLEGAL_REQUEST 5
#define SCSI_UNIT_ATTENTION 6
#define SCSI_DATA_PROTECT 7
#define SCSI_BLANK_CHECK 8
#define SCSI_VENDOR_SPECIFIC 9
#define SCSI_COPY_ABORTED 10
#define SCSI_ABORTED_COMMAND 11
#define SCSI_VOLUME_OVERFLOW 13
#define SCSI_MISCOMPARE 14
#define SCSI_INVALID_COMMAND 0x20
#define SCSI_INVALID_FIELED_IN_COMMAND 0x24
#define SCSI_PARAMETER_LIST_LENGTH_ERROR 0x1A
#define SCSI_INVALID_FIELD_IN_PARAMETER_LIST 0x26
#define SCSI_ADDRESS_OUT_OF_RANGE 0x21
#define SCSI_MEDIUM_NOT_PRESENT 0x3A
#define SCSI_MEDIUM_HAVE_CHANGED 0x28
#define SCSI_READ_FORMAT_CAPACITY_DATA_LEN 0x0C
#define SCSI_READ_CAPACITY10_DATA_LEN 0x08
#define SCSI_MODE_SENSE10_DATA_LEN 0x08
#define SCSI_MODE_SENSE6_DATA_LEN 0x04
#define SCSI_REQUEST_SENSE_DATA_LEN 0x12
#define SCSI_STANDARD_INQUIRY_DATA_LEN 0x24
#define SCSI_BLKVFY 0x04
extern uint32_t SCSI_lba;
extern uint32_t SCSI_blkLen;
void scsi_inquiry_cmd(uint8_t lun);
void scsi_request_sense_cmd(uint8_t lun);
void scsi_start_stop_unit_cmd(uint8_t lun);
void scsi_mode_sense6_cmd(uint8_t lun);
void scsi_mode_sense10_cmd(uint8_t lun);
void scsi_read_format_capacity_cmd(uint8_t lun);
void scsi_read_capacity10_cmd(uint8_t lun);
void scsi_read10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr);
void scsi_write10_cmd(uint8_t lun, uint32_t lba, uint32_t blockNbr);
void scsi_test_unit_ready_cmd(uint8_t lun);
void scsi_verify10_cmd(uint8_t lun);
void scsi_format_cmd(uint8_t lun);
void scsi_set_sense_data(uint8_t lun, uint8_t sensKey, uint8_t asc);
void scsi_invalid_cmd(uint8_t lun);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,120 @@
#include "usb_scsi.h"
uint8_t SCSI_page00InquiryData[] = {
0x00, /* PERIPHERAL QUALIFIER & PERIPHERAL DEVICE TYPE*/
0x00,
0x00,
0x00,
0x00 /* Supported Pages 00*/
};
uint8_t SCSI_standardInquiryData[] = {
0x00, /* Direct Access Device */
0x80, /* RMB = 1: Removable Medium */
0x02, /* Version: No conformance claim to standard */
0x02,
36 - 4, /* Additional Length */
0x00, /* SCCS = 1: Storage Controller Component */
0x00,
0x00,
/* Vendor Identification */
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ',
/* Product Identification */
'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ',
'D', 'i', 's', 'k', ' ', ' ', ' ',
/* Product Revision Level */
'1', '.', '0', ' '
};
uint8_t SCSI_standardInquiryData2[] = {
0x00, /* Direct Access Device */
0x80, /* RMB = 1: Removable Medium */
0x02, /* Version: No conformance claim to standard */
0x02,
36 - 4, /* Additional Length */
0x00, /* SCCS = 1: Storage Controller Component */
0x00,
0x00,
/* Vendor Identification */
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ',
/* Product Identification */
'N', 'A', 'N', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ',
'D', 'i', 's', 'k', ' ',
/* Product Revision Level */
'1', '.', '0', ' '
};
uint8_t SCSI_senseData[] = {
0x70, /*RespCode*/
0x00, /*SegmentNumber*/
SCSI_NO_SENSE, /* Sens_Key*/
0x00,
0x00,
0x00,
0x00, /*Information*/
0x0A, /*AdditionalSenseLength*/
0x00,
0x00,
0x00,
0x00, /*CmdInformation*/
SCSI_NO_SENSE, /*Asc*/
0x00, /*ASCQ*/
0x00, /*FRUC*/
0x00, /*TBD*/
0x00,
0x00 /*SenseKeySpecific*/
};
uint8_t SCSI_modeSense6Data[] = {
0x03,
0x00,
0x00,
0x00,
};
uint8_t SCSI_modeSense10Data[] = {
0x00,
0x06,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
uint8_t SCSI_readFormatCapacityData[] = {
0x00,
0x00,
0x00,
0x08, /* Capacity List Length */
/* Block Count */
0,
0,
0,
0,
/* Block Length */
0x02, /* Descriptor Code: Formatted Media */
0,
0,
0
};
uint8_t SCSI_readFormatCapacity10Data[] = {
/* Last Logical Block */
0,
0,
0,
0,
/* Block Length */
0,
0,
0,
0
};

View File

@ -0,0 +1,580 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file libmaple/usb/stm32f1/usb_hid.c
* @brief USB HID (human interface device) support
*
* FIXME: this works on the STM32F1 USB peripherals, and probably no
* place else. Nonportable bits really need to be factored out, and
* the result made cleaner.
*/
#include "usb_serial.h"
#include "usb_generic.h"
#include <string.h>
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
#define CDCACM_ENDPOINT_TX 0
#define CDCACM_ENDPOINT_MANAGEMENT 1
#define CDCACM_ENDPOINT_RX 2
uint16 GetEPTxAddr(uint8 /*bEpNum*/);
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
static void serialUSBReset(void);
static RESULT serialUSBDataSetup(uint8 request);
static RESULT serialUSBNoDataSetup(uint8 request);
static void vcomDataTxCb(void);
static void vcomDataRxCb(void);
#define NUM_SERIAL_ENDPOINTS 3
#define CCI_INTERFACE_OFFSET 0x00
#define DCI_INTERFACE_OFFSET 0x01
#define SERIAL_MANAGEMENT_INTERFACE_NUMBER (CCI_INTERFACE_OFFSET+usbSerialPart.startInterface)
/*
* Descriptors
*/
typedef struct {
//CDCACM
IADescriptor IAD;
usb_descriptor_interface CCI_Interface;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement;
CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union;
usb_descriptor_endpoint ManagementEndpoint;
usb_descriptor_interface DCI_Interface;
usb_descriptor_endpoint DataOutEndpoint;
usb_descriptor_endpoint DataInEndpoint;
} __packed serial_part_config;
static const serial_part_config serialPartConfigData = {
.IAD = {
.bLength = 0x08,
.bDescriptorType = 0x0B,
.bFirstInterface = CCI_INTERFACE_OFFSET, // PATCH
.bInterfaceCount = 0x02,
.bFunctionClass = 0x02,
.bFunctionSubClass = 0x02,
.bFunctionProtocol = 0x01,
.iFunction = 0x02,
},
.CCI_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = CCI_INTERFACE_OFFSET, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x01,
.bInterfaceClass = USB_INTERFACE_CLASS_CDC,
.bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM,
.bInterfaceProtocol = 0x01, /* Common AT Commands */
.iInterface = 0x00,
},
.CDC_Functional_IntHeader = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
.bDescriptorType = 0x24,
.SubType = 0x00,
.Data = {0x01, 0x10},
},
.CDC_Functional_CallManagement = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
.bDescriptorType = 0x24,
.SubType = 0x01,
.Data = {0x03, DCI_INTERFACE_OFFSET}, // PATCH
},
.CDC_Functional_ACM = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1),
.bDescriptorType = 0x24,
.SubType = 0x02,
.Data = {0x06},
},
.CDC_Functional_Union = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
.bDescriptorType = 0x24,
.SubType = 0x06,
.Data = {CCI_INTERFACE_OFFSET, DCI_INTERFACE_OFFSET}, // PATCH, PATCH
},
.ManagementEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN |
CDCACM_ENDPOINT_MANAGEMENT), // PATCH
.bmAttributes = USB_EP_TYPE_INTERRUPT,
.wMaxPacketSize = USBHID_CDCACM_MANAGEMENT_EPSIZE,
.bInterval = 0xFF,
},
.DCI_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = DCI_INTERFACE_OFFSET, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = USB_INTERFACE_CLASS_DIC,
.bInterfaceSubClass = 0x00, /* None */
.bInterfaceProtocol = 0x00, /* None */
.iInterface = 0x00,
},
.DataOutEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT |
CDCACM_ENDPOINT_RX), // patch
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = USBHID_CDCACM_RX_EPSIZE,
.bInterval = 0x00,
},
.DataInEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | CDCACM_ENDPOINT_TX), // PATCH
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = USBHID_CDCACM_TX_EPSIZE,
.bInterval = 0x00,
}
};
#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s]
static USBEndpointInfo serialEndpoints[3] = {
{
.callback = vcomDataTxCb,
.bufferSize = USBHID_CDCACM_TX_EPSIZE,
.type = USB_EP_EP_TYPE_BULK,
.tx = 1,
},
{
.callback = NULL,
.bufferSize = USBHID_CDCACM_MANAGEMENT_EPSIZE,
.type = USB_EP_EP_TYPE_INTERRUPT,
.tx = 1,
},
{
.callback = vcomDataRxCb,
.bufferSize = USBHID_CDCACM_RX_EPSIZE,
.type = USB_EP_EP_TYPE_BULK,
.tx = 0,
},
};
static void getSerialPartDescriptor(uint8* out) {
memcpy(out, &serialPartConfigData, sizeof(serial_part_config));
// patch to reflect where the part goes in the descriptor
OUT_BYTE(serialPartConfigData, ManagementEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint;
OUT_BYTE(serialPartConfigData, DataOutEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint;
OUT_BYTE(serialPartConfigData, DataInEndpoint.bEndpointAddress) += usbSerialPart.startEndpoint;
OUT_BYTE(serialPartConfigData, IAD.bFirstInterface) += usbSerialPart.startInterface;
OUT_BYTE(serialPartConfigData, CCI_Interface.bInterfaceNumber) += usbSerialPart.startInterface;
OUT_BYTE(serialPartConfigData, DCI_Interface.bInterfaceNumber) += usbSerialPart.startInterface;
OUT_BYTE(serialPartConfigData, CDC_Functional_CallManagement.Data[1]) += usbSerialPart.startInterface;
OUT_BYTE(serialPartConfigData, CDC_Functional_Union.Data[0]) += usbSerialPart.startInterface;
OUT_BYTE(serialPartConfigData, CDC_Functional_Union.Data[1]) += usbSerialPart.startInterface;
}
USBCompositePart usbSerialPart = {
.numInterfaces = 2,
.numEndpoints = sizeof(serialEndpoints)/sizeof(*serialEndpoints),
.descriptorSize = sizeof(serial_part_config),
.getPartDescriptor = getSerialPartDescriptor,
.usbInit = NULL,
.usbReset = serialUSBReset,
.usbDataSetup = serialUSBDataSetup,
.usbNoDataSetup = serialUSBNoDataSetup,
.endpoints = serialEndpoints
};
#define CDC_SERIAL_RX_BUFFER_SIZE 256 // must be power of 2
#define CDC_SERIAL_RX_BUFFER_SIZE_MASK (CDC_SERIAL_RX_BUFFER_SIZE-1)
/* Received data */
static volatile uint8 vcomBufferRx[CDC_SERIAL_RX_BUFFER_SIZE];
/* Write index to vcomBufferRx */
static volatile uint32 vcom_rx_head;
/* Read index from vcomBufferRx */
static volatile uint32 vcom_rx_tail;
#define CDC_SERIAL_TX_BUFFER_SIZE 256 // must be power of 2
#define CDC_SERIAL_TX_BUFFER_SIZE_MASK (CDC_SERIAL_TX_BUFFER_SIZE-1)
// Tx data
static volatile uint8 vcomBufferTx[CDC_SERIAL_TX_BUFFER_SIZE];
// Write index to vcomBufferTx
static volatile uint32 vcom_tx_head;
// Read index from vcomBufferTx
static volatile uint32 vcom_tx_tail;
/* Other state (line coding, DTR/RTS) */
static volatile composite_cdcacm_line_coding line_coding = {
/* This default is 115200 baud, 8N1. */
.dwDTERate = 115200,
.bCharFormat = USBHID_CDCACM_STOP_BITS_1,
.bParityType = USBHID_CDCACM_PARITY_NONE,
.bDataBits = 8,
};
/* DTR in bit 0, RTS in bit 1. */
static volatile uint8 line_dtr_rts = 0;
static void (*rx_hook)(unsigned, void*) = 0;
static void (*iface_setup_hook)(unsigned, void*) = 0;
void composite_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)) {
if (hook_flags & USBHID_CDCACM_HOOK_RX) {
rx_hook = hook;
}
if (hook_flags & USBHID_CDCACM_HOOK_IFACE_SETUP) {
iface_setup_hook = hook;
}
}
void composite_cdcacm_putc(char ch) {
while (!composite_cdcacm_tx((uint8*)&ch, 1))
;
}
/* This function is non-blocking.
*
* It copies data from a user buffer into the USB peripheral TX
* buffer, and returns the number of bytes copied. */
uint32 composite_cdcacm_tx(const uint8* buf, uint32 len)
{
if (len==0) return 0; // no data to send
uint32 head = vcom_tx_head; // load volatile variable
uint32 tx_unsent = (head - vcom_tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
// We can only put bytes in the buffer if there is place
if (len > (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1) ) {
len = (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1);
}
if (len==0) return 0; // buffer full
uint16 i;
// copy data from user buffer to USB Tx buffer
for (i=0; i<len; i++) {
vcomBufferTx[head] = buf[i];
head = (head+1) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
}
vcom_tx_head = head; // store volatile variable
while(usbGenericTransmitting >= 0);
if (usbGenericTransmitting<0) {
vcomDataTxCb(); // initiate data transmission
}
return len;
}
uint32 composite_cdcacm_data_available(void) {
return (vcom_rx_head - vcom_rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
}
uint16 composite_cdcacm_get_pending(void) {
return (vcom_tx_head - vcom_tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
}
/* Non-blocking byte receive.
*
* Copies up to len bytes from our private data buffer (*NOT* the PMA)
* into buf and deq's the FIFO. */
uint32 composite_cdcacm_rx(uint8* buf, uint32 len)
{
/* Copy bytes to buffer. */
uint32 n_copied = composite_cdcacm_peek(buf, len);
/* Mark bytes as read. */
uint16 tail = vcom_rx_tail; // load volatile variable
tail = (tail + n_copied) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
vcom_rx_tail = tail; // store volatile variable
uint32 rx_unread = (vcom_rx_head - tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
// If buffer was emptied to a pre-set value, re-enable the RX endpoint
if ( rx_unread <= 64 ) { // experimental value, gives the best performance
usb_set_ep_rx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address, USB_EP_STAT_RX_VALID);
}
return n_copied;
}
/* Non-blocking byte lookahead.
*
* Looks at unread bytes without marking them as read. */
uint32 composite_cdcacm_peek(uint8* buf, uint32 len)
{
unsigned i;
uint32 tail = vcom_rx_tail;
uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
if (len > rx_unread) {
len = rx_unread;
}
for (i = 0; i < len; i++) {
buf[i] = vcomBufferRx[tail];
tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
}
return len;
}
uint32 composite_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len)
{
unsigned i;
uint32 tail = (vcom_rx_tail + offset) & CDC_SERIAL_RX_BUFFER_SIZE_MASK ;
uint32 rx_unread = (vcom_rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
if (len + offset > rx_unread) {
len = rx_unread - offset;
}
for (i = 0; i < len; i++) {
buf[i] = vcomBufferRx[tail];
tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
}
return len;
}
/* Roger Clark. Added. for Arduino 1.0 API support of Serial.peek() */
int composite_cdcacm_peek_char()
{
if (composite_cdcacm_data_available() == 0)
{
return -1;
}
return vcomBufferRx[vcom_rx_tail];
}
uint8 composite_cdcacm_get_dtr() {
return ((line_dtr_rts & USBHID_CDCACM_CONTROL_LINE_DTR) != 0);
}
uint8 composite_cdcacm_get_rts() {
return ((line_dtr_rts & USBHID_CDCACM_CONTROL_LINE_RTS) != 0);
}
void composite_cdcacm_get_line_coding(composite_cdcacm_line_coding *ret) {
ret->dwDTERate = line_coding.dwDTERate;
ret->bCharFormat = line_coding.bCharFormat;
ret->bParityType = line_coding.bParityType;
ret->bDataBits = line_coding.bDataBits;
}
int composite_cdcacm_get_baud(void) {
return line_coding.dwDTERate;
}
int composite_cdcacm_get_stop_bits(void) {
return line_coding.bCharFormat;
}
int composite_cdcacm_get_parity(void) {
return line_coding.bParityType;
}
int composite_cdcacm_get_n_data_bits(void) {
return line_coding.bDataBits;
}
/*
* Callbacks
*/
static void vcomDataTxCb(void)
{
uint32 tail = vcom_tx_tail; // load volatile variable
uint32 tx_unsent = (vcom_tx_head - tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
if (tx_unsent==0) {
if ( (--usbGenericTransmitting)==0) goto flush_vcom; // no more data to send
return; // it was already flushed, keep Tx endpoint disabled
}
usbGenericTransmitting = 1;
// We can only send up to USBHID_CDCACM_TX_EPSIZE bytes in the endpoint.
if (tx_unsent > USBHID_CDCACM_TX_EPSIZE) {
tx_unsent = USBHID_CDCACM_TX_EPSIZE;
}
// copy the bytes from USB Tx buffer to PMA buffer
uint32 *dst = usb_pma_ptr(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].pmaAddress);
uint16 tmp = 0;
uint16 val;
unsigned i;
for (i = 0; i < tx_unsent; i++) {
val = vcomBufferTx[tail];
tail = (tail + 1) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
if (i&1) {
*dst++ = tmp | (val<<8);
} else {
tmp = val;
}
}
if ( tx_unsent&1 ) {
*dst = tmp;
}
vcom_tx_tail = tail; // store volatile variable
flush_vcom:
// enable Tx endpoint
usb_set_ep_tx_count(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].address, tx_unsent);
usb_set_ep_tx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_TX].address, USB_EP_STAT_TX_VALID);
}
static void vcomDataRxCb(void)
{
uint32 head = vcom_rx_head; // load volatile variable
uint32 ep_rx_size = usb_get_ep_rx_count(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address);
// This copy won't overwrite unread bytes as long as there is
// enough room in the USB Rx buffer for next packet
uint32 *src = usb_pma_ptr(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].pmaAddress);
uint16 tmp = 0;
uint8 val;
uint32 i;
for (i = 0; i < ep_rx_size; i++) {
if (i&1) {
val = tmp>>8;
} else {
tmp = *src++;
val = tmp&0xFF;
}
vcomBufferRx[head] = val;
head = (head + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
}
vcom_rx_head = head; // store volatile variable
uint32 rx_unread = (head - vcom_rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
// only enable further Rx if there is enough room to receive one more packet
if ( rx_unread < (CDC_SERIAL_RX_BUFFER_SIZE-USBHID_CDCACM_RX_EPSIZE) ) {
usb_set_ep_rx_stat(usbSerialPart.endpoints[CDCACM_ENDPOINT_RX].address, USB_EP_STAT_RX_VALID);
}
if (rx_hook) {
rx_hook(USBHID_CDCACM_HOOK_RX, 0);
}
}
static uint8* vcomGetSetLineCoding(uint16 length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(struct composite_cdcacm_line_coding);
}
return (uint8*)&line_coding;
}
static void serialUSBReset(void) {
//VCOM
vcom_rx_head = 0;
vcom_rx_tail = 0;
vcom_tx_head = 0;
vcom_tx_tail = 0;
}
static RESULT serialUSBDataSetup(uint8 request) {
uint8* (*CopyRoutine)(uint16) = 0;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) &&
pInformation->USBwIndex0 == SERIAL_MANAGEMENT_INTERFACE_NUMBER) {
switch (request) {
case USBHID_CDCACM_GET_LINE_CODING:
CopyRoutine = vcomGetSetLineCoding;
break;
case USBHID_CDCACM_SET_LINE_CODING:
CopyRoutine = vcomGetSetLineCoding;
break;
default:
break;
}
/* Call the user hook. */
if (iface_setup_hook) {
uint8 req_copy = request;
iface_setup_hook(USBHID_CDCACM_HOOK_IFACE_SETUP, &req_copy);
}
}
if (CopyRoutine == NULL){
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
static RESULT serialUSBNoDataSetup(uint8 request) {
RESULT ret = USB_UNSUPPORT;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) &&
pInformation->USBwIndex0 == SERIAL_MANAGEMENT_INTERFACE_NUMBER) {
switch(request) {
case USBHID_CDCACM_SET_COMM_FEATURE:
/* We support set comm. feature, but don't handle it. */
ret = USB_SUCCESS;
break;
case USBHID_CDCACM_SET_CONTROL_LINE_STATE:
/* Track changes to DTR and RTS. */
line_dtr_rts = (pInformation->USBwValues.bw.bb0 &
(USBHID_CDCACM_CONTROL_LINE_DTR |
USBHID_CDCACM_CONTROL_LINE_RTS));
ret = USB_SUCCESS;
break;
}
/* Call the user hook. */
if (iface_setup_hook) {
uint8 req_copy = request;
iface_setup_hook(USBHID_CDCACM_HOOK_IFACE_SETUP, &req_copy);
}
}
return ret;
}

View File

@ -0,0 +1,157 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file libmaple/include/libmaple/usb_device.h
* @brief USB Composite with CDC ACM and HID support
*
* IMPORTANT: this API is unstable, and may change without notice.
*/
#ifndef _USB_SERIAL_H_
#define _USB_SERIAL_H_
#include <libmaple/libmaple_types.h>
#include <libmaple/usb.h>
#include "usb_generic.h"
#ifdef __cplusplus
extern "C" {
#endif
extern USBCompositePart usbSerialPart;
/*
* CDC ACM Requests
*/
#define USBHID_CDCACM_SET_LINE_CODING 0x20
#define USBHID_CDCACM_GET_LINE_CODING 0x21
#define USBHID_CDCACM_SET_COMM_FEATURE 0x02
#define USBHID_CDCACM_SET_CONTROL_LINE_STATE 0x22
#define USBHID_CDCACM_CONTROL_LINE_DTR (0x01)
#define USBHID_CDCACM_CONTROL_LINE_RTS (0x02)
#define USBHID_CDCACM_MANAGEMENT_EPSIZE 0x10
#define USBHID_CDCACM_RX_EPSIZE 0x40
#define USBHID_CDCACM_TX_EPSIZE 0x40
/*
* Descriptors, etc.
*/
#define USBHID_CDCACM_CTRL_ENDP 0
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bFirstInterface;
uint8_t bInterfaceCount;
uint8_t bFunctionClass;
uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol;
uint8_t iFunction;
} IADescriptor;
#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize)
#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
struct { \
uint8 bLength; \
uint8 bDescriptorType; \
uint8 SubType; \
uint8 Data[DataSize]; \
} __packed
#define USB_DEVICE_CLASS_CDC 0x02
#define USB_DEVICE_SUBCLASS_CDC 0x00
#define USB_INTERFACE_CLASS_CDC 0x02
#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02
#define USB_INTERFACE_CLASS_DIC 0x0A
/*
* CDC ACM interface
*/
void composite_cdcacm_putc(char ch);
uint32 composite_cdcacm_tx(const uint8* buf, uint32 len);
uint32 composite_cdcacm_rx(uint8* buf, uint32 len);
uint32 composite_cdcacm_peek(uint8* buf, uint32 len);
uint32 composite_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len);
uint32 composite_cdcacm_data_available(void); /* in RX buffer */
uint16 composite_cdcacm_get_pending(void);
uint8 usb_is_transmitting(void);
uint8 composite_cdcacm_get_dtr(void);
uint8 composite_cdcacm_get_rts(void);
typedef struct composite_cdcacm_line_coding {
uint32 dwDTERate; /* Baud rate */
#define USBHID_CDCACM_STOP_BITS_1 0
#define USBHID_CDCACM_STOP_BITS_1_5 1
#define USBHID_CDCACM_STOP_BITS_2 2
uint8 bCharFormat; /* Stop bits */
#define USBHID_CDCACM_PARITY_NONE 0
#define USBHID_CDCACM_PARITY_ODD 1
#define USBHID_CDCACM_PARITY_EVEN 2
#define USBHID_CDCACM_PARITY_MARK 3
#define USBHID_CDCACM_PARITY_SPACE 4
uint8 bParityType; /* Parity type */
uint8 bDataBits; /* Data bits: 5, 6, 7, 8, or 16 */
} __packed composite_cdcacm_line_coding;
/* Retrieve a copy of the current line coding structure. */
void composite_cdcacm_get_line_coding(composite_cdcacm_line_coding*);
/* Line coding conveniences. */
int composite_cdcacm_get_baud(void); /* dwDTERate */
int composite_cdcacm_get_stop_bits(void); /* bCharFormat */
int composite_cdcacm_get_parity(void); /* bParityType */
int composite_cdcacm_get_n_data_bits(void); /* bDataBits */
/*
* Hack: hooks for bootloader reset signalling
*/
#define USBHID_CDCACM_HOOK_RX 0x1
#define USBHID_CDCACM_HOOK_IFACE_SETUP 0x2
void composite_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*));
static inline __always_inline void composite_cdcacm_remove_hooks(unsigned hook_flags) {
composite_cdcacm_set_hooks(hook_flags, 0);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,61 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 LeafLabs, LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* @file wirish/stm32f1/boards_setup.cpp
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief STM32F1 chip setup.
*
* This file controls how init() behaves on the STM32F1. Be very
* careful when changing anything here. Many of these values depend
* upon each other.
*/
#include "boards_private.h"
#include "USBHID.h"
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
#include <boards.h>
#include <usb_serial.h>
namespace wirish {
namespace priv {
void board_setup_usb(void) {
//Serial = CompositeSerial;
#ifdef GENERIC_BOOTLOADER
//Reset the USB interface on generic boards - developed by Victor PV
gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_OUTPUT_PP);
gpio_write_bit(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit,0);
for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed, and USB pins will get configured in Serial.begin
gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING);
#endif
}
}
}

View File

@ -0,0 +1,486 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
/**
* FIXME: this works on the STM32F1 USB peripherals, and probably no
* place else. Nonportable bits really need to be factored out, and
* the result made cleaner.
*/
#include "usb_generic.h"
#include "usb_x360.h"
#include <string.h>
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
typedef enum _HID_REQUESTS
{
GET_REPORT = 1,
GET_IDLE,
GET_PROTOCOL,
SET_REPORT = 9,
SET_IDLE,
SET_PROTOCOL
} HID_REQUESTS;
#define USB_ENDPOINT_IN(addr) ((addr) | 0x80)
#define HID_ENDPOINT_INT 1
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
#define HID_DESCRIPTOR_TYPE 0x21
#define REPORT_DESCRIPTOR 0x22
typedef struct
{
uint8_t len; // 9
uint8_t dtype; // 0x21
uint8_t versionL; // 0x101
uint8_t versionH; // 0x101
uint8_t country;
uint8_t numDesc;
uint8_t desctype; // 0x22 report
uint8_t descLenL;
uint8_t descLenH;
} HIDDescriptor;
#define X360_INTERFACE_OFFSET 0
#define X360_INTERFACE_NUMBER (X360_INTERFACE_OFFSET+usbX360Part.startInterface)
#define X360_ENDPOINT_TX 0
#define X360_ENDPOINT_RX 1
#define USB_X360_RX_ADDR x360Endpoints[X360_ENDPOINT_RX].pmaAddress
#define USB_X360_TX_ADDR x360Endpoints[X360_ENDPOINT_TX].pmaAddress
#define USB_X360_RX_ENDP x360Endpoints[X360_ENDPOINT_RX].address
#define USB_X360_TX_ENDP x360Endpoints[X360_ENDPOINT_TX].address
u16 GetEPTxAddr(u8 bEpNum);
static uint32 ProtocolValue;
static void x360DataTxCb(void);
static void x360DataRxCb(void);
static void (*x360_rumble_callback)(uint8 left, uint8 right);
static void (*x360_led_callback)(uint8 pattern);
static void x360Reset(void);
static RESULT x360DataSetup(uint8 request);
static RESULT x360NoDataSetup(uint8 request);
static uint8 *HID_GetProtocolValue(uint16 Length);
/*
* Descriptors
*/
#if 0
const uint8_t hid_report_descriptor[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x3a, // USAGE (Counted Buffer)
0xa1, 0x02, // COLLECTION (Logical)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x3f, // USAGE (Reserved)
0x09, 0x3b, // USAGE (Byte Count)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x45, 0x01, // PHYSICAL_MAXIMUM (1)
0x95, 0x04, // REPORT_COUNT (4)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x0c, // USAGE_MINIMUM (Button 12)
0x29, 0x0f, // USAGE_MAXIMUM (Button 15)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x45, 0x01, // PHYSICAL_MAXIMUM (1)
0x95, 0x04, // REPORT_COUNT (4)
0x05, 0x09, // USAGE_PAGE (Button)
0x09, 0x09, // USAGE (Button 9)
0x09, 0x0a, // USAGE (Button 10)
0x09, 0x07, // USAGE (Button 7)
0x09, 0x08, // USAGE (Button 8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x45, 0x01, // PHYSICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x05, 0x09, // USAGE_PAGE (Button)
0x09, 0x05, // USAGE (Button 5)
0x09, 0x06, // USAGE (Button 6)
0x09, 0x0b, // USAGE (Button 11)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x45, 0x01, // PHYSICAL_MAXIMUM (1)
0x95, 0x04, // REPORT_COUNT (4)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x04, // USAGE_MAXIMUM (Button 4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255)
0x95, 0x02, // REPORT_COUNT (2)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x32, // USAGE (Z)
0x09, 0x35, // USAGE (Rz)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x10, // REPORT_SIZE (16)
0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768)
0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
0x36, 0x00, 0x80, // PHYSICAL_MINIMUM (-32768)
0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x95, 0x02, // REPORT_COUNT (2)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x95, 0x02, // REPORT_COUNT (2)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
#endif
typedef struct {
// usb_descriptor_config_header Config_Header;
usb_descriptor_interface HID_Interface;
uint8 unknown_descriptor1[17];
usb_descriptor_endpoint DataInEndpoint;
usb_descriptor_endpoint DataOutEndpoint;
} __packed usb_descriptor_config;
#define MAX_POWER (100 >> 1)
static const usb_descriptor_config X360Descriptor_Config =
{
#if 0
.Config_Header = {
.bLength = sizeof(usb_descriptor_config_header),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
.wTotalLength = sizeof(usb_descriptor_config),//0,
.bNumInterfaces = 0x01,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED |
USB_CONFIG_ATTR_SELF_POWERED),
.bMaxPower = MAX_POWER,
},
#endif
.HID_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = X360_INTERFACE_OFFSET, // PATCH
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = 0xFF,
.bInterfaceSubClass = 0x5D,
.bInterfaceProtocol = 0x01,
.iInterface = 0x00,
},
.unknown_descriptor1 = {
17,33,0,1,1,37,129,20,0,0,0,0,19,2,8,0,0,
},
.DataInEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | X360_ENDPOINT_TX),//PATCH
.bmAttributes = USB_EP_TYPE_INTERRUPT,
.wMaxPacketSize = 0x20,
.bInterval = 4,
},
.DataOutEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | X360_ENDPOINT_RX),//PATCH
.bmAttributes = USB_EP_TYPE_INTERRUPT,
.wMaxPacketSize = 0x20,
.bInterval = 8,
},
};
static USBEndpointInfo x360Endpoints[2] = {
{
.callback = x360DataTxCb,
.bufferSize = 0x20,
.type = USB_EP_EP_TYPE_INTERRUPT,
.tx = 1
},
{
.callback = x360DataRxCb,
.bufferSize = 0x20,
.type = USB_EP_EP_TYPE_INTERRUPT,
.tx = 0,
}
};
#define OUT_BYTE(s,v) out[(uint8*)&(s.v)-(uint8*)&s]
static void getX360PartDescriptor(uint8* out) {
memcpy(out, &X360Descriptor_Config, sizeof(X360Descriptor_Config));
// patch to reflect where the part goes in the descriptor
OUT_BYTE(X360Descriptor_Config, HID_Interface.bInterfaceNumber) += usbX360Part.startInterface;
OUT_BYTE(X360Descriptor_Config, DataOutEndpoint.bEndpointAddress) += usbX360Part.startEndpoint;
OUT_BYTE(X360Descriptor_Config, DataInEndpoint.bEndpointAddress) += usbX360Part.startEndpoint;
}
USBCompositePart usbX360Part = {
.numInterfaces = 1,
.numEndpoints = sizeof(x360Endpoints)/sizeof(*x360Endpoints),
.descriptorSize = sizeof(X360Descriptor_Config),
.getPartDescriptor = getX360PartDescriptor,
.usbInit = NULL,
.usbReset = x360Reset,
.usbDataSetup = x360DataSetup,
.usbNoDataSetup = x360NoDataSetup,
.endpoints = x360Endpoints
};
/*
* Etc.
*/
/* I/O state */
/* Received data */
static volatile uint8 hidBufferRx[USB_X360_RX_EPSIZE];
/* Number of bytes left to transmit */
static volatile uint32 n_unsent_bytes = 0;
/* Are we currently sending an IN packet? */
static volatile uint8 transmitting = 0;
/*
* HID interface
*/
void x360_set_rumble_callback(void (*callback)(uint8 left, uint8 right)) {
x360_rumble_callback = callback;
}
void x360_set_led_callback(void (*callback)(uint8 pattern)) {
x360_led_callback = callback;
}
/*void x360_disable(void) {
x360_set_rumble_callback(NULL);
x360_set_led_callback(NULL);
usb_generic_disable();
}*/
void x360_putc(char ch) {
while (!x360_tx((uint8*)&ch, 1))
;
}
/* This function is non-blocking.
*
* It copies data from a usercode buffer into the USB peripheral TX
* buffer, and returns the number of bytes copied. */
uint32 x360_tx(const uint8* buf, uint32 len) {
/* Last transmission hasn't finished, so abort. */
if (x360_is_transmitting()) {
return 0;
}
/* We can only put USB_X360_TX_EPSIZE bytes in the buffer. */
if (len > USB_X360_TX_EPSIZE) {
len = USB_X360_TX_EPSIZE;
}
/* Queue bytes for sending. */
if (len) {
usb_copy_to_pma(buf, len, GetEPTxAddr(USB_X360_TX_ENDP));//USB_X360_TX_ADDR);
}
// We still need to wait for the interrupt, even if we're sending
// zero bytes. (Sending zero-size packets is useful for flushing
// host-side buffers.)
usb_set_ep_tx_count(USB_X360_TX_ENDP, len);
n_unsent_bytes = len;
transmitting = 1;
usb_set_ep_tx_stat(USB_X360_TX_ENDP, USB_EP_STAT_TX_VALID);
return len;
}
uint8 x360_is_transmitting(void) {
return transmitting;
}
uint16 x360_get_pending(void) {
return n_unsent_bytes;
}
static void x360DataRxCb(void)
{
uint32 ep_rx_size = usb_get_ep_rx_count(USB_X360_RX_ENDP);
// This copy won't overwrite unread bytes as long as there is
// enough room in the USB Rx buffer for next packet
uint32 *src = usb_pma_ptr(USB_X360_RX_ADDR);
uint16 tmp = 0;
uint8 val;
uint32 i;
for (i = 0; i < ep_rx_size; i++) {
if (i&1) {
val = tmp>>8;
} else {
tmp = *src++;
val = tmp&0xFF;
}
hidBufferRx[i] = val;
}
if (ep_rx_size == 3) {
if (x360_led_callback != NULL && hidBufferRx[0] == 1 && hidBufferRx[1] == 3)
x360_led_callback(hidBufferRx[2]);
}
else if (ep_rx_size == 8) {
if (x360_rumble_callback != NULL && hidBufferRx[0] == 0 && hidBufferRx[1] == 8)
x360_rumble_callback(hidBufferRx[3],hidBufferRx[4]);
}
usb_set_ep_rx_stat(USB_X360_RX_ENDP, USB_EP_STAT_RX_VALID);
}
/*
* Callbacks
*/
static void x360DataTxCb(void) {
n_unsent_bytes = 0;
transmitting = 0;
}
static RESULT x360DataSetup(uint8 request) {
uint8* (*CopyRoutine)(uint16) = 0;
#if 0
if (request == GET_DESCRIPTOR
&& pInformation->USBwIndex0 == X360_INTERFACE_NUMBER &&
&& (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
&& (pInformation->USBwIndex0 == 0)){
if (pInformation->USBwValue1 == REPORT_DESCRIPTOR){
CopyRoutine = HID_GetReportDescriptor;
} else
if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){
CopyRoutine = HID_GetHIDDescriptor;
}
} /* End of GET_DESCRIPTOR */
/*** GET_PROTOCOL ***/
else
#endif
if(pInformation->USBwIndex0 == X360_INTERFACE_NUMBER &&
(Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& request == GET_PROTOCOL){
CopyRoutine = HID_GetProtocolValue;
}
if (CopyRoutine == NULL){
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
static RESULT x360NoDataSetup(uint8 request) {
if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& (request == SET_PROTOCOL)){
uint8 wValue0 = pInformation->USBwValue0;
ProtocolValue = wValue0;
return USB_SUCCESS;
}else{
return USB_UNSUPPORT;
}
}
static uint8* HID_GetProtocolValue(uint16 Length){
if (Length == 0){
pInformation->Ctrl_Info.Usb_wLength = 1;
return NULL;
} else {
return (uint8 *)(&ProtocolValue);
}
}
static void x360Reset(void) {
/* Reset the RX/TX state */
n_unsent_bytes = 0;
transmitting = 0;
}

View File

@ -0,0 +1,75 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs LLC.
*
* 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 THE AUTHORS OR COPYRIGHT HOLDERS
* 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.
*****************************************************************************/
#ifndef _USB_X360_H
#define _USB_X360_H
#include <libmaple/libmaple_types.h>
#include <libmaple/gpio.h>
#include <libmaple/usb.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Descriptors, etc.
*/
//extern const uint8_t hid_report_descriptor[];
/*
* Endpoint configuration
*/
#define USB_X360_TX_EPSIZE 0x20
#define USB_X360_RX_EPSIZE 0x20
/*
* HID interface
*/
extern USBCompositePart usbX360Part;
void x360_enable();
void x360_disable();
void x360_putc(char ch);
uint32 x360_tx(const uint8* buf, uint32 len);
uint32 x360_rx(uint8* buf, uint32 len);
uint32 x360_hid_peek(uint8* buf, uint32 len);
uint32 x360_data_available(void); /* in RX buffer */
uint16 x360_get_pending(void);
uint8 x360_is_transmitting(void);
void x360_set_rx_callback(void (*callback)(const uint8* buffer, uint32 size));
void x360_set_rumble_callback(void (*callback)(uint8 left, uint8 right));
void x360_set_led_callback(void (*callback)(uint8 pattern));
#ifdef __cplusplus
}
#endif
#endif