all sources to LF

This commit is contained in:
Andrew J. Kroll 2015-02-22 13:18:45 -05:00
parent 56c0265fa8
commit d25f28109d
37 changed files with 14144 additions and 14144 deletions

1624
Usb.cpp

File diff suppressed because it is too large Load diff

82
Usb.h
View file

@ -1,41 +1,41 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* USB functions */
#ifndef _usb_h_
#define _usb_h_
// WARNING: Do not change the order of includes, or stuff will break!
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
// None of these should ever be included by a driver, or a user's sketch.
#include "settings.h"
#include "printhex.h"
#include "message.h"
#include "hexdump.h"
#include "sink_parser.h"
#include "max3421e.h"
#include "address.h"
#include "avrpins.h"
#include "usb_ch9.h"
#include "usbhost.h"
#include "UsbCore.h"
#include "parsetools.h"
#include "confdescparser.h"
#endif //_usb_h_
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* USB functions */
#ifndef _usb_h_
#define _usb_h_
// WARNING: Do not change the order of includes, or stuff will break!
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
// None of these should ever be included by a driver, or a user's sketch.
#include "settings.h"
#include "printhex.h"
#include "message.h"
#include "hexdump.h"
#include "sink_parser.h"
#include "max3421e.h"
#include "address.h"
#include "avrpins.h"
#include "usb_ch9.h"
#include "usbhost.h"
#include "UsbCore.h"
#include "parsetools.h"
#include "confdescparser.h"
#endif //_usb_h_

564
address.h
View file

@ -1,282 +1,282 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__ADDRESS_H__)
#error "Never include address.h directly; include Usb.h instead"
#else
#define __ADDRESS_H__
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
struct EpInfo {
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union {
uint8_t epAttribs;
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
} __attribute__((packed));
// 7 6 5 4 3 2 1 0
// ---------------------------------
// | | H | P | P | P | A | A | A |
// ---------------------------------
//
// H - if 1 the address is a hub address
// P - parent hub address
// A - device address / port number in case of hub
//
struct UsbDeviceAddress {
union {
struct {
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zero
} __attribute__((packed));
uint8_t devAddress;
};
} __attribute__((packed));
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice {
EpInfo *epinfo; // endpoint info pointer
UsbDeviceAddress address;
uint8_t epcount; // number of endpoints
bool lowspeed; // indicates if a device is the low speed one
// uint8_t devclass; // device class
} __attribute__((packed));
class AddressPool {
public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0;
};
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_INDEX 0xFF
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED>
class AddressPoolImpl : public AddressPool {
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
uint8_t hubCounter; // hub counter is kept
// in order to avoid hub address duplication
UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initializes address pool entry
void InitEntry(uint8_t index) {
thePool[index].address.devAddress = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0) {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
if(thePool[i].address.devAddress == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
if(thePool[i].address.bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index) {
// Zero field is reserved and should not be affected
if(index == 0)
return;
UsbDeviceAddress uda = thePool[index].address;
// If a hub was switched off all port addresses should be freed
if(uda.bmHub == 1) {
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if(hubCounter == uda.bmAddress)
hubCounter--;
}
InitEntry(index);
}
// Initializes the whole address pool at once
void InitAllAddresses() {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
};
public:
AddressPoolImpl() : hubCounter(0) {
// Zero address is reserved
InitEntry(0);
thePool[0].address.devAddress = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
dev0ep.maxPktSize = 8;
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
InitAllAddresses();
};
// Returns a pointer to a specified address entry
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
if(!addr)
return thePool;
uint8_t index = FindAddressIndex(addr);
return (!index) ? NULL : thePool + index;
};
// Performs an operation specified by pfunc for each addressed device
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
if(!pfunc)
return;
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if(thePool[i].address.devAddress)
pfunc(thePool + i);
};
// Allocates new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
/* if (parent != 0 && port == 0)
USB_HOST_SERIAL.println("PRT:0"); */
UsbDeviceAddress _parent;
_parent.devAddress = parent;
if(_parent.bmReserved || port > 7)
//if(parent > 127 || port > 7)
return 0;
if(is_hub && hubCounter == 7)
return 0;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
if(!index) // if empty entry is not found
return 0;
if(_parent.devAddress == 0) {
if(is_hub) {
thePool[index].address.devAddress = 0x41;
hubCounter++;
} else
thePool[index].address.devAddress = 1;
return thePool[index].address.devAddress;
}
UsbDeviceAddress addr;
addr.devAddress = 0; // Ensure all bits are zero
addr.bmParent = _parent.bmAddress;
if(is_hub) {
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
} else {
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = addr;
/*
USB_HOST_SERIAL.print("Addr:");
USB_HOST_SERIAL.print(addr.bmHub, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.print(addr.bmParent, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
*/
return thePool[index].address.devAddress;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr) {
// if the root hub is disconnected all the addresses should be initialized
if(addr == 0x41) {
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
// Returns number of hubs attached
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
//uint8_t GetNumHubs()
//{
// return hubCounter;
//};
//uint8_t GetNumDevices()
//{
// uint8_t counter = 0;
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
// if (thePool[i].address != 0);
// counter ++;
// return counter;
//};
};
#endif // __ADDRESS_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__ADDRESS_H__)
#error "Never include address.h directly; include Usb.h instead"
#else
#define __ADDRESS_H__
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
struct EpInfo {
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union {
uint8_t epAttribs;
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
} __attribute__((packed));
// 7 6 5 4 3 2 1 0
// ---------------------------------
// | | H | P | P | P | A | A | A |
// ---------------------------------
//
// H - if 1 the address is a hub address
// P - parent hub address
// A - device address / port number in case of hub
//
struct UsbDeviceAddress {
union {
struct {
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zero
} __attribute__((packed));
uint8_t devAddress;
};
} __attribute__((packed));
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice {
EpInfo *epinfo; // endpoint info pointer
UsbDeviceAddress address;
uint8_t epcount; // number of endpoints
bool lowspeed; // indicates if a device is the low speed one
// uint8_t devclass; // device class
} __attribute__((packed));
class AddressPool {
public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0;
};
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_INDEX 0xFF
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED>
class AddressPoolImpl : public AddressPool {
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
uint8_t hubCounter; // hub counter is kept
// in order to avoid hub address duplication
UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initializes address pool entry
void InitEntry(uint8_t index) {
thePool[index].address.devAddress = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0) {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
if(thePool[i].address.devAddress == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
if(thePool[i].address.bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index) {
// Zero field is reserved and should not be affected
if(index == 0)
return;
UsbDeviceAddress uda = thePool[index].address;
// If a hub was switched off all port addresses should be freed
if(uda.bmHub == 1) {
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if(hubCounter == uda.bmAddress)
hubCounter--;
}
InitEntry(index);
}
// Initializes the whole address pool at once
void InitAllAddresses() {
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
};
public:
AddressPoolImpl() : hubCounter(0) {
// Zero address is reserved
InitEntry(0);
thePool[0].address.devAddress = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
dev0ep.maxPktSize = 8;
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
InitAllAddresses();
};
// Returns a pointer to a specified address entry
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
if(!addr)
return thePool;
uint8_t index = FindAddressIndex(addr);
return (!index) ? NULL : thePool + index;
};
// Performs an operation specified by pfunc for each addressed device
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
if(!pfunc)
return;
for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if(thePool[i].address.devAddress)
pfunc(thePool + i);
};
// Allocates new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
/* if (parent != 0 && port == 0)
USB_HOST_SERIAL.println("PRT:0"); */
UsbDeviceAddress _parent;
_parent.devAddress = parent;
if(_parent.bmReserved || port > 7)
//if(parent > 127 || port > 7)
return 0;
if(is_hub && hubCounter == 7)
return 0;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
if(!index) // if empty entry is not found
return 0;
if(_parent.devAddress == 0) {
if(is_hub) {
thePool[index].address.devAddress = 0x41;
hubCounter++;
} else
thePool[index].address.devAddress = 1;
return thePool[index].address.devAddress;
}
UsbDeviceAddress addr;
addr.devAddress = 0; // Ensure all bits are zero
addr.bmParent = _parent.bmAddress;
if(is_hub) {
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
} else {
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = addr;
/*
USB_HOST_SERIAL.print("Addr:");
USB_HOST_SERIAL.print(addr.bmHub, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.print(addr.bmParent, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
*/
return thePool[index].address.devAddress;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr) {
// if the root hub is disconnected all the addresses should be initialized
if(addr == 0x41) {
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
// Returns number of hubs attached
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
//uint8_t GetNumHubs()
//{
// return hubCounter;
//};
//uint8_t GetNumDevices()
//{
// uint8_t counter = 0;
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
// if (thePool[i].address != 0);
// counter ++;
// return counter;
//};
};
#endif // __ADDRESS_H__

742
adk.cpp
View file

@ -1,371 +1,371 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* Google ADK interface */
#include "adk.h"
const uint8_t ADK::epDataInIndex = 1;
const uint8_t ADK::epDataOutIndex = 2;
ADK::ADK(USB *p, const char* manufacturer,
const char* model,
const char* description,
const char* version,
const char* uri,
const char* serial) :
/* ADK ID Strings */
manufacturer(manufacturer),
model(model),
description(description),
version(version),
uri(uri),
serial(serial),
pUsb(p), //pointer to USB class instance - mandatory
bAddress(0), //device address - mandatory
bConfNum(0), //configuration number
bNumEP(1), //if config descriptor needs to be parsed
ready(false) {
// initialize endpoint data structures
for(uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
// register in USB subsystem
if(pUsb) {
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
}
}
uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
return Init(parent, port, lowspeed); // Just call Init. Yes, really!
}
/* Connection initialization of an Android phone */
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
uint8_t num_of_conf; // number of configurations
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("\r\nADK Init");
// check if address has already been assigned to an instance
if(bAddress) {
USBTRACE("\r\nAddress in use");
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p) {
USBTRACE("\r\nAddress not found");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if(!p->epinfo) {
USBTRACE("epinfo is null\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode) {
goto FailGetDevDescr;
}
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
// Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
//USBTRACE2("setAddr:",rcode);
return rcode;
}//if (rcode...
//USBTRACE2("\r\nAddr:", bAddress);
// Spec says you should wait at least 200ms.
//delay(300);
p->lowspeed = false;
//get pointer to assigned address record
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p) {
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
p->lowspeed = lowspeed;
// Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode) {
goto FailSetDevTblEntry;
}
//check if ADK device is already in accessory mode; if yes, configure and exit
if(udd->idVendor == ADK_VID &&
(udd->idProduct == ADK_PID || udd->idProduct == ADB_PID)) {
USBTRACE("\r\nAcc.mode device detected");
/* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
num_of_conf = udd->bNumConfigurations;
//USBTRACE2("\r\nNC:",num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
delay(1);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
#if defined(XOOM)
//added by Jaylen Scott Vanorden
if(rcode) {
USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
// Try once more
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
}
#endif
if(rcode) {
goto FailGetConfDescr;
}
if(bNumEP > 2) {
break;
}
} // for (uint8_t i=0; i<num_of_conf; i++...
if(bNumEP == 3) {
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if(rcode) {
goto FailSetDevTblEntry;
}
}
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode) {
goto FailSetConfDescr;
}
/* print endpoint structure */
/*
USBTRACE("\r\nEndpoint Structure:");
USBTRACE("\r\nEP0:");
USBTRACE2("\r\nAddr: ", epInfo[0].epAddr);
USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize);
USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs);
USBTRACE("\r\nEpout:");
USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr);
USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize);
USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs);
USBTRACE("\r\nEpin:");
USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr);
USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize);
USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs);
*/
USBTRACE("\r\nConfiguration successful");
ready = true;
return 0; //successful configuration
}//if( buf->idVendor == ADK_VID...
//probe device - get accessory protocol revision
{
uint16_t adkproto = -1;
delay(1);
rcode = getProto((uint8_t*) & adkproto);
#if defined(XOOM)
//added by Jaylen Scott Vanorden
if(rcode) {
USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
// Try once more
rcode = getProto((uint8_t*) & adkproto);
}
#endif
if(rcode) {
goto FailGetProto; //init fails
}
USBTRACE2("\r\nADK protocol rev. ", adkproto);
}
delay(100);
//sending ID strings
sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
delay(10);
sendStr(ACCESSORY_STRING_MODEL, model);
delay(10);
sendStr(ACCESSORY_STRING_DESCRIPTION, description);
delay(10);
sendStr(ACCESSORY_STRING_VERSION, version);
delay(10);
sendStr(ACCESSORY_STRING_URI, uri);
delay(10);
sendStr(ACCESSORY_STRING_SERIAL, serial);
delay(100);
//switch to accessory mode
//the Android phone will reset
rcode = switchAcc();
if(rcode) {
goto FailSwAcc; //init fails
}
rcode = USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
delay(100); // Give Android a chance to do its reset. This is a guess, and possibly could be lower.
goto SwAttempt; //switch to accessory mode attempted
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr(rcode);
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry(rcode);
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr(rcode);
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr(rcode);
goto Fail;
#endif
FailGetProto:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\ngetProto:");
goto Fail;
#endif
FailSwAcc:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\nswAcc:");
goto Fail;
#endif
//FailOnInit:
// USBTRACE("OnInit:");
// goto Fail;
//
SwAttempt:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\nAccessory mode switch attempt");
Fail:
#endif
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
//NotifyFail(rcode);
Release();
return rcode;
}
/* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
//added by Yuuichi Akagawa
if(bNumEP == 3) {
return;
}
bConfNum = conf;
if((pep->bmAttributes & 0x02) == 2) {
uint8_t index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
bNumEP++;
//PrintEndpointDescriptor(pep);
}
}
/* Performs a cleanup after failed Init() attempt */
uint8_t ADK::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1; //must have to be reset to 1
bAddress = 0;
ready = false;
return 0;
}
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
//USBTRACE2("\r\nAddr: ", bAddress );
//USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* Google ADK interface */
#include "adk.h"
const uint8_t ADK::epDataInIndex = 1;
const uint8_t ADK::epDataOutIndex = 2;
ADK::ADK(USB *p, const char* manufacturer,
const char* model,
const char* description,
const char* version,
const char* uri,
const char* serial) :
/* ADK ID Strings */
manufacturer(manufacturer),
model(model),
description(description),
version(version),
uri(uri),
serial(serial),
pUsb(p), //pointer to USB class instance - mandatory
bAddress(0), //device address - mandatory
bConfNum(0), //configuration number
bNumEP(1), //if config descriptor needs to be parsed
ready(false) {
// initialize endpoint data structures
for(uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
// register in USB subsystem
if(pUsb) {
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
}
}
uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
return Init(parent, port, lowspeed); // Just call Init. Yes, really!
}
/* Connection initialization of an Android phone */
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
uint8_t num_of_conf; // number of configurations
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("\r\nADK Init");
// check if address has already been assigned to an instance
if(bAddress) {
USBTRACE("\r\nAddress in use");
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p) {
USBTRACE("\r\nAddress not found");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if(!p->epinfo) {
USBTRACE("epinfo is null\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode) {
goto FailGetDevDescr;
}
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
// Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
//USBTRACE2("setAddr:",rcode);
return rcode;
}//if (rcode...
//USBTRACE2("\r\nAddr:", bAddress);
// Spec says you should wait at least 200ms.
//delay(300);
p->lowspeed = false;
//get pointer to assigned address record
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p) {
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
p->lowspeed = lowspeed;
// Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode) {
goto FailSetDevTblEntry;
}
//check if ADK device is already in accessory mode; if yes, configure and exit
if(udd->idVendor == ADK_VID &&
(udd->idProduct == ADK_PID || udd->idProduct == ADB_PID)) {
USBTRACE("\r\nAcc.mode device detected");
/* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
num_of_conf = udd->bNumConfigurations;
//USBTRACE2("\r\nNC:",num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
delay(1);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
#if defined(XOOM)
//added by Jaylen Scott Vanorden
if(rcode) {
USBTRACE2("\r\nGot 1st bad code for config: ", rcode);
// Try once more
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
}
#endif
if(rcode) {
goto FailGetConfDescr;
}
if(bNumEP > 2) {
break;
}
} // for (uint8_t i=0; i<num_of_conf; i++...
if(bNumEP == 3) {
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if(rcode) {
goto FailSetDevTblEntry;
}
}
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode) {
goto FailSetConfDescr;
}
/* print endpoint structure */
/*
USBTRACE("\r\nEndpoint Structure:");
USBTRACE("\r\nEP0:");
USBTRACE2("\r\nAddr: ", epInfo[0].epAddr);
USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize);
USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs);
USBTRACE("\r\nEpout:");
USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr);
USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize);
USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs);
USBTRACE("\r\nEpin:");
USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr);
USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize);
USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs);
*/
USBTRACE("\r\nConfiguration successful");
ready = true;
return 0; //successful configuration
}//if( buf->idVendor == ADK_VID...
//probe device - get accessory protocol revision
{
uint16_t adkproto = -1;
delay(1);
rcode = getProto((uint8_t*) & adkproto);
#if defined(XOOM)
//added by Jaylen Scott Vanorden
if(rcode) {
USBTRACE2("\r\nGot 1st bad code for proto: ", rcode);
// Try once more
rcode = getProto((uint8_t*) & adkproto);
}
#endif
if(rcode) {
goto FailGetProto; //init fails
}
USBTRACE2("\r\nADK protocol rev. ", adkproto);
}
delay(100);
//sending ID strings
sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
delay(10);
sendStr(ACCESSORY_STRING_MODEL, model);
delay(10);
sendStr(ACCESSORY_STRING_DESCRIPTION, description);
delay(10);
sendStr(ACCESSORY_STRING_VERSION, version);
delay(10);
sendStr(ACCESSORY_STRING_URI, uri);
delay(10);
sendStr(ACCESSORY_STRING_SERIAL, serial);
delay(100);
//switch to accessory mode
//the Android phone will reset
rcode = switchAcc();
if(rcode) {
goto FailSwAcc; //init fails
}
rcode = USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
delay(100); // Give Android a chance to do its reset. This is a guess, and possibly could be lower.
goto SwAttempt; //switch to accessory mode attempted
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr(rcode);
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry(rcode);
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr(rcode);
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr(rcode);
goto Fail;
#endif
FailGetProto:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\ngetProto:");
goto Fail;
#endif
FailSwAcc:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\nswAcc:");
goto Fail;
#endif
//FailOnInit:
// USBTRACE("OnInit:");
// goto Fail;
//
SwAttempt:
#ifdef DEBUG_USB_HOST
USBTRACE("\r\nAccessory mode switch attempt");
Fail:
#endif
//USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
//NotifyFail(rcode);
Release();
return rcode;
}
/* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
//ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
//added by Yuuichi Akagawa
if(bNumEP == 3) {
return;
}
bConfNum = conf;
if((pep->bmAttributes & 0x02) == 2) {
uint8_t index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
bNumEP++;
//PrintEndpointDescriptor(pep);
}
}
/* Performs a cleanup after failed Init() attempt */
uint8_t ADK::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1; //must have to be reset to 1
bAddress = 0;
ready = false;
return 0;
}
uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
//USBTRACE2("\r\nAddr: ", bAddress );
//USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

280
adk.h
View file

@ -1,140 +1,140 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* Google ADK interface support header */
#if !defined(_ADK_H_)
#define _ADK_H_
#include "Usb.h"
#define ADK_VID 0x18D1
#define ADK_PID 0x2D00
#define ADB_PID 0x2D01
#define XOOM //enables repeating getProto() and getConf() attempts
//necessary for slow devices such as Motorola XOOM
//defined by default, can be commented out to save memory
/* requests */
#define ADK_GETPROTO 51 //check USB accessory protocol version
#define ADK_SENDSTR 52 //send identifying string
#define ADK_ACCSTART 53 //start device in accessory mode
#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
#define ACCESSORY_STRING_MANUFACTURER 0
#define ACCESSORY_STRING_MODEL 1
#define ACCESSORY_STRING_DESCRIPTION 2
#define ACCESSORY_STRING_VERSION 3
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT
class ADK;
class ADK : public USBDeviceConfig, public UsbConfigXtracter {
private:
/* ID strings */
const char* manufacturer;
const char* model;
const char* description;
const char* version;
const char* uri;
const char* serial;
/* ADK proprietary requests */
uint8_t getProto(uint8_t* adkproto);
uint8_t sendStr(uint8_t index, const char* str);
uint8_t switchAcc(void);
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
/* mandatory members */
USB *pUsb;
uint8_t bAddress;
uint8_t bConfNum; // configuration number
uint8_t bNumEP; // total number of EP in the configuration
bool ready;
/* Endpoint data structure */
EpInfo epInfo[ADK_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
ADK(USB *pUsb, const char* manufacturer,
const char* model,
const char* description,
const char* version,
const char* uri,
const char* serial);
// Methods for receiving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
virtual uint8_t Poll() {
return 0;
};
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return ready;
};
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
return (vid == ADK_VID && (pid == ADK_PID || pid == ADB_PID));
};
//UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; //class ADK : public USBDeviceConfig ...
/* get ADK protocol version */
/* returns 2 bytes in *adkproto */
inline uint8_t ADK::getProto(uint8_t* adkproto) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL));
}
/* send ADK string */
inline uint8_t ADK::sendStr(uint8_t index, const char* str) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL));
}
/* switch to accessory mode */
inline uint8_t ADK::switchAcc(void) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
}
#endif // _ADK_H_
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* Google ADK interface support header */
#if !defined(_ADK_H_)
#define _ADK_H_
#include "Usb.h"
#define ADK_VID 0x18D1
#define ADK_PID 0x2D00
#define ADB_PID 0x2D01
#define XOOM //enables repeating getProto() and getConf() attempts
//necessary for slow devices such as Motorola XOOM
//defined by default, can be commented out to save memory
/* requests */
#define ADK_GETPROTO 51 //check USB accessory protocol version
#define ADK_SENDSTR 52 //send identifying string
#define ADK_ACCSTART 53 //start device in accessory mode
#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
#define ACCESSORY_STRING_MANUFACTURER 0
#define ACCESSORY_STRING_MODEL 1
#define ACCESSORY_STRING_DESCRIPTION 2
#define ACCESSORY_STRING_VERSION 3
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT
class ADK;
class ADK : public USBDeviceConfig, public UsbConfigXtracter {
private:
/* ID strings */
const char* manufacturer;
const char* model;
const char* description;
const char* version;
const char* uri;
const char* serial;
/* ADK proprietary requests */
uint8_t getProto(uint8_t* adkproto);
uint8_t sendStr(uint8_t index, const char* str);
uint8_t switchAcc(void);
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
/* mandatory members */
USB *pUsb;
uint8_t bAddress;
uint8_t bConfNum; // configuration number
uint8_t bNumEP; // total number of EP in the configuration
bool ready;
/* Endpoint data structure */
EpInfo epInfo[ADK_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
ADK(USB *pUsb, const char* manufacturer,
const char* model,
const char* description,
const char* version,
const char* uri,
const char* serial);
// Methods for receiving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
virtual uint8_t Poll() {
return 0;
};
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return ready;
};
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
return (vid == ADK_VID && (pid == ADK_PID || pid == ADB_PID));
};
//UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
}; //class ADK : public USBDeviceConfig ...
/* get ADK protocol version */
/* returns 2 bytes in *adkproto */
inline uint8_t ADK::getProto(uint8_t* adkproto) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL));
}
/* send ADK string */
inline uint8_t ADK::sendStr(uint8_t index, const char* str) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL));
}
/* switch to accessory mode */
inline uint8_t ADK::switchAcc(void) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
}
#endif // _ADK_H_

2000
avrpins.h

File diff suppressed because it is too large Load diff

View file

@ -1,351 +1,351 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "cdcacm.h"
const uint8_t ACM::epDataInIndex = 1;
const uint8_t ACM::epDataOutIndex = 2;
const uint8_t ACM::epInterruptInIndex = 3;
ACM::ACM(USB *p, CDCAsyncOper *pasync) :
pUsb(p),
pAsync(pasync),
bAddress(0),
bControlIface(0),
bDataIface(0),
bNumEP(1),
qNextPollTime(0),
bPollEnable(false),
ready(false) {
for(uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
//epInfo[i].bmNakPower = USB_NAK_NOWAIT;
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
//if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
}
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("ACM Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
CDC_SUBCLASS_ACM,
CDC_PROTOCOL_ITU_T_V_250,
CP_MASK_COMPARE_CLASS |
CP_MASK_COMPARE_SUBCLASS |
CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
if(rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 4)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
rcode = pAsync->OnInit(this);
if(rcode)
goto FailOnInit;
USBTRACE("ACM configured\r\n");
ready = true;
//bPollEnable = true;
//USBTRACE("Poll enabled\r\n");
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index;
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
if((pep->bmAttributes & 0x02) == 2)
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP++;
PrintEndpointDescriptor(pep);
}
uint8_t ACM::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bControlIface = 0;
bDataIface = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
uint8_t ACM::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
//uint32_t time_now = millis();
//if (qNextPollTime <= time_now)
//{
// qNextPollTime = time_now + 100;
// uint8_t rcode;
// const uint8_t constBufSize = 16;
// uint8_t buf[constBufSize];
// for (uint8_t i=0; i<constBufSize; i++)
// buf[i] = 0;
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
// if (rcode)
// return rcode;
// for (uint8_t i=0; i<read; i++)
// {
// PrintHex<uint8_t>(buf[i]);
// USB_HOST_SERIAL.print(" ");
// }
// USBTRACE("\r\n");
//}
return rcode;
}
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
}
uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
}
uint8_t ACM::ClearCommFeature(uint16_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
}
uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
}
uint8_t ACM::SetControlLineState(uint8_t state) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::SendBreak(uint16_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
}
void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "cdcacm.h"
const uint8_t ACM::epDataInIndex = 1;
const uint8_t ACM::epDataOutIndex = 2;
const uint8_t ACM::epInterruptInIndex = 3;
ACM::ACM(USB *p, CDCAsyncOper *pasync) :
pUsb(p),
pAsync(pasync),
bAddress(0),
bControlIface(0),
bDataIface(0),
bNumEP(1),
qNextPollTime(0),
bPollEnable(false),
ready(false) {
for(uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
//epInfo[i].bmNakPower = USB_NAK_NOWAIT;
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
//if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
}
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("ACM Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
CDC_SUBCLASS_ACM,
CDC_PROTOCOL_ITU_T_V_250,
CP_MASK_COMPARE_CLASS |
CP_MASK_COMPARE_SUBCLASS |
CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
CP_MASK_COMPARE_CLASS> CdcDataParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
if(rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 4)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
rcode = pAsync->OnInit(this);
if(rcode)
goto FailOnInit;
USBTRACE("ACM configured\r\n");
ready = true;
//bPollEnable = true;
//USBTRACE("Poll enabled\r\n");
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index;
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
if((pep->bmAttributes & 0x02) == 2)
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP++;
PrintEndpointDescriptor(pep);
}
uint8_t ACM::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bControlIface = 0;
bDataIface = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
uint8_t ACM::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
//uint32_t time_now = millis();
//if (qNextPollTime <= time_now)
//{
// qNextPollTime = time_now + 100;
// uint8_t rcode;
// const uint8_t constBufSize = 16;
// uint8_t buf[constBufSize];
// for (uint8_t i=0; i<constBufSize; i++)
// buf[i] = 0;
// uint16_t read = (constBufSize > epInfo[epInterruptInIndex].maxPktSize)
// ? epInfo[epInterruptInIndex].maxPktSize : constBufSize;
// rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
// if (rcode)
// return rcode;
// for (uint8_t i=0; i<read; i++)
// {
// PrintHex<uint8_t>(buf[i]);
// USB_HOST_SERIAL.print(" ");
// }
// USBTRACE("\r\n");
//}
return rcode;
}
uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
}
uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
}
uint8_t ACM::ClearCommFeature(uint16_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
}
uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
}
uint8_t ACM::SetControlLineState(uint8_t state) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
}
uint8_t ACM::SendBreak(uint16_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
}
void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

388
cdcacm.h
View file

@ -1,194 +1,194 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CDCACM_H__)
#define __CDCACM_H__
#include "Usb.h"
#define bmREQ_CDCOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_CDCIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
// CDC Subclass Constants
#define CDC_SUBCLASS_DLCM 0x01 // Direct Line Control Model
#define CDC_SUBCLASS_ACM 0x02 // Abstract Control Model
#define CDC_SUBCLASS_TCM 0x03 // Telephone Control Model
#define CDC_SUBCLASS_MCCM 0x04 // Multi Channel Control Model
#define CDC_SUBCLASS_CAPI 0x05 // CAPI Control Model
#define CDC_SUBCLASS_ETHERNET 0x06 // Ethernet Network Control Model
#define CDC_SUBCLASS_ATM 0x07 // ATM Network Control Model
#define CDC_SUBCLASS_WIRELESS_HANDSET 0x08 // Wireless Handset Control Model
#define CDC_SUBCLASS_DEVICE_MANAGEMENT 0x09 // Device Management
#define CDC_SUBCLASS_MOBILE_DIRECT_LINE 0x0A // Mobile Direct Line Model
#define CDC_SUBCLASS_OBEX 0x0B // OBEX
#define CDC_SUBCLASS_ETHERNET_EMU 0x0C // Ethernet Emulation Model
// Communication Interface Class Control Protocol Codes
#define CDC_PROTOCOL_ITU_T_V_250 0x01 // AT Commands defined by ITU-T V.250
#define CDC_PROTOCOL_PCCA_101 0x02 // AT Commands defined by PCCA-101
#define CDC_PROTOCOL_PCCA_101_O 0x03 // AT Commands defined by PCCA-101 & Annex O
#define CDC_PROTOCOL_GSM_7_07 0x04 // AT Commands defined by GSM 7.07
#define CDC_PROTOCOL_3GPP_27_07 0x05 // AT Commands defined by 3GPP 27.007
#define CDC_PROTOCOL_C_S0017_0 0x06 // AT Commands defined by TIA for CDMA
#define CDC_PROTOCOL_USB_EEM 0x07 // Ethernet Emulation Model
// CDC Commands defined by CDC 1.2
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
// CDC Commands defined by PSTN 1.2
#define CDC_SET_COMM_FEATURE 0x02
#define CDC_GET_COMM_FEATURE 0x03
#define CDC_CLEAR_COMM_FEATURE 0x04
#define CDC_SET_AUX_LINE_STATE 0x10
#define CDC_SET_HOOK_STATE 0x11
#define CDC_PULSE_SETUP 0x12
#define CDC_SEND_PULSE 0x13
#define CDC_SET_PULSE_TIME 0x14
#define CDC_RING_AUX_JACK 0x15
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define CDC_SET_RINGER_PARMS 0x30
#define CDC_GET_RINGER_PARMS 0x31
#define CDC_SET_OPERATION_PARMS 0x32
#define CDC_GET_OPERATION_PARMS 0x33
#define CDC_SET_LINE_PARMS 0x34
#define CDC_GET_LINE_PARMS 0x35
#define CDC_DIAL_DIGITS 0x36
//Class-Specific Notification Codes
#define NETWORK_CONNECTION 0x00
#define RESPONSE_AVAILABLE 0x01
#define AUX_JACK_HOOK_STATE 0x08
#define RING_DETECT 0x09
#define SERIAL_STATE 0x20
#define CALL_STATE_CHANGE 0x28
#define LINE_STATE_CHANGE 0x29
#define CONNECTION_SPEED_CHANGE 0x2a
// CDC Functional Descriptor Structures
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
uint8_t bDataInterface;
} CALL_MGMNT_FUNC_DESCR;
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR,
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bRingerVolSteps;
uint8_t bNumRingerPatterns;
} TEL_RINGER_FUNC_DESCR;
typedef struct {
uint32_t dwDTERate; // Data Terminal Rate in bits per second
uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
} LINE_CODING;
typedef struct {
uint8_t bmRequestType; // 0xa1 for class-specific notifications
uint8_t bNotification;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length
} CLASS_NOTIFICATION;
class ACM;
class CDCAsyncOper {
public:
virtual uint8_t OnInit(ACM *pacm) {
};
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
//virtual void OnDisconnected(ACM *pacm) = 0;
};
#define ACM_MAX_ENDPOINTS 4
class ACM : public USBDeviceConfig, public UsbConfigXtracter {
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
USB *pUsb;
CDCAsyncOper *pAsync;
uint8_t bAddress;
uint8_t bConfNum; // configuration number
uint8_t bControlIface; // Control interface value
uint8_t bDataIface; // Data interface value
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
bool ready; //device ready indicator
EpInfo epInfo[ACM_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
ACM(USB *pusb, CDCAsyncOper *pasync);
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
uint8_t ClearCommFeature(uint16_t fid);
uint8_t SetLineCoding(const LINE_CODING *dataptr);
uint8_t GetLineCoding(LINE_CODING *dataptr);
uint8_t SetControlLineState(uint8_t state);
uint8_t SendBreak(uint16_t duration);
uint8_t GetNotif(uint16_t *bytes_rcvd, uint8_t *dataptr);
// Methods for recieving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return ready;
};
// UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
};
#endif // __CDCACM_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CDCACM_H__)
#define __CDCACM_H__
#include "Usb.h"
#define bmREQ_CDCOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_CDCIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
// CDC Subclass Constants
#define CDC_SUBCLASS_DLCM 0x01 // Direct Line Control Model
#define CDC_SUBCLASS_ACM 0x02 // Abstract Control Model
#define CDC_SUBCLASS_TCM 0x03 // Telephone Control Model
#define CDC_SUBCLASS_MCCM 0x04 // Multi Channel Control Model
#define CDC_SUBCLASS_CAPI 0x05 // CAPI Control Model
#define CDC_SUBCLASS_ETHERNET 0x06 // Ethernet Network Control Model
#define CDC_SUBCLASS_ATM 0x07 // ATM Network Control Model
#define CDC_SUBCLASS_WIRELESS_HANDSET 0x08 // Wireless Handset Control Model
#define CDC_SUBCLASS_DEVICE_MANAGEMENT 0x09 // Device Management
#define CDC_SUBCLASS_MOBILE_DIRECT_LINE 0x0A // Mobile Direct Line Model
#define CDC_SUBCLASS_OBEX 0x0B // OBEX
#define CDC_SUBCLASS_ETHERNET_EMU 0x0C // Ethernet Emulation Model
// Communication Interface Class Control Protocol Codes
#define CDC_PROTOCOL_ITU_T_V_250 0x01 // AT Commands defined by ITU-T V.250
#define CDC_PROTOCOL_PCCA_101 0x02 // AT Commands defined by PCCA-101
#define CDC_PROTOCOL_PCCA_101_O 0x03 // AT Commands defined by PCCA-101 & Annex O
#define CDC_PROTOCOL_GSM_7_07 0x04 // AT Commands defined by GSM 7.07
#define CDC_PROTOCOL_3GPP_27_07 0x05 // AT Commands defined by 3GPP 27.007
#define CDC_PROTOCOL_C_S0017_0 0x06 // AT Commands defined by TIA for CDMA
#define CDC_PROTOCOL_USB_EEM 0x07 // Ethernet Emulation Model
// CDC Commands defined by CDC 1.2
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
// CDC Commands defined by PSTN 1.2
#define CDC_SET_COMM_FEATURE 0x02
#define CDC_GET_COMM_FEATURE 0x03
#define CDC_CLEAR_COMM_FEATURE 0x04
#define CDC_SET_AUX_LINE_STATE 0x10
#define CDC_SET_HOOK_STATE 0x11
#define CDC_PULSE_SETUP 0x12
#define CDC_SEND_PULSE 0x13
#define CDC_SET_PULSE_TIME 0x14
#define CDC_RING_AUX_JACK 0x15
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define CDC_SET_RINGER_PARMS 0x30
#define CDC_GET_RINGER_PARMS 0x31
#define CDC_SET_OPERATION_PARMS 0x32
#define CDC_GET_OPERATION_PARMS 0x33
#define CDC_SET_LINE_PARMS 0x34
#define CDC_GET_LINE_PARMS 0x35
#define CDC_DIAL_DIGITS 0x36
//Class-Specific Notification Codes
#define NETWORK_CONNECTION 0x00
#define RESPONSE_AVAILABLE 0x01
#define AUX_JACK_HOOK_STATE 0x08
#define RING_DETECT 0x09
#define SERIAL_STATE 0x20
#define CALL_STATE_CHANGE 0x28
#define LINE_STATE_CHANGE 0x29
#define CONNECTION_SPEED_CHANGE 0x2a
// CDC Functional Descriptor Structures
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
uint8_t bDataInterface;
} CALL_MGMNT_FUNC_DESCR;
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
} ACM_FUNC_DESCR, DLM_FUNC_DESCR, TEL_OPER_MODES_FUNC_DESCR,
TEL_CALL_STATE_REP_CPBL_FUNC_DESCR;
typedef struct {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bRingerVolSteps;
uint8_t bNumRingerPatterns;
} TEL_RINGER_FUNC_DESCR;
typedef struct {
uint32_t dwDTERate; // Data Terminal Rate in bits per second
uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16)
} LINE_CODING;
typedef struct {
uint8_t bmRequestType; // 0xa1 for class-specific notifications
uint8_t bNotification;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t bmState; //UART state bitmap for SERIAL_STATE, other notifications variable length
} CLASS_NOTIFICATION;
class ACM;
class CDCAsyncOper {
public:
virtual uint8_t OnInit(ACM *pacm) {
};
//virtual void OnDataRcvd(ACM *pacm, uint8_t nbytes, uint8_t *dataptr) = 0;
//virtual void OnDisconnected(ACM *pacm) = 0;
};
#define ACM_MAX_ENDPOINTS 4
class ACM : public USBDeviceConfig, public UsbConfigXtracter {
protected:
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
USB *pUsb;
CDCAsyncOper *pAsync;
uint8_t bAddress;
uint8_t bConfNum; // configuration number
uint8_t bControlIface; // Control interface value
uint8_t bDataIface; // Data interface value
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
bool ready; //device ready indicator
EpInfo epInfo[ACM_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
ACM(USB *pusb, CDCAsyncOper *pasync);
uint8_t SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
uint8_t GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr);
uint8_t ClearCommFeature(uint16_t fid);
uint8_t SetLineCoding(const LINE_CODING *dataptr);
uint8_t GetLineCoding(LINE_CODING *dataptr);
uint8_t SetControlLineState(uint8_t state);
uint8_t SendBreak(uint16_t duration);
uint8_t GetNotif(uint16_t *bytes_rcvd, uint8_t *dataptr);
// Methods for recieving and sending data
uint8_t RcvData(uint16_t *nbytesptr, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return ready;
};
// UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
};
#endif // __CDCACM_H__

View file

@ -1,339 +1,339 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "cdcftdi.h"
const uint8_t FTDI::epDataInIndex = 1;
const uint8_t FTDI::epDataOutIndex = 2;
const uint8_t FTDI::epInterruptInIndex = 3;
FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) :
pAsync(pasync),
pUsb(p),
bAddress(0),
bNumEP(1),
wFTDIType(0) {
for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
//if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
}
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
//uint8_t len = 0;
//uint16_t cd_len = 0;
uint8_t num_of_conf; // number of configurations
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("FTDI Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
if(udd->idVendor != FTDI_VID || udd->idProduct != FTDI_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Save type of FTDI chip
wFTDIType = udd->bcdDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
if(rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
USBTRACE2("NumEP:", bNumEP);
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
rcode = pAsync->OnInit(this);
if(rcode)
goto FailOnInit;
USBTRACE("FTDI configured\r\n");
bPollEnable = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index;
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
if((pep->bmAttributes & 0x02) == 2)
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP++;
PrintEndpointDescriptor(pep);
}
uint8_t FTDI::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bNumEP = 1;
qNextPollTime = 0;
bPollEnable = false;
return pAsync->OnRelease(this);
}
uint8_t FTDI::Poll() {
uint8_t rcode = 0;
//if (!bPollEnable)
// return 0;
//if (qNextPollTime <= millis())
//{
// USB_HOST_SERIAL.println(bAddress, HEX);
// qNextPollTime = millis() + 100;
//}
return rcode;
}
uint8_t FTDI::SetBaudRate(uint32_t baud) {
uint16_t baud_value, baud_index = 0;
uint32_t divisor3;
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
if(wFTDIType == FT232AM) {
if((divisor3 & 0x7) == 7)
divisor3++; // round x.7/8 up to x+1
baud_value = divisor3 >> 3;
divisor3 &= 0x7;
if(divisor3 == 1) baud_value |= 0xc000;
else // 0.125
if(divisor3 >= 4) baud_value |= 0x4000;
else // 0.5
if(divisor3 != 0) baud_value |= 0x8000; // 0.25
if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
} else {
static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
baud_value = divisor3 >> 3;
baud_value |= divfrac [divisor3 & 0x7] << 14;
baud_index = divindex[divisor3 & 0x7];
/* Deal with special cases for highest baud rates. */
if(baud_value == 1) baud_value = 0;
else // 1.0
if(baud_value == 0x4001) baud_value = 1; // 1.5
}
USBTRACE2("baud_value:", baud_value);
USBTRACE2("baud_index:", baud_index);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetModemControl(uint16_t signal) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetData(uint16_t databm) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
}
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "cdcftdi.h"
const uint8_t FTDI::epDataInIndex = 1;
const uint8_t FTDI::epDataOutIndex = 2;
const uint8_t FTDI::epInterruptInIndex = 3;
FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) :
pAsync(pasync),
pUsb(p),
bAddress(0),
bNumEP(1),
wFTDIType(0) {
for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
//if (!i)
epInfo[i].bmNakPower = USB_NAK_MAX_POWER;
}
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
//uint8_t len = 0;
//uint16_t cd_len = 0;
uint8_t num_of_conf; // number of configurations
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("FTDI Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
if(udd->idVendor != FTDI_VID || udd->idProduct != FTDI_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Save type of FTDI chip
wFTDIType = udd->bcdDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
if(rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
USBTRACE2("NumEP:", bNumEP);
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
rcode = pAsync->OnInit(this);
if(rcode)
goto FailOnInit;
USBTRACE("FTDI configured\r\n");
bPollEnable = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index;
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
if((pep->bmAttributes & 0x02) == 2)
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
else
return;
// Fill in the endpoint info structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP++;
PrintEndpointDescriptor(pep);
}
uint8_t FTDI::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bNumEP = 1;
qNextPollTime = 0;
bPollEnable = false;
return pAsync->OnRelease(this);
}
uint8_t FTDI::Poll() {
uint8_t rcode = 0;
//if (!bPollEnable)
// return 0;
//if (qNextPollTime <= millis())
//{
// USB_HOST_SERIAL.println(bAddress, HEX);
// qNextPollTime = millis() + 100;
//}
return rcode;
}
uint8_t FTDI::SetBaudRate(uint32_t baud) {
uint16_t baud_value, baud_index = 0;
uint32_t divisor3;
divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
if(wFTDIType == FT232AM) {
if((divisor3 & 0x7) == 7)
divisor3++; // round x.7/8 up to x+1
baud_value = divisor3 >> 3;
divisor3 &= 0x7;
if(divisor3 == 1) baud_value |= 0xc000;
else // 0.125
if(divisor3 >= 4) baud_value |= 0x4000;
else // 0.5
if(divisor3 != 0) baud_value |= 0x8000; // 0.25
if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
} else {
static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
baud_value = divisor3 >> 3;
baud_value |= divfrac [divisor3 & 0x7] << 14;
baud_index = divindex[divisor3 & 0x7];
/* Deal with special cases for highest baud rates. */
if(baud_value == 1) baud_value = 0;
else // 1.0
if(baud_value == 0x4001) baud_value = 1; // 1.5
}
USBTRACE2("baud_value:", baud_value);
USBTRACE2("baud_index:", baud_index);
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetModemControl(uint16_t signal) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
}
uint8_t FTDI::SetData(uint16_t databm) {
return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
}
uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
}
uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
}
void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
Notify(PSTR("\r\n"), 0x80);
}

286
cdcftdi.h
View file

@ -1,143 +1,143 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CDCFTDI_H__)
#define __CDCFTDI_H__
#include "Usb.h"
#define bmREQ_FTDI_OUT 0x40
#define bmREQ_FTDI_IN 0xc0
//#define bmREQ_FTDI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
//#define bmREQ_FTDI_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define FTDI_VID 0x0403 // FTDI VID
#define FTDI_PID 0x6001 // FTDI PID
#define FT232AM 0x0200
#define FT232BM 0x0400
#define FT2232 0x0500
#define FT232R 0x0600
// Commands
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 )
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
class FTDI;
class FTDIAsyncOper {
public:
virtual uint8_t OnInit(FTDI *pftdi) {
};
virtual uint8_t OnRelease(FTDI *pftdi) {
};
};
// Only single port chips are currently supported by the library,
// so only three endpoints are allocated.
#define FTDI_MAX_ENDPOINTS 3
class FTDI : public USBDeviceConfig, public UsbConfigXtracter {
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
FTDIAsyncOper *pAsync;
USB *pUsb;
uint8_t bAddress;
uint8_t bConfNum; // configuration number
uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint16_t wFTDIType; // Type of FTDI chip
EpInfo epInfo[FTDI_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
FTDI(USB *pusb, FTDIAsyncOper *pasync);
uint8_t SetBaudRate(uint32_t baud);
uint8_t SetModemControl(uint16_t control);
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
uint8_t SetData(uint16_t databm);
// Methods for recieving and sending data
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
return (vid == FTDI_VID && pid == FTDI_PID);
}
};
#endif // __CDCFTDI_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CDCFTDI_H__)
#define __CDCFTDI_H__
#include "Usb.h"
#define bmREQ_FTDI_OUT 0x40
#define bmREQ_FTDI_IN 0xc0
//#define bmREQ_FTDI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
//#define bmREQ_FTDI_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define FTDI_VID 0x0403 // FTDI VID
#define FTDI_PID 0x6001 // FTDI PID
#define FT232AM 0x0200
#define FT232BM 0x0400
#define FT2232 0x0500
#define FT232R 0x0600
// Commands
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 )
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 )
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8))
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
class FTDI;
class FTDIAsyncOper {
public:
virtual uint8_t OnInit(FTDI *pftdi) {
};
virtual uint8_t OnRelease(FTDI *pftdi) {
};
};
// Only single port chips are currently supported by the library,
// so only three endpoints are allocated.
#define FTDI_MAX_ENDPOINTS 3
class FTDI : public USBDeviceConfig, public UsbConfigXtracter {
static const uint8_t epDataInIndex; // DataIn endpoint index
static const uint8_t epDataOutIndex; // DataOUT endpoint index
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
FTDIAsyncOper *pAsync;
USB *pUsb;
uint8_t bAddress;
uint8_t bConfNum; // configuration number
uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint16_t wFTDIType; // Type of FTDI chip
EpInfo epInfo[FTDI_MAX_ENDPOINTS];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
FTDI(USB *pusb, FTDIAsyncOper *pasync);
uint8_t SetBaudRate(uint32_t baud);
uint8_t SetModemControl(uint16_t control);
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13);
uint8_t SetData(uint16_t databm);
// Methods for recieving and sending data
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr);
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
// UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
return (vid == FTDI_VID && pid == FTDI_PID);
}
};
#endif // __CDCFTDI_H__

View file

@ -1,210 +1,210 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "cdcprolific.h"
PL2303::PL2303(USB *p, CDCAsyncOper *pasync) :
ACM(p, pasync),
wPLType(0) {
}
uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("PL Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
if(udd->idVendor != PL_VID && udd->idProduct != PL_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Save type of PL chip
wPLType = udd->bcdDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
if(rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
rcode = pAsync->OnInit(this);
if(rcode)
goto FailOnInit;
USBTRACE("PL configured\r\n");
//bPollEnable = true;
ready = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
//uint8_t PL::Poll()
//{
// uint8_t rcode = 0;
//
// //if (!bPollEnable)
// // return 0;
//
// //if (qNextPollTime <= millis())
// //{
// // USB_HOST_SERIAL.println(bAddress, HEX);
//
// // qNextPollTime = millis() + 100;
// //}
// return rcode;
//}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "cdcprolific.h"
PL2303::PL2303(USB *p, CDCAsyncOper *pasync) :
ACM(p, pasync),
wPLType(0) {
}
uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("PL Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
if(udd->idVendor != PL_VID && udd->idProduct != PL_PID)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Save type of PL chip
wPLType = udd->bcdDevice;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
if(rcode)
goto FailGetConfDescr;
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
rcode = pAsync->OnInit(this);
if(rcode)
goto FailOnInit;
USBTRACE("PL configured\r\n");
//bPollEnable = true;
ready = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
//uint8_t PL::Poll()
//{
// uint8_t rcode = 0;
//
// //if (!bPollEnable)
// // return 0;
//
// //if (qNextPollTime <= millis())
// //{
// // USB_HOST_SERIAL.println(bAddress, HEX);
//
// // qNextPollTime = millis() + 100;
// //}
// return rcode;
//}

View file

@ -1,135 +1,135 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CDCPROLIFIC_H__)
#define __CDCPROLIFIC_H__
#include "cdcacm.h"
#define PL_VID 0x067B
#define PL_PID ( 0x2303 || 0x0609 )
//#define PL_PID 0x0609
#define PROLIFIC_REV_H 0x0202
#define PROLIFIC_REV_X 0x0300
#define PROLIFIC_REV_HX_CHIP_D 0x0400
#define PROLIFIC_REV_1 0x0001
#define kXOnChar '\x11'
#define kXOffChar '\x13'
#define SPECIAL_SHIFT (5)
#define SPECIAL_MASK ((1<<SPECIAL_SHIFT) - 1)
#define STATE_ALL ( PD_RS232_S_MASK | PD_S_MASK )
#define FLOW_RX_AUTO ( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO )
#define FLOW_TX_AUTO ( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD )
#define CAN_BE_AUTO ( FLOW_RX_AUTO | FLOW_TX_AUTO )
#define CAN_NOTIFY ( PD_RS232_N_MASK )
#define EXTERNAL_MASK ( PD_S_MASK | (PD_RS232_S_MASK & ~PD_RS232_S_LOOP) )
#define INTERNAL_DELAY ( PD_RS232_S_LOOP )
#define DEFAULT_AUTO ( PD_RS232_A_DTR | PD_RS232_A_RFR | PD_RS232_A_CTS | PD_RS232_A_DSR )
#define DEFAULT_NOTIFY 0x00
#define DEFAULT_STATE ( PD_S_TX_ENABLE | PD_S_RX_ENABLE | PD_RS232_A_TXO | PD_RS232_A_RXO )
#define CONTINUE_SEND 1
#define PAUSE_SEND 2
#define kRxAutoFlow ((UInt32)( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO ))
#define kTxAutoFlow ((UInt32)( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD ))
#define kControl_StateMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
#define kRxQueueState ((UInt32)( PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER | PD_S_RXQ_HIGH_WATER | PD_S_RXQ_FULL ))
#define kTxQueueState ((UInt32)( PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_TXQ_HIGH_WATER | PD_S_TXQ_FULL ))
#define kCONTROL_DTR 0x01
#define kCONTROL_RTS 0x02
#define kStateTransientMask 0x74
#define kBreakError 0x04
#define kFrameError 0x10
#define kParityError 0x20
#define kOverrunError 0x40
#define kCTS 0x80
#define kDSR 0x02
#define kRI 0x08
#define kDCD 0x01
#define kHandshakeInMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
#define VENDOR_WRITE_REQUEST_TYPE 0x40
#define VENDOR_WRITE_REQUEST 0x01
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
// Device Configuration Registers (DCR0, DCR1, DCR2)
#define SET_DCR0 0x00
#define GET_DCR0 0x80
#define DCR0_INIT 0x01
#define DCR0_INIT_H 0x41
#define DCR0_INIT_X 0x61
#define SET_DCR1 0x01
#define GET_DCR1 0x81
#define DCR1_INIT_H 0x80
#define DCR1_INIT_X 0x00
#define SET_DCR2 0x02
#define GET_DCR2 0x82
#define DCR2_INIT_H 0x24
#define DCR2_INIT_X 0x44
// On-chip Data Buffers:
#define RESET_DOWNSTREAM_DATA_PIPE 0x08
#define RESET_UPSTREAM_DATA_PIPE 0x09
#define PL_MAX_ENDPOINTS 4
enum tXO_State {
kXOnSent = -2,
kXOffSent = -1,
kXO_Idle = 0,
kXOffNeeded = 1,
kXOnNeeded = 2
};
enum pl2303_type {
unknown,
type_1, /* don't know the difference between type 0 and */
rev_X, /* type 1, until someone from prolific tells us... */
rev_HX, /* HX version of the pl2303 chip */
rev_H
};
class PL2303 : public ACM {
uint16_t wPLType; // Type of chip
public:
PL2303(USB *pusb, CDCAsyncOper *pasync);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
//virtual uint8_t Release();
//virtual uint8_t Poll();
//virtual uint8_t GetAddress() { return bAddress; };
//// UsbConfigXtracter implementation
//virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
};
#endif // __CDCPROLIFIC_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__CDCPROLIFIC_H__)
#define __CDCPROLIFIC_H__
#include "cdcacm.h"
#define PL_VID 0x067B
#define PL_PID ( 0x2303 || 0x0609 )
//#define PL_PID 0x0609
#define PROLIFIC_REV_H 0x0202
#define PROLIFIC_REV_X 0x0300
#define PROLIFIC_REV_HX_CHIP_D 0x0400
#define PROLIFIC_REV_1 0x0001
#define kXOnChar '\x11'
#define kXOffChar '\x13'
#define SPECIAL_SHIFT (5)
#define SPECIAL_MASK ((1<<SPECIAL_SHIFT) - 1)
#define STATE_ALL ( PD_RS232_S_MASK | PD_S_MASK )
#define FLOW_RX_AUTO ( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO )
#define FLOW_TX_AUTO ( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD )
#define CAN_BE_AUTO ( FLOW_RX_AUTO | FLOW_TX_AUTO )
#define CAN_NOTIFY ( PD_RS232_N_MASK )
#define EXTERNAL_MASK ( PD_S_MASK | (PD_RS232_S_MASK & ~PD_RS232_S_LOOP) )
#define INTERNAL_DELAY ( PD_RS232_S_LOOP )
#define DEFAULT_AUTO ( PD_RS232_A_DTR | PD_RS232_A_RFR | PD_RS232_A_CTS | PD_RS232_A_DSR )
#define DEFAULT_NOTIFY 0x00
#define DEFAULT_STATE ( PD_S_TX_ENABLE | PD_S_RX_ENABLE | PD_RS232_A_TXO | PD_RS232_A_RXO )
#define CONTINUE_SEND 1
#define PAUSE_SEND 2
#define kRxAutoFlow ((UInt32)( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO ))
#define kTxAutoFlow ((UInt32)( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD ))
#define kControl_StateMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
#define kRxQueueState ((UInt32)( PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER | PD_S_RXQ_HIGH_WATER | PD_S_RXQ_FULL ))
#define kTxQueueState ((UInt32)( PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_TXQ_HIGH_WATER | PD_S_TXQ_FULL ))
#define kCONTROL_DTR 0x01
#define kCONTROL_RTS 0x02
#define kStateTransientMask 0x74
#define kBreakError 0x04
#define kFrameError 0x10
#define kParityError 0x20
#define kOverrunError 0x40
#define kCTS 0x80
#define kDSR 0x02
#define kRI 0x08
#define kDCD 0x01
#define kHandshakeInMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
#define VENDOR_WRITE_REQUEST_TYPE 0x40
#define VENDOR_WRITE_REQUEST 0x01
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
// Device Configuration Registers (DCR0, DCR1, DCR2)
#define SET_DCR0 0x00
#define GET_DCR0 0x80
#define DCR0_INIT 0x01
#define DCR0_INIT_H 0x41
#define DCR0_INIT_X 0x61
#define SET_DCR1 0x01
#define GET_DCR1 0x81
#define DCR1_INIT_H 0x80
#define DCR1_INIT_X 0x00
#define SET_DCR2 0x02
#define GET_DCR2 0x82
#define DCR2_INIT_H 0x24
#define DCR2_INIT_X 0x44
// On-chip Data Buffers:
#define RESET_DOWNSTREAM_DATA_PIPE 0x08
#define RESET_UPSTREAM_DATA_PIPE 0x09
#define PL_MAX_ENDPOINTS 4
enum tXO_State {
kXOnSent = -2,
kXOffSent = -1,
kXO_Idle = 0,
kXOffNeeded = 1,
kXOnNeeded = 2
};
enum pl2303_type {
unknown,
type_1, /* don't know the difference between type 0 and */
rev_X, /* type 1, until someone from prolific tells us... */
rev_HX, /* HX version of the pl2303 chip */
rev_H
};
class PL2303 : public ACM {
uint16_t wPLType; // Type of chip
public:
PL2303(USB *pusb, CDCAsyncOper *pasync);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
//virtual uint8_t Release();
//virtual uint8_t Poll();
//virtual uint8_t GetAddress() { return bAddress; };
//// UsbConfigXtracter implementation
//virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
};
#endif // __CDCPROLIFIC_H__

View file

@ -1,219 +1,219 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
#error "Never include confdescparser.h directly; include Usb.h instead"
#else
#define __CONFDESCPARSER_H__
class UsbConfigXtracter {
public:
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) {
};
};
#define CP_MASK_COMPARE_CLASS 1
#define CP_MASK_COMPARE_SUBCLASS 2
#define CP_MASK_COMPARE_PROTOCOL 4
#define CP_MASK_COMPARE_ALL 7
// Configuration Descriptor Parser Class Template
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
class ConfigDescParser : public USBReadParser {
UsbConfigXtracter *theXtractor;
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
ByteSkipper theSkipper;
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
uint8_t stateParseDescr; // ParseDescriptor state
uint8_t dscrLen; // Descriptor length
uint8_t dscrType; // Descriptor type
bool isGoodInterface; // Apropriate interface flag
uint8_t confValue; // Configuration value
uint8_t protoValue; // Protocol value
uint8_t ifaceNumber; // Interface number
uint8_t ifaceAltSet; // Interface alternate settings
bool UseOr;
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
public:
void SetOR(void) {
UseOr = true;
}
ConfigDescParser(UsbConfigXtracter *xtractor);
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
};
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
theXtractor(xtractor),
stateParseDescr(0),
dscrLen(0),
dscrType(0),
UseOr(false) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) {
uint16_t cntdn = (uint16_t)len;
uint8_t *p = (uint8_t*)pbuf;
while(cntdn)
if(!ParseDescriptor(&p, &cntdn))
return;
}
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
switch(stateParseDescr) {
case 0:
theBuffer.valueSize = 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 1;
case 1:
if(!valParser.Parse(pp, pcntdn))
return false;
dscrLen = *((uint8_t*)theBuffer.pValue);
dscrType = *((uint8_t*)theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
// the pointer is positioned two bytes ahead in order for the rest of descriptor
// to be read right after the size and the type fields.
// This should be used carefully. varBuffer should be used directly to handle data
// in the buffer.
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;
case 3:
switch(dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
case USB_DESCRIPTOR_CONFIGURATION:
theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2;
break;
case USB_DESCRIPTOR_ENDPOINT:
theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2;
break;
case HID_DESCRIPTOR_HID:
theBuffer.valueSize = dscrLen - 2;
break;
}
valParser.Initialize(&theBuffer);
stateParseDescr = 4;
case 4:
switch(dscrType) {
case USB_DESCRIPTOR_CONFIGURATION:
if(!valParser.Parse(pp, pcntdn))
return false;
confValue = ucd->bConfigurationValue;
break;
case USB_DESCRIPTOR_INTERFACE:
if(!valParser.Parse(pp, pcntdn))
return false;
if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
break;
if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
break;
if(UseOr) {
if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
break;
} else {
if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
break;
}
isGoodInterface = true;
ifaceNumber = uid->bInterfaceNumber;
ifaceAltSet = uid->bAlternateSetting;
protoValue = uid->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if(!valParser.Parse(pp, pcntdn))
return false;
if(isGoodInterface)
if(theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
break;
//case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn))
// return false;
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
// break;
default:
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
return false;
}
theBuffer.pValue = varBuffer;
stateParseDescr = 0;
}
return true;
}
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
//Notify(PSTR("\r\nbDescrType:\t\t"));
//PrintHex<uint8_t>(pDesc->bDescrType);
//
//Notify(PSTR("\r\nwDescriptorLength:\t"));
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"), 0x80);
}
#endif // __CONFDESCPARSER_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
#error "Never include confdescparser.h directly; include Usb.h instead"
#else
#define __CONFDESCPARSER_H__
class UsbConfigXtracter {
public:
//virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
//virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) {
};
};
#define CP_MASK_COMPARE_CLASS 1
#define CP_MASK_COMPARE_SUBCLASS 2
#define CP_MASK_COMPARE_PROTOCOL 4
#define CP_MASK_COMPARE_ALL 7
// Configuration Descriptor Parser Class Template
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
class ConfigDescParser : public USBReadParser {
UsbConfigXtracter *theXtractor;
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
ByteSkipper theSkipper;
uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
uint8_t stateParseDescr; // ParseDescriptor state
uint8_t dscrLen; // Descriptor length
uint8_t dscrType; // Descriptor type
bool isGoodInterface; // Apropriate interface flag
uint8_t confValue; // Configuration value
uint8_t protoValue; // Protocol value
uint8_t ifaceNumber; // Interface number
uint8_t ifaceAltSet; // Interface alternate settings
bool UseOr;
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
public:
void SetOR(void) {
UseOr = true;
}
ConfigDescParser(UsbConfigXtracter *xtractor);
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
};
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
theXtractor(xtractor),
stateParseDescr(0),
dscrLen(0),
dscrType(0),
UseOr(false) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) {
uint16_t cntdn = (uint16_t)len;
uint8_t *p = (uint8_t*)pbuf;
while(cntdn)
if(!ParseDescriptor(&p, &cntdn))
return;
}
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
switch(stateParseDescr) {
case 0:
theBuffer.valueSize = 2;
valParser.Initialize(&theBuffer);
stateParseDescr = 1;
case 1:
if(!valParser.Parse(pp, pcntdn))
return false;
dscrLen = *((uint8_t*)theBuffer.pValue);
dscrType = *((uint8_t*)theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
// the pointer is positioned two bytes ahead in order for the rest of descriptor
// to be read right after the size and the type fields.
// This should be used carefully. varBuffer should be used directly to handle data
// in the buffer.
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;
case 3:
switch(dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
case USB_DESCRIPTOR_CONFIGURATION:
theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2;
break;
case USB_DESCRIPTOR_ENDPOINT:
theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2;
break;
case HID_DESCRIPTOR_HID:
theBuffer.valueSize = dscrLen - 2;
break;
}
valParser.Initialize(&theBuffer);
stateParseDescr = 4;
case 4:
switch(dscrType) {
case USB_DESCRIPTOR_CONFIGURATION:
if(!valParser.Parse(pp, pcntdn))
return false;
confValue = ucd->bConfigurationValue;
break;
case USB_DESCRIPTOR_INTERFACE:
if(!valParser.Parse(pp, pcntdn))
return false;
if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
break;
if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
break;
if(UseOr) {
if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
break;
} else {
if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
break;
}
isGoodInterface = true;
ifaceNumber = uid->bInterfaceNumber;
ifaceAltSet = uid->bAlternateSetting;
protoValue = uid->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if(!valParser.Parse(pp, pcntdn))
return false;
if(isGoodInterface)
if(theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
break;
//case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn))
// return false;
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
// break;
default:
if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
return false;
}
theBuffer.pValue = varBuffer;
stateParseDescr = 0;
}
return true;
}
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
//Notify(PSTR("\r\nbDescrType:\t\t"));
//PrintHex<uint8_t>(pDesc->bDescrType);
//
//Notify(PSTR("\r\nwDescriptorLength:\t"));
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"), 0x80);
}
#endif // __CONFDESCPARSER_H__

680
gpl2.txt
View file

@ -1,340 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

224
hid.cpp
View file

@ -1,112 +1,112 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "hid.h"
//get HID report descriptor
/* WRONG! Endpoint is _ALWAYS_ ZERO for HID! We want the _INTERFACE_ value here!
uint8_t HID::GetReportDescr(uint8_t ep, USBReadParser *parser) {
const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
uint8_t rcode = pUsb->ctrlReq(bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser);
//return ((rcode != hrSTALL) ? rcode : 0);
return rcode;
}
*/
uint8_t HID::GetReportDescr(uint16_t wIndex, USBReadParser *parser) {
const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
uint8_t rcode = pUsb->ctrlReq(bAddress, 0x00, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, wIndex, 128, constBufLen, buf, (USBReadParser*)parser);
//return ((rcode != hrSTALL) ? rcode : 0);
return rcode;
}
//uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
//{
// return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr ));
//}
uint8_t HID::SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
uint8_t HID::GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
uint8_t HID::GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL));
}
uint8_t HID::SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL));
}
uint8_t HID::SetProtocol(uint8_t iface, uint8_t protocol) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL));
}
uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL));
}
void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
}
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
D_PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
D_PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "hid.h"
//get HID report descriptor
/* WRONG! Endpoint is _ALWAYS_ ZERO for HID! We want the _INTERFACE_ value here!
uint8_t HID::GetReportDescr(uint8_t ep, USBReadParser *parser) {
const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
uint8_t rcode = pUsb->ctrlReq(bAddress, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser);
//return ((rcode != hrSTALL) ? rcode : 0);
return rcode;
}
*/
uint8_t HID::GetReportDescr(uint16_t wIndex, USBReadParser *parser) {
const uint8_t constBufLen = 64;
uint8_t buf[constBufLen];
uint8_t rcode = pUsb->ctrlReq(bAddress, 0x00, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, wIndex, 128, constBufLen, buf, (USBReadParser*)parser);
//return ((rcode != hrSTALL) ? rcode : 0);
return rcode;
}
//uint8_t HID::getHidDescr( uint8_t ep, uint16_t nbytes, uint8_t* dataptr )
//{
// return( pUsb->ctrlReq( bAddress, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_HID, 0x0000, nbytes, dataptr ));
//}
uint8_t HID::SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
uint8_t HID::GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
}
uint8_t HID::GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL));
}
uint8_t HID::SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL));
}
uint8_t HID::SetProtocol(uint8_t iface, uint8_t protocol) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL));
}
uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL));
}
void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
Notify(PSTR("Endpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
}
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
D_PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
D_PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
D_PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
}

368
hid.h
View file

@ -1,184 +1,184 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HID_H__)
#define __HID_H__
#include "Usb.h"
#include "hidusagestr.h"
#define MAX_REPORT_PARSERS 2
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
#define DATA_SIZE_MASK 0x03
#define TYPE_MASK 0x0C
#define TAG_MASK 0xF0
#define DATA_SIZE_0 0x00
#define DATA_SIZE_1 0x01
#define DATA_SIZE_2 0x02
#define DATA_SIZE_4 0x03
#define TYPE_MAIN 0x00
#define TYPE_GLOBAL 0x04
#define TYPE_LOCAL 0x08
#define TAG_MAIN_INPUT 0x80
#define TAG_MAIN_OUTPUT 0x90
#define TAG_MAIN_COLLECTION 0xA0
#define TAG_MAIN_FEATURE 0xB0
#define TAG_MAIN_ENDCOLLECTION 0xC0
#define TAG_GLOBAL_USAGEPAGE 0x00
#define TAG_GLOBAL_LOGICALMIN 0x10
#define TAG_GLOBAL_LOGICALMAX 0x20
#define TAG_GLOBAL_PHYSMIN 0x30
#define TAG_GLOBAL_PHYSMAX 0x40
#define TAG_GLOBAL_UNITEXP 0x50
#define TAG_GLOBAL_UNIT 0x60
#define TAG_GLOBAL_REPORTSIZE 0x70
#define TAG_GLOBAL_REPORTID 0x80
#define TAG_GLOBAL_REPORTCOUNT 0x90
#define TAG_GLOBAL_PUSH 0xA0
#define TAG_GLOBAL_POP 0xB0
#define TAG_LOCAL_USAGE 0x00
#define TAG_LOCAL_USAGEMIN 0x10
#define TAG_LOCAL_USAGEMAX 0x20
/* HID requests */
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
/* HID constants. Not part of chapter 9 */
/* Class-Specific Requests */
#define HID_REQUEST_GET_REPORT 0x01
#define HID_REQUEST_GET_IDLE 0x02
#define HID_REQUEST_GET_PROTOCOL 0x03
#define HID_REQUEST_SET_REPORT 0x09
#define HID_REQUEST_SET_IDLE 0x0A
#define HID_REQUEST_SET_PROTOCOL 0x0B
/* Class Descriptor Types */
#define HID_DESCRIPTOR_HID 0x21
#define HID_DESCRIPTOR_REPORT 0x22
#define HID_DESRIPTOR_PHY 0x23
/* Protocol Selection */
#define HID_BOOT_PROTOCOL 0x00
#define HID_RPT_PROTOCOL 0x01
/* HID Interface Class Code */
#define HID_INTF 0x03
/* HID Interface Class SubClass Codes */
#define HID_BOOT_INTF_SUBCLASS 0x01
/* HID Interface Class Protocol Codes */
#define HID_PROTOCOL_NONE 0x00
#define HID_PROTOCOL_KEYBOARD 0x01
#define HID_PROTOCOL_MOUSE 0x02
#define HID_ITEM_TYPE_MAIN 0
#define HID_ITEM_TYPE_GLOBAL 1
#define HID_ITEM_TYPE_LOCAL 2
#define HID_ITEM_TYPE_RESERVED 3
#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value
#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask
#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value
#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value
#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value
#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value
#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value
#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0
#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1
#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2
#define HID_MAIN_ITEM_COLLECTION_REPORT 3
#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4
#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
struct HidItemPrefix {
uint8_t bSize : 2;
uint8_t bType : 2;
uint8_t bTag : 4;
};
struct MainItemIOFeature {
uint8_t bmIsConstantOrData : 1;
uint8_t bmIsArrayOrVariable : 1;
uint8_t bmIsRelativeOrAbsolute : 1;
uint8_t bmIsWrapOrNoWrap : 1;
uint8_t bmIsNonLonearOrLinear : 1;
uint8_t bmIsNoPreferedOrPrefered : 1;
uint8_t bmIsNullOrNoNull : 1;
uint8_t bmIsVolatileOrNonVolatile : 1;
};
class HID;
class HIDReportParser {
public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
};
class HID : public USBDeviceConfig, public UsbConfigXtracter {
protected:
USB *pUsb; // USB class instance pointer
uint8_t bAddress; // address
protected:
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
static const uint8_t maxHidInterfaces = 3;
static const uint8_t maxEpPerInterface = 2;
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
virtual HIDReportParser* GetReportParser(uint8_t id) {};
public:
HID(USB *pusb) : pUsb(pusb) {
};
const USB* GetUsb() {
return pUsb;
};
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {};
uint8_t SetProtocol(uint8_t iface, uint8_t protocol);
uint8_t GetProtocol(uint8_t iface, uint8_t* dataptr);
uint8_t GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr);
uint8_t SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration);
uint8_t GetReportDescr(uint16_t wIndex, USBReadParser *parser = NULL);
uint8_t GetHidDescr(uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
};
#endif // __HID_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HID_H__)
#define __HID_H__
#include "Usb.h"
#include "hidusagestr.h"
#define MAX_REPORT_PARSERS 2
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
#define DATA_SIZE_MASK 0x03
#define TYPE_MASK 0x0C
#define TAG_MASK 0xF0
#define DATA_SIZE_0 0x00
#define DATA_SIZE_1 0x01
#define DATA_SIZE_2 0x02
#define DATA_SIZE_4 0x03
#define TYPE_MAIN 0x00
#define TYPE_GLOBAL 0x04
#define TYPE_LOCAL 0x08
#define TAG_MAIN_INPUT 0x80
#define TAG_MAIN_OUTPUT 0x90
#define TAG_MAIN_COLLECTION 0xA0
#define TAG_MAIN_FEATURE 0xB0
#define TAG_MAIN_ENDCOLLECTION 0xC0
#define TAG_GLOBAL_USAGEPAGE 0x00
#define TAG_GLOBAL_LOGICALMIN 0x10
#define TAG_GLOBAL_LOGICALMAX 0x20
#define TAG_GLOBAL_PHYSMIN 0x30
#define TAG_GLOBAL_PHYSMAX 0x40
#define TAG_GLOBAL_UNITEXP 0x50
#define TAG_GLOBAL_UNIT 0x60
#define TAG_GLOBAL_REPORTSIZE 0x70
#define TAG_GLOBAL_REPORTID 0x80
#define TAG_GLOBAL_REPORTCOUNT 0x90
#define TAG_GLOBAL_PUSH 0xA0
#define TAG_GLOBAL_POP 0xB0
#define TAG_LOCAL_USAGE 0x00
#define TAG_LOCAL_USAGEMIN 0x10
#define TAG_LOCAL_USAGEMAX 0x20
/* HID requests */
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
/* HID constants. Not part of chapter 9 */
/* Class-Specific Requests */
#define HID_REQUEST_GET_REPORT 0x01
#define HID_REQUEST_GET_IDLE 0x02
#define HID_REQUEST_GET_PROTOCOL 0x03
#define HID_REQUEST_SET_REPORT 0x09
#define HID_REQUEST_SET_IDLE 0x0A
#define HID_REQUEST_SET_PROTOCOL 0x0B
/* Class Descriptor Types */
#define HID_DESCRIPTOR_HID 0x21
#define HID_DESCRIPTOR_REPORT 0x22
#define HID_DESRIPTOR_PHY 0x23
/* Protocol Selection */
#define HID_BOOT_PROTOCOL 0x00
#define HID_RPT_PROTOCOL 0x01
/* HID Interface Class Code */
#define HID_INTF 0x03
/* HID Interface Class SubClass Codes */
#define HID_BOOT_INTF_SUBCLASS 0x01
/* HID Interface Class Protocol Codes */
#define HID_PROTOCOL_NONE 0x00
#define HID_PROTOCOL_KEYBOARD 0x01
#define HID_PROTOCOL_MOUSE 0x02
#define HID_ITEM_TYPE_MAIN 0
#define HID_ITEM_TYPE_GLOBAL 1
#define HID_ITEM_TYPE_LOCAL 2
#define HID_ITEM_TYPE_RESERVED 3
#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value
#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask
#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value
#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value
#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value
#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value
#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value
#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0
#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1
#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2
#define HID_MAIN_ITEM_COLLECTION_REPORT 3
#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4
#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
struct HidItemPrefix {
uint8_t bSize : 2;
uint8_t bType : 2;
uint8_t bTag : 4;
};
struct MainItemIOFeature {
uint8_t bmIsConstantOrData : 1;
uint8_t bmIsArrayOrVariable : 1;
uint8_t bmIsRelativeOrAbsolute : 1;
uint8_t bmIsWrapOrNoWrap : 1;
uint8_t bmIsNonLonearOrLinear : 1;
uint8_t bmIsNoPreferedOrPrefered : 1;
uint8_t bmIsNullOrNoNull : 1;
uint8_t bmIsVolatileOrNonVolatile : 1;
};
class HID;
class HIDReportParser {
public:
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) = 0;
};
class HID : public USBDeviceConfig, public UsbConfigXtracter {
protected:
USB *pUsb; // USB class instance pointer
uint8_t bAddress; // address
protected:
static const uint8_t epInterruptInIndex = 1; // InterruptIN endpoint index
static const uint8_t epInterruptOutIndex = 2; // InterruptOUT endpoint index
static const uint8_t maxHidInterfaces = 3;
static const uint8_t maxEpPerInterface = 2;
static const uint8_t totalEndpoints = (maxHidInterfaces * maxEpPerInterface + 1);
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
virtual HIDReportParser* GetReportParser(uint8_t id) {};
public:
HID(USB *pusb) : pUsb(pusb) {
};
const USB* GetUsb() {
return pUsb;
};
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {};
uint8_t SetProtocol(uint8_t iface, uint8_t protocol);
uint8_t GetProtocol(uint8_t iface, uint8_t* dataptr);
uint8_t GetIdle(uint8_t iface, uint8_t reportID, uint8_t* dataptr);
uint8_t SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration);
uint8_t GetReportDescr(uint16_t wIndex, USBReadParser *parser = NULL);
uint8_t GetHidDescr(uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t GetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetReport(uint8_t ep, uint8_t iface, uint8_t report_type, uint8_t report_id, uint16_t nbytes, uint8_t* dataptr);
};
#endif // __HID_H__

View file

@ -1,201 +1,201 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "hidboot.h"
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
MOUSEINFO *pmi = (MOUSEINFO*)buf;
// Future:
// bool event;
#if 0
if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1)
OnLeftButtonDown(pmi);
if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0)
OnLeftButtonUp(pmi);
if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1)
OnRightButtonDown(pmi);
if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0)
OnRightButtonUp(pmi);
if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1)
OnMiddleButtonDown(pmi);
if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0)
OnMiddleButtonUp(pmi);
if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY)
OnMouseMove(pmi);
if (len > sizeof (MOUSEINFO))
for (uint8_t i = 0; i<sizeof (MOUSEINFO); i++)
prevState.bInfo[i] = buf[i];
#else
//
// Optimization idea:
//
// 1: Don't pass the structure on every event. Buttons would not need it.
// 2: Only pass x/y values in the movement routine.
//
// These two changes (with the ones I have made) will save extra flash.
// The only "bad" thing is that it could break old code.
//
// Future thoughts:
//
// The extra space gained can be used for a generic mouse event that can be called
// when there are _ANY_ changes. This one you _MAY_ want to pass everything, however the
// sketch could already have noted these facts to support drag/drop scroll wheel stuff, etc.
//
// Why do we need to pass the structure for buttons?
// The function call not enough of a hint for what is happening?
if(prevState.mouseInfo.bmLeftButton != pmi->bmLeftButton ) {
if(pmi->bmLeftButton) {
OnLeftButtonDown(pmi);
} else {
OnLeftButtonUp(pmi);
}
// Future:
// event = true;
}
if(prevState.mouseInfo.bmRightButton != pmi->bmRightButton) {
if(pmi->bmRightButton) {
OnRightButtonDown(pmi);
} else {
OnRightButtonUp(pmi);
}
// Future:
// event = true;
}
if(prevState.mouseInfo.bmMiddleButton != pmi->bmMiddleButton) {
if(pmi->bmMiddleButton) {
OnMiddleButtonDown(pmi);
} else {
OnMiddleButtonUp(pmi);
}
// Future:
// event = true;
}
//
// Scroll wheel(s), are not part of the spec, but we could support it.
// Logitech wireless keyboard and mouse combo reports scroll wheel in byte 4
// We wouldn't even need to save this information.
//if(len > 3) {
//}
//
// Mice only report motion when they actually move!
// Why not just pass the x/y values to simplify things??
if(pmi->dX || pmi->dY) {
OnMouseMove(pmi);
// Future:
// event = true;
}
//
// Future:
// Provide a callback that operates on the gathered events from above.
//
// if(event) OnMouse();
//
// Only the first byte matters (buttons). We do NOT need to save position info.
prevState.bInfo[0] = buf[0];
#endif
};
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
// On error - return
if (buf[2] == 1)
return;
//KBDINFO *pki = (KBDINFO*)buf;
// provide event for changed control key state
if (prevState.bInfo[0x00] != buf[0x00]) {
OnControlKeysChanged(prevState.bInfo[0x00], buf[0x00]);
}
for (uint8_t i = 2; i < 8; i++) {
bool down = false;
bool up = false;
for (uint8_t j = 2; j < 8; j++) {
if (buf[i] == prevState.bInfo[j] && buf[i] != 1)
down = true;
if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1)
up = true;
}
if (!down) {
HandleLockingKeys(hid, buf[i]);
OnKeyDown(*buf, buf[i]);
}
if (!up)
OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]);
}
for (uint8_t i = 0; i < 8; i++)
prevState.bInfo[i] = buf[i];
};
const uint8_t KeyboardReportParser::numKeys[10] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
const uint8_t KeyboardReportParser::symKeysUp[12] PROGMEM = {'_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'};
const uint8_t KeyboardReportParser::symKeysLo[12] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'};
const uint8_t KeyboardReportParser::padKeys[5] PROGMEM = {'/', '*', '-', '+', 0x13};
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) {
uint8_t shift = (mod & 0x22);
// [a-z]
if (VALUE_WITHIN(key, 0x04, 0x1d)) {
// Upper case letters
if ((kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0))
return (key - 4 + 'A');
// Lower case letters
else
return (key - 4 + 'a');
}// Numbers
else if (VALUE_WITHIN(key, 0x1e, 0x27)) {
if (shift)
return ((uint8_t)pgm_read_byte(&getNumKeys()[key - 0x1e]));
else
return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
}// Keypad Numbers
else if(VALUE_WITHIN(key, 0x59, 0x61)) {
if(kbdLockingKeys.kbdLeds.bmNumLock == 1)
return (key - 0x59 + '1');
} else if(VALUE_WITHIN(key, 0x2d, 0x38))
return ((shift) ? (uint8_t)pgm_read_byte(&getSymKeysUp()[key - 0x2d]) : (uint8_t)pgm_read_byte(&getSymKeysLo()[key - 0x2d]));
else if(VALUE_WITHIN(key, 0x54, 0x58))
return (uint8_t)pgm_read_byte(&getPadKeys()[key - 0x54]);
else {
switch(key) {
case UHS_HID_BOOT_KEY_SPACE: return (0x20);
case UHS_HID_BOOT_KEY_ENTER: return (0x13);
case UHS_HID_BOOT_KEY_ZERO2: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0': 0);
case UHS_HID_BOOT_KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.': 0);
}
}
return ( 0);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "hidboot.h"
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
MOUSEINFO *pmi = (MOUSEINFO*)buf;
// Future:
// bool event;
#if 0
if (prevState.mouseInfo.bmLeftButton == 0 && pmi->bmLeftButton == 1)
OnLeftButtonDown(pmi);
if (prevState.mouseInfo.bmLeftButton == 1 && pmi->bmLeftButton == 0)
OnLeftButtonUp(pmi);
if (prevState.mouseInfo.bmRightButton == 0 && pmi->bmRightButton == 1)
OnRightButtonDown(pmi);
if (prevState.mouseInfo.bmRightButton == 1 && pmi->bmRightButton == 0)
OnRightButtonUp(pmi);
if (prevState.mouseInfo.bmMiddleButton == 0 && pmi->bmMiddleButton == 1)
OnMiddleButtonDown(pmi);
if (prevState.mouseInfo.bmMiddleButton == 1 && pmi->bmMiddleButton == 0)
OnMiddleButtonUp(pmi);
if (prevState.mouseInfo.dX != pmi->dX || prevState.mouseInfo.dY != pmi->dY)
OnMouseMove(pmi);
if (len > sizeof (MOUSEINFO))
for (uint8_t i = 0; i<sizeof (MOUSEINFO); i++)
prevState.bInfo[i] = buf[i];
#else
//
// Optimization idea:
//
// 1: Don't pass the structure on every event. Buttons would not need it.
// 2: Only pass x/y values in the movement routine.
//
// These two changes (with the ones I have made) will save extra flash.
// The only "bad" thing is that it could break old code.
//
// Future thoughts:
//
// The extra space gained can be used for a generic mouse event that can be called
// when there are _ANY_ changes. This one you _MAY_ want to pass everything, however the
// sketch could already have noted these facts to support drag/drop scroll wheel stuff, etc.
//
// Why do we need to pass the structure for buttons?
// The function call not enough of a hint for what is happening?
if(prevState.mouseInfo.bmLeftButton != pmi->bmLeftButton ) {
if(pmi->bmLeftButton) {
OnLeftButtonDown(pmi);
} else {
OnLeftButtonUp(pmi);
}
// Future:
// event = true;
}
if(prevState.mouseInfo.bmRightButton != pmi->bmRightButton) {
if(pmi->bmRightButton) {
OnRightButtonDown(pmi);
} else {
OnRightButtonUp(pmi);
}
// Future:
// event = true;
}
if(prevState.mouseInfo.bmMiddleButton != pmi->bmMiddleButton) {
if(pmi->bmMiddleButton) {
OnMiddleButtonDown(pmi);
} else {
OnMiddleButtonUp(pmi);
}
// Future:
// event = true;
}
//
// Scroll wheel(s), are not part of the spec, but we could support it.
// Logitech wireless keyboard and mouse combo reports scroll wheel in byte 4
// We wouldn't even need to save this information.
//if(len > 3) {
//}
//
// Mice only report motion when they actually move!
// Why not just pass the x/y values to simplify things??
if(pmi->dX || pmi->dY) {
OnMouseMove(pmi);
// Future:
// event = true;
}
//
// Future:
// Provide a callback that operates on the gathered events from above.
//
// if(event) OnMouse();
//
// Only the first byte matters (buttons). We do NOT need to save position info.
prevState.bInfo[0] = buf[0];
#endif
};
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
// On error - return
if (buf[2] == 1)
return;
//KBDINFO *pki = (KBDINFO*)buf;
// provide event for changed control key state
if (prevState.bInfo[0x00] != buf[0x00]) {
OnControlKeysChanged(prevState.bInfo[0x00], buf[0x00]);
}
for (uint8_t i = 2; i < 8; i++) {
bool down = false;
bool up = false;
for (uint8_t j = 2; j < 8; j++) {
if (buf[i] == prevState.bInfo[j] && buf[i] != 1)
down = true;
if (buf[j] == prevState.bInfo[i] && prevState.bInfo[i] != 1)
up = true;
}
if (!down) {
HandleLockingKeys(hid, buf[i]);
OnKeyDown(*buf, buf[i]);
}
if (!up)
OnKeyUp(prevState.bInfo[0], prevState.bInfo[i]);
}
for (uint8_t i = 0; i < 8; i++)
prevState.bInfo[i] = buf[i];
};
const uint8_t KeyboardReportParser::numKeys[10] PROGMEM = {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
const uint8_t KeyboardReportParser::symKeysUp[12] PROGMEM = {'_', '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'};
const uint8_t KeyboardReportParser::symKeysLo[12] PROGMEM = {'-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/'};
const uint8_t KeyboardReportParser::padKeys[5] PROGMEM = {'/', '*', '-', '+', 0x13};
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) {
uint8_t shift = (mod & 0x22);
// [a-z]
if (VALUE_WITHIN(key, 0x04, 0x1d)) {
// Upper case letters
if ((kbdLockingKeys.kbdLeds.bmCapsLock == 0 && (mod & 2)) ||
(kbdLockingKeys.kbdLeds.bmCapsLock == 1 && (mod & 2) == 0))
return (key - 4 + 'A');
// Lower case letters
else
return (key - 4 + 'a');
}// Numbers
else if (VALUE_WITHIN(key, 0x1e, 0x27)) {
if (shift)
return ((uint8_t)pgm_read_byte(&getNumKeys()[key - 0x1e]));
else
return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
}// Keypad Numbers
else if(VALUE_WITHIN(key, 0x59, 0x61)) {
if(kbdLockingKeys.kbdLeds.bmNumLock == 1)
return (key - 0x59 + '1');
} else if(VALUE_WITHIN(key, 0x2d, 0x38))
return ((shift) ? (uint8_t)pgm_read_byte(&getSymKeysUp()[key - 0x2d]) : (uint8_t)pgm_read_byte(&getSymKeysLo()[key - 0x2d]));
else if(VALUE_WITHIN(key, 0x54, 0x58))
return (uint8_t)pgm_read_byte(&getPadKeys()[key - 0x54]);
else {
switch(key) {
case UHS_HID_BOOT_KEY_SPACE: return (0x20);
case UHS_HID_BOOT_KEY_ENTER: return (0x13);
case UHS_HID_BOOT_KEY_ZERO2: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '0': 0);
case UHS_HID_BOOT_KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.': 0);
}
}
return ( 0);
}

1228
hidboot.h

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,176 +1,176 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HIDDESCRIPTORPARSER_H__)
#define __HIDDESCRIPTORPARSER_H__
#include "hid.h"
class ReportDescParserBase : public USBReadParser {
public:
typedef void (*UsagePageFunc)(uint16_t usage);
static void PrintGenericDesktopPageUsage(uint16_t usage);
static void PrintSimulationControlsPageUsage(uint16_t usage);
static void PrintVRControlsPageUsage(uint16_t usage);
static void PrintSportsControlsPageUsage(uint16_t usage);
static void PrintGameControlsPageUsage(uint16_t usage);
static void PrintGenericDeviceControlsPageUsage(uint16_t usage);
static void PrintLEDPageUsage(uint16_t usage);
static void PrintButtonPageUsage(uint16_t usage);
static void PrintOrdinalPageUsage(uint16_t usage);
static void PrintTelephonyPageUsage(uint16_t usage);
static void PrintConsumerPageUsage(uint16_t usage);
static void PrintDigitizerPageUsage(uint16_t usage);
static void PrintAlphanumDisplayPageUsage(uint16_t usage);
static void PrintMedicalInstrumentPageUsage(uint16_t usage);
static void PrintValue(uint8_t *p, uint8_t len);
static void PrintByteValue(uint8_t data);
static void PrintItemTitle(uint8_t prefix);
static const char * const usagePageTitles0[];
static const char * const usagePageTitles1[];
static const char * const genDesktopTitles0[];
static const char * const genDesktopTitles1[];
static const char * const genDesktopTitles2[];
static const char * const genDesktopTitles3[];
static const char * const genDesktopTitles4[];
static const char * const simuTitles0[];
static const char * const simuTitles1[];
static const char * const simuTitles2[];
static const char * const vrTitles0[];
static const char * const vrTitles1[];
static const char * const sportsCtrlTitles0[];
static const char * const sportsCtrlTitles1[];
static const char * const sportsCtrlTitles2[];
static const char * const gameTitles0[];
static const char * const gameTitles1[];
static const char * const genDevCtrlTitles[];
static const char * const ledTitles[];
static const char * const telTitles0[];
static const char * const telTitles1[];
static const char * const telTitles2[];
static const char * const telTitles3[];
static const char * const telTitles4[];
static const char * const telTitles5[];
static const char * const consTitles0[];
static const char * const consTitles1[];
static const char * const consTitles2[];
static const char * const consTitles3[];
static const char * const consTitles4[];
static const char * const consTitles5[];
static const char * const consTitles6[];
static const char * const consTitles7[];
static const char * const consTitles8[];
static const char * const consTitles9[];
static const char * const consTitlesA[];
static const char * const consTitlesB[];
static const char * const consTitlesC[];
static const char * const consTitlesD[];
static const char * const consTitlesE[];
static const char * const digitTitles0[];
static const char * const digitTitles1[];
static const char * const digitTitles2[];
static const char * const aplphanumTitles0[];
static const char * const aplphanumTitles1[];
static const char * const aplphanumTitles2[];
static const char * const medInstrTitles0[];
static const char * const medInstrTitles1[];
static const char * const medInstrTitles2[];
static const char * const medInstrTitles3[];
static const char * const medInstrTitles4[];
protected:
static UsagePageFunc usagePageFunctions[];
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
ByteSkipper theSkipper;
uint8_t varBuffer[sizeof (USB_CONFIGURATION_DESCRIPTOR)];
uint8_t itemParseState; // Item parser state variable
uint8_t itemSize; // Item size
uint8_t itemPrefix; // Item prefix (first byte)
uint8_t rptSize; // Report Size
uint8_t rptCount; // Report Count
uint16_t totalSize; // Report size in bits
// Method should be defined here if virtual.
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
UsagePageFunc pfUsage;
static void PrintUsagePage(uint16_t page);
void SetUsagePage(uint16_t page);
public:
ReportDescParserBase() :
itemParseState(0),
itemSize(0),
itemPrefix(0),
rptSize(0),
rptCount(0),
pfUsage(NULL) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
enum {
enErrorSuccess = 0
, enErrorIncomplete // value or record is partialy read in buffer
, enErrorBufferTooSmall
};
};
class ReportDescParser : public ReportDescParserBase {
};
class ReportDescParser2 : public ReportDescParserBase {
uint8_t rptId; // Report ID
uint8_t useMin; // Usage Minimum
uint8_t useMax; // Usage Maximum
uint8_t fieldCount; // Number of field being currently processed
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
uint8_t *pBuf; // Report buffer pointer
uint8_t bLen; // Report length
protected:
// Method should be defined here if virtual.
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
public:
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
ReportDescParserBase(), rptId(0), useMin(0), useMax(0), fieldCount(0), pBuf(pbuf), bLen(len) {
};
};
class UniversalReportParser : public HIDReportParser {
public:
// Method should be defined here if virtual.
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
#endif // __HIDDESCRIPTORPARSER_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HIDDESCRIPTORPARSER_H__)
#define __HIDDESCRIPTORPARSER_H__
#include "hid.h"
class ReportDescParserBase : public USBReadParser {
public:
typedef void (*UsagePageFunc)(uint16_t usage);
static void PrintGenericDesktopPageUsage(uint16_t usage);
static void PrintSimulationControlsPageUsage(uint16_t usage);
static void PrintVRControlsPageUsage(uint16_t usage);
static void PrintSportsControlsPageUsage(uint16_t usage);
static void PrintGameControlsPageUsage(uint16_t usage);
static void PrintGenericDeviceControlsPageUsage(uint16_t usage);
static void PrintLEDPageUsage(uint16_t usage);
static void PrintButtonPageUsage(uint16_t usage);
static void PrintOrdinalPageUsage(uint16_t usage);
static void PrintTelephonyPageUsage(uint16_t usage);
static void PrintConsumerPageUsage(uint16_t usage);
static void PrintDigitizerPageUsage(uint16_t usage);
static void PrintAlphanumDisplayPageUsage(uint16_t usage);
static void PrintMedicalInstrumentPageUsage(uint16_t usage);
static void PrintValue(uint8_t *p, uint8_t len);
static void PrintByteValue(uint8_t data);
static void PrintItemTitle(uint8_t prefix);
static const char * const usagePageTitles0[];
static const char * const usagePageTitles1[];
static const char * const genDesktopTitles0[];
static const char * const genDesktopTitles1[];
static const char * const genDesktopTitles2[];
static const char * const genDesktopTitles3[];
static const char * const genDesktopTitles4[];
static const char * const simuTitles0[];
static const char * const simuTitles1[];
static const char * const simuTitles2[];
static const char * const vrTitles0[];
static const char * const vrTitles1[];
static const char * const sportsCtrlTitles0[];
static const char * const sportsCtrlTitles1[];
static const char * const sportsCtrlTitles2[];
static const char * const gameTitles0[];
static const char * const gameTitles1[];
static const char * const genDevCtrlTitles[];
static const char * const ledTitles[];
static const char * const telTitles0[];
static const char * const telTitles1[];
static const char * const telTitles2[];
static const char * const telTitles3[];
static const char * const telTitles4[];
static const char * const telTitles5[];
static const char * const consTitles0[];
static const char * const consTitles1[];
static const char * const consTitles2[];
static const char * const consTitles3[];
static const char * const consTitles4[];
static const char * const consTitles5[];
static const char * const consTitles6[];
static const char * const consTitles7[];
static const char * const consTitles8[];
static const char * const consTitles9[];
static const char * const consTitlesA[];
static const char * const consTitlesB[];
static const char * const consTitlesC[];
static const char * const consTitlesD[];
static const char * const consTitlesE[];
static const char * const digitTitles0[];
static const char * const digitTitles1[];
static const char * const digitTitles2[];
static const char * const aplphanumTitles0[];
static const char * const aplphanumTitles1[];
static const char * const aplphanumTitles2[];
static const char * const medInstrTitles0[];
static const char * const medInstrTitles1[];
static const char * const medInstrTitles2[];
static const char * const medInstrTitles3[];
static const char * const medInstrTitles4[];
protected:
static UsagePageFunc usagePageFunctions[];
MultiValueBuffer theBuffer;
MultiByteValueParser valParser;
ByteSkipper theSkipper;
uint8_t varBuffer[sizeof (USB_CONFIGURATION_DESCRIPTOR)];
uint8_t itemParseState; // Item parser state variable
uint8_t itemSize; // Item size
uint8_t itemPrefix; // Item prefix (first byte)
uint8_t rptSize; // Report Size
uint8_t rptCount; // Report Count
uint16_t totalSize; // Report size in bits
// Method should be defined here if virtual.
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
UsagePageFunc pfUsage;
static void PrintUsagePage(uint16_t page);
void SetUsagePage(uint16_t page);
public:
ReportDescParserBase() :
itemParseState(0),
itemSize(0),
itemPrefix(0),
rptSize(0),
rptCount(0),
pfUsage(NULL) {
theBuffer.pValue = varBuffer;
valParser.Initialize(&theBuffer);
theSkipper.Initialize(&theBuffer);
};
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
enum {
enErrorSuccess = 0
, enErrorIncomplete // value or record is partialy read in buffer
, enErrorBufferTooSmall
};
};
class ReportDescParser : public ReportDescParserBase {
};
class ReportDescParser2 : public ReportDescParserBase {
uint8_t rptId; // Report ID
uint8_t useMin; // Usage Minimum
uint8_t useMax; // Usage Maximum
uint8_t fieldCount; // Number of field being currently processed
void OnInputItem(uint8_t itm); // Method which is called every time Input item is found
uint8_t *pBuf; // Report buffer pointer
uint8_t bLen; // Report length
protected:
// Method should be defined here if virtual.
virtual uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn);
public:
ReportDescParser2(uint16_t len, uint8_t *pbuf) :
ReportDescParserBase(), rptId(0), useMin(0), useMax(0), fieldCount(0), pBuf(pbuf), bLen(len) {
};
};
class UniversalReportParser : public HIDReportParser {
public:
// Method should be defined here if virtual.
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
#endif // __HIDDESCRIPTORPARSER_H__

View file

@ -1,420 +1,420 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "hiduniversal.h"
HIDUniversal::HIDUniversal(USB *p) :
HID(p),
qNextPollTime(0),
pollInterval(0),
bPollEnable(false),
bHasReportId(false) {
Initialize();
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
for(uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
if(descrInfo[i].bDescrType == type) {
if(n == num)
return descrInfo[i].wDescriptorLength;
n++;
}
}
return 0;
}
void HIDUniversal::Initialize() {
for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
rptParsers[i].rptId = 0;
rptParsers[i].rptParser = NULL;
}
for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
descrInfo[i].bDescrType = 0;
descrInfo[i].wDescriptorLength = 0;
}
for(uint8_t i = 0; i < maxHidInterfaces; i++) {
hidInterfaces[i].bmInterface = 0;
hidInterfaces[i].bmProtocol = 0;
for(uint8_t j = 0; j < maxEpPerInterface; j++)
hidInterfaces[i].epIndex[j] = 0;
}
for(uint8_t i = 0; i < totalEndpoints; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
bNumEP = 1;
bNumIface = 0;
bConfNum = 0;
pollInterval = 0;
ZeroMemory(constBuffLen, prevBuf);
}
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
rptParsers[i].rptId = id;
rptParsers[i].rptParser = prs;
return true;
}
}
return false;
}
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
if(!bHasReportId)
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
if(rptParsers[i].rptId == id)
return rptParsers[i].rptParser;
}
return NULL;
}
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t len = 0;
uint8_t num_of_conf; // number of configurations
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("HU Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
if(!rcode)
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
goto FailGetDevDescr;
}
// Restore p->epinfo
p->epinfo = oldep_ptr;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
//delay(2); //per USB 2.0 sect.9.2.6.3
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
if(len)
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
if(rcode)
goto FailGetDevDescr;
VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
PID = udd->idProduct;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<USB_CLASS_HID, 0, 0,
CP_MASK_COMPARE_CLASS> confDescrParser(this);
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Cnf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
for(uint8_t i = 0; i < bNumIface; i++) {
if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
continue;
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
if(rcode && rcode != hrSTALL)
goto FailSetIdle;
}
USBTRACE("HU configured\r\n");
OnInitSuccessful();
bPollEnable = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailSetIdle:
#ifdef DEBUG_USB_HOST
USBTRACE("SetIdle:");
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
&& hidInterfaces[i].bmProtocol == proto)
return hidInterfaces + i;
return NULL;
}
void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
// If the first configuration satisfies, the others are not concidered.
if(bNumEP > 1 && conf != bConfNum)
return;
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index = 0;
HIDInterface *piface = FindInterface(iface, alt, proto);
// Fill in interface structure in case of new interface
if(!piface) {
piface = hidInterfaces + bNumIface;
piface->bmInterface = iface;
piface->bmAltSet = alt;
piface->bmProtocol = proto;
bNumIface++;
}
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
index = epInterruptOutIndex;
if(index) {
// Fill in the endpoint info structure
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[bNumEP].epAttribs = 0;
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
// Fill in the endpoint index list
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
pollInterval = pep->bInterval;
bNumEP++;
}
//PrintEndpointDescriptor(pep);
}
uint8_t HIDUniversal::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
for(uint8_t i = 0; i < len; i++)
if(buf1[i] != buf2[i])
return false;
return true;
}
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
for(uint8_t i = 0; i < len; i++)
buf[i] = 0;
}
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
for(uint8_t i = 0; i < len; i++)
dest[i] = src[i];
}
uint8_t HIDUniversal::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
if((long)(millis() - qNextPollTime) >= 0L) {
qNextPollTime = millis() + pollInterval;
uint8_t buf[constBuffLen];
for(uint8_t i = 0; i < bNumIface; i++) {
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
uint16_t read = (uint16_t)epInfo[index].maxPktSize;
ZeroMemory(constBuffLen, buf);
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
if(rcode) {
if(rcode != hrNAK)
USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
return rcode;
}
if(read > constBuffLen)
read = constBuffLen;
bool identical = BuffersIdentical(read, buf, prevBuf);
SaveBuffer(read, buf, prevBuf);
if(identical)
return 0;
#if 0
Notify(PSTR("\r\nBuf: "), 0x80);
for(uint8_t i = 0; i < read; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
#endif
ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
if(prs)
prs->Parse(this, bHasReportId, (uint8_t)read, buf);
}
}
return rcode;
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "hiduniversal.h"
HIDUniversal::HIDUniversal(USB *p) :
HID(p),
qNextPollTime(0),
pollInterval(0),
bPollEnable(false),
bHasReportId(false) {
Initialize();
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
for(uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
if(descrInfo[i].bDescrType == type) {
if(n == num)
return descrInfo[i].wDescriptorLength;
n++;
}
}
return 0;
}
void HIDUniversal::Initialize() {
for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
rptParsers[i].rptId = 0;
rptParsers[i].rptParser = NULL;
}
for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
descrInfo[i].bDescrType = 0;
descrInfo[i].wDescriptorLength = 0;
}
for(uint8_t i = 0; i < maxHidInterfaces; i++) {
hidInterfaces[i].bmInterface = 0;
hidInterfaces[i].bmProtocol = 0;
for(uint8_t j = 0; j < maxEpPerInterface; j++)
hidInterfaces[i].epIndex[j] = 0;
}
for(uint8_t i = 0; i < totalEndpoints; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
bNumEP = 1;
bNumIface = 0;
bConfNum = 0;
pollInterval = 0;
ZeroMemory(constBuffLen, prevBuf);
}
bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
rptParsers[i].rptId = id;
rptParsers[i].rptParser = prs;
return true;
}
}
return false;
}
HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
if(!bHasReportId)
return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
if(rptParsers[i].rptId == id)
return rptParsers[i].rptParser;
}
return NULL;
}
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t len = 0;
uint8_t num_of_conf; // number of configurations
//uint8_t num_of_intf; // number of interfaces
AddressPool &addrPool = pUsb->GetAddressPool();
USBTRACE("HU Init\r\n");
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
if(!rcode)
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
goto FailGetDevDescr;
}
// Restore p->epinfo
p->epinfo = oldep_ptr;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
//delay(2); //per USB 2.0 sect.9.2.6.3
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
if(len)
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
if(rcode)
goto FailGetDevDescr;
VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
PID = udd->idProduct;
num_of_conf = udd->bNumConfigurations;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
ConfigDescParser<USB_CLASS_HID, 0, 0,
CP_MASK_COMPARE_CLASS> confDescrParser(this);
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
} // for
if(bNumEP < 2)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Cnf:", bConfNum);
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
for(uint8_t i = 0; i < bNumIface; i++) {
if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
continue;
rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
if(rcode && rcode != hrSTALL)
goto FailSetIdle;
}
USBTRACE("HU configured\r\n");
OnInitSuccessful();
bPollEnable = true;
return 0;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr();
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailSetIdle:
#ifdef DEBUG_USB_HOST
USBTRACE("SetIdle:");
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
&& hidInterfaces[i].bmProtocol == proto)
return hidInterfaces + i;
return NULL;
}
void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
// If the first configuration satisfies, the others are not concidered.
if(bNumEP > 1 && conf != bConfNum)
return;
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index = 0;
HIDInterface *piface = FindInterface(iface, alt, proto);
// Fill in interface structure in case of new interface
if(!piface) {
piface = hidInterfaces + bNumIface;
piface->bmInterface = iface;
piface->bmAltSet = alt;
piface->bmProtocol = proto;
bNumIface++;
}
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
index = epInterruptInIndex;
else
index = epInterruptOutIndex;
if(index) {
// Fill in the endpoint info structure
epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[bNumEP].epAttribs = 0;
epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
// Fill in the endpoint index list
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
pollInterval = pep->bInterval;
bNumEP++;
}
//PrintEndpointDescriptor(pep);
}
uint8_t HIDUniversal::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
for(uint8_t i = 0; i < len; i++)
if(buf1[i] != buf2[i])
return false;
return true;
}
void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
for(uint8_t i = 0; i < len; i++)
buf[i] = 0;
}
void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
for(uint8_t i = 0; i < len; i++)
dest[i] = src[i];
}
uint8_t HIDUniversal::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
if((long)(millis() - qNextPollTime) >= 0L) {
qNextPollTime = millis() + pollInterval;
uint8_t buf[constBuffLen];
for(uint8_t i = 0; i < bNumIface; i++) {
uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
uint16_t read = (uint16_t)epInfo[index].maxPktSize;
ZeroMemory(constBuffLen, buf);
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
if(rcode) {
if(rcode != hrNAK)
USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
return rcode;
}
if(read > constBuffLen)
read = constBuffLen;
bool identical = BuffersIdentical(read, buf, prevBuf);
SaveBuffer(read, buf, prevBuf);
if(identical)
return 0;
#if 0
Notify(PSTR("\r\nBuf: "), 0x80);
for(uint8_t i = 0; i < read; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
#endif
ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
if(prs)
prs->Parse(this, bHasReportId, (uint8_t)read, buf);
}
}
return rcode;
}

View file

@ -1,105 +1,105 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HIDUNIVERSAL_H__)
#define __HIDUNIVERSAL_H__
#include "hid.h"
//#include "hidescriptorparser.h"
class HIDUniversal : public HID {
struct ReportParser {
uint8_t rptId;
HIDReportParser *rptParser;
} rptParsers[MAX_REPORT_PARSERS];
// HID class specific descriptor type and length info obtained from HID descriptor
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
// Returns HID class specific descriptor length by its type and order number
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
struct HIDInterface {
struct {
uint8_t bmInterface : 3;
uint8_t bmAltSet : 3;
uint8_t bmProtocol : 2;
};
uint8_t epIndex[maxEpPerInterface];
};
uint8_t bConfNum; // configuration number
uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
uint8_t pollInterval;
bool bPollEnable; // poll enable flag
static const uint16_t constBuffLen = 64; // event buffer length
uint8_t prevBuf[constBuffLen]; // previous event buffer
void Initialize();
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto);
void ZeroMemory(uint8_t len, uint8_t *buf);
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2);
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
protected:
EpInfo epInfo[totalEndpoints];
HIDInterface hidInterfaces[maxHidInterfaces];
bool bHasReportId;
uint16_t PID, VID; // PID and VID of connected device
// HID implementation
HIDReportParser* GetReportParser(uint8_t id);
virtual uint8_t OnInitSuccessful() {
return 0;
};
virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
return;
};
public:
HIDUniversal(USB *p);
// HID implementation
bool SetReportParser(uint8_t id, HIDReportParser *prs);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return bPollEnable;
};
// UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
};
#endif // __HIDUNIVERSAL_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__HIDUNIVERSAL_H__)
#define __HIDUNIVERSAL_H__
#include "hid.h"
//#include "hidescriptorparser.h"
class HIDUniversal : public HID {
struct ReportParser {
uint8_t rptId;
HIDReportParser *rptParser;
} rptParsers[MAX_REPORT_PARSERS];
// HID class specific descriptor type and length info obtained from HID descriptor
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE descrInfo[HID_MAX_HID_CLASS_DESCRIPTORS];
// Returns HID class specific descriptor length by its type and order number
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
struct HIDInterface {
struct {
uint8_t bmInterface : 3;
uint8_t bmAltSet : 3;
uint8_t bmProtocol : 2;
};
uint8_t epIndex[maxEpPerInterface];
};
uint8_t bConfNum; // configuration number
uint8_t bNumIface; // number of interfaces in the configuration
uint8_t bNumEP; // total number of EP in the configuration
uint32_t qNextPollTime; // next poll time
uint8_t pollInterval;
bool bPollEnable; // poll enable flag
static const uint16_t constBuffLen = 64; // event buffer length
uint8_t prevBuf[constBuffLen]; // previous event buffer
void Initialize();
HIDInterface* FindInterface(uint8_t iface, uint8_t alt, uint8_t proto);
void ZeroMemory(uint8_t len, uint8_t *buf);
bool BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2);
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
protected:
EpInfo epInfo[totalEndpoints];
HIDInterface hidInterfaces[maxHidInterfaces];
bool bHasReportId;
uint16_t PID, VID; // PID and VID of connected device
// HID implementation
HIDReportParser* GetReportParser(uint8_t id);
virtual uint8_t OnInitSuccessful() {
return 0;
};
virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
return;
};
public:
HIDUniversal(USB *p);
// HID implementation
bool SetReportParser(uint8_t id, HIDReportParser *prs);
// USBDeviceConfig implementation
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool isReady() {
return bPollEnable;
};
// UsbConfigXtracter implementation
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
};
#endif // __HIDUNIVERSAL_H__

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,233 +1,233 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(_max3421e_h_)
#error "Never include max3421e.h directly; include Usb.h instead"
#else
#define _max3421e_h_
/* MAX3421E register/bit names and bitmasks */
/* Arduino pin definitions */
/* pin numbers to port numbers */
//#define MAX_INT 9 // Duemielanove
//#define MAX_GPX 8
#define SE0 0
#define SE1 1
#define FSHOST 2
#define LSHOST 3
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
//
// MAX3421E Registers in HOST mode.
//
#define rRCVFIFO 0x08 //1<<3
#define rSNDFIFO 0x10 //2<<3
#define rSUDFIFO 0x20 //4<<3
#define rRCVBC 0x30 //6<<3
#define rSNDBC 0x38 //7<<3
#define rUSBIRQ 0x68 //13<<3
/* USBIRQ Bits */
#define bmVBUSIRQ 0x40 //b6
#define bmNOVBUSIRQ 0x20 //b5
#define bmOSCOKIRQ 0x01 //b0
#define rUSBIEN 0x70 //14<<3
/* USBIEN Bits */
#define bmVBUSIE 0x40 //b6
#define bmNOVBUSIE 0x20 //b5
#define bmOSCOKIE 0x01 //b0
#define rUSBCTL 0x78 //15<<3
/* USBCTL Bits */
#define bmCHIPRES 0x20 //b5
#define bmPWRDOWN 0x10 //b4
#define rCPUCTL 0x80 //16<<3
/* CPUCTL Bits */
#define bmPUSLEWID1 0x80 //b7
#define bmPULSEWID0 0x40 //b6
#define bmIE 0x01 //b0
#define rPINCTL 0x88 //17<<3
/* PINCTL Bits */
#define bmFDUPSPI 0x10 //b4
#define bmINTLEVEL 0x08 //b3
#define bmPOSINT 0x04 //b2
#define bmGPXB 0x02 //b1
#define bmGPXA 0x01 //b0
// GPX pin selections
#define GPX_OPERATE 0x00
#define GPX_VBDET 0x01
#define GPX_BUSACT 0x02
#define GPX_SOF 0x03
#define rREVISION 0x90 //18<<3
#define rIOPINS1 0xa0 //20<<3
/* IOPINS1 Bits */
#define bmGPOUT0 0x01
#define bmGPOUT1 0x02
#define bmGPOUT2 0x04
#define bmGPOUT3 0x08
#define bmGPIN0 0x10
#define bmGPIN1 0x20
#define bmGPIN2 0x40
#define bmGPIN3 0x80
#define rIOPINS2 0xa8 //21<<3
/* IOPINS2 Bits */
#define bmGPOUT4 0x01
#define bmGPOUT5 0x02
#define bmGPOUT6 0x04
#define bmGPOUT7 0x08
#define bmGPIN4 0x10
#define bmGPIN5 0x20
#define bmGPIN6 0x40
#define bmGPIN7 0x80
#define rGPINIRQ 0xb0 //22<<3
/* GPINIRQ Bits */
#define bmGPINIRQ0 0x01
#define bmGPINIRQ1 0x02
#define bmGPINIRQ2 0x04
#define bmGPINIRQ3 0x08
#define bmGPINIRQ4 0x10
#define bmGPINIRQ5 0x20
#define bmGPINIRQ6 0x40
#define bmGPINIRQ7 0x80
#define rGPINIEN 0xb8 //23<<3
/* GPINIEN Bits */
#define bmGPINIEN0 0x01
#define bmGPINIEN1 0x02
#define bmGPINIEN2 0x04
#define bmGPINIEN3 0x08
#define bmGPINIEN4 0x10
#define bmGPINIEN5 0x20
#define bmGPINIEN6 0x40
#define bmGPINIEN7 0x80
#define rGPINPOL 0xc0 //24<<3
/* GPINPOL Bits */
#define bmGPINPOL0 0x01
#define bmGPINPOL1 0x02
#define bmGPINPOL2 0x04
#define bmGPINPOL3 0x08
#define bmGPINPOL4 0x10
#define bmGPINPOL5 0x20
#define bmGPINPOL6 0x40
#define bmGPINPOL7 0x80
#define rHIRQ 0xc8 //25<<3
/* HIRQ Bits */
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
#define bmRWUIRQ 0x02
#define bmRCVDAVIRQ 0x04
#define bmSNDBAVIRQ 0x08
#define bmSUSDNIRQ 0x10
#define bmCONDETIRQ 0x20
#define bmFRAMEIRQ 0x40
#define bmHXFRDNIRQ 0x80
#define rHIEN 0xd0 //26<<3
/* HIEN Bits */
#define bmBUSEVENTIE 0x01
#define bmRWUIE 0x02
#define bmRCVDAVIE 0x04
#define bmSNDBAVIE 0x08
#define bmSUSDNIE 0x10
#define bmCONDETIE 0x20
#define bmFRAMEIE 0x40
#define bmHXFRDNIE 0x80
#define rMODE 0xd8 //27<<3
/* MODE Bits */
#define bmHOST 0x01
#define bmLOWSPEED 0x02
#define bmHUBPRE 0x04
#define bmSOFKAENAB 0x08
#define bmSEPIRQ 0x10
#define bmDELAYISO 0x20
#define bmDMPULLDN 0x40
#define bmDPPULLDN 0x80
#define rPERADDR 0xe0 //28<<3
#define rHCTL 0xe8 //29<<3
/* HCTL Bits */
#define bmBUSRST 0x01
#define bmFRMRST 0x02
#define bmSAMPLEBUS 0x04
#define bmSIGRSM 0x08
#define bmRCVTOG0 0x10
#define bmRCVTOG1 0x20
#define bmSNDTOG0 0x40
#define bmSNDTOG1 0x80
#define rHXFR 0xf0 //30<<3
/* Host transfer token values for writing the HXFR register (R30) */
/* OR this bit field with the endpoint number in bits 3:0 */
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
#define rHRSL 0xf8 //31<<3
/* HRSL Bits */
#define bmRCVTOGRD 0x10
#define bmSNDTOGRD 0x20
#define bmKSTATUS 0x40
#define bmJSTATUS 0x80
#define bmSE0 0x00 //SE0 - disconnect state
#define bmSE1 0xc0 //SE1 - illegal state
/* Host error result codes, the 4 LSB's in the HRSL register */
#define hrSUCCESS 0x00
#define hrBUSY 0x01
#define hrBADREQ 0x02
#define hrUNDEF 0x03
#define hrNAK 0x04
#define hrSTALL 0x05
#define hrTOGERR 0x06
#define hrWRONGPID 0x07
#define hrBADBC 0x08
#define hrPIDERR 0x09
#define hrPKTERR 0x0A
#define hrCRCERR 0x0B
#define hrKERR 0x0C
#define hrJERR 0x0D
#define hrTIMEOUT 0x0E
#define hrBABBLE 0x0F
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
#endif //_max3421e_h_
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(_max3421e_h_)
#error "Never include max3421e.h directly; include Usb.h instead"
#else
#define _max3421e_h_
/* MAX3421E register/bit names and bitmasks */
/* Arduino pin definitions */
/* pin numbers to port numbers */
//#define MAX_INT 9 // Duemielanove
//#define MAX_GPX 8
#define SE0 0
#define SE1 1
#define FSHOST 2
#define LSHOST 3
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
//
// MAX3421E Registers in HOST mode.
//
#define rRCVFIFO 0x08 //1<<3
#define rSNDFIFO 0x10 //2<<3
#define rSUDFIFO 0x20 //4<<3
#define rRCVBC 0x30 //6<<3
#define rSNDBC 0x38 //7<<3
#define rUSBIRQ 0x68 //13<<3
/* USBIRQ Bits */
#define bmVBUSIRQ 0x40 //b6
#define bmNOVBUSIRQ 0x20 //b5
#define bmOSCOKIRQ 0x01 //b0
#define rUSBIEN 0x70 //14<<3
/* USBIEN Bits */
#define bmVBUSIE 0x40 //b6
#define bmNOVBUSIE 0x20 //b5
#define bmOSCOKIE 0x01 //b0
#define rUSBCTL 0x78 //15<<3
/* USBCTL Bits */
#define bmCHIPRES 0x20 //b5
#define bmPWRDOWN 0x10 //b4
#define rCPUCTL 0x80 //16<<3
/* CPUCTL Bits */
#define bmPUSLEWID1 0x80 //b7
#define bmPULSEWID0 0x40 //b6
#define bmIE 0x01 //b0
#define rPINCTL 0x88 //17<<3
/* PINCTL Bits */
#define bmFDUPSPI 0x10 //b4
#define bmINTLEVEL 0x08 //b3
#define bmPOSINT 0x04 //b2
#define bmGPXB 0x02 //b1
#define bmGPXA 0x01 //b0
// GPX pin selections
#define GPX_OPERATE 0x00
#define GPX_VBDET 0x01
#define GPX_BUSACT 0x02
#define GPX_SOF 0x03
#define rREVISION 0x90 //18<<3
#define rIOPINS1 0xa0 //20<<3
/* IOPINS1 Bits */
#define bmGPOUT0 0x01
#define bmGPOUT1 0x02
#define bmGPOUT2 0x04
#define bmGPOUT3 0x08
#define bmGPIN0 0x10
#define bmGPIN1 0x20
#define bmGPIN2 0x40
#define bmGPIN3 0x80
#define rIOPINS2 0xa8 //21<<3
/* IOPINS2 Bits */
#define bmGPOUT4 0x01
#define bmGPOUT5 0x02
#define bmGPOUT6 0x04
#define bmGPOUT7 0x08
#define bmGPIN4 0x10
#define bmGPIN5 0x20
#define bmGPIN6 0x40
#define bmGPIN7 0x80
#define rGPINIRQ 0xb0 //22<<3
/* GPINIRQ Bits */
#define bmGPINIRQ0 0x01
#define bmGPINIRQ1 0x02
#define bmGPINIRQ2 0x04
#define bmGPINIRQ3 0x08
#define bmGPINIRQ4 0x10
#define bmGPINIRQ5 0x20
#define bmGPINIRQ6 0x40
#define bmGPINIRQ7 0x80
#define rGPINIEN 0xb8 //23<<3
/* GPINIEN Bits */
#define bmGPINIEN0 0x01
#define bmGPINIEN1 0x02
#define bmGPINIEN2 0x04
#define bmGPINIEN3 0x08
#define bmGPINIEN4 0x10
#define bmGPINIEN5 0x20
#define bmGPINIEN6 0x40
#define bmGPINIEN7 0x80
#define rGPINPOL 0xc0 //24<<3
/* GPINPOL Bits */
#define bmGPINPOL0 0x01
#define bmGPINPOL1 0x02
#define bmGPINPOL2 0x04
#define bmGPINPOL3 0x08
#define bmGPINPOL4 0x10
#define bmGPINPOL5 0x20
#define bmGPINPOL6 0x40
#define bmGPINPOL7 0x80
#define rHIRQ 0xc8 //25<<3
/* HIRQ Bits */
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
#define bmRWUIRQ 0x02
#define bmRCVDAVIRQ 0x04
#define bmSNDBAVIRQ 0x08
#define bmSUSDNIRQ 0x10
#define bmCONDETIRQ 0x20
#define bmFRAMEIRQ 0x40
#define bmHXFRDNIRQ 0x80
#define rHIEN 0xd0 //26<<3
/* HIEN Bits */
#define bmBUSEVENTIE 0x01
#define bmRWUIE 0x02
#define bmRCVDAVIE 0x04
#define bmSNDBAVIE 0x08
#define bmSUSDNIE 0x10
#define bmCONDETIE 0x20
#define bmFRAMEIE 0x40
#define bmHXFRDNIE 0x80
#define rMODE 0xd8 //27<<3
/* MODE Bits */
#define bmHOST 0x01
#define bmLOWSPEED 0x02
#define bmHUBPRE 0x04
#define bmSOFKAENAB 0x08
#define bmSEPIRQ 0x10
#define bmDELAYISO 0x20
#define bmDMPULLDN 0x40
#define bmDPPULLDN 0x80
#define rPERADDR 0xe0 //28<<3
#define rHCTL 0xe8 //29<<3
/* HCTL Bits */
#define bmBUSRST 0x01
#define bmFRMRST 0x02
#define bmSAMPLEBUS 0x04
#define bmSIGRSM 0x08
#define bmRCVTOG0 0x10
#define bmRCVTOG1 0x20
#define bmSNDTOG0 0x40
#define bmSNDTOG1 0x80
#define rHXFR 0xf0 //30<<3
/* Host transfer token values for writing the HXFR register (R30) */
/* OR this bit field with the endpoint number in bits 3:0 */
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
#define rHRSL 0xf8 //31<<3
/* HRSL Bits */
#define bmRCVTOGRD 0x10
#define bmSNDTOGRD 0x20
#define bmKSTATUS 0x40
#define bmJSTATUS 0x80
#define bmSE0 0x00 //SE0 - disconnect state
#define bmSE1 0xc0 //SE1 - illegal state
/* Host error result codes, the 4 LSB's in the HRSL register */
#define hrSUCCESS 0x00
#define hrBUSY 0x01
#define hrBADREQ 0x02
#define hrUNDEF 0x03
#define hrNAK 0x04
#define hrSTALL 0x05
#define hrTOGERR 0x06
#define hrWRONGPID 0x07
#define hrBADBC 0x08
#define hrPIDERR 0x09
#define hrPKTERR 0x0A
#define hrCRCERR 0x0B
#define hrKERR 0x0C
#define hrJERR 0x0D
#define hrTIMEOUT 0x0E
#define hrBABBLE 0x0F
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
#endif //_max3421e_h_

View file

@ -1,255 +1,255 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "max_LCD.h"
#include <string.h>
// pin definition and set/clear
#define RS 0x04 // RS pin
#define E 0x08 // E pin
#define SET_RS lcdPins |= RS
#define CLR_RS lcdPins &= ~RS
#define SET_E lcdPins |= E
#define CLR_E lcdPins &= ~E
#define SENDlcdPins() pUsb->gpioWr( lcdPins )
#define LCD_sendcmd(a) { CLR_RS; \
sendbyte(a); \
}
#define LCD_sendchar(a) { SET_RS; \
sendbyte(a); \
}
static byte lcdPins; //copy of LCD pins
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) {
lcdPins = 0;
}
void Max_LCD::init() {
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
// MAX3421E::gpioWr(0x55);
begin(16, 1);
}
void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
if(lines > 1) {
_displayfunction |= LCD_2LINE;
}
_numlines = lines;
_currline = 0;
// for some 1 line displays you can select a 10 pixel high font
if((dotsize != 0) && (lines == 1)) {
_displayfunction |= LCD_5x10DOTS;
}
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
delayMicroseconds(50000);
lcdPins = 0x30;
SET_E;
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(10000); // wait min 4.1ms
//second try
SET_E;
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(10000); // wait min 4.1ms
// third go!
SET_E;
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(10000);
// finally, set to 4-bit interface
lcdPins = 0x20;
//SET_RS;
SET_E;
SENDlcdPins();
//CLR_RS;
CLR_E;
SENDlcdPins();
delayMicroseconds(10000);
// finally, set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();
// clear it off
clear();
// Initialize to default text direction (for romance languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
command(LCD_ENTRYMODESET | _displaymode);
}
/********** high level commands, for the user! */
void Max_LCD::clear() {
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void Max_LCD::home() {
command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void Max_LCD::setCursor(uint8_t col, uint8_t row) {
int row_offsets[] = {0x00, 0x40, 0x14, 0x54};
if(row > _numlines) {
row = _numlines - 1; // we count rows starting w/0
}
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
// Turn the display on/off (quickly)
void Max_LCD::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::display() {
_displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void Max_LCD::noCursor() {
_displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::cursor() {
_displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turn on and off the blinking cursor
void Max_LCD::noBlink() {
_displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::blink() {
_displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void Max_LCD::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void Max_LCD::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void Max_LCD::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void Max_LCD::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void Max_LCD::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void Max_LCD::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for(int i = 0; i < 8; i++) {
write(charmap[i]);
}
}
/*********** mid level commands, for sending data/cmds */
inline void Max_LCD::command(uint8_t value) {
LCD_sendcmd(value);
delayMicroseconds(100);
}
#if defined(ARDUINO) && ARDUINO >=100
inline size_t Max_LCD::write(uint8_t value) {
LCD_sendchar(value);
return 1; // Assume success
}
#else
inline void Max_LCD::write(uint8_t value) {
LCD_sendchar(value);
}
#endif
void Max_LCD::sendbyte(uint8_t val) {
lcdPins &= 0x0f; //prepare place for the upper nibble
lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable
SET_E; //send
SENDlcdPins();
delayMicroseconds(2);
CLR_E;
delayMicroseconds(2);
SENDlcdPins();
lcdPins &= 0x0f; //prepare place for the lower nibble
lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable
SET_E; //send
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(100);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "max_LCD.h"
#include <string.h>
// pin definition and set/clear
#define RS 0x04 // RS pin
#define E 0x08 // E pin
#define SET_RS lcdPins |= RS
#define CLR_RS lcdPins &= ~RS
#define SET_E lcdPins |= E
#define CLR_E lcdPins &= ~E
#define SENDlcdPins() pUsb->gpioWr( lcdPins )
#define LCD_sendcmd(a) { CLR_RS; \
sendbyte(a); \
}
#define LCD_sendchar(a) { SET_RS; \
sendbyte(a); \
}
static byte lcdPins; //copy of LCD pins
Max_LCD::Max_LCD(USB *pusb) : pUsb(pusb) {
lcdPins = 0;
}
void Max_LCD::init() {
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
// MAX3421E::gpioWr(0x55);
begin(16, 1);
}
void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
if(lines > 1) {
_displayfunction |= LCD_2LINE;
}
_numlines = lines;
_currline = 0;
// for some 1 line displays you can select a 10 pixel high font
if((dotsize != 0) && (lines == 1)) {
_displayfunction |= LCD_5x10DOTS;
}
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
// according to datasheet, we need at least 40ms after power rises above 2.7V
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
delayMicroseconds(50000);
lcdPins = 0x30;
SET_E;
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(10000); // wait min 4.1ms
//second try
SET_E;
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(10000); // wait min 4.1ms
// third go!
SET_E;
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(10000);
// finally, set to 4-bit interface
lcdPins = 0x20;
//SET_RS;
SET_E;
SENDlcdPins();
//CLR_RS;
CLR_E;
SENDlcdPins();
delayMicroseconds(10000);
// finally, set # lines, font size, etc.
command(LCD_FUNCTIONSET | _displayfunction);
// turn the display on with no cursor or blinking default
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();
// clear it off
clear();
// Initialize to default text direction (for romance languages)
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
command(LCD_ENTRYMODESET | _displaymode);
}
/********** high level commands, for the user! */
void Max_LCD::clear() {
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void Max_LCD::home() {
command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
}
void Max_LCD::setCursor(uint8_t col, uint8_t row) {
int row_offsets[] = {0x00, 0x40, 0x14, 0x54};
if(row > _numlines) {
row = _numlines - 1; // we count rows starting w/0
}
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
// Turn the display on/off (quickly)
void Max_LCD::noDisplay() {
_displaycontrol &= ~LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::display() {
_displaycontrol |= LCD_DISPLAYON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turns the underline cursor on/off
void Max_LCD::noCursor() {
_displaycontrol &= ~LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::cursor() {
_displaycontrol |= LCD_CURSORON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// Turn on and off the blinking cursor
void Max_LCD::noBlink() {
_displaycontrol &= ~LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void Max_LCD::blink() {
_displaycontrol |= LCD_BLINKON;
command(LCD_DISPLAYCONTROL | _displaycontrol);
}
// These commands scroll the display without changing the RAM
void Max_LCD::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void Max_LCD::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void Max_LCD::leftToRight(void) {
_displaymode |= LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This is for text that flows Right to Left
void Max_LCD::rightToLeft(void) {
_displaymode &= ~LCD_ENTRYLEFT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'right justify' text from the cursor
void Max_LCD::autoscroll(void) {
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// This will 'left justify' text from the cursor
void Max_LCD::noAutoscroll(void) {
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
command(LCD_ENTRYMODESET | _displaymode);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for(int i = 0; i < 8; i++) {
write(charmap[i]);
}
}
/*********** mid level commands, for sending data/cmds */
inline void Max_LCD::command(uint8_t value) {
LCD_sendcmd(value);
delayMicroseconds(100);
}
#if defined(ARDUINO) && ARDUINO >=100
inline size_t Max_LCD::write(uint8_t value) {
LCD_sendchar(value);
return 1; // Assume success
}
#else
inline void Max_LCD::write(uint8_t value) {
LCD_sendchar(value);
}
#endif
void Max_LCD::sendbyte(uint8_t val) {
lcdPins &= 0x0f; //prepare place for the upper nibble
lcdPins |= (val & 0xf0); //copy upper nibble to LCD variable
SET_E; //send
SENDlcdPins();
delayMicroseconds(2);
CLR_E;
delayMicroseconds(2);
SENDlcdPins();
lcdPins &= 0x0f; //prepare place for the lower nibble
lcdPins |= (val << 4) & 0xf0; //copy lower nibble to LCD variable
SET_E; //send
SENDlcdPins();
CLR_E;
SENDlcdPins();
delayMicroseconds(100);
}

212
max_LCD.h
View file

@ -1,106 +1,106 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
//HD44780 compatible LCD display via MAX3421E GPOUT support header
//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3]
//
#ifndef _Max_LCD_h_
#define _Max_LCD_h_
#include "Usb.h"
#include "Print.h"
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
class Max_LCD : public Print {
USB *pUsb;
public:
Max_LCD(USB *pusb);
void init();
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void clear();
void home();
void noDisplay();
void display();
void noBlink();
void blink();
void noCursor();
void cursor();
void scrollDisplayLeft();
void scrollDisplayRight();
void leftToRight();
void rightToLeft();
void autoscroll();
void noAutoscroll();
void createChar(uint8_t, uint8_t[]);
void setCursor(uint8_t, uint8_t);
void command(uint8_t);
#if defined(ARDUINO) && ARDUINO >=100
size_t write(uint8_t);
using Print::write;
#else
void write(uint8_t);
#endif
private:
void sendbyte(uint8_t val);
uint8_t _displayfunction; //tokill
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines, _currline;
};
#endif
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
//HD44780 compatible LCD display via MAX3421E GPOUT support header
//pinout: D[4-7] -> GPOUT[4-7], RS-> GPOUT[2], E ->GPOUT[3]
//
#ifndef _Max_LCD_h_
#define _Max_LCD_h_
#include "Usb.h"
#include "Print.h"
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
class Max_LCD : public Print {
USB *pUsb;
public:
Max_LCD(USB *pusb);
void init();
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void clear();
void home();
void noDisplay();
void display();
void noBlink();
void blink();
void noCursor();
void cursor();
void scrollDisplayLeft();
void scrollDisplayRight();
void leftToRight();
void rightToLeft();
void autoscroll();
void noAutoscroll();
void createChar(uint8_t, uint8_t[]);
void setCursor(uint8_t, uint8_t);
void command(uint8_t);
#if defined(ARDUINO) && ARDUINO >=100
size_t write(uint8_t);
using Print::write;
#else
void write(uint8_t);
#endif
private:
void sendbyte(uint8_t val);
uint8_t _displayfunction; //tokill
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines, _currline;
};
#endif

View file

@ -1,116 +1,116 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "Usb.h"
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
// this allows for 126 other debugging levels.
// TO-DO: Allow assignment to a different serial port by software
int UsbDEBUGlvl = 0x80;
void E_Notifyc(char c, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(c);
#else
USB_HOST_SERIAL.print(c, BYTE);
#endif
//USB_HOST_SERIAL.flush();
}
void E_Notify(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
}
void E_NotifyStr(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = *msg++)) E_Notifyc(c, lvl);
}
void E_Notify(uint8_t b, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(b);
#else
USB_HOST_SERIAL.print(b, DEC);
#endif
//USB_HOST_SERIAL.flush();
}
void E_Notify(double d, int lvl) {
if(UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(d);
//USB_HOST_SERIAL.flush();
}
#ifdef DEBUG_USB_HOST
void NotifyFailGetDevDescr(void) {
Notify(PSTR("\r\ngetDevDescr "), 0x80);
}
void NotifyFailSetDevTblEntry(void) {
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
}
void NotifyFailGetConfDescr(void) {
Notify(PSTR("\r\ngetConf "), 0x80);
}
void NotifyFailSetConfDescr(void) {
Notify(PSTR("\r\nsetConf "), 0x80);
}
void NotifyFailGetDevDescr(uint8_t reason) {
NotifyFailGetDevDescr();
NotifyFail(reason);
}
void NotifyFailSetDevTblEntry(uint8_t reason) {
NotifyFailSetDevTblEntry();
NotifyFail(reason);
}
void NotifyFailGetConfDescr(uint8_t reason) {
NotifyFailGetConfDescr();
NotifyFail(reason);
}
void NotifyFailSetConfDescr(uint8_t reason) {
NotifyFailSetConfDescr();
NotifyFail(reason);
}
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
D_PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
D_PrintHex<uint16_t > (PID, 0x80);
}
void NotifyFail(uint8_t rcode) {
D_PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
#endif
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "Usb.h"
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
// this allows for 126 other debugging levels.
// TO-DO: Allow assignment to a different serial port by software
int UsbDEBUGlvl = 0x80;
void E_Notifyc(char c, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(c);
#else
USB_HOST_SERIAL.print(c, BYTE);
#endif
//USB_HOST_SERIAL.flush();
}
void E_Notify(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
}
void E_NotifyStr(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = *msg++)) E_Notifyc(c, lvl);
}
void E_Notify(uint8_t b, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(b);
#else
USB_HOST_SERIAL.print(b, DEC);
#endif
//USB_HOST_SERIAL.flush();
}
void E_Notify(double d, int lvl) {
if(UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(d);
//USB_HOST_SERIAL.flush();
}
#ifdef DEBUG_USB_HOST
void NotifyFailGetDevDescr(void) {
Notify(PSTR("\r\ngetDevDescr "), 0x80);
}
void NotifyFailSetDevTblEntry(void) {
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
}
void NotifyFailGetConfDescr(void) {
Notify(PSTR("\r\ngetConf "), 0x80);
}
void NotifyFailSetConfDescr(void) {
Notify(PSTR("\r\nsetConf "), 0x80);
}
void NotifyFailGetDevDescr(uint8_t reason) {
NotifyFailGetDevDescr();
NotifyFail(reason);
}
void NotifyFailSetDevTblEntry(uint8_t reason) {
NotifyFailSetDevTblEntry();
NotifyFail(reason);
}
void NotifyFailGetConfDescr(uint8_t reason) {
NotifyFailGetConfDescr();
NotifyFail(reason);
}
void NotifyFailSetConfDescr(uint8_t reason) {
NotifyFailSetConfDescr();
NotifyFail(reason);
}
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
D_PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
D_PrintHex<uint16_t > (PID, 0x80);
}
void NotifyFail(uint8_t rcode) {
D_PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
#endif

156
message.h
View file

@ -1,78 +1,78 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__MESSAGE_H__)
#error "Never include message.h directly; include Usb.h instead"
#else
#define __MESSAGE_H__
extern int UsbDEBUGlvl;
void E_Notify(char const * msg, int lvl);
void E_Notify(uint8_t b, int lvl);
void E_NotifyStr(char const * msg, int lvl);
void E_Notifyc(char c, int lvl);
#ifdef DEBUG_USB_HOST
#define Notify E_Notify
#define NotifyStr E_NotifyStr
#define Notifyc E_Notifyc
void NotifyFailGetDevDescr(uint8_t reason);
void NotifyFailSetDevTblEntry(uint8_t reason);
void NotifyFailGetConfDescr(uint8_t reason);
void NotifyFailSetConfDescr(uint8_t reason);
void NotifyFailGetDevDescr(void);
void NotifyFailSetDevTblEntry(void);
void NotifyFailGetConfDescr(void);
void NotifyFailSetConfDescr(void);
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
void NotifyFail(uint8_t rcode);
#else
#define Notify(...) ((void)0)
#define NotifyStr(...) ((void)0)
#define Notifyc(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailSetConfDescr(...) ((void)0)
#define NotifyFailUnknownDevice(...) ((void)0)
#define NotifyFail(...) ((void)0)
#endif
template <class ERROR_TYPE>
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, level);
Notify(PSTR(": "), level);
D_PrintHex<ERROR_TYPE > (rcode, level);
Notify(PSTR("\r\n"), level);
#endif
}
template <class ERROR_TYPE>
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
#endif
}
#endif // __MESSAGE_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__MESSAGE_H__)
#error "Never include message.h directly; include Usb.h instead"
#else
#define __MESSAGE_H__
extern int UsbDEBUGlvl;
void E_Notify(char const * msg, int lvl);
void E_Notify(uint8_t b, int lvl);
void E_NotifyStr(char const * msg, int lvl);
void E_Notifyc(char c, int lvl);
#ifdef DEBUG_USB_HOST
#define Notify E_Notify
#define NotifyStr E_NotifyStr
#define Notifyc E_Notifyc
void NotifyFailGetDevDescr(uint8_t reason);
void NotifyFailSetDevTblEntry(uint8_t reason);
void NotifyFailGetConfDescr(uint8_t reason);
void NotifyFailSetConfDescr(uint8_t reason);
void NotifyFailGetDevDescr(void);
void NotifyFailSetDevTblEntry(void);
void NotifyFailGetConfDescr(void);
void NotifyFailSetConfDescr(void);
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
void NotifyFail(uint8_t rcode);
#else
#define Notify(...) ((void)0)
#define NotifyStr(...) ((void)0)
#define Notifyc(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailSetConfDescr(...) ((void)0)
#define NotifyFailUnknownDevice(...) ((void)0)
#define NotifyFail(...) ((void)0)
#endif
template <class ERROR_TYPE>
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, level);
Notify(PSTR(": "), level);
D_PrintHex<ERROR_TYPE > (rcode, level);
Notify(PSTR("\r\n"), level);
#endif
}
template <class ERROR_TYPE>
void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
#endif
}
#endif // __MESSAGE_H__

View file

@ -1,67 +1,67 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "Usb.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
if(!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for(; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize - countDown] = (**pp);
if(countDown)
return false;
countDown = valueSize;
return true;
}
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
switch(nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
case 1:
if(!theParser.Parse(pp, pcntdn))
return false;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 3:
for(; arLenCntdn; arLenCntdn--) {
if(!theParser.Parse(pp, pcntdn))
return false;
if(pf)
pf(pBuf, (arLen - arLenCntdn), me);
}
nStage = 0;
}
return true;
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "Usb.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
if(!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for(; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize - countDown] = (**pp);
if(countDown)
return false;
countDown = valueSize;
return true;
}
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
switch(nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
case 1:
if(!theParser.Parse(pp, pcntdn))
return false;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 3:
for(; arLenCntdn; arLenCntdn--) {
if(!theParser.Parse(pp, pcntdn))
return false;
if(pf)
pf(pBuf, (arLen - arLenCntdn), me);
}
nStage = 0;
}
return true;
}

View file

@ -1,140 +1,140 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__PARSETOOLS_H__)
#error "Never include parsetools.h directly; include Usb.h instead"
#else
#define __PARSETOOLS_H__
struct MultiValueBuffer {
uint8_t valueSize;
void *pValue;
} __attribute__((packed));
class MultiByteValueParser {
uint8_t * pBuf;
uint8_t countDown;
uint8_t valueSize;
public:
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
const uint8_t* GetBuffer() {
return pBuf;
};
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
};
bool Parse(uint8_t **pp, uint16_t *pcntdn);
};
class ByteSkipper {
uint8_t *pBuf;
uint8_t nStage;
uint16_t countDown;
public:
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
};
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = 0;
};
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
switch(nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if(!countDown)
nStage = 0;
};
return (!countDown);
};
};
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
class PTPListParser {
public:
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private:
uint8_t nStage;
uint8_t enStage;
uint32_t arLen;
uint32_t arLenCntdn;
uint8_t lenSize; // size of the array length field in bytes
uint8_t valSize; // size of the array element in bytes
MultiValueBuffer *pBuf;
// The only parser for both size and array element parsing
MultiByteValueParser theParser;
uint8_t /*ParseMode*/ prsMode;
public:
PTPListParser() :
nStage(0),
enStage(0),
arLen(0),
arLenCntdn(0),
lenSize(0),
valSize(0),
pBuf(NULL),
prsMode(modeArray) {
};
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
pBuf = p;
lenSize = len_size;
valSize = val_size;
prsMode = mode;
if(prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
} else {
arLenCntdn = arLen = 0;
nStage = 0;
}
enStage = 0;
theParser.Initialize(p);
};
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
};
#endif // __PARSETOOLS_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__PARSETOOLS_H__)
#error "Never include parsetools.h directly; include Usb.h instead"
#else
#define __PARSETOOLS_H__
struct MultiValueBuffer {
uint8_t valueSize;
void *pValue;
} __attribute__((packed));
class MultiByteValueParser {
uint8_t * pBuf;
uint8_t countDown;
uint8_t valueSize;
public:
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
const uint8_t* GetBuffer() {
return pBuf;
};
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
};
bool Parse(uint8_t **pp, uint16_t *pcntdn);
};
class ByteSkipper {
uint8_t *pBuf;
uint8_t nStage;
uint16_t countDown;
public:
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
};
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = 0;
};
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
switch(nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if(!countDown)
nStage = 0;
};
return (!countDown);
};
};
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
class PTPListParser {
public:
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private:
uint8_t nStage;
uint8_t enStage;
uint32_t arLen;
uint32_t arLenCntdn;
uint8_t lenSize; // size of the array length field in bytes
uint8_t valSize; // size of the array element in bytes
MultiValueBuffer *pBuf;
// The only parser for both size and array element parsing
MultiByteValueParser theParser;
uint8_t /*ParseMode*/ prsMode;
public:
PTPListParser() :
nStage(0),
enStage(0),
arLen(0),
arLenCntdn(0),
lenSize(0),
valSize(0),
pBuf(NULL),
prsMode(modeArray) {
};
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
pBuf = p;
lenSize = len_size;
valSize = val_size;
prsMode = mode;
if(prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
} else {
arLenCntdn = arLen = 0;
nStage = 0;
}
enStage = 0;
theParser.Initialize(p);
};
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
};
#endif // __PARSETOOLS_H__

332
usb_ch9.h
View file

@ -1,166 +1,166 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(_ch9_h_)
#error "Never include usb_ch9.h directly; include Usb.h instead"
#else
/* USB chapter 9 structures */
#define _ch9_h_
/* Misc.USB constants */
#define DEV_DESCR_LEN 18 //device descriptor length
#define CONF_DESCR_LEN 9 //configuration descriptor length
#define INTR_DESCR_LEN 9 //interface descriptor length
#define EP_DESCR_LEN 7 //endpoint descriptor length
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
/* Setup Data Constants */
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
/* USB descriptors */
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
#define HID_DESCRIPTOR_HID 0x21
/* OTG SET FEATURE Constants */
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
/* USB Endpoint Transfer Types */
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
#define USB_FEATURE_TEST_MODE 2 // Device recipient
/* descriptor data structures */
/* Device descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
uint16_t bcdUSB; // USB Spec Release Number (BCD).
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
uint16_t idProduct; // Product ID (assigned by the manufacturer).
uint16_t bcdDevice; // Device release number (BCD).
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations.
} __attribute__((packed)) USB_DEVICE_DESCRIPTOR;
/* Configuration descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
uint8_t bConfigurationValue; // Value of this configuration (1 based).
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
uint8_t bmAttributes; // Configuration characteristics.
uint8_t bMaxPower; // Maximum power consumed by this configuration.
} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR;
/* Interface descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
uint8_t bInterfaceNumber; // Number of this interface (0 based).
uint8_t bAlternateSetting; // Value of this alternate interface setting.
uint8_t bNumEndpoints; // Number of endpoints in this interface.
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t iInterface; // Index of String Descriptor describing the interface.
} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR;
/* Endpoint descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
uint8_t bmAttributes; // Endpoint transfer type.
uint16_t wMaxPacketSize; // Maximum packet size.
uint8_t bInterval; // Polling interval in frames.
} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR;
/* HID descriptor */
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID; // HID class specification release
uint8_t bCountryCode;
uint8_t bNumDescriptors; // Number of additional class specific descriptors
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} __attribute__((packed)) USB_HID_DESCRIPTOR;
typedef struct {
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
#endif // _ch9_h_
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(_ch9_h_)
#error "Never include usb_ch9.h directly; include Usb.h instead"
#else
/* USB chapter 9 structures */
#define _ch9_h_
/* Misc.USB constants */
#define DEV_DESCR_LEN 18 //device descriptor length
#define CONF_DESCR_LEN 9 //configuration descriptor length
#define INTR_DESCR_LEN 9 //interface descriptor length
#define EP_DESCR_LEN 7 //endpoint descriptor length
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
/* Setup Data Constants */
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
/* USB descriptors */
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
#define HID_DESCRIPTOR_HID 0x21
/* OTG SET FEATURE Constants */
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
/* USB Endpoint Transfer Types */
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
#define USB_FEATURE_TEST_MODE 2 // Device recipient
/* descriptor data structures */
/* Device descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
uint16_t bcdUSB; // USB Spec Release Number (BCD).
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
uint16_t idProduct; // Product ID (assigned by the manufacturer).
uint16_t bcdDevice; // Device release number (BCD).
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations.
} __attribute__((packed)) USB_DEVICE_DESCRIPTOR;
/* Configuration descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
uint8_t bConfigurationValue; // Value of this configuration (1 based).
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
uint8_t bmAttributes; // Configuration characteristics.
uint8_t bMaxPower; // Maximum power consumed by this configuration.
} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR;
/* Interface descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
uint8_t bInterfaceNumber; // Number of this interface (0 based).
uint8_t bAlternateSetting; // Value of this alternate interface setting.
uint8_t bNumEndpoints; // Number of endpoints in this interface.
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t iInterface; // Index of String Descriptor describing the interface.
} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR;
/* Endpoint descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
uint8_t bmAttributes; // Endpoint transfer type.
uint16_t wMaxPacketSize; // Maximum packet size.
uint8_t bInterval; // Polling interval in frames.
} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR;
/* HID descriptor */
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID; // HID class specification release
uint8_t bCountryCode;
uint8_t bNumDescriptors; // Number of additional class specific descriptors
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} __attribute__((packed)) USB_HID_DESCRIPTOR;
typedef struct {
uint8_t bDescrType; // Type of class descriptor
uint16_t wDescriptorLength; // Total size of the Report descriptor
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
#endif // _ch9_h_

916
usbhost.h
View file

@ -1,458 +1,458 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* MAX3421E-based USB Host Library header file */
#if !defined(_usb_h_) || defined(_USBHOST_H_)
#error "Never include usbhost.h directly; include Usb.h instead"
#else
#define _USBHOST_H_
#if USING_SPI4TEENSY3
#include <spi4teensy3.h>
#include <sys/types.h>
#endif
/* SPI initialization */
template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
public:
#if USING_SPI4TEENSY3
static void init() {
// spi4teensy3 inits everything for us, except /SS
// CLK, MOSI and MISO are hard coded for now.
// spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0
spi4teensy3::init(); // full speed, cpol 0, cpha 0
SPI_SS::SetDirWrite();
SPI_SS::Set();
}
#elif !defined(SPDR)
static void init() {
SPI_SS::SetDirWrite();
SPI_SS::Set();
SPI.begin();
#if defined(__MIPSEL__)
SPI.setClockDivider(1);
#else
SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
#endif
}
#else
static void init() {
//uint8_t tmp;
SPI_CLK::SetDirWrite();
SPI_MOSI::SetDirWrite();
SPI_MISO::SetDirRead();
SPI_SS::SetDirWrite();
/* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
SPCR = 0x50;
SPSR = 0x01; // 0x01
/**/
//tmp = SPSR;
//tmp = SPDR;
}
#endif
};
/* SPI pin definitions. see avrpins.h */
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
#elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))
typedef SPi< P13, P11, P12, P10 > spi;
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
typedef SPi< P76, P75, P74, P10 > spi;
#elif defined(__MIPSEL__)
typedef SPi< P13, P11, P12, P10 > spi;
#else
#error "No SPI entry in usbhost.h"
#endif
typedef enum {
vbus_on = 0,
vbus_off = GPX_VBDET
} VBUS_t;
template< typename SPI_SS, typename INTR > class MAX3421e /* : public spi */ {
static uint8_t vbusState;
public:
MAX3421e();
void regWr(uint8_t reg, uint8_t data);
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
void gpioWr(uint8_t data);
uint8_t regRd(uint8_t reg);
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
uint8_t gpioRd();
uint16_t reset();
int8_t Init();
int8_t Init(int mseconds);
void vbusPower(VBUS_t state) {
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state));
}
uint8_t getVbusState(void) {
return vbusState;
};
void busprobe();
uint8_t GpxHandler();
uint8_t IntHandler();
uint8_t Task();
};
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::vbusState = 0;
/* constructor */
template< typename SPI_SS, typename INTR >
MAX3421e< SPI_SS, INTR >::MAX3421e() {
// Leaving ADK hardware setup in here, for now. This really belongs with the other parts.
#ifdef BOARD_MEGA_ADK
// For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH
P55::SetDirWrite();
P55::Set();
#endif
};
/* write single byte into MAX3421 register */
template< typename SPI_SS, typename INTR >
void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
uint8_t c[2];
c[0] = reg | 0x02;
c[1] = data;
spi4teensy3::send(c, 2);
#elif !defined(SPDR)
SPI.transfer(reg | 0x02);
SPI.transfer(data);
#else
SPDR = (reg | 0x02);
while(!(SPSR & (1 << SPIF)));
SPDR = data;
while(!(SPSR & (1 << SPIF)));
#endif
SPI_SS::Set();
XMEM_RELEASE_SPI();
return;
};
/* multiple-byte write */
/* returns a pointer to memory position after last written */
template< typename SPI_SS, typename INTR >
uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
spi4teensy3::send(reg | 0x02);
spi4teensy3::send(data_p, nbytes);
data_p += nbytes;
#elif !defined(SPDR)
SPI.transfer(reg | 0x02);
while(nbytes) {
SPI.transfer(*data_p);
nbytes--;
data_p++; // advance data pointer
}
#else
SPDR = (reg | 0x02); //set WR bit and send register number
while(nbytes) {
while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
SPDR = (*data_p); // send next data byte
nbytes--;
data_p++; // advance data pointer
}
while(!(SPSR & (1 << SPIF)));
#endif
SPI_SS::Set();
XMEM_RELEASE_SPI();
return ( data_p);
}
/* GPIO write */
/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
template< typename SPI_SS, typename INTR >
void MAX3421e< SPI_SS, INTR >::gpioWr(uint8_t data) {
regWr(rIOPINS1, data);
data >>= 4;
regWr(rIOPINS2, data);
return;
}
/* single host register read */
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
spi4teensy3::send(reg);
uint8_t rv = spi4teensy3::receive();
SPI_SS::Set();
#elif !defined(SPDR)
SPI.transfer(reg);
uint8_t rv = SPI.transfer(0);
SPI_SS::Set();
#else
SPDR = reg;
while(!(SPSR & (1 << SPIF)));
SPDR = 0; //send empty byte
while(!(SPSR & (1 << SPIF)));
SPI_SS::Set();
uint8_t rv = SPDR;
#endif
XMEM_RELEASE_SPI();
return (rv);
}
/* multiple-byte register read */
/* returns a pointer to a memory position after last read */
template< typename SPI_SS, typename INTR >
uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
spi4teensy3::send(reg);
spi4teensy3::receive(data_p, nbytes);
data_p += nbytes;
#elif !defined(SPDR)
SPI.transfer(reg);
while(nbytes) {
*data_p++ = SPI.transfer(0);
nbytes--;
}
#else
SPDR = reg;
while(!(SPSR & (1 << SPIF))); //wait
while(nbytes) {
SPDR = 0; //send empty byte
nbytes--;
while(!(SPSR & (1 << SPIF)));
#if 0
{
*data_p = SPDR;
printf("%2.2x ", *data_p);
}
data_p++;
}
printf("\r\n");
#else
*data_p++ = SPDR;
}
#endif
#endif
SPI_SS::Set();
XMEM_RELEASE_SPI();
return ( data_p);
}
/* GPIO read. See gpioWr for explanation */
/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::gpioRd() {
uint8_t gpin = 0;
gpin = regRd(rIOPINS2); //pins 4-7
gpin &= 0xf0; //clean lower nibble
gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
return ( gpin);
}
/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
or zero if PLL haven't stabilized in 65535 cycles */
template< typename SPI_SS, typename INTR >
uint16_t MAX3421e< SPI_SS, INTR >::reset() {
uint16_t i = 0;
regWr(rUSBCTL, bmCHIPRES);
regWr(rUSBCTL, 0x00);
while(++i) {
if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
break;
}
}
return ( i);
}
/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
template< typename SPI_SS, typename INTR >
int8_t MAX3421e< SPI_SS, INTR >::Init() {
XMEM_ACQUIRE_SPI();
// Moved here.
// you really should not init hardware in the constructor when it involves locks.
// Also avoids the vbus flicker issue confusing some devices.
/* pin and peripheral setup */
SPI_SS::SetDirWrite();
SPI_SS::Set();
spi::init();
INTR::SetDirRead();
XMEM_RELEASE_SPI();
/* MAX3421E - full-duplex SPI, level interrupt */
// GPX pin on. Moved here, otherwise we flicker the vbus.
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
return ( -1);
}
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
/* check if device is connected */
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
busprobe(); //check if anything is connected
regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
regWr(rCPUCTL, 0x01); //enable interrupt pin
return ( 0);
}
/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
template< typename SPI_SS, typename INTR >
int8_t MAX3421e< SPI_SS, INTR >::Init(int mseconds) {
XMEM_ACQUIRE_SPI();
// Moved here.
// you really should not init hardware in the constructor when it involves locks.
// Also avoids the vbus flicker issue confusing some devices.
/* pin and peripheral setup */
SPI_SS::SetDirWrite();
SPI_SS::Set();
spi::init();
INTR::SetDirRead();
XMEM_RELEASE_SPI();
/* MAX3421E - full-duplex SPI, level interrupt, vbus off */
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
return ( -1);
}
// Delay a minimum of 1 second to ensure any capacitors are drained.
// 1 second is required to make sure we do not smoke a Microdrive!
if(mseconds < 1000) mseconds = 1000;
delay(mseconds);
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
/* check if device is connected */
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
busprobe(); //check if anything is connected
regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
regWr(rCPUCTL, 0x01); //enable interrupt pin
// GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
return ( 0);
}
/* probe bus to determine device presence and speed and switch host to this speed */
template< typename SPI_SS, typename INTR >
void MAX3421e< SPI_SS, INTR >::busprobe() {
uint8_t bus_sample;
bus_sample = regRd(rHRSL); //Get J,K status
bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
switch(bus_sample) { //start full-speed or low-speed host
case( bmJSTATUS):
if((regRd(rMODE) & bmLOWSPEED) == 0) {
regWr(rMODE, MODE_FS_HOST); //start full-speed host
vbusState = FSHOST;
} else {
regWr(rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
}
break;
case( bmKSTATUS):
if((regRd(rMODE) & bmLOWSPEED) == 0) {
regWr(rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
} else {
regWr(rMODE, MODE_FS_HOST); //start full-speed host
vbusState = FSHOST;
}
break;
case( bmSE1): //illegal state
vbusState = SE1;
break;
case( bmSE0): //disconnected state
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
vbusState = SE0;
break;
}//end switch( bus_sample )
}
/* MAX3421 state change task and interrupt handler */
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::Task(void) {
uint8_t rcode = 0;
uint8_t pinvalue;
//USB_HOST_SERIAL.print("Vbus state: ");
//USB_HOST_SERIAL.println( vbusState, HEX );
pinvalue = INTR::IsSet(); //Read();
//pinvalue = digitalRead( MAX_INT );
if(pinvalue == 0) {
rcode = IntHandler();
}
// pinvalue = digitalRead( MAX_GPX );
// if( pinvalue == LOW ) {
// GpxHandler();
// }
// usbSM(); //USB state machine
return ( rcode);
}
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::IntHandler() {
uint8_t HIRQ;
uint8_t HIRQ_sendback = 0x00;
HIRQ = regRd(rHIRQ); //determine interrupt source
//if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
// HIRQ_sendback |= bmFRAMEIRQ;
//}//end FRAMEIRQ handling
if(HIRQ & bmCONDETIRQ) {
busprobe();
HIRQ_sendback |= bmCONDETIRQ;
}
/* End HIRQ interrupts handling, clear serviced IRQs */
regWr(rHIRQ, HIRQ_sendback);
return ( HIRQ_sendback);
}
//template< typename SPI_SS, typename INTR >
//uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler()
//{
// uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
//// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload
//// vbusPwr( OFF ); //attempt powercycle
//// delay( 1000 );
//// vbusPwr( ON );
//// regWr( rGPINIRQ, bmGPINIRQ7 );
//// }
// return( GPINIRQ );
//}
#endif //_USBHOST_H_
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* MAX3421E-based USB Host Library header file */
#if !defined(_usb_h_) || defined(_USBHOST_H_)
#error "Never include usbhost.h directly; include Usb.h instead"
#else
#define _USBHOST_H_
#if USING_SPI4TEENSY3
#include <spi4teensy3.h>
#include <sys/types.h>
#endif
/* SPI initialization */
template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
public:
#if USING_SPI4TEENSY3
static void init() {
// spi4teensy3 inits everything for us, except /SS
// CLK, MOSI and MISO are hard coded for now.
// spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0
spi4teensy3::init(); // full speed, cpol 0, cpha 0
SPI_SS::SetDirWrite();
SPI_SS::Set();
}
#elif !defined(SPDR)
static void init() {
SPI_SS::SetDirWrite();
SPI_SS::Set();
SPI.begin();
#if defined(__MIPSEL__)
SPI.setClockDivider(1);
#else
SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
#endif
}
#else
static void init() {
//uint8_t tmp;
SPI_CLK::SetDirWrite();
SPI_MOSI::SetDirWrite();
SPI_MISO::SetDirRead();
SPI_SS::SetDirWrite();
/* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
SPCR = 0x50;
SPSR = 0x01; // 0x01
/**/
//tmp = SPSR;
//tmp = SPDR;
}
#endif
};
/* SPI pin definitions. see avrpins.h */
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
#elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))
typedef SPi< P13, P11, P12, P10 > spi;
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
typedef SPi< P76, P75, P74, P10 > spi;
#elif defined(__MIPSEL__)
typedef SPi< P13, P11, P12, P10 > spi;
#else
#error "No SPI entry in usbhost.h"
#endif
typedef enum {
vbus_on = 0,
vbus_off = GPX_VBDET
} VBUS_t;
template< typename SPI_SS, typename INTR > class MAX3421e /* : public spi */ {
static uint8_t vbusState;
public:
MAX3421e();
void regWr(uint8_t reg, uint8_t data);
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
void gpioWr(uint8_t data);
uint8_t regRd(uint8_t reg);
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
uint8_t gpioRd();
uint16_t reset();
int8_t Init();
int8_t Init(int mseconds);
void vbusPower(VBUS_t state) {
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state));
}
uint8_t getVbusState(void) {
return vbusState;
};
void busprobe();
uint8_t GpxHandler();
uint8_t IntHandler();
uint8_t Task();
};
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::vbusState = 0;
/* constructor */
template< typename SPI_SS, typename INTR >
MAX3421e< SPI_SS, INTR >::MAX3421e() {
// Leaving ADK hardware setup in here, for now. This really belongs with the other parts.
#ifdef BOARD_MEGA_ADK
// For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH
P55::SetDirWrite();
P55::Set();
#endif
};
/* write single byte into MAX3421 register */
template< typename SPI_SS, typename INTR >
void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
uint8_t c[2];
c[0] = reg | 0x02;
c[1] = data;
spi4teensy3::send(c, 2);
#elif !defined(SPDR)
SPI.transfer(reg | 0x02);
SPI.transfer(data);
#else
SPDR = (reg | 0x02);
while(!(SPSR & (1 << SPIF)));
SPDR = data;
while(!(SPSR & (1 << SPIF)));
#endif
SPI_SS::Set();
XMEM_RELEASE_SPI();
return;
};
/* multiple-byte write */
/* returns a pointer to memory position after last written */
template< typename SPI_SS, typename INTR >
uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
spi4teensy3::send(reg | 0x02);
spi4teensy3::send(data_p, nbytes);
data_p += nbytes;
#elif !defined(SPDR)
SPI.transfer(reg | 0x02);
while(nbytes) {
SPI.transfer(*data_p);
nbytes--;
data_p++; // advance data pointer
}
#else
SPDR = (reg | 0x02); //set WR bit and send register number
while(nbytes) {
while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
SPDR = (*data_p); // send next data byte
nbytes--;
data_p++; // advance data pointer
}
while(!(SPSR & (1 << SPIF)));
#endif
SPI_SS::Set();
XMEM_RELEASE_SPI();
return ( data_p);
}
/* GPIO write */
/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
template< typename SPI_SS, typename INTR >
void MAX3421e< SPI_SS, INTR >::gpioWr(uint8_t data) {
regWr(rIOPINS1, data);
data >>= 4;
regWr(rIOPINS2, data);
return;
}
/* single host register read */
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
spi4teensy3::send(reg);
uint8_t rv = spi4teensy3::receive();
SPI_SS::Set();
#elif !defined(SPDR)
SPI.transfer(reg);
uint8_t rv = SPI.transfer(0);
SPI_SS::Set();
#else
SPDR = reg;
while(!(SPSR & (1 << SPIF)));
SPDR = 0; //send empty byte
while(!(SPSR & (1 << SPIF)));
SPI_SS::Set();
uint8_t rv = SPDR;
#endif
XMEM_RELEASE_SPI();
return (rv);
}
/* multiple-byte register read */
/* returns a pointer to a memory position after last read */
template< typename SPI_SS, typename INTR >
uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
XMEM_ACQUIRE_SPI();
SPI_SS::Clear();
#if USING_SPI4TEENSY3
spi4teensy3::send(reg);
spi4teensy3::receive(data_p, nbytes);
data_p += nbytes;
#elif !defined(SPDR)
SPI.transfer(reg);
while(nbytes) {
*data_p++ = SPI.transfer(0);
nbytes--;
}
#else
SPDR = reg;
while(!(SPSR & (1 << SPIF))); //wait
while(nbytes) {
SPDR = 0; //send empty byte
nbytes--;
while(!(SPSR & (1 << SPIF)));
#if 0
{
*data_p = SPDR;
printf("%2.2x ", *data_p);
}
data_p++;
}
printf("\r\n");
#else
*data_p++ = SPDR;
}
#endif
#endif
SPI_SS::Set();
XMEM_RELEASE_SPI();
return ( data_p);
}
/* GPIO read. See gpioWr for explanation */
/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::gpioRd() {
uint8_t gpin = 0;
gpin = regRd(rIOPINS2); //pins 4-7
gpin &= 0xf0; //clean lower nibble
gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
return ( gpin);
}
/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
or zero if PLL haven't stabilized in 65535 cycles */
template< typename SPI_SS, typename INTR >
uint16_t MAX3421e< SPI_SS, INTR >::reset() {
uint16_t i = 0;
regWr(rUSBCTL, bmCHIPRES);
regWr(rUSBCTL, 0x00);
while(++i) {
if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
break;
}
}
return ( i);
}
/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
template< typename SPI_SS, typename INTR >
int8_t MAX3421e< SPI_SS, INTR >::Init() {
XMEM_ACQUIRE_SPI();
// Moved here.
// you really should not init hardware in the constructor when it involves locks.
// Also avoids the vbus flicker issue confusing some devices.
/* pin and peripheral setup */
SPI_SS::SetDirWrite();
SPI_SS::Set();
spi::init();
INTR::SetDirRead();
XMEM_RELEASE_SPI();
/* MAX3421E - full-duplex SPI, level interrupt */
// GPX pin on. Moved here, otherwise we flicker the vbus.
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
return ( -1);
}
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
/* check if device is connected */
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
busprobe(); //check if anything is connected
regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
regWr(rCPUCTL, 0x01); //enable interrupt pin
return ( 0);
}
/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
template< typename SPI_SS, typename INTR >
int8_t MAX3421e< SPI_SS, INTR >::Init(int mseconds) {
XMEM_ACQUIRE_SPI();
// Moved here.
// you really should not init hardware in the constructor when it involves locks.
// Also avoids the vbus flicker issue confusing some devices.
/* pin and peripheral setup */
SPI_SS::SetDirWrite();
SPI_SS::Set();
spi::init();
INTR::SetDirRead();
XMEM_RELEASE_SPI();
/* MAX3421E - full-duplex SPI, level interrupt, vbus off */
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
return ( -1);
}
// Delay a minimum of 1 second to ensure any capacitors are drained.
// 1 second is required to make sure we do not smoke a Microdrive!
if(mseconds < 1000) mseconds = 1000;
delay(mseconds);
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
/* check if device is connected */
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
busprobe(); //check if anything is connected
regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
regWr(rCPUCTL, 0x01); //enable interrupt pin
// GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
return ( 0);
}
/* probe bus to determine device presence and speed and switch host to this speed */
template< typename SPI_SS, typename INTR >
void MAX3421e< SPI_SS, INTR >::busprobe() {
uint8_t bus_sample;
bus_sample = regRd(rHRSL); //Get J,K status
bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
switch(bus_sample) { //start full-speed or low-speed host
case( bmJSTATUS):
if((regRd(rMODE) & bmLOWSPEED) == 0) {
regWr(rMODE, MODE_FS_HOST); //start full-speed host
vbusState = FSHOST;
} else {
regWr(rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
}
break;
case( bmKSTATUS):
if((regRd(rMODE) & bmLOWSPEED) == 0) {
regWr(rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
} else {
regWr(rMODE, MODE_FS_HOST); //start full-speed host
vbusState = FSHOST;
}
break;
case( bmSE1): //illegal state
vbusState = SE1;
break;
case( bmSE0): //disconnected state
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
vbusState = SE0;
break;
}//end switch( bus_sample )
}
/* MAX3421 state change task and interrupt handler */
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::Task(void) {
uint8_t rcode = 0;
uint8_t pinvalue;
//USB_HOST_SERIAL.print("Vbus state: ");
//USB_HOST_SERIAL.println( vbusState, HEX );
pinvalue = INTR::IsSet(); //Read();
//pinvalue = digitalRead( MAX_INT );
if(pinvalue == 0) {
rcode = IntHandler();
}
// pinvalue = digitalRead( MAX_GPX );
// if( pinvalue == LOW ) {
// GpxHandler();
// }
// usbSM(); //USB state machine
return ( rcode);
}
template< typename SPI_SS, typename INTR >
uint8_t MAX3421e< SPI_SS, INTR >::IntHandler() {
uint8_t HIRQ;
uint8_t HIRQ_sendback = 0x00;
HIRQ = regRd(rHIRQ); //determine interrupt source
//if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
// HIRQ_sendback |= bmFRAMEIRQ;
//}//end FRAMEIRQ handling
if(HIRQ & bmCONDETIRQ) {
busprobe();
HIRQ_sendback |= bmCONDETIRQ;
}
/* End HIRQ interrupts handling, clear serviced IRQs */
regWr(rHIRQ, HIRQ_sendback);
return ( HIRQ_sendback);
}
//template< typename SPI_SS, typename INTR >
//uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler()
//{
// uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
//// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload
//// vbusPwr( OFF ); //attempt powercycle
//// delay( 1000 );
//// vbusPwr( ON );
//// regWr( rGPINIRQ, bmGPINIRQ7 );
//// }
// return( GPINIRQ );
//}
#endif //_USBHOST_H_

View file

@ -1,425 +1,425 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "usbhub.h"
bool USBHub::bResetInitiated = false;
USBHub::USBHub(USB *p) :
pUsb(p),
bAddress(0),
bNbrPorts(0),
//bInitState(0),
qNextPollTime(0),
bPollEnable(false) {
epInfo[0].epAddr = 0;
epInfo[0].maxPktSize = 8;
epInfo[0].epAttribs = 0;
epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
epInfo[1].epAddr = 1;
epInfo[1].maxPktSize = 8; //kludge
epInfo[1].epAttribs = 0;
epInfo[1].bmNakPower = USB_NAK_NOWAIT;
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[32];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
HubDescriptor* hd = reinterpret_cast<HubDescriptor*>(buf);
USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t len = 0;
uint16_t cd_len = 0;
//USBTRACE("\r\nHub Init Start ");
//D_PrintHex<uint8_t > (bInitState, 0x80);
AddressPool &addrPool = pUsb->GetAddressPool();
//switch (bInitState) {
// case 0:
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
p->lowspeed = false;
if(!rcode)
len = (buf[0] > 32) ? 32 : buf[0];
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
return rcode;
}
// Extract device class from device descriptor
// If device class is not a hub return
if(udd->bDeviceClass != 0x09)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, (udd->bDeviceClass == 0x09) ? true : false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
addrPool.FreeAddress(bAddress);
bAddress = 0;
return rcode;
}
//USBTRACE2("\r\nHub address: ", bAddress );
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(len)
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
if(rcode)
goto FailGetDevDescr;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
if(rcode)
goto FailSetDevTblEntry;
// bInitState = 1;
// case 1:
// Get hub descriptor
rcode = GetHubDescriptor(0, 8, buf);
if(rcode)
goto FailGetHubDescr;
// Save number of ports for future use
bNbrPorts = hd->bNbrPorts;
// bInitState = 2;
// case 2:
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
if(!rcode) {
cd_len = ucd->wTotalLength;
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
}
if(rcode)
goto FailGetConfDescr;
// The following code is of no practical use in real life applications.
// It only intended for the usb protocol sniffer to properly parse hub-class requests.
{
uint8_t buf2[24];
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
if(rcode)
goto FailGetConfDescr;
}
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, buf[5]);
if(rcode)
goto FailSetConfDescr;
// bInitState = 3;
// case 3:
// Power on all ports
for(uint8_t j = 1; j <= bNbrPorts; j++)
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
pUsb->SetHubPreMask();
bPollEnable = true;
// bInitState = 0;
//}
//bInitState = 0;
//USBTRACE("...OK\r\n");
return 0;
// Oleg, No debugging?? -- xxxajk
FailGetDevDescr:
goto Fail;
FailSetDevTblEntry:
goto Fail;
FailGetHubDescr:
goto Fail;
FailGetConfDescr:
goto Fail;
FailSetConfDescr:
goto Fail;
Fail:
USBTRACE("...FAIL\r\n");
return rcode;
}
uint8_t USBHub::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
if(bAddress == 0x41)
pUsb->SetHubPreMask();
bAddress = 0;
bNbrPorts = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
uint8_t USBHub::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
if(((long)(millis() - qNextPollTime) >= 0L)) {
rcode = CheckHubStatus();
qNextPollTime = millis() + 100;
}
return rcode;
}
uint8_t USBHub::CheckHubStatus() {
uint8_t rcode;
uint8_t buf[8];
uint16_t read = 1;
rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
if(rcode)
return rcode;
//if (buf[0] & 0x01) // Hub Status Change
//{
// pUsb->PrintHubStatus(addr);
// rcode = GetHubStatus(1, 0, 1, 4, buf);
// if (rcode)
// {
// USB_HOST_SERIAL.print("GetHubStatus Error");
// USB_HOST_SERIAL.println(rcode, HEX);
// return rcode;
// }
//}
for(uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
if(buf[0] & mask) {
HubEvent evt;
evt.bmEvent = 0;
rcode = GetPortStatus(port, 4, evt.evtBuff);
if(rcode)
continue;
rcode = PortStatusChange(port, evt);
if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0;
if(rcode)
return rcode;
}
} // for
for(uint8_t port = 1; port <= bNbrPorts; port++) {
HubEvent evt;
evt.bmEvent = 0;
rcode = GetPortStatus(port, 4, evt.evtBuff);
if(rcode)
continue;
if((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED)
continue;
// Emulate connection event for the port
evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION;
rcode = PortStatusChange(port, evt);
if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0;
if(rcode)
return rcode;
} // for
return 0;
}
void USBHub::ResetHubPort(uint8_t port) {
HubEvent evt;
evt.bmEvent = 0;
uint8_t rcode;
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
for(int i = 0; i < 3; i++) {
rcode = GetPortStatus(port, 4, evt.evtBuff);
if(rcode) break; // Some kind of error, bail.
if(evt.bmEvent == bmHUB_PORT_EVENT_RESET_COMPLETE || evt.bmEvent == bmHUB_PORT_EVENT_LS_RESET_COMPLETE) {
break;
}
delay(100); // simulate polling.
}
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
delay(20);
}
uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) {
switch(evt.bmEvent) {
// Device connected event
case bmHUB_PORT_EVENT_CONNECT:
case bmHUB_PORT_EVENT_LS_CONNECT:
if(bResetInitiated)
return 0;
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
bResetInitiated = true;
return HUB_ERROR_PORT_HAS_BEEN_RESET;
// Device disconnected event
case bmHUB_PORT_EVENT_DISCONNECT:
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
bResetInitiated = false;
UsbDeviceAddress a;
a.devAddress = 0;
a.bmHub = 0;
a.bmParent = bAddress;
a.bmAddress = port;
pUsb->ReleaseDevice(a.devAddress);
return 0;
// Reset complete event
case bmHUB_PORT_EVENT_RESET_COMPLETE:
case bmHUB_PORT_EVENT_LS_RESET_COMPLETE:
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
delay(20);
a.devAddress = bAddress;
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED));
bResetInitiated = false;
break;
} // switch (evt.bmEvent)
return 0;
}
void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) {
uint8_t rcode = 0;
HubEvent evt;
rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
if(rcode) {
USB_HOST_SERIAL.println("ERROR!");
return;
}
USB_HOST_SERIAL.print("\r\nPort ");
USB_HOST_SERIAL.println(port, DEC);
USB_HOST_SERIAL.println("Status");
USB_HOST_SERIAL.print("CONNECTION:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
USB_HOST_SERIAL.print("ENABLE:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
USB_HOST_SERIAL.print("SUSPEND:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
USB_HOST_SERIAL.print("OVER_CURRENT:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
USB_HOST_SERIAL.print("RESET:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
USB_HOST_SERIAL.print("POWER:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
USB_HOST_SERIAL.print("LOW_SPEED:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
USB_HOST_SERIAL.print("HIGH_SPEED:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
USB_HOST_SERIAL.print("TEST:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
USB_HOST_SERIAL.print("INDICATOR:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
if(!print_changes)
return;
USB_HOST_SERIAL.println("\r\nChange");
USB_HOST_SERIAL.print("CONNECTION:\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
USB_HOST_SERIAL.print("ENABLE:\t\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
USB_HOST_SERIAL.print("SUSPEND:\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
USB_HOST_SERIAL.print("OVER_CURRENT:\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
USB_HOST_SERIAL.print("RESET:\t\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
}
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#include "usbhub.h"
bool USBHub::bResetInitiated = false;
USBHub::USBHub(USB *p) :
pUsb(p),
bAddress(0),
bNbrPorts(0),
//bInitState(0),
qNextPollTime(0),
bPollEnable(false) {
epInfo[0].epAddr = 0;
epInfo[0].maxPktSize = 8;
epInfo[0].epAttribs = 0;
epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
epInfo[1].epAddr = 1;
epInfo[1].maxPktSize = 8; //kludge
epInfo[1].epAttribs = 0;
epInfo[1].bmNakPower = USB_NAK_NOWAIT;
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[32];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
HubDescriptor* hd = reinterpret_cast<HubDescriptor*>(buf);
USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint8_t len = 0;
uint16_t cd_len = 0;
//USBTRACE("\r\nHub Init Start ");
//D_PrintHex<uint8_t > (bInitState, 0x80);
AddressPool &addrPool = pUsb->GetAddressPool();
//switch (bInitState) {
// case 0:
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if(!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
p->lowspeed = false;
if(!rcode)
len = (buf[0] > 32) ? 32 : buf[0];
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
return rcode;
}
// Extract device class from device descriptor
// If device class is not a hub return
if(udd->bDeviceClass != 0x09)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, (udd->bDeviceClass == 0x09) ? true : false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from the device descriptor
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
// Restore p->epinfo
p->epinfo = oldep_ptr;
addrPool.FreeAddress(bAddress);
bAddress = 0;
return rcode;
}
//USBTRACE2("\r\nHub address: ", bAddress );
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(len)
rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
if(rcode)
goto FailGetDevDescr;
// Assign epInfo to epinfo pointer
rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
if(rcode)
goto FailSetDevTblEntry;
// bInitState = 1;
// case 1:
// Get hub descriptor
rcode = GetHubDescriptor(0, 8, buf);
if(rcode)
goto FailGetHubDescr;
// Save number of ports for future use
bNbrPorts = hd->bNbrPorts;
// bInitState = 2;
// case 2:
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
if(!rcode) {
cd_len = ucd->wTotalLength;
rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
}
if(rcode)
goto FailGetConfDescr;
// The following code is of no practical use in real life applications.
// It only intended for the usb protocol sniffer to properly parse hub-class requests.
{
uint8_t buf2[24];
rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
if(rcode)
goto FailGetConfDescr;
}
// Set Configuration Value
rcode = pUsb->setConf(bAddress, 0, buf[5]);
if(rcode)
goto FailSetConfDescr;
// bInitState = 3;
// case 3:
// Power on all ports
for(uint8_t j = 1; j <= bNbrPorts; j++)
SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
pUsb->SetHubPreMask();
bPollEnable = true;
// bInitState = 0;
//}
//bInitState = 0;
//USBTRACE("...OK\r\n");
return 0;
// Oleg, No debugging?? -- xxxajk
FailGetDevDescr:
goto Fail;
FailSetDevTblEntry:
goto Fail;
FailGetHubDescr:
goto Fail;
FailGetConfDescr:
goto Fail;
FailSetConfDescr:
goto Fail;
Fail:
USBTRACE("...FAIL\r\n");
return rcode;
}
uint8_t USBHub::Release() {
pUsb->GetAddressPool().FreeAddress(bAddress);
if(bAddress == 0x41)
pUsb->SetHubPreMask();
bAddress = 0;
bNbrPorts = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
uint8_t USBHub::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
if(((long)(millis() - qNextPollTime) >= 0L)) {
rcode = CheckHubStatus();
qNextPollTime = millis() + 100;
}
return rcode;
}
uint8_t USBHub::CheckHubStatus() {
uint8_t rcode;
uint8_t buf[8];
uint16_t read = 1;
rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
if(rcode)
return rcode;
//if (buf[0] & 0x01) // Hub Status Change
//{
// pUsb->PrintHubStatus(addr);
// rcode = GetHubStatus(1, 0, 1, 4, buf);
// if (rcode)
// {
// USB_HOST_SERIAL.print("GetHubStatus Error");
// USB_HOST_SERIAL.println(rcode, HEX);
// return rcode;
// }
//}
for(uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
if(buf[0] & mask) {
HubEvent evt;
evt.bmEvent = 0;
rcode = GetPortStatus(port, 4, evt.evtBuff);
if(rcode)
continue;
rcode = PortStatusChange(port, evt);
if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0;
if(rcode)
return rcode;
}
} // for
for(uint8_t port = 1; port <= bNbrPorts; port++) {
HubEvent evt;
evt.bmEvent = 0;
rcode = GetPortStatus(port, 4, evt.evtBuff);
if(rcode)
continue;
if((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED)
continue;
// Emulate connection event for the port
evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION;
rcode = PortStatusChange(port, evt);
if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0;
if(rcode)
return rcode;
} // for
return 0;
}
void USBHub::ResetHubPort(uint8_t port) {
HubEvent evt;
evt.bmEvent = 0;
uint8_t rcode;
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
for(int i = 0; i < 3; i++) {
rcode = GetPortStatus(port, 4, evt.evtBuff);
if(rcode) break; // Some kind of error, bail.
if(evt.bmEvent == bmHUB_PORT_EVENT_RESET_COMPLETE || evt.bmEvent == bmHUB_PORT_EVENT_LS_RESET_COMPLETE) {
break;
}
delay(100); // simulate polling.
}
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
delay(20);
}
uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) {
switch(evt.bmEvent) {
// Device connected event
case bmHUB_PORT_EVENT_CONNECT:
case bmHUB_PORT_EVENT_LS_CONNECT:
if(bResetInitiated)
return 0;
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
bResetInitiated = true;
return HUB_ERROR_PORT_HAS_BEEN_RESET;
// Device disconnected event
case bmHUB_PORT_EVENT_DISCONNECT:
ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
bResetInitiated = false;
UsbDeviceAddress a;
a.devAddress = 0;
a.bmHub = 0;
a.bmParent = bAddress;
a.bmAddress = port;
pUsb->ReleaseDevice(a.devAddress);
return 0;
// Reset complete event
case bmHUB_PORT_EVENT_RESET_COMPLETE:
case bmHUB_PORT_EVENT_LS_RESET_COMPLETE:
ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
delay(20);
a.devAddress = bAddress;
pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED));
bResetInitiated = false;
break;
} // switch (evt.bmEvent)
return 0;
}
void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) {
uint8_t rcode = 0;
HubEvent evt;
rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
if(rcode) {
USB_HOST_SERIAL.println("ERROR!");
return;
}
USB_HOST_SERIAL.print("\r\nPort ");
USB_HOST_SERIAL.println(port, DEC);
USB_HOST_SERIAL.println("Status");
USB_HOST_SERIAL.print("CONNECTION:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
USB_HOST_SERIAL.print("ENABLE:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
USB_HOST_SERIAL.print("SUSPEND:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
USB_HOST_SERIAL.print("OVER_CURRENT:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
USB_HOST_SERIAL.print("RESET:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
USB_HOST_SERIAL.print("POWER:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
USB_HOST_SERIAL.print("LOW_SPEED:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
USB_HOST_SERIAL.print("HIGH_SPEED:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
USB_HOST_SERIAL.print("TEST:\t\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
USB_HOST_SERIAL.print("INDICATOR:\t");
USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
if(!print_changes)
return;
USB_HOST_SERIAL.println("\r\nChange");
USB_HOST_SERIAL.print("CONNECTION:\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
USB_HOST_SERIAL.print("ENABLE:\t\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
USB_HOST_SERIAL.print("SUSPEND:\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
USB_HOST_SERIAL.print("OVER_CURRENT:\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
USB_HOST_SERIAL.print("RESET:\t\t");
USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
}

504
usbhub.h
View file

@ -1,252 +1,252 @@
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__USBHUB_H__)
#define __USBHUB_H__
#include "Usb.h"
#define USB_DESCRIPTOR_HUB 0x09 // Hub descriptor type
// Hub Requests
#define bmREQ_CLEAR_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_CLEAR_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_CLEAR_TT_BUFFER USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_GET_HUB_DESCRIPTOR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_GET_HUB_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_GET_PORT_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_RESET_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_SET_HUB_DESCRIPTOR USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_SET_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_SET_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_GET_TT_STATE USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_STOP_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
// Hub Class Requests
#define HUB_REQUEST_CLEAR_TT_BUFFER 8
#define HUB_REQUEST_RESET_TT 9
#define HUB_REQUEST_GET_TT_STATE 10
#define HUB_REQUEST_STOP_TT 11
// Hub Features
#define HUB_FEATURE_C_HUB_LOCAL_POWER 0
#define HUB_FEATURE_C_HUB_OVER_CURRENT 1
#define HUB_FEATURE_PORT_CONNECTION 0
#define HUB_FEATURE_PORT_ENABLE 1
#define HUB_FEATURE_PORT_SUSPEND 2
#define HUB_FEATURE_PORT_OVER_CURRENT 3
#define HUB_FEATURE_PORT_RESET 4
#define HUB_FEATURE_PORT_POWER 8
#define HUB_FEATURE_PORT_LOW_SPEED 9
#define HUB_FEATURE_C_PORT_CONNECTION 16
#define HUB_FEATURE_C_PORT_ENABLE 17
#define HUB_FEATURE_C_PORT_SUSPEND 18
#define HUB_FEATURE_C_PORT_OVER_CURRENT 19
#define HUB_FEATURE_C_PORT_RESET 20
#define HUB_FEATURE_PORT_TEST 21
#define HUB_FEATURE_PORT_INDICATOR 22
// Hub Port Test Modes
#define HUB_PORT_TEST_MODE_J 1
#define HUB_PORT_TEST_MODE_K 2
#define HUB_PORT_TEST_MODE_SE0_NAK 3
#define HUB_PORT_TEST_MODE_PACKET 4
#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5
// Hub Port Indicator Color
#define HUB_PORT_INDICATOR_AUTO 0
#define HUB_PORT_INDICATOR_AMBER 1
#define HUB_PORT_INDICATOR_GREEN 2
#define HUB_PORT_INDICATOR_OFF 3
// Hub Port Status Bitmasks
#define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001
#define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002
#define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004
#define bmHUB_PORT_STATUS_PORT_OVER_CURRENT 0x0008
#define bmHUB_PORT_STATUS_PORT_RESET 0x0010
#define bmHUB_PORT_STATUS_PORT_POWER 0x0100
#define bmHUB_PORT_STATUS_PORT_LOW_SPEED 0x0200
#define bmHUB_PORT_STATUS_PORT_HIGH_SPEED 0x0400
#define bmHUB_PORT_STATUS_PORT_TEST 0x0800
#define bmHUB_PORT_STATUS_PORT_INDICATOR 0x1000
// Hub Port Status Change Bitmasks (used one byte instead of two)
#define bmHUB_PORT_STATUS_C_PORT_CONNECTION 0x0001
#define bmHUB_PORT_STATUS_C_PORT_ENABLE 0x0002
#define bmHUB_PORT_STATUS_C_PORT_SUSPEND 0x0004
#define bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT 0x0008
#define bmHUB_PORT_STATUS_C_PORT_RESET 0x0010
// Hub Status Bitmasks (used one byte instead of two)
#define bmHUB_STATUS_LOCAL_POWER_SOURCE 0x01
#define bmHUB_STATUS_OVER_CURRENT 0x12
// Hub Status Change Bitmasks (used one byte instead of two)
#define bmHUB_STATUS_C_LOCAL_POWER_SOURCE 0x01
#define bmHUB_STATUS_C_OVER_CURRENT 0x12
// Hub Port Configuring Substates
#define USB_STATE_HUB_PORT_CONFIGURING 0xb0
#define USB_STATE_HUB_PORT_POWERED_OFF 0xb1
#define USB_STATE_HUB_PORT_WAIT_FOR_POWER_GOOD 0xb2
#define USB_STATE_HUB_PORT_DISCONNECTED 0xb3
#define USB_STATE_HUB_PORT_DISABLED 0xb4
#define USB_STATE_HUB_PORT_RESETTING 0xb5
#define USB_STATE_HUB_PORT_ENABLED 0xb6
// Additional Error Codes
#define HUB_ERROR_PORT_HAS_BEEN_RESET 0xb1
// The bit mask to check for all necessary state bits
#define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
// Bit mask to check for DISABLED state in HubEvent::bmStatus field
#define bmHUB_PORT_STATE_CHECK_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
// Hub Port States
#define bmHUB_PORT_STATE_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION)
// Hub Port Events
#define bmHUB_PORT_EVENT_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION)
#define bmHUB_PORT_EVENT_DISCONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER)
#define bmHUB_PORT_EVENT_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION)
#define bmHUB_PORT_EVENT_LS_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
#define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
#define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
struct HubDescriptor {
uint8_t bDescLength; // descriptor length
uint8_t bDescriptorType; // descriptor type
uint8_t bNbrPorts; // number of ports a hub equiped with
struct {
uint16_t LogPwrSwitchMode : 2;
uint16_t CompoundDevice : 1;
uint16_t OverCurrentProtectMode : 2;
uint16_t TTThinkTime : 2;
uint16_t PortIndicatorsSupported : 1;
uint16_t Reserved : 8;
} __attribute__((packed));
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
} __attribute__((packed));
struct HubEvent {
union {
struct {
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
} __attribute__((packed));
uint32_t bmEvent;
uint8_t evtBuff[4];
};
} __attribute__((packed));
class USBHub : USBDeviceConfig {
static bool bResetInitiated; // True when reset is triggered
USB *pUsb; // USB class instance pointer
EpInfo epInfo[2]; // interrupt endpoint info structure
uint8_t bAddress; // address
uint8_t bNbrPorts; // number of ports
// uint8_t bInitState; // initialization state variable
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint8_t CheckHubStatus();
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
public:
USBHub(USB *p);
uint8_t ClearHubFeature(uint8_t fid);
uint8_t ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
uint8_t GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr);
uint8_t GetHubStatus(uint16_t nbytes, uint8_t* dataptr);
uint8_t GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubFeature(uint8_t fid);
uint8_t SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
void PrintHubStatus();
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
void ResetHubPort(uint8_t port);
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool DEVCLASSOK(uint8_t klass) {
return (klass == 0x09);
}
};
// Clear Hub Feature
inline uint8_t USBHub::ClearHubFeature(uint8_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
}
// Clear Port Feature
inline uint8_t USBHub::ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000 | port) | (sel << 8)), 0, 0, NULL, NULL));
}
// Get Hub Descriptor
inline uint8_t USBHub::GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL));
}
// Get Hub Status
inline uint8_t USBHub::GetHubStatus(uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL));
}
// Get Port Status
inline uint8_t USBHub::GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL));
}
// Set Hub Descriptor
inline uint8_t USBHub::SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL));
}
// Set Hub Feature
inline uint8_t USBHub::SetHubFeature(uint8_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
}
// Set Port Feature
inline uint8_t USBHub::SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000 | sel) << 8) | port), 0, 0, NULL, NULL));
}
void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false);
#endif // __USBHUB_H__
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(__USBHUB_H__)
#define __USBHUB_H__
#include "Usb.h"
#define USB_DESCRIPTOR_HUB 0x09 // Hub descriptor type
// Hub Requests
#define bmREQ_CLEAR_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_CLEAR_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_CLEAR_TT_BUFFER USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_GET_HUB_DESCRIPTOR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_GET_HUB_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_GET_PORT_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_RESET_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_SET_HUB_DESCRIPTOR USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_SET_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_SET_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_GET_TT_STATE USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_STOP_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
// Hub Class Requests
#define HUB_REQUEST_CLEAR_TT_BUFFER 8
#define HUB_REQUEST_RESET_TT 9
#define HUB_REQUEST_GET_TT_STATE 10
#define HUB_REQUEST_STOP_TT 11
// Hub Features
#define HUB_FEATURE_C_HUB_LOCAL_POWER 0
#define HUB_FEATURE_C_HUB_OVER_CURRENT 1
#define HUB_FEATURE_PORT_CONNECTION 0
#define HUB_FEATURE_PORT_ENABLE 1
#define HUB_FEATURE_PORT_SUSPEND 2
#define HUB_FEATURE_PORT_OVER_CURRENT 3
#define HUB_FEATURE_PORT_RESET 4
#define HUB_FEATURE_PORT_POWER 8
#define HUB_FEATURE_PORT_LOW_SPEED 9
#define HUB_FEATURE_C_PORT_CONNECTION 16
#define HUB_FEATURE_C_PORT_ENABLE 17
#define HUB_FEATURE_C_PORT_SUSPEND 18
#define HUB_FEATURE_C_PORT_OVER_CURRENT 19
#define HUB_FEATURE_C_PORT_RESET 20
#define HUB_FEATURE_PORT_TEST 21
#define HUB_FEATURE_PORT_INDICATOR 22
// Hub Port Test Modes
#define HUB_PORT_TEST_MODE_J 1
#define HUB_PORT_TEST_MODE_K 2
#define HUB_PORT_TEST_MODE_SE0_NAK 3
#define HUB_PORT_TEST_MODE_PACKET 4
#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5
// Hub Port Indicator Color
#define HUB_PORT_INDICATOR_AUTO 0
#define HUB_PORT_INDICATOR_AMBER 1
#define HUB_PORT_INDICATOR_GREEN 2
#define HUB_PORT_INDICATOR_OFF 3
// Hub Port Status Bitmasks
#define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001
#define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002
#define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004
#define bmHUB_PORT_STATUS_PORT_OVER_CURRENT 0x0008
#define bmHUB_PORT_STATUS_PORT_RESET 0x0010
#define bmHUB_PORT_STATUS_PORT_POWER 0x0100
#define bmHUB_PORT_STATUS_PORT_LOW_SPEED 0x0200
#define bmHUB_PORT_STATUS_PORT_HIGH_SPEED 0x0400
#define bmHUB_PORT_STATUS_PORT_TEST 0x0800
#define bmHUB_PORT_STATUS_PORT_INDICATOR 0x1000
// Hub Port Status Change Bitmasks (used one byte instead of two)
#define bmHUB_PORT_STATUS_C_PORT_CONNECTION 0x0001
#define bmHUB_PORT_STATUS_C_PORT_ENABLE 0x0002
#define bmHUB_PORT_STATUS_C_PORT_SUSPEND 0x0004
#define bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT 0x0008
#define bmHUB_PORT_STATUS_C_PORT_RESET 0x0010
// Hub Status Bitmasks (used one byte instead of two)
#define bmHUB_STATUS_LOCAL_POWER_SOURCE 0x01
#define bmHUB_STATUS_OVER_CURRENT 0x12
// Hub Status Change Bitmasks (used one byte instead of two)
#define bmHUB_STATUS_C_LOCAL_POWER_SOURCE 0x01
#define bmHUB_STATUS_C_OVER_CURRENT 0x12
// Hub Port Configuring Substates
#define USB_STATE_HUB_PORT_CONFIGURING 0xb0
#define USB_STATE_HUB_PORT_POWERED_OFF 0xb1
#define USB_STATE_HUB_PORT_WAIT_FOR_POWER_GOOD 0xb2
#define USB_STATE_HUB_PORT_DISCONNECTED 0xb3
#define USB_STATE_HUB_PORT_DISABLED 0xb4
#define USB_STATE_HUB_PORT_RESETTING 0xb5
#define USB_STATE_HUB_PORT_ENABLED 0xb6
// Additional Error Codes
#define HUB_ERROR_PORT_HAS_BEEN_RESET 0xb1
// The bit mask to check for all necessary state bits
#define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
// Bit mask to check for DISABLED state in HubEvent::bmStatus field
#define bmHUB_PORT_STATE_CHECK_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
// Hub Port States
#define bmHUB_PORT_STATE_DISABLED (0x0000 | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION)
// Hub Port Events
#define bmHUB_PORT_EVENT_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION)
#define bmHUB_PORT_EVENT_DISCONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER)
#define bmHUB_PORT_EVENT_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION)
#define bmHUB_PORT_EVENT_LS_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
#define bmHUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
#define bmHUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_LOW_SPEED)
struct HubDescriptor {
uint8_t bDescLength; // descriptor length
uint8_t bDescriptorType; // descriptor type
uint8_t bNbrPorts; // number of ports a hub equiped with
struct {
uint16_t LogPwrSwitchMode : 2;
uint16_t CompoundDevice : 1;
uint16_t OverCurrentProtectMode : 2;
uint16_t TTThinkTime : 2;
uint16_t PortIndicatorsSupported : 1;
uint16_t Reserved : 8;
} __attribute__((packed));
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
} __attribute__((packed));
struct HubEvent {
union {
struct {
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
} __attribute__((packed));
uint32_t bmEvent;
uint8_t evtBuff[4];
};
} __attribute__((packed));
class USBHub : USBDeviceConfig {
static bool bResetInitiated; // True when reset is triggered
USB *pUsb; // USB class instance pointer
EpInfo epInfo[2]; // interrupt endpoint info structure
uint8_t bAddress; // address
uint8_t bNbrPorts; // number of ports
// uint8_t bInitState; // initialization state variable
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint8_t CheckHubStatus();
uint8_t PortStatusChange(uint8_t port, HubEvent &evt);
public:
USBHub(USB *p);
uint8_t ClearHubFeature(uint8_t fid);
uint8_t ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
uint8_t GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr);
uint8_t GetHubStatus(uint16_t nbytes, uint8_t* dataptr);
uint8_t GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr);
uint8_t SetHubFeature(uint8_t fid);
uint8_t SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel = 0);
void PrintHubStatus();
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Release();
uint8_t Poll();
void ResetHubPort(uint8_t port);
virtual uint8_t GetAddress() {
return bAddress;
};
virtual bool DEVCLASSOK(uint8_t klass) {
return (klass == 0x09);
}
};
// Clear Hub Feature
inline uint8_t USBHub::ClearHubFeature(uint8_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
}
// Clear Port Feature
inline uint8_t USBHub::ClearPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000 | port) | (sel << 8)), 0, 0, NULL, NULL));
}
// Get Hub Descriptor
inline uint8_t USBHub::GetHubDescriptor(uint8_t index, uint16_t nbytes, uint8_t *dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes, dataptr, NULL));
}
// Get Hub Status
inline uint8_t USBHub::GetHubStatus(uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, nbytes, dataptr, NULL));
}
// Get Port Status
inline uint8_t USBHub::GetPortStatus(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL));
}
// Set Hub Descriptor
inline uint8_t USBHub::SetHubDescriptor(uint8_t port, uint16_t nbytes, uint8_t* dataptr) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, nbytes, dataptr, NULL));
}
// Set Hub Feature
inline uint8_t USBHub::SetHubFeature(uint8_t fid) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, 0, NULL, NULL));
}
// Set Port Feature
inline uint8_t USBHub::SetPortFeature(uint8_t fid, uint8_t port, uint8_t sel) {
return ( pUsb->ctrlReq(bAddress, 0, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000 | sel) << 8) | port), 0, 0, NULL, NULL));
}
void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port, bool print_changes = false);
#endif // __USBHUB_H__