![](/media/cache/profiles/1f47cef5e38c952f94c5d61726027439.50x50_q85.jpg)
Based on PS3_BlueUSB with reference to http://blog.goo.ne.jp/roboz80/e/10e7bf38d3a63b996ca2894e9fb5e3b6
Revision 0:44619612f575, committed 2011-07-05
- Comitter:
- kenbumono
- Date:
- Tue Jul 05 08:25:40 2011 +0000
- Commit message:
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AutoEvents.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,311 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +Tue Apr 26 2011 Bart Janssens: added PS3 USB support +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "USBHost.h" +#include "Utils.h" +#include "ps3.h" + +#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol) +#define AUTO_KEYBOARD AUTOEVT(CLASS_HID,1,1) +#define AUTO_MOUSE AUTOEVT(CLASS_HID,1,2) +//#define AUTO_PS3 AUTOEVT(CLASS_HID,0,0) + +u8 auto_mouse[4]; // buttons,dx,dy,scroll +u8 auto_keyboard[8]; // modifiers,reserved,keycode1..keycode6 +u8 auto_joystick[4]; // x,y,buttons,throttle +//u8 auto_ps3[48]; + + + + +void AutoEventCallback(int device, int endpoint, int status, u8* data, int len, void* userData) +{ + int evt = (int)userData; + switch (evt) + { + case AUTO_KEYBOARD: + printf("AUTO_KEYBOARD "); + break; + case AUTO_MOUSE: + printf("AUTO_MOUSE "); + break; +// case AUTO_PS3: +// printf("AUTO_PS3 "); +// ParsePs3Report(data,len); +// break; + default: + printf("HUH "); + } + //printfBytes("data",data,len); + USBInterruptTransfer(device,endpoint,data,len,AutoEventCallback,userData); +} + +// Establish transfers for interrupt events +void AddAutoEvent(int device, InterfaceDescriptor* id, EndpointDescriptor* ed) +{ + printf("message from endpoint %02X\r\n",ed->bEndpointAddress); + printf("Class Sub Proto: %02X %02X %02X\r\n",id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol); + //if ((ed->bmAttributes & 3) != ENDPOINT_INTERRUPT || !(ed->bEndpointAddress & 0x80)) + // return; + + // Make automatic interrupt enpoints for known devices + u32 evt = AUTOEVT(id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol); + printf("Evt: %08X \r\n",evt); + u8* dst = 0; + int len; + switch (evt) + { + case AUTO_MOUSE: + dst = auto_mouse; + len = sizeof(auto_mouse); + break; + case AUTO_KEYBOARD: + dst = auto_keyboard; + len = sizeof(auto_keyboard); + break; +// case AUTO_PS3: +// printf("PS3 event ? \r\n"); +// dst = auto_ps3; +// len = sizeof(auto_ps3); + default: + printf("Interrupt endpoint %02X %08X\r\n",ed->bEndpointAddress,evt); + break; + } + if (dst) + { + printf("Auto Event for %02X %08X\r\n",ed->bEndpointAddress,evt); + USBInterruptTransfer(device,ed->bEndpointAddress,dst,len,AutoEventCallback,(void*)evt); + } +} + +void PrintString(int device, int i) +{ + u8 buffer[256]; + int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,i,buffer,255); + if (le < 0) + return; + char* dst = (char*)buffer; + for (int j = 2; j < le; j += 2) + *dst++ = buffer[j]; + *dst = 0; + printf("%d:%s\r\n",i,(const char*)buffer); + } + +// Walk descriptors and create endpoints for a given device +int StartAutoEvent(int device, int configuration, int interfaceNumber) +{ + + printf("StartAutoEvent \r\n"); + + u8 buffer[255]; + int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255); + if (err < 0) + return err; + + int len = buffer[2] | (buffer[3] << 8); + u8* d = buffer; + u8* end = d + len; + while (d < end) + { + if (d[1] == DESCRIPTOR_TYPE_INTERFACE) + { + InterfaceDescriptor* id = (InterfaceDescriptor*)d; + if (id->bInterfaceNumber == interfaceNumber) + { + d += d[0]; + while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) + { + if (d[1] == DESCRIPTOR_TYPE_ENDPOINT) + AddAutoEvent(device,id,(EndpointDescriptor*)d); + d += d[0]; + } + } + } + d += d[0]; + } + return 0; +} + +/* +int StartPS3Event(int device, int configuration, int interfaceNumber) +{ + + printf("StartPS3Event \r\n"); + + EndpointDescriptor* ep; + + u8 buf[4]; + buf[0] = 0x42; + buf[1] = 0x0c; + buf[2] = 0x00; + buf[3] = 0x00; + + u8 buf2[8]; + u8 buf3[8]; + + buf2[0] = 0x01; + buf2[1] = 0x00; + buf2[2] = 0x00; + buf2[3] = 0x02; + buf2[4] = 0x72; + buf2[5] = 0xAD; + buf2[6] = 0xF3; + buf2[7] = 0x5B; + + + + + int result; + int err; + + u8 buffer[255]; + err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255); + if (err < 0) + return err; + + + + //configure the device + //err = USBControlTransfer(device, HOST_TO_DEVICE|REQUEST_TYPE_STANDARD|RECIPIENT_DEVICE, SET_CONFIGURATION, 1, 0, 0, 0, 0, 0 ); + err = SetConfiguration(device,1); + printf("set config result = %d\r\n", err); + + // get Mac address + //err = USBControlTransfer(device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_DEVICE, HID_REQUEST_GET_REPORT, 0x03f5, 0, buf3, sizeof(buf3), 0, 0 ); + //printf("get Mac to %02X:%02X:%02X:%02X:%02X:%02X , result = %d\r\n", buf3[2], buf3[3], buf3[4], buf3[5], buf3[6], buf3[7], err); + + // set Mac address + err = USBControlTransfer(device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x03f5, 0, buf2, sizeof(buf2), 0, 0 ); + printf("set Mac to %02X:%02X:%02X:%02X:%02X:%02X , result = %d\r\n", buf2[2], buf2[3], buf2[4], buf2[5], buf2[6], buf2[7], err); + + // get Mac address + //err = USBControlTransfer(device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_DEVICE, HID_REQUEST_GET_REPORT, 0x03f5, 0, buf3, sizeof(buf3), 0, 0 ); + //printf("get Mac to %02X:%02X:%02X:%02X:%02X:%02X , result = %d\r\n", buf3[2], buf3[3], buf3[4], buf3[5], buf3[6], buf3[7], err); + + err = USBControlTransfer(device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x03f4,0, buf, sizeof(buf), 0, 0 ); + printf("set report result = %d\r\n", err); + //USBTransfer(device,0,DEVICE_TO_HOST,buf,sizeof(buf),0,0); + + int len = buffer[2] | (buffer[3] << 8); + u8* d = buffer; + u8* end = d + len; + while (d < end) + { + if (d[1] == DESCRIPTOR_TYPE_INTERFACE) + { + InterfaceDescriptor* id = (InterfaceDescriptor*)d; + if (id->bInterfaceNumber == interfaceNumber) + { + d += d[0]; + while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) + { + if (d[1] == DESCRIPTOR_TYPE_ENDPOINT) + ep = (EndpointDescriptor*)d; + + if (ep->bEndpointAddress == 0x02) { + printf("PS3 input endpoint (0x02) found\r\n"); + + } + if (ep->bEndpointAddress == 0x81) { + printf("PS3 output endpoint (0x81) found\r\n"); + AddAutoEvent(device,id,(EndpointDescriptor*)d); + } + d += d[0]; + } + } + } + d += d[0]; + } + return 0; +} +*/ + +// Implemented in main.cpp +int OnDiskInsert(int device); + +// Implemented in TestShell.cpp +int OnBluetoothInsert(int device); + +void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc) +{ + printf("LoadDevice %d %02X:%02X:%02X\r\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol); + char s[128]; + u8 my_mac[6] = {0x00, 0x1B, 0xDC, 0x04, 0xDA, 0xF0}; // mac address of my Bluetooth device + + u8 buf2[6]; + + buf2[0] = 0x00; + buf2[1] = 0x1E; + buf2[2] = 0x35; + buf2[3] = 0x2E; + buf2[4] = 0xD5; + buf2[5] = 0x1D; + + + for (int i = 1; i < 3; i++) + { + if (GetString(device,i,s,sizeof(s)) < 0) + break; + printf("%d: %s\r\n",i,s); + } + + switch (interfaceDesc->bInterfaceClass) + { + case CLASS_MASS_STORAGE: + if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50) + OnDiskInsert(device); // it's SCSI! + break; + case CLASS_WIRELESS_CONTROLLER: + if (interfaceDesc->bInterfaceSubClass == 0x01 && interfaceDesc->bInterfaceProtocol == 0x01) + OnBluetoothInsert(device); // it's bluetooth! + break; + case CLASS_HID: + printf("idVendor = %04X idProduct = %04X \r\n",deviceDesc->idVendor,deviceDesc->idProduct); + //printf("device = %d configuration = %d interfaceNumber = %d\r\n", device, configuration, interfaceNumber); + //if (deviceDesc->idVendor == 0x054C && deviceDesc->idProduct == 0x0268) StartPS3Event(device,1,0); + if (deviceDesc->idVendor == 0x054C && deviceDesc->idProduct == 0x0268) { + Ps3USB _Ps3USB(device,1,0); + + _Ps3USB.SetPair(my_mac); + _Ps3USB.Enable(); + _Ps3USB.Led(1); + _Ps3USB.Rumble(0x20,0xff,0x20,0xff); + _Ps3USB.ShowPair(); + + } + else StartAutoEvent(device,1,0); + break; + default: + printf("Not yet supported \r\n"); + //StartAutoEvent(device,1,0); + break; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_unsupported/code/fatfilesystem/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/L2CAP.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,409 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Utils.h" +#include "hci.h" + +#define L2CAP_COMMAND_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CONF_REQ 0x04 +#define L2CAP_CONF_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_RSP 0x0b + + + /* L2CAP command codes */ + const char* L2CAP_ComandCodeStr(int c) + { + switch (c) + { + case L2CAP_COMMAND_REJ: return "L2CAP_COMMAND_REJ"; + case L2CAP_CONN_REQ: return "L2CAP_CONN_REQ"; + case L2CAP_CONN_RSP: return "L2CAP_CONN_RSP"; + case L2CAP_CONF_REQ: return "L2CAP_CONF_REQ"; + case L2CAP_CONF_RSP: return "L2CAP_CONF_RSP"; + case L2CAP_DISCONN_REQ: return "L2CAP_DISCONN_REQ"; + case L2CAP_DISCONN_RSP: return "L2CAP_DISCONN_RSP"; + case L2CAP_ECHO_REQ: return "L2CAP_ECHO_REQ"; + case L2CAP_ECHO_RSP: return "L2CAP_ECHO_RSP"; + case L2CAP_INFO_REQ: return "L2CAP_INFO_REQ"; + case L2CAP_INFO_RSP: return "L2CAP_INFO_RSP"; + } + return "unknown"; + } + +typedef struct +{ + u16 handle; + u16 length; // total + u16 l2capLength; // length -4 + u16 cid; // Signaling packet CID = 1 + u8 data[64]; // Largest thing to send!!! todo +} L2CAPData; + +typedef struct +{ + u16 handle; + u16 length; // total + u16 l2capLength; // length -4 + u16 cid; // Signaling packet CID = 1 + + // Payload + u8 cmd; // + u8 id; + u16 cmdLength; // total-8 + u16 params[4]; // Params +} L2CAPCmd; + +void printf(const BD_ADDR* addr); + +// +void BTDevice::Init() +{ + memset(&_info,0,sizeof(inquiry_info)); + _handle = 0; + _name[0] = 0; + _state = 0; +} + +// virtual SocketHandler +int BTDevice::Open(SocketInternal* sock, SocketAddrHdr* addr) +{ + printf("Call to BTDevice Open \r\n"); + L2CAPSocket* s = (L2CAPSocket*)sock; + L2CAPAddr* a = (L2CAPAddr*)addr; + s->scid = 0x40 + sock->ID-1; // are these reserved? + s->dcid = 0; + Connect(s->scid,a->psm); + return sock->ID; +} + +// virtual SocketHandler +int BTDevice::Create(SocketInternal* sock, SocketAddrHdr* addr) +{ + printf("Call to BTDevice Create \r\n"); + L2CAPSocket* s = (L2CAPSocket*)sock; + L2CAPAddr* a = (L2CAPAddr*)addr; + + //Connect(s->scid,a->psm); + return sock->ID; +} + +int BTDevice::Accept(SocketInternal* sock, SocketAddrHdr* addr) +{ + printf("Call to BTDevice Accept \r\n"); + L2CAPSocket* s = (L2CAPSocket*)sock; + L2CAPAddr* a = (L2CAPAddr*)addr; + + + printf("ID = %d scid = %d dcid = %d \r\n",sock->ID, s->scid, s->dcid); + + return sock->ID; +} + + + + +// virtual SocketHandler +int BTDevice::Send(SocketInternal* sock, const u8* data, int len) +{ + printf("Call to BTDevice Send \r\n"); + L2CAPData d; + L2CAPSocket* s = (L2CAPSocket*)sock; + + d.handle = _handle | 0x2000; + d.length = 4 + len; + d.l2capLength = len; + d.cid = s->dcid; + + if (len > 64) + return -1; + memcpy(d.data,data,len); + return Send((u8*)&d,len+8); +} + +// virtual SocketHandler +int BTDevice::Close(SocketInternal* sock) +{ + printf("L2CAP close %d\r\n",sock->ID); + L2CAPSocket* s = (L2CAPSocket*)sock; + return Disconnect(s->scid,s->dcid); +} + +L2CAPSocket* BTDevice::SCIDToSocket(int scid) +{ + return (L2CAPSocket*)GetSocketInternal(scid-0x40+1); +} + +int BTDevice::Send(const u8* data, int len) +{ + printfBytes("L2CP send: ",data,len); + _transport->ACLSend(data,len); + return 0; +} + +int BTDevice::Send(u8 c, u8 id, u16* params, int count) +{ + L2CAPCmd cmd; + cmd.handle = _handle | 0x2000; + cmd.length = 8 + count*2; + + cmd.l2capLength = cmd.length-4; + cmd.cid = 1; // Signaling packet + + cmd.cmd = c; + cmd.id = id; + cmd.cmdLength = count*2; + for (int i = 0; i < count; i++) + cmd.params[i] = params[i]; + return Send((u8*)&cmd,cmd.length+4); +} + +int BTDevice::Connect(int scid, int psm) +{ + u16 p[2]; + p[0] = psm; + p[1] = scid; + return Send(L2CAP_CONN_REQ,_txid++,p,2); +} + +int BTDevice::Disconnect(int scid, int dcid) +{ + u16 p[2]; + p[0] = dcid; + p[1] = scid; + return Send(L2CAP_DISCONN_REQ,_txid++,p,2); +} + +int BTDevice::ConfigureRequest(int dcid) +{ + u16 p[4]; + p[0] = dcid; + p[1] = 0; + p[2] = 0x0201; // Options + p[3] = 0x02A0; // 672 + return Send(L2CAP_CONF_REQ,_txid++,p,4); +} + +int BTDevice::ConfigureResponse(u8 rxid, int dcid) +{ + u16 p[3]; + p[0] = dcid; + p[1] = 0; + p[2] = 0; + return Send(L2CAP_CONF_RSP,rxid,p,3); +} + +int BTDevice::DisconnectResponse(u8 rxid, int scid, int dcid) +{ + u16 p[2]; + p[0] = dcid; + p[1] = scid; + return Send(L2CAP_DISCONN_RSP,rxid,p,2); +} + +int BTDevice::AcceptResponse(u8 rxid, int scid, int dcid) +{ + printf("Connection accepted \r\n"); + u16 p[4]; + p[0] = scid; + p[1] = dcid; + p[2] = L2CAP_CONN_SUCCESS; + p[3] = 0; + + return Send(L2CAP_CONN_RSP,rxid,p,4); + +} + +int BTDevice::RefuseResponse(u8 rxid) +{ + printf("Connection refused \r\n"); + u16 p[2]; + p[0] = L2CAP_CONN_REF_PSM; + p[1] = 0; + + return Send(L2CAP_CONN_RSP,rxid,p,2); +} + + +//int BTDevice::InUse(int psm) +//{ +// for (int i = 0; i < MAX_PORTS; i++){ +// printf("Listen Q %d = %d \r\n",i, _listen[i]); +// if ( _listen[i] == psm ) { +// printf("We are listening on port %d \r\n",psm); //in use +// return 0; +// } +// } +// printf("We are not listening on port %d \r\n",psm); +// return 1; +//} + + + + +void BTDevice::Control(const BD_ADDR* addr, const u8* data, int len) +{ + + SocketInternal* sock; + L2CAPSocket* s; + int psm,scid,dcid,flags; + + printf("From address "); + printf(addr); + printf(" : "); + + int cc = data[8]; + printf(L2CAP_ComandCodeStr(cc)); + int result = LE16(data+16); + printf(" Result %d\r\n",result); + + + switch (cc) + { + case L2CAP_COMMAND_REJ: + break; + case L2CAP_CONN_REQ: + { + psm = LE16(data+12); + scid = LE16(data+14); + printf("Connection request scid = %d psm = %d \r\n",scid,psm); + + // check if we listen on the port + //if ( InUse(psm) ) { + if ( Socket_InUse(SOCKET_L2CAP,psm) ) { + RefuseResponse(data[9]); + + + } else { + L2CAPAddr sockAddr; + sockAddr.bdaddr = *addr; + sock = Socket_Create(SOCKET_L2CAP, &sockAddr.hdr, psm); + s = (L2CAPSocket*)sock; + s->scid = 0x40 + sock->ID-1; // are these reserved? + s->dcid = scid; + AcceptResponse(data[9],s->scid,s->dcid); + + ConfigureRequest(s->dcid); // handshake + + sock->SetState(SocketState_Accept); + } + + /** + for (int i = 0; i < MAX_PORTS; i++){ + if ( _listen[i] == psm ) { + printf("We are listening on port %d \r\n",psm); //in use + RefuseResponse(data[9]); + break; + } + } + **/ + + //L2CAPAddr sockAddr; + //sockAddr.bdaddr = addr; + //sockAddr.psm = psm; + + } + break; + + // Response to our initial connect from Remote + case L2CAP_CONN_RSP: + { + if (result == 0) + { + printf("Connect succeeded\r\n"); + dcid = LE16(data+12); + scid = LE16(data+14); + L2CAPSocket* s = SCIDToSocket(scid); + if (s) + { + s->dcid = dcid; + ConfigureRequest(dcid); + } + } else + printf("Connect failed?\r\n"); + } + break; + + case L2CAP_CONF_RSP: + { + scid = LE16(data+12); + SocketInternal* s = (SocketInternal*)SCIDToSocket(scid); + if (s) + s->SetState(SocketState_Open); + } + break; + + case L2CAP_CONF_REQ: + { + u16 dcid = LE16(data+12); + u16 flags = LE16(data+14); + printf("Config request dcid = %02X flags = %02X\r\n", dcid, flags); + scid = LE16(data+12); + L2CAPSocket* s = SCIDToSocket(scid); + if (s) + ConfigureResponse(data[9],s->dcid); + } + break; + case L2CAP_DISCONN_REQ: { + int dcid = LE16(data+12); + int scid = LE16(data+14); + L2CAPSocket* s = SCIDToSocket(scid); + //s->si.SetState(SocketState_Closed); + DisconnectResponse(data[9], scid, dcid); + } + break; + + } +} + +void BTDevice::ACLRecv(const BD_ADDR* addr, const u8* data, int len) +{ + //printfBytes("L2CP recv: ",data,16); + int handle = LE16(data); + if (handle != (0x2000 | _handle)) + return; + + int cid = LE16(data+6); + if (cid == 1) + { + Control(addr,data,len); + return; + } + + SocketInternal* s = (SocketInternal*)SCIDToSocket(cid); + if (s) + s->Recv(data+8,LE16(data+2)-4); + else + printf("Bad event cid %d\r\n",cid); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MassStorage.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,180 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "stdlib.h" +#include "stdio.h" +#include "string.h" + +#include "Utils.h" +#include "USBHost.h" + + +int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize); +int MassStorage_ReadBlock(int device, u32 block, u8* dst); +int MassStorage_WriteBlock(int device, u32 block, const u8* dst); + + +#define ERR_BAD_CSW_SIGNATURE -200 + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +// Command Block +typedef struct +{ + u32 Signature; + u32 Tag; + u32 TransferLength; + u8 Flags; + u8 LUN; + u8 CBLength; + u8 CB[16]; // only 6 really +} CBW; + +// Status block +typedef struct +{ + u32 Signature; + u32 Tag; + u32 DataResidue; + u8 Status; +} CSW; + +int SCSIRequestSense(int device); + +int DoSCSI(int device, const u8* cmd, int cmdLen, int flags, u8* data, u32 transferLen) +{ + CBW cbw; + cbw.Signature = CBW_SIGNATURE; + cbw.Tag = 0; + cbw.TransferLength = transferLen; + cbw.Flags = flags; + cbw.LUN = 0; + cbw.CBLength = cmdLen; + memset(cbw.CB,0,sizeof(cbw.CB)); + memcpy(cbw.CB,cmd,cmdLen); + + int r; + r = USBBulkTransfer(device,0x01,(u8*)&cbw,31); // Send the command + if (r < 0) + return r; + + if (data) + { + r = USBBulkTransfer(device,flags | 1,data,transferLen); + if (r < 0) + return r; + } + + CSW csw; + csw.Signature = 0; + r = USBBulkTransfer(device,0x81,(u8*)&csw,13); + if (r < 0) + return r; + + if (csw.Signature != CSW_SIGNATURE) + return ERR_BAD_CSW_SIGNATURE; + + // ModeSense? + if (csw.Status == 1 && cmd[0] != 3) + return SCSIRequestSense(device); + + return csw.Status; +} + +int SCSITestUnitReady(int device) +{ + u8 cmd[6]; + memset(cmd,0,6); + return DoSCSI(device,cmd,6,DEVICE_TO_HOST,0,0); +} + +int SCSIRequestSense(int device) +{ + u8 cmd[6] = {0x03,0,0,0,18,0}; + u8 result[18]; + int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,18); + return r; +} + +int SCSIInquiry(int device) +{ + u8 cmd[6] = {0x12,0,0,0,36,0}; + u8 result[36+2]; + result[36] = '\n'; + result[37] = 0; + int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,36); + if (r == 0) + printf((const char*)result + 8); + return r; +} + +int SCSIReadCapacity(int device, u32* blockCount, u32* blockSize) +{ + u8 cmd[10] = {0x25,0,0,0,8,0,0,0,0,0}; + u8 result[8]; + *blockSize = 0; + *blockCount = 0; + int r = DoSCSI(device,cmd,10,DEVICE_TO_HOST,result,8); + if (r == 0) + { + *blockCount = BE32(result); + *blockSize = BE32(result+4); + } + return r; +} + +int SCSITransfer(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize, int direction) +{ + // USB hardware will only do 4k per transfer + while (blockCount*blockSize > 4096) + { + int count = 4096/blockSize; + int r = SCSITransfer(device,blockAddr,count,dst,blockSize,direction); + dst += count*blockSize; + blockAddr += count; + blockCount -= count; + } + + u8 cmd[10]; + memset(cmd,0,10); + cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; + BE32(blockAddr,cmd+2); + BE16(blockCount,cmd+7); + return DoSCSI(device,cmd,10,direction,dst,blockSize*blockCount); +} + +int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize) +{ + return SCSIReadCapacity(device,blockCount,blockSize); +} + +int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512) +{ + return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,DEVICE_TO_HOST); +} + +int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512) +{ + return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,HOST_TO_DEVICE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Ps3USB.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,276 @@ +/* +Copyright (c) 2011 Bart Janssens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "USBHost.h" +#include "hci.h" +#include "Utils.h" +#include "ps3.h" +#include "motordriver.h" + +#include "mbed.h" + + + +#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol) +#define PS3EVT AUTOEVT(CLASS_HID,0,0) +#define byteswap(x) ((x >> 8) | (x << 8)) + +u8 ps3_data[48]; + + +Ps3USB::Ps3USB(int device, int configuration, int interfaceNumber) +{ + printf("Creating new sixaxis \r\n"); + _device = device; + _configuration = configuration; + _interfaceNumber = interfaceNumber; + printf("device = %d configuration = %d interfaceNumber = %d\r\n", device, configuration, interfaceNumber); + int result; + int err; + + _count = 1; + + u8 abuffer[48] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, + 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, + 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(ledrumble,abuffer,48); + + EndpointDescriptor* ep; + + u8 buffer[255]; + err = GetDescriptor(_device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255); + if (err < 0) + printf("Failed to get descriptor\r\n"); + + + int len = buffer[2] | (buffer[3] << 8); + u8* d = buffer; + u8* end = d + len; + while (d < end) + { + if (d[1] == DESCRIPTOR_TYPE_INTERFACE) + { + InterfaceDescriptor* id = (InterfaceDescriptor*)d; + if (id->bInterfaceNumber == _interfaceNumber) + { + d += d[0]; + while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) + { + if (d[1] == DESCRIPTOR_TYPE_ENDPOINT) + ep = (EndpointDescriptor*)d; + + if (ep->bEndpointAddress == 0x02) { + printf("PS3 input endpoint (0x02) found\r\n"); + input_ep = 0x02; + + } + if (ep->bEndpointAddress == 0x81) { + printf("PS3 output endpoint (0x81) found\r\n"); + output_ep = 0x81; + //AddAutoEvent(device,id,(EndpointDescriptor*)d); + } + d += d[0]; + } + } + } + d += d[0]; + } + + } + + int Ps3USB::Enable() + { + int err; + + u8 enable[4] = {0x42,0x0c,0x00,0x00}; + + + err = USBControlTransfer(_device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x03f4,0, enable, sizeof(enable), 0, 0 ); + //printf("set report result = %d\r\n", err); + _count ++; + if (_count == 25) _count = 1; + + err = USBInterruptTransfer(_device,output_ep,ps3_data,sizeof(ps3_data),PS3EventCallback,this); + wait_ms(4); + + return 0; + + } + + + + + int Ps3USB::SetPair(u8* bdAddr) + { + int err; + + u8 buf[8]; + u8 buf2[6]; + + memcpy(buf2,bdAddr,6); + + buf[0] = 0x01; + buf[1] = 0x00; + buf[2] = buf2[0]; + buf[3] = buf2[1]; + buf[4] = buf2[2]; + buf[5] = buf2[3]; + buf[6] = buf2[4]; + buf[7] = buf2[5]; + + //set Mac address + err = USBControlTransfer(_device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x03f5, 0, buf, sizeof(buf), 0, 0 ); + wait_ms(4); + printf("set Mac address to %02X:%02X:%02X:%02X:%02X:%02X , result = %d\r\n", buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], err); + + return 0; + } + + int Ps3USB::ShowPair() + { + int err; + + u8 buf[8]; + //get Mac address + err = USBControlTransfer(_device, DEVICE_TO_HOST|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_GET_REPORT, 0x03f5, 0, buf, sizeof(buf), 0, 0 ); + wait_ms(4); + printf("Mac address is set to %02X:%02X:%02X:%02X:%02X:%02X , result = %d\r\n",buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], err); + + + return 0; + } + + int Ps3USB::Led(int i) + { + int err; + u8 ledpattern[7] = {0x02, 0x04, 0x08, 0x10, 0x12, 0x14, 0x18 }; + u8 buf[48]; + + if (i < 7) ledrumble[9] = ledpattern[i]; + memcpy(buf, ledrumble, 48); + + err = USBControlTransfer(_device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x0201,0, buf, sizeof(buf), 0, 0 ); + wait_ms(4); + + return 0; + } + + // left and right: duration and power, both from 0 to 255 + int Ps3USB::Rumble(u8 duration_right, u8 power_right, u8 duration_left, u8 power_left) + { + int err; + u8 buf[48]; + + memcpy(buf, ledrumble, 48); + buf[1] = duration_right; + buf[2] = power_right; + buf[3] = duration_left; + buf[4] = power_left; + + err = USBControlTransfer(_device, HOST_TO_DEVICE|REQUEST_TYPE_CLASS|RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x0201,0, buf, sizeof(buf), 0, 0 ); + wait_ms(4); + + return 0; + } + + + void PS3EventCallback(int device, int endpoint, int status, u8* data, int len, void* userData) + { + Ps3USB* t = (Ps3USB*)userData; + + t->_count ++; + if (t->_count == 25) t->_count = 1; + + ParsePs3Result(data, sizeof(ps3report),t->_count); + USBInterruptTransfer(device, endpoint , data, len, PS3EventCallback, userData); + wait_ms(4); + + } + + Motor A(p22, p7, p8, 1); // pwm, fwd, rev, can break + Motor B(p21, p5, p6, 1); // pwm, fwd, rev, can break + + int ParsePs3Result(const u8* data,int len,int count) + { + float speed; + ps3report* _ps3report = (ps3report*)data; + +/* if (count == 24) printf("LSX LSY RSX RSY UPA RPA DPA RPA L2 R2 L1 R1 TRI CIR CRO SQU ACX ACY ACZ GYZ \r\n"); + printf("%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %4d %4d %4d %4d \r\n", + _ps3report->LeftStickX, + _ps3report->LeftStickY, + _ps3report->RightStickX, + _ps3report->RightStickY, + _ps3report->PressureUp, + _ps3report->PressureRight, + _ps3report->PressureDown, + _ps3report->PressureLeft, + _ps3report->PressureL2, + _ps3report->PressureR2, + _ps3report->PressureL1, + _ps3report->PressureR1, + _ps3report->PressureTriangle, + _ps3report->PressureCircle, + _ps3report->PressureCross, + _ps3report->PressureSquare, + (_ps3report->AccelX), + (_ps3report->AccelY), + (_ps3report->AccelZ), + (_ps3report->GyroZ)); + +*/ + //printfBytes("data",data,len); + if(100 <= _ps3report->LeftStickY && _ps3report->LeftStickY <= 155) + { + A.stop(0); + } else if(0 <= _ps3report->LeftStickY && _ps3report->LeftStickY <= 99) { + speed = (100 - _ps3report->LeftStickY) * 0.01; + A.speed(speed); + printf("A:%f", speed); + } else { + speed = (155 - _ps3report->LeftStickY) * 0.01; + A.speed(speed); + printf("A:%f", speed); + } + + if(100 <= _ps3report->RightStickY && _ps3report->RightStickY <= 155) + { + B.stop(0); + } else if(0 <= _ps3report->RightStickY && _ps3report->RightStickY <= 99) { + speed = (100 - _ps3report->RightStickY) * 0.01; + B.speed(speed); + printf("B:%f", speed); + } else { + speed = (155 - _ps3report->RightStickY) * 0.01; + B.speed(speed); + printf("B:%f", speed); + } + } + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Socket.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,287 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +Tue Apr 26 2011 Bart Janssens: added a socket listener +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Utils.h" +#include "Socket.h" + +#define MAX_SOCKET_HANDLERS 3 +#define MAX_SOCKETS 16 +#define MAX_LISTEN 8 + +class SocketInternalPad +{ + public: + SocketInternal si; + u8 pad[8]; +}; + + + + +class SocketManager +{ + SocketHandler* _handlers[MAX_SOCKET_HANDLERS]; + SocketInternalPad _sockets[MAX_SOCKETS]; + SocketListener _listeners[MAX_LISTEN]; + + public: + SocketManager() + { + memset(_handlers,0,sizeof(_handlers)); + memset(_sockets,0,sizeof(_sockets)); + memset(_listeners,0,sizeof(_listeners)); + } + + SocketHandler* GetHandler(int type) + { + if (type < 1 || type > MAX_SOCKET_HANDLERS) + return 0; + return _handlers[type - 1]; + } + + SocketInternal* GetInternal(int s) + { + if (s < 1 || s > MAX_SOCKETS) + return 0; + return &_sockets[s - 1].si; + } + + int RegisterSocketHandler(int type, SocketHandler* handler) + { + if (type < 1 || type > MAX_SOCKET_HANDLERS) + return ERR_SOCKET_TYPE_NOT_FOUND; + _handlers[type - 1] = handler; + return 0; + } + + int Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData) + { + SocketHandler* h = GetHandler(type); + if (!h) + return ERR_SOCKET_TYPE_NOT_FOUND; + + for (int i = 0; i < MAX_SOCKETS; i++) + { + SocketInternal* si = (SocketInternal*)(_sockets+i); + if (si->ID == 0) + { + //printf("Call to Socket Manager Open \r\n"); + si->ID = i+1; + si->Type = type; + si->Callback = callback; + si->userData = userData; + return h->Open(si,addr); + } + } + return ERR_SOCKET_NONE_LEFT; + } + + SocketInternal* Create(int type, SocketAddrHdr* addr, int port) + { + SocketInternal* si; + SocketListener* li; + SocketHandler* h = GetHandler(type); + if (!h) + return 0; + + for (int i = 0; i < MAX_SOCKETS; i++) + { + si = (SocketInternal*)(_sockets+i); + if (si->ID == 0) + { + si->ID = i+1; + si->State = SocketState_Listen; + si->Type = type; + si->port = port; + for (int i = 0; i < MAX_LISTEN; i++){ + li = (SocketListener*)(_listeners+i); + if (( li->Type == si->Type )&& (li->port == si->port)) { + si->Callback = li->Callback; + si->userData = li->userData; + h->Create(si,addr); + return si; + } + + } + } + } + + } + + + int Listen(int type, int port, SocketCallback callback,void* userData) + { + SocketListener* li; + SocketHandler* h = GetHandler(type); + if (!h) return ERR_SOCKET_TYPE_NOT_FOUND; + + //printf("Call to Socket Manager Listen \r\n"); + for (int i = 0; i < MAX_LISTEN; i++) + { + li = (SocketListener*)(_listeners+i); + if (( li->Type == type )&& (li->port == port)) { + //printf("Port %d is already in use\r\n",port); + return ERR_SOCKET_IN_USE; //in use + } + } + + for (int i = 0; i < MAX_LISTEN; i++) + { + li = (SocketListener*)(_listeners+i); + if (( li->Type == 0 )&& (li->port == 0)) { + li->ID = i+1; + li->Type = type; + li->port = port; + li->Callback = callback; + li->userData = userData; + //printf("Listening on port %d \r\n",port); + return 0; + } + } + //printf("Max listen ports reached\r\n",port); + return ERR_SOCKET_NONE_LEFT; + } + + int InUse(int type, int port) + { + SocketListener* li; + SocketHandler* h = GetHandler(type); + if (!h) return ERR_SOCKET_TYPE_NOT_FOUND; + for (int i = 0; i < MAX_LISTEN; i++) + { + li = (SocketListener*)(_listeners+i); + if (( li->Type == type )&& (li->port == port)) { + + //printf("Listen check on port %d OK\r\n",port); + return 0; + } + } + //printf("Listen check on port %d NOK\r\n",port); + return ERR_SOCKET_NONE_LEFT; + } + + + int Accept(int socket, SocketCallback callback, void* userData) + { + SocketInternal* si = GetInternal(socket); + if (!si || si->ID != socket) + return ERR_SOCKET_NOT_FOUND; + + si->Callback = callback; + si->userData = userData; + + //printf("Call to Socket Manager Accept \r\n"); + return 0; + + } + + int Send(int socket, const u8* data, int len) + { + //printf("Call to Socket Manager Send \r\n"); + SocketInternal* si = GetInternal(socket); + //printf("socket = %d si->ID = %d si->Type = %d \r\n", socket, si->ID, si->Type); + if (!si || si->ID != socket){ + //printf("send: socket not found \r\n"); + return ERR_SOCKET_NOT_FOUND; + } + //printf("Calling l2cap send \r\n"); + + SocketHandler* h = GetHandler(si->Type); + if (!h) { + //printf("Send: no socket type found \r\n"); + return ERR_SOCKET_TYPE_NOT_FOUND; + } + return h->Send(si,data,len); + + } + + int Close(int socket) + { + SocketInternal* si = GetInternal(socket); + if (!si || si->ID != socket) + return ERR_SOCKET_NOT_FOUND; + si->ID = 0; + return GetHandler(si->Type)->Close(si); + } +}; + +SocketManager gSocketManager; + +int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData) +{ + //printf("Call to Socket Open \r\n"); + return gSocketManager.Open(type,addr,callback,userData); +} + +SocketInternal* Socket_Create(int type, SocketAddrHdr* addr, int port) +{ + return gSocketManager.Create(type, addr, port); +} + +int Socket_Send(int socket, const u8* data, int len) +{ + //printf("Call to Socket_Send \r\n"); + return gSocketManager.Send(socket,data,len); +} + +int Socket_Close(int socket) +{ + return gSocketManager.Close(socket); +} + +int Socket_Listen(int type, int port,SocketCallback callback, void* userData) +{ + //printf("Call to Socket_Listen \r\n"); + return gSocketManager.Listen(type, port,callback,userData); +} + +int Socket_InUse(int type, int port) +{ + //printf("Call to Socket_InUse \r\n"); + return gSocketManager.InUse(type, port); +} + +int Socket_Accept(int socket, SocketCallback callback, void* userData) +{ + //printf("Call to Socket_Accept \r\n"); + return gSocketManager.Accept(socket, callback, userData); +} + +int RegisterSocketHandler(int type, SocketHandler* handler) +{ + return gSocketManager.RegisterSocketHandler(type,handler); +} + +SocketInternal* GetSocketInternal(int socket) +{ + return gSocketManager.GetInternal(socket); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Socket.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,122 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +Tue Apr 26 2011 Bart Janssens: added a socket listener +*/ + +#ifndef SOCKET_H_INCLUDED +#define SOCKET_H_INCLUDED + +#define SOCKET_HCI 1 +#define SOCKET_L2CAP 2 +#define SOCKET_RFCOM 3 + +typedef struct +{ + u8 AddressSpecific[0]; // BDADDR,psm etc +} SocketAddrHdr; + + + +enum SocketState +{ + SocketState_Unknown, + SocketState_Opening, + SocketState_Open, + SocketState_Closing, + SocketState_Closed, + SocketState_Listen, + SocketState_Accept +}; + +typedef void (*SocketCallback)(int socket, SocketState state, const u8* data, int len, void* userData); + +class SocketListener +{ + public: + int ID; + int Type; + int port; + SocketCallback Callback; + void* userData; +}; + +//=========================================================================== +//=========================================================================== +// Don't need to look at or use anything below this line: +// Internal representation of socket + +class SocketHandler; +class SocketInternal +{ + public: + + u8 ID; + u8 State; + u8 Type; + u8 B0; + int port; + SocketCallback Callback; + void* userData; + u8 Data[0]; // Extra socket data starts here + + void Recv(const u8* data, int len) + { + Callback(ID,(SocketState)State,data,len,userData); + } + + void SetState(SocketState state) + { + State = state; + Callback(ID,(SocketState)State,0,0,userData); + } +}; + +class SocketHandler +{ + public: + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) = 0; + virtual int Create(SocketInternal* sock, SocketAddrHdr* addr) = 0; + virtual int Send(SocketInternal* sock, const u8* data, int len) = 0; + virtual int Close(SocketInternal* sock) = 0; + virtual int Accept(SocketInternal* sock, SocketAddrHdr* addr) = 0; +}; + +int RegisterSocketHandler(int type, SocketHandler* handler); +SocketInternal* GetSocketInternal(int socket); + +int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData); // Open a socket +int Socket_Listen(int type, int port,SocketCallback callback, void* userData); +int Socket_InUse(int type, int port); +int Socket_Accept(int socket, SocketCallback callback, void* userData); +SocketInternal* Socket_Create(int type,SocketAddrHdr* addr, int port); +int Socket_Send(int socket, const u8* data, int len); +int Socket_State(int socket); +int Socket_Close(int socket); + +#define ERR_SOCKET_TYPE_NOT_FOUND -200 +#define ERR_SOCKET_NOT_FOUND -201 +#define ERR_SOCKET_NONE_LEFT -202 +#define ERR_SOCKET_IN_USE -203 + +#endif // SOCKET_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TestShell.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,565 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +Tue Apr 26 2011 Bart Janssens: added PS3 Bluetooth support +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Utils.h" +#include "USBHost.h" +#include "hci.h" +#include "ps3.h" + +#include "mbed.h" + +void printf(const BD_ADDR* addr) +{ + const u8* a = addr->addr; + printf("%02X:%02X:%02X:%02X:%02X:%02X",a[5],a[4],a[3],a[2],a[1],a[0]); +} + +#define MAX_HCL_SIZE 260 +#define MAX_ACL_SIZE 400 + +class HCITransportUSB : public HCITransport +{ + int _device; + u8* _hciBuffer; + u8* _aclBuffer; + + public: + void Open(int device, u8* hciBuffer, u8* aclBuffer) + { + _device = device; + _hciBuffer = hciBuffer; + _aclBuffer = aclBuffer; + USBInterruptTransfer(_device,0x81,_hciBuffer,MAX_HCL_SIZE,HciCallback,this); + USBBulkTransfer(_device,0x82,_aclBuffer,MAX_ACL_SIZE,AclCallback,this); + } + + static void HciCallback(int device, int endpoint, int status, u8* data, int len, void* userData) + { + HCI* t = ((HCITransportUSB*)userData)->_target; + if (t) + t->HCIRecv(data,len); + USBInterruptTransfer(device,0x81,data,MAX_HCL_SIZE,HciCallback,userData); + } + + static void AclCallback(int device, int endpoint, int status, u8* data, int len, void* userData) + { + HCI* t = ((HCITransportUSB*)userData)->_target; + if (t) + t->ACLRecv(data,len); + USBBulkTransfer(device,0x82,data,MAX_ACL_SIZE,AclCallback,userData); + } + + virtual void HCISend(const u8* data, int len) + { + USBControlTransfer(_device,REQUEST_TYPE_CLASS, 0, 0, 0,(u8*)data,len); + } + + virtual void ACLSend(const u8* data, int len) + { + USBBulkTransfer(_device,0x02,(u8*)data,len); + } +}; + + +#define WII_REMOTE 0x042500 +#define PS3_REMOTE 0x080500 + +class HIDBluetooth +{ + int _control; // Sockets for control (out) and interrupt (in) + int _interrupt; + int _devClass; + BD_ADDR _addr; + u8 _pad[2]; // Struct align + int _ready; + Timeout _timeout; + int _count; + +public: + HIDBluetooth() : _control(0),_interrupt(0),_devClass(0), _ready(1) {}; + + + bool InUse() + { + return _control != 0; + } + + void attimeout() + { + printf("Timeout reached\r\n"); + } + + static void OnHidInterrupt(int socket, SocketState state,const u8* data, int len, void* userData) + { + HIDBluetooth* t = (HIDBluetooth*)userData; + t->_ready = 0; + if (data) + { + //printf("devClass = %06X \r\n",t->_devClass); + if (t->_devClass == WII_REMOTE && data[1] == 0x30) + { + printf("================wii====================\r\n"); + t->WIILed(); + t->WIIHid(); // ask for accelerometer + t->_devClass = 0; + + + const u8* d = data; + switch (d[1]) + { + case 0x02: + { + int x = (signed char)d[3]; + int y = (signed char)d[4]; + printf("Mouse %2X dx:%d dy:%d\r\n",d[2],x,y); + } + break; + + case 0x37: // Accelerometer http://wiki.wiimoteproject.com/Reports + { + int pad = (d[2] & 0x9F) | ((d[3] & 0x9F) << 8); + int x = (d[2] & 0x60) >> 5 | d[4] << 2; + int y = (d[3] & 0x20) >> 4 | d[5] << 2; + int z = (d[3] & 0x40) >> 5 | d[6] << 2; + printf("WII %04X %d %d %d\r\n",pad,x,y,z); + } + break; + default: + printHex(data,len); + } + } + if (t->_devClass == PS3_REMOTE) + { + t->_count ++; + if (t->_count == 25) t->_count = 1; + ParsePs3Result((data + 1), sizeof(ps3report),t->_count); + } + else { + printf("Not yet implemented \r\n"); + + } + } + + } + + static void OnHidControl(int socket, SocketState state, const u8* data, int len, void* userData) + { + //HIDBluetooth* t = (HIDBluetooth*)userData; + + //printf("OnHidControl\r\n"); + + } + + static void OnAcceptCtrlSocket(int socket, SocketState state, const u8* data, int len, void* userData) + { + HIDBluetooth* t = (HIDBluetooth*)userData; + + t->_control = socket; + + //printf("Ctrl Socket number = %d \r\n", socket); + + Socket_Accept(socket,OnHidControl,userData); + u8 enable[6] = { + 0x53, /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE */ + 0xf4, 0x42, 0x03, 0x00, 0x00 }; + Socket_Send(socket,enable,6); + + + } + + static void OnAcceptDataSocket(int socket, SocketState state, const u8* data, int len, void* userData) + { + HIDBluetooth* t = (HIDBluetooth*)userData; + t->_interrupt = socket; + + printf("OnAcceptDataSocket: Data Socket accept here \r\n"); + printf("OnAcceptDataSocket: Data Socket number = %d \r\n", socket); + + //printf("OnAcceptDataSocket: Ctrl Socket = %d Data Socket accept = %d \r\n", t->_control, t->_interrupt); + + Socket_Accept(socket,OnHidInterrupt,userData); + + //if (data) + // printHex(data,len); + } + + void Open(BD_ADDR* bdAddr, inquiry_info* info) + { + printf("L2CAPAddr size %d\r\n",sizeof(L2CAPAddr)); + _addr = *bdAddr; + L2CAPAddr sockAddr; + sockAddr.bdaddr = _addr; + sockAddr.psm = L2CAP_PSM_HID_INTR; + printf("Socket_Open size %d\r\n",sizeof(L2CAPAddr)); + _interrupt = Socket_Open(SOCKET_L2CAP,&sockAddr.hdr,OnHidInterrupt,this); + sockAddr.psm = L2CAP_PSM_HID_CNTL; + _control = Socket_Open(SOCKET_L2CAP,&sockAddr.hdr,OnHidControl,this); + + printfBytes("OPEN DEVICE CLASS",info->dev_class,3); + _devClass = (info->dev_class[0] << 16) | (info->dev_class[1] << 8) | info->dev_class[2]; + } + + void Listen(BD_ADDR* bdAddr, inquiry_info* info) + { + int result; + //printf("L2CAPAddr size %d\r\n",sizeof(L2CAPAddr)); + _addr = *bdAddr; + L2CAPAddr sockAddr; + sockAddr.bdaddr = _addr; + + _count = 1; + _ready = 1; + + // set a buffer for the led&rumble report + u8 abuffer[37] = { + 0x52, /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT */ + 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1E, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, + }; + memcpy(_ledrumble,abuffer,37); + + result = Socket_Listen(SOCKET_L2CAP,L2CAP_PSM_HID_CNTL,OnAcceptCtrlSocket,this); + printf("listen return code ctrl socket = %d \r\n", result); + + + result = Socket_Listen(SOCKET_L2CAP,L2CAP_PSM_HID_INTR,OnAcceptDataSocket,this); + printf("listen return code data socket = %d \r\n", result); + + printfBytes("OPEN DEVICE CLASS",info->dev_class,3); + _devClass = (info->dev_class[0] << 16) | (info->dev_class[1] << 8) | info->dev_class[2]; + + while (_ready){ // wait till we receive data from PS3Hid + USBLoop(); + } + USBLoop(); + + + + } + + void Close() + { + if (_control) + Socket_Close(_control); + if (_interrupt) + Socket_Close(_interrupt); + _control = _interrupt = 0; + } + + void WIILed(int id = 0x10) + { + u8 led[3] = {0x52, 0x11, id}; + if (_control) + Socket_Send(_control,led,3); + } + + void WIIHid(int report = 0x37) + { + u8 hid[4] = { 0x52, 0x12, 0x00, report }; + if (_control != -1) + Socket_Send(_control,hid,4); + } + + + + void Ps3Hid_Led(int i) + { + printf("Ps3Hid led %d\r\n",i); + u8 ledpattern[7] = {0x02, 0x04, 0x08, 0x10, 0x12, 0x14, 0x18 }; + u8 buf[37]; + + if (i < 7) _ledrumble[11] = ledpattern[i]; + memcpy(buf, _ledrumble, 37); + + if (_control != -1) + Socket_Send(_control,buf,37); + wait_ms(4); + } + + void Ps3Hid_Rumble(u8 duration_right, u8 power_right, u8 duration_left, u8 power_left ) + { + printf("Ps3Hid rumble \r\n"); + u8 buf[37]; + + memcpy(buf, _ledrumble, 37); + buf[3] = duration_right; + buf[4] = power_right; + buf[5] = duration_left; + buf[6] = power_left; + + if (_control != -1) + Socket_Send(_control,buf,37); + wait_ms(4); + } + + int CheckHID() + { + printf("CheckHID \r\n"); + printf("Ctrl = %d Intr = %d \r\n", _control, _interrupt); + if (_control < 1) { + printf("Ps3 not ready \r\n"); + return 1; + } else { + printf("Ps3 ready %d \r\n",_control); + return 0; + } + } + private: + u8 _ledrumble[37] ; +}; + + +HCI* gHCI = 0; + +#define MAX_HID_DEVICES 8 + +int GetConsoleChar(); +class ShellApp +{ + char _line[64]; + HIDBluetooth _hids[MAX_HID_DEVICES]; + +public: + void Ready() + { + printf("HIDBluetooth %d\r\n",sizeof(HIDBluetooth)); + memset(_hids,0,sizeof(_hids)); + //Inquiry(); + Scan(); + } + + // We have connected to a device + void ConnectionComplete(HCI* hci, connection_info* info) + { + printf("ConnectionComplete "); + BD_ADDR* a = &info->bdaddr; + printf(a); + BTDevice* bt = hci->Find(a); + HIDBluetooth* hid = NewHIDBluetooth(); + printf("%08x %08x\r\n",bt,hid); + if (hid) + hid->Listen(a,&bt->_info); // use Listen for PS3, Open for WII + hid->Ps3Hid_Led(0); // set led 1 + hid->Ps3Hid_Rumble(0x20,0xff,0x20,0xff); // rumble + + } + + HIDBluetooth* NewHIDBluetooth() + { + for (int i = 0; i < MAX_HID_DEVICES; i++) + if (!_hids[i].InUse()) + return _hids+i; + return 0; + } + + void ConnectDevices() + { + printf("ConnectDevices\n"); + + BTDevice* devs[8]; + int count = gHCI->GetDevices(devs,8); + for (int i = 0; i < count; i++) + { + printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3); + if (devs[i]->_handle == 0) + { + BD_ADDR* bd = &devs[i]->_info.bdaddr; + printf("Connecting to "); + printf(bd); + printf("\r\n"); + gHCI->CreateConnection(bd); + } + } + } + + const char* ReadLine() + { + int i; + for (i = 0; i < 255; ) + { + USBLoop(); + int c = GetConsoleChar(); + if (c == -1) + continue; + if (c == '\n' || c == 13) + break; + _line[i++] = c; + } + _line[i] = 0; + return _line; + } + + void Inquiry() + { + printf("Inquiry..\r\n"); + gHCI->Inquiry(); + } + + void List() + { + #if 0 + printf("%d devices\r\n",_deviceCount); + for (int i = 0; i < _deviceCount; i++) + { + printf(&_devices[i].info.bdaddr); + printf("\r\n"); + } + #endif + } + + void Scan() + { + printf("Scanning...\r\n"); + gHCI->WriteScanEnable(); + } + + void Connect() + { + ConnectDevices(); + } + + + void Disconnect() + { + gHCI->DisconnectAll(); + } + + void CloseMouse() + { + } + + void Quit() + { + CloseMouse(); + } + + void Run() + { + for(;;) + { + const char* cmd = ReadLine(); + if (strcmp(cmd,"scan") == 0 || strcmp(cmd,"inquiry") == 0) + Inquiry(); + else if (strcmp(cmd,"ls") == 0) + List(); + else if (strcmp(cmd,"connect") == 0) + Connect(); + else if (strcmp(cmd,"disconnect") == 0) + Disconnect(); + else if (strcmp(cmd,"q")== 0) + { + Quit(); + break; + } else { + printf("eh? %s\r\n",cmd); + } + } + } +}; + +// Instance +ShellApp gApp; + +static int HciCallback(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len) +{ + switch (evt) + { + case CALLBACK_READY: + printf("CALLBACK_READY\r\n"); + gApp.Ready(); + break; + + case CALLBACK_INQUIRY_RESULT: + printf("CALLBACK_INQUIRY_RESULT "); + printf((BD_ADDR*)data); + printf("\r\n"); + break; + + case CALLBACK_INQUIRY_DONE: + printf("CALLBACK_INQUIRY_DONE\r\n"); + gApp.ConnectDevices(); + break; + + case CALLBACK_REMOTE_NAME: + { + BD_ADDR* addr = (BD_ADDR*)data; + const char* name = (const char*)(data + 6); + printf(addr); + printf(" % s\r\n",name); + } + break; + + case CALLBACK_CONNECTION_COMPLETE: + gApp.ConnectionComplete(hci,(connection_info*)data); + break; + }; + return 0; +} + +// these should be placed in the DMA SRAM +typedef struct +{ + u8 _hciBuffer[MAX_HCL_SIZE]; + u8 _aclBuffer[MAX_ACL_SIZE]; +} SRAMPlacement; + +HCITransportUSB _HCITransportUSB; +HCI _HCI; + +u8* USBGetBuffer(u32* len); +int OnBluetoothInsert(int device) +{ + printf("Bluetooth inserted of %d\r\n",device); + u32 sramLen; + u8* sram = USBGetBuffer(&sramLen); + sram = (u8*)(((u32)sram + 1023) & ~1023); + SRAMPlacement* s = (SRAMPlacement*)sram; + _HCITransportUSB.Open(device,s->_hciBuffer,s->_aclBuffer); + _HCI.Open(&_HCITransportUSB,HciCallback); + RegisterSocketHandler(SOCKET_L2CAP,&_HCI); + gHCI = &_HCI; + //gApp.Inquiry(); + //gApp.Scan(); + gApp.Connect(); + return 0; +} + +void TestShell() +{ + USBInit(); + gApp.Run(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextLCD.lib Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/tlunzer/code/TextLCD/#a7c08c5305b3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,1072 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "mbed.h" +#include "USBHost.h" + +// Config (default uses x bytes) +#define MAX_DEVICES 8 // Max number of devices +#define MAX_ENDPOINTS_TOTAL 16 // Max number of endpoints total +#define MAX_ENDPOINTS_PER_DEVICE 8 // Max number of endpoints for any one device + +#define USBLOG 1 +#if USBLOG +#define LOG(...) printf(__VA_ARGS__) +#else +#define LOG(...) do {} while(0) +#endif + +// USB host structures + +#define USB_RAM_SIZE 16*1024 // AHB SRAM block 1 TODO MACHINE DEPENDENT +#define USB_RAM_BASE 0x2007C000 + +#define TOKEN_SETUP 0 +#define TOKEN_IN 1 +#define TOKEN_OUT 2 + +// Status flags from hub +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVER_CURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOW_SPEED 9 + +#define C_PORT_CONNECTION 16 +#define C_PORT_ENABLE 17 +#define C_PORT_SUSPEND 18 +#define C_PORT_OVER_CURRENT 19 +#define C_PORT_RESET 20 + +typedef struct { + u8 bm_request_type; + u8 b_request; + u16 w_value; + u16 w_index; + u16 w_length; +} Setup; + + +// Hub stuff is kept private just to keep api simple +int SetPortFeature(int device, int feature, int index); +int ClearPortFeature(int device, int feature, int index); +int SetPortPower(int device, int port); +int SetPortReset(int device, int port); +int GetPortStatus(int device, int port, u32* status); + +//=================================================================== +//=================================================================== +// Hardware defines + +// HcControl +#define PeriodicListEnable 0x00000004 +#define IsochronousEnable 0x00000008 +#define ControlListEnable 0x00000010 +#define BulkListEnable 0x00000020 +#define OperationalMask 0x00000080 +#define HostControllerFunctionalState 0x000000C0 + +// HcCommandStatus +#define HostControllerReset 0x00000001 +#define ControlListFilled 0x00000002 +#define BulkListFilled 0x00000004 + +// HcInterruptStatus Register +#define WritebackDoneHead 0x00000002 +#define StartofFrame 0x00000004 +#define ResumeDetected 0x00000008 +#define UnrecoverableError 0x00000010 +#define FrameNumberOverflow 0x00000020 +#define RootHubStatusChange 0x00000040 +#define OwnershipChange 0x00000080 +#define MasterInterruptEnable 0x80000000 + +// HcRhStatus +#define SetGlobalPower 0x00010000 +#define DeviceRemoteWakeupEnable 0x00008000 + +// HcRhPortStatus (hub 0, port 1) +#define CurrentConnectStatus 0x00000001 +#define PortEnableStatus 0x00000002 +#define PortSuspendStatus 0x00000004 +#define PortOverCurrentIndicator 0x00000008 +#define PortResetStatus 0x00000010 + +#define PortPowerStatus 0x00000100 +#define LowspeedDevice 0x00000200 +#define HighspeedDevice 0x00000400 + +#define ConnectStatusChange (CurrentConnectStatus << 16) +#define PortResetStatusChange (PortResetStatus << 16) + + +#define TD_ROUNDING (u32)0x00040000 +#define TD_SETUP (u32)0x00000000 +#define TD_IN (u32)0x00100000 +#define TD_OUT (u32)0x00080000 +#define TD_DELAY_INT(x) (u32)((x) << 21) +#define TD_TOGGLE_0 (u32)0x02000000 +#define TD_TOGGLE_1 (u32)0x03000000 +#define TD_CC (u32)0xF0000000 + +// HostController EndPoint Descriptor +typedef struct { + volatile u32 Control; + volatile u32 TailTd; + volatile u32 HeadTd; + volatile u32 Next; +} HCED; + +// HostController Transfer Descriptor +typedef struct { + volatile u32 Control; + volatile u32 CurrBufPtr; + volatile u32 Next; + volatile u32 BufEnd; +} HCTD; + +// Host Controller Communication Area +typedef struct { + volatile u32 InterruptTable[32]; + volatile u16 FrameNumber; + volatile u16 FrameNumberPad; + volatile u32 DoneHead; + volatile u8 Reserved[120]; +} HCCA; + +//==================================================================================== +//==================================================================================== + +class HostController; +class Endpoint; +class Device; + +// must be 3*16 bytes long +class Endpoint +{ +public: + HCED EndpointDescriptor; // Pointer to EndpointDescriptor == Pointer to Endpoint + HCTD TDHead; + + enum State + { + Free, + NotQueued, + Idle, + SetupQueued, + DataQueued, + StatusQueued, + CallbackPending + }; + + volatile u8 CurrentState; + u8 Flags; // 0x80 In, 0x03 mask endpoint type + + u16 Length; + u8* Data; + USBCallback Callback; // Must be a multiple of 16 bytes long + void* UserData; + + int Address() + { + int ep = (EndpointDescriptor.Control >> 7) & 0xF; + if (ep) + ep |= Flags & 0x80; + return ep; + } + + int Device() + { + return EndpointDescriptor.Control & 0x7F; + } + + int Status() + { + return (TDHead.Control >> 28) & 0xF; + } + + u32 Enqueue(u32 head) + { + if (CurrentState == NotQueued) + { + EndpointDescriptor.Next = head; + head = (u32)&EndpointDescriptor; + CurrentState = Idle; + } + return head; + } +}; + +class Device +{ +public: + u8 _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2]; + u8 Hub; + u8 Port; + u8 Addr; + u8 Pad; + + // Only if this device is a hub + u8 HubPortCount; // nonzero if this is a hub + u8 HubInterruptData; + u8 HubMap; + u8 HubMask; + + int Flags; // 1 = Disconnected + + Setup SetupBuffer; + + // Allocate endpoint zero + int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed) + { + Hub = hub; + Port = port; + Addr = addr; + Flags = lowSpeed; + memset(_endpointMap,0xFF,sizeof(_endpointMap)); + return 0; + } + + int SetEndpointIndex(int ep, int endpointIndex) + { + for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) + { + if (_endpointMap[i] == 0xFF) // Add endpoint to map + { + _endpointMap[i] = ep; + _endpointMap[i+1] = endpointIndex; + return 0; + } + } + return ERR_ENDPOINT_NONE_LEFT; + } + + int GetEndpointIndex(int ep) + { + for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) + { + if (_endpointMap[i] == ep) + return _endpointMap[i+1]; + if (_endpointMap[i] == 0xFF) + break; + } + return -1; + } +}; + +class HostController +{ +public: + HCCA CommunicationArea; + Endpoint Endpoints[MAX_ENDPOINTS_TOTAL]; // Multiple of 16 + + Endpoint EndpointZero; // For device enumeration + HCTD _commonTail; + Setup _setupZero; + + Device Devices[MAX_DEVICES]; + u32 _frameNumber; // 32 bit ms counter + + u8 _callbacksPending; // Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue + u8 _rootHubStatusChange; // Root hub status has changed, set from ISR + u8 _unused0; + u8 _unused1; + + u8 _connectPending; // Reset has initiated a connect + u8 _connectCountdown; // Number of ms left after reset before we can connect + u8 _connectHub; // Will connect on this hub + u8 _connectPort; // ... and this port + + u8 SRAM[0]; // Start of free SRAM + + void Loop() + { + u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber; // extend to 32 bits + _frameNumber += elapsed; + + // Do callbacks, if any + while (_callbacksPending) + { + for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) + { + Endpoint* endpoint = Endpoints + i; + if (endpoint->CurrentState == Endpoint::CallbackPending) + { + _callbacksPending--; + endpoint->CurrentState = Endpoint::Idle; + endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData); + } + } + } + + // Deal with changes on the root hub + if (_rootHubStatusChange) + { + u32 status = LPC_USB->HcRhPortStatus1; + _rootHubStatusChange = 0; + if (status >> 16) + { + HubStatusChange(0,1,status); + LPC_USB->HcRhPortStatus1 = status & 0xFFFF0000; // clear status changes + } + } + + // Connect after reset timeout + if (_connectCountdown) + { + if (elapsed >= _connectCountdown) + { + _connectCountdown = 0; + Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80); + } else + _connectCountdown -= elapsed; + } + } + + // HubInterrupt - bitmap in dev->HubInterruptData + void HubInterrupt(int device) + { + Device* dev = &Devices[device-1]; + for (int i = 0; i < dev->HubPortCount; i++) + { + int port = i+1; + if (dev->HubInterruptData & (1 << port)) + { + u32 status = 0; + GetPortStatus(device,port,&status); + if (status >> 16) + { + if (_connectPending && (status & ConnectStatusChange)) + continue; // Don't connect again until previous device has been added and addressed + + HubStatusChange(device,port,status); + if (status & ConnectStatusChange) + ClearPortFeature(device,C_PORT_CONNECTION,port); + if (status & PortResetStatusChange) + ClearPortFeature(device,C_PORT_RESET,port); + } + } + } + } + + static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData) + { + HostController* controller = (HostController*)userData; + if (status == 0) + controller->HubInterrupt(device); + USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData); + } + + int InitHub(int device) + { + u8 buf[16]; + int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf)); + if (r < 0) + return ERR_HUB_INIT_FAILED; + + // turn on power on the hubs ports + Device* dev = &Devices[device-1]; + int ports = buf[2]; + dev->HubPortCount = ports; + for (int i = 0; i < ports; i++) + SetPortPower(device,i+1); + + // Enable hub change interrupts + return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this); + } + + int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval) + { + LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\r\n",device,ep,attributes,maxPacketSize,interval); + Device* dev = &Devices[device-1]; + Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize); + if (!endpoint) + return ERR_ENDPOINT_NONE_LEFT; + dev->SetEndpointIndex(ep,endpoint - Endpoints); + endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed + return 0; // TODO ed->bInterval + } + + int AddEndpoint(int device, EndpointDescriptor* ed) + { + return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval); + } + + // allocate a endpoint + Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize) + { + for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) + { + Endpoint* ep = &Endpoints[i]; + if (ep->CurrentState == 0) + { + //LOG("Allocated endpoint %d to %02X:%02X\r\n",i,device,endpointAddress); + ep->Flags = (endpointAddress & 0x80) | (type & 3); + ep->CurrentState = Endpoint::NotQueued; + ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device; + return ep; + } + } + return 0; + } + + Endpoint* GetEndpoint(int device, int ep) + { + if (device == 0) + { + //printf("WARNING: USING DEVICE 0\n"); + return &EndpointZero; + } + if (device > MAX_DEVICES) + return 0; + int i = Devices[device-1].GetEndpointIndex(ep); + if (i == -1) + return 0; + return Endpoints + i; + } + + int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state) + { + //LOG("Transfer %02X T:%d Len:%d S:%d\r\n",endpoint->Address(),token,len,state); + + int toggle = 0; + if (endpoint->Address() == 0) + toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1; + + if (token != TOKEN_SETUP) + token = (token == TOKEN_IN ? TD_IN : TD_OUT); + + HCTD* head = &endpoint->TDHead; + HCTD* tail = &_commonTail; + + head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC; + head->CurrBufPtr = (u32)data; + head->BufEnd = (u32)(data + len - 1); + head->Next = (u32)tail; + + HCED* ed = &endpoint->EndpointDescriptor; + ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002); // carry toggle + ed->TailTd = (u32)tail; + + //HCTD* td = head; + //LOG("%04X TD %08X %08X %08X Next:%08X\r\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next); + //LOG("%04X ED %08X %08X %08X\r\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd); + + switch (endpoint->Flags & 3) + { + case ENDPOINT_CONTROL: + LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED); // May change state NotQueued->Idle + endpoint->CurrentState = state; // Get in before an int + LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled; + LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable; + break; + + case ENDPOINT_BULK: + LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED); + endpoint->CurrentState = state; + LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled; + LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable; + break; + + case ENDPOINT_INTERRUPT: + CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]); + endpoint->CurrentState = state; + LPC_USB->HcControl |= PeriodicListEnable; + break; + } + return 0; + } + + // Remove an endpoint from an active queue + bool Remove(HCED* ed, volatile HCED** queue) + { + if (*queue == 0) + return false; + if (*queue == (volatile HCED*)ed) + { + *queue = (volatile HCED*)ed->Next; // At head of queue + return true; + } + + volatile HCED* head = *queue; + while (head) + { + if (head->Next == (u32)ed) + { + head->Next = ed->Next; + return true; + } + head = (volatile HCED*)head->Next; + } + return false; + } + + void Release(Endpoint* endpoint) + { + if (endpoint->CurrentState == Endpoint::NotQueued) + { + // Never event used it, nothing to do + } + else + { + HCED* ed = (HCED*)endpoint; + ed->Control |= 0x4000; // SKIP + switch (endpoint->Flags & 0x03) + { + case ENDPOINT_CONTROL: + Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED); + break; + case ENDPOINT_BULK: + Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED); + break; + case ENDPOINT_INTERRUPT: + for (int i = 0; i < 32; i++) + Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]); + break; + } + + u16 fn = CommunicationArea.FrameNumber; + while (fn == CommunicationArea.FrameNumber) + ; // Wait for next frame + + } + + // In theory, the endpoint is now dead. + // TODO: Will Callbacks ever be pending? BUGBUG + memset(endpoint,0,sizeof(Endpoint)); + } + + // Pop the last TD from the list + HCTD* Reverse(HCTD* current) + { + HCTD *result = NULL,*temp; + while (current) + { + temp = (HCTD*)current->Next; + current->Next = (u32)result; + result = current; + current = temp; + } + return result; + } + + // Called from interrupt... + // Control endpoints use a state machine to progress through the transfers + void ProcessDoneQueue(u32 tdList) + { + HCTD* list = Reverse((HCTD*)tdList); + while (list) + { + Endpoint* endpoint = (Endpoint*)(list-1); + list = (HCTD*)list->Next; + int ep = endpoint->Address(); + bool in = endpoint->Flags & 0x80; + int status = (endpoint->TDHead.Control >> 28) & 0xF; + + //LOG("ProcessDoneQueue %02X %08X\r\n",ep,endpoint->TDHead.Control); + + if (status != 0) + { + //LOG("ProcessDoneQueue status %02X %d\r\n",ep,status); + endpoint->CurrentState = Endpoint::Idle; + } else { + switch (endpoint->CurrentState) + { + case Endpoint::SetupQueued: + if (endpoint->Length == 0) + Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Skip Data Phase + else + Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued); // Setup is done, now Data + break; + + case Endpoint::DataQueued: + if (endpoint->TDHead.CurrBufPtr) + endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data; + + if (ep == 0) + Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Data is done, now Status, Control only + else + endpoint->CurrentState = Endpoint::Idle; + break; + + case Endpoint::StatusQueued: // Transaction is done + endpoint->CurrentState = Endpoint::Idle; + break; + } + } + + // Complete, flag if we need a callback + if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle) + { + endpoint->CurrentState = Endpoint::CallbackPending; + _callbacksPending++; + } + } + } + + // Hack to reset devices that don't want to connect + int AddDevice(int hub, int port, bool isLowSpeed) + { + int device = AddDeviceCore(hub,port,isLowSpeed); + if (device < 0) + { + LOG("========RETRY ADD DEVICE========\r\n"); // This will go for ever.. TODO power cycle root? + Disconnect(hub,port); // Could not read descriptor at assigned address, reset this port and try again + ResetPort(hub,port); // Cheap bluetooth dongles often need this on a hotplug + return -1; + } + return device; + } + + int AddDeviceCore(int hub, int port, bool isLowSpeed) + { + int lowSpeed = isLowSpeed ? 0x2000 : 0; + DeviceDescriptor desc; + EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed; // MaxPacketSize == 8 + int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8); + if (r < 0) + { + LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\r\n"); + return r; + } + + EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed; // Actual MaxPacketSize + r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); + if (r < 0) + return r; + + LOG("\nClass %02X found %04X:%04X\r\n",desc.bDeviceClass,desc.idVendor,desc.idProduct); + + // Now assign the device an address, move off EndpointZero + int device = 0; + for (int i = 0; i < MAX_DEVICES; i++) + { + if (Devices[i].Port == 0) + { + device = i+1; + break; + } + } + if (!device) + return ERR_DEVICE_NONE_LEFT; + + r = SetAddress(0,device); + if (r) + return r; + DelayMS(2); + + // Now at a nonzero address, create control endpoint + Device* dev = &Devices[device-1]; + dev->Init(&desc,hub,port,device,lowSpeed); + AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0); + _connectPending = 0; + + // Verify this all works + r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); + if (r < 0) + return r; + + // Set to interface 0 by default + // Calls LoadDevice if interface is found + r = SetConfigurationAndInterface(device,1,0,&desc); + + if (desc.bDeviceClass == CLASS_HUB) + InitHub(device); // Handle hubs in this code + + return device; + } + + // Walk descriptors and create endpoints for a given device + // TODO configuration !=1, alternate settings etc. + int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc) + { + u8 buffer[255]; + int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer)); + if (err < 0) + return err; + + err = SetConfiguration(device,configuration); + if (err < 0) + return err; + + // Add the endpoints for this interface + int len = buffer[2] | (buffer[3] << 8); + u8* d = buffer; + u8* end = d + len; + InterfaceDescriptor* found = 0; + while (d < end) + { + if (d[1] == DESCRIPTOR_TYPE_INTERFACE) + { + InterfaceDescriptor* id = (InterfaceDescriptor*)d; + if (id->bInterfaceNumber == interfaceNumber) + { + found = id; + d += d[0]; + while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) + { + switch (d[1]) + { + case DESCRIPTOR_TYPE_ENDPOINT: + AddEndpoint(device,(EndpointDescriptor*)d); + break; + default: + LOG("Skipping descriptor %02X (%d bytes)\r\n",d[1],d[0]); + } + d += d[0]; + } + } + } + d += d[0]; + } + + if (!found) + return ERR_INTERFACE_NOT_FOUND; + OnLoadDevice(device,desc,found); + return 0; + } + + void Init() + { + LOG("USB INIT (Controller is %d bytes)\r\n",sizeof(*this)); + memset(this,0,sizeof(HostController)); + EndpointZero.CurrentState = Endpoint::NotQueued; + HWInit(&CommunicationArea); + DelayMS(10); + } + + void ResetPort(int hub, int port) + { + LOG("ResetPort Hub:%d Port:%d\r\n",hub,port); + _connectPending++; // Only reset/add 1 device at a time + if (hub == 0) + LPC_USB->HcRhPortStatus1 = PortResetStatus; // Reset Root Hub, port 1 + else + SetPortReset(hub,port); // or reset other hub + } + + void Disconnect(int hub, int port) + { + LOG("Disconnect Hub:%d Port:%d\r\n",hub,port); // Mark a device for destruction + for (int i = 0; i < MAX_DEVICES; i++) + { + Device* dev = Devices + i; + if (dev->Port == port && dev->Hub == hub) + { + // Disconnect everything that is attached to this device if it is a hub + for (int p = 0; p < dev->HubPortCount; p++) + Disconnect(i+1,p+1); + + // Now release endpoints + for (int j = 1; j < MAX_ENDPOINTS_PER_DEVICE*2; j += 2) + { + u8 endpointIndex = dev->_endpointMap[j]; + if (endpointIndex != 0xFF) + Release(Endpoints + endpointIndex); + } + dev->Port = 0; // Device is now free + dev->Flags = 0; + return; + } + } + } + + // called after reset + void Connect(int hub, int port, bool lowspeed) + { + LOG("Connect Hub:%d Port:%d %s\r\n",hub,port,lowspeed ? "slow" : "full"); + AddDevice(hub,port,lowspeed); + } + + // Called from interrupt + void HubStatusChange(int hub, int port, u32 status) + { + LOG("HubStatusChange Hub:%d Port:%d %08X\r\n",hub,port,status); + if (status & ConnectStatusChange) + { + if (status & CurrentConnectStatus) // Connecting + ResetPort(hub,port); // Reset to initiate connect (state machine?) + else + Disconnect(hub,port); + } + + if (status & PortResetStatusChange) + { + if (!(status & PortResetStatus)) + { + _connectCountdown = 200; // Schedule a connection in 200ms + if (status & LowspeedDevice) + port |= 0x80; + _connectHub = hub; + _connectPort = port; + } + } + } + + #define HOST_CLK_EN (1<<0) + #define PORTSEL_CLK_EN (1<<3) + #define AHB_CLK_EN (1<<4) + #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) + + #define FRAMEINTERVAL (12000-1) // 1ms + #define DEFAULT_FMINTERVAL ((((6 * (FRAMEINTERVAL - 210)) / 7) << 16) | FRAMEINTERVAL) + + void DelayMS(int ms) + { + u16 f = ms + CommunicationArea.FrameNumber; + while (f != CommunicationArea.FrameNumber) + ; + } + + static void HWInit(HCCA* cca) + { + NVIC_DisableIRQ(USB_IRQn); + + // turn on power for USB + LPC_SC->PCONP |= (1UL<<31); + // Enable USB host clock, port selection and AHB clock + LPC_USB->USBClkCtrl |= CLOCK_MASK; + // Wait for clocks to become available + while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) + ; + + // We are a Host + LPC_USB->OTGStCtrl |= 1; + LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; // we don't need port selection clock until we do OTG + + // configure USB pins + LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28)); + LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // USB D+/D- + + LPC_PINCON->PINSEL3 &= ~((3 << 6) | (3 << 22)); // USB_PPWR, USB_OVRCR + LPC_PINCON->PINSEL3 |= ((2 << 6) | (2 << 22)); + + LPC_PINCON->PINSEL4 &= ~(3 << 18); // USB_CONNECT + LPC_PINCON->PINSEL4 |= (1 << 18); + + // Reset OHCI block + LPC_USB->HcControl = 0; + LPC_USB->HcControlHeadED = 0; + LPC_USB->HcBulkHeadED = 0; + + LPC_USB->HcCommandStatus = HostControllerReset; + LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; + LPC_USB->HcPeriodicStart = FRAMEINTERVAL*90/100; + + LPC_USB->HcControl = (LPC_USB->HcControl & (~HostControllerFunctionalState)) | OperationalMask; + LPC_USB->HcRhStatus = SetGlobalPower; + + LPC_USB->HcHCCA = (u32)cca; + LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; + LPC_USB->HcInterruptEnable = MasterInterruptEnable | WritebackDoneHead | RootHubStatusChange | FrameNumberOverflow; + + NVIC_SetPriority(USB_IRQn, 0); + NVIC_EnableIRQ(USB_IRQn); + while (cca->FrameNumber < 10) + ; // 10ms delay before diving in + } +}; + +//==================================================================================== +//==================================================================================== +// Host controller instance and Interrupt handler + +static HostController _controller __attribute__((at(USB_RAM_BASE))); + +extern "C" void USB_IRQHandler(void) __irq; +void USB_IRQHandler (void) __irq +{ + u32 int_status = LPC_USB->HcInterruptStatus; + + if (int_status & RootHubStatusChange) // Root hub status change + _controller._rootHubStatusChange++; // Just flag the controller, will be processed in USBLoop + + u32 head = 0; + if (int_status & WritebackDoneHead) + { + head = _controller.CommunicationArea.DoneHead; // Writeback Done + _controller.CommunicationArea.DoneHead = 0; + } + LPC_USB->HcInterruptStatus = int_status; + + if (head) + _controller.ProcessDoneQueue(head); // TODO - low bit can be set BUGBUG +} + +//==================================================================================== +//==================================================================================== +// API Methods + +void USBInit() +{ + return _controller.Init(); +} + +void USBLoop() +{ + return _controller.Loop(); +} + +u8* USBGetBuffer(u32* len) +{ + *len = USB_RAM_SIZE - sizeof(HostController); + return _controller.SRAM; +} + +static Setup* GetSetup(int device) +{ + if (device == 0) + return &_controller._setupZero; + + if (device < 1 || device > MAX_DEVICES) + return 0; + return &_controller.Devices[device-1].SetupBuffer; +} + +// Loop until IO on endpoint is complete +static int WaitIODone(Endpoint* endpoint) +{ + if (endpoint->CurrentState == Endpoint::NotQueued) + return 0; + while (endpoint->CurrentState != Endpoint::Idle) + USBLoop(); // May generate callbacks, mount or unmount devices etc + int status = endpoint->Status(); + if (status == 0) + return endpoint->Length; + return -status; +} + +int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData) +{ + Endpoint* endpoint = _controller.GetEndpoint(device,ep); + if (!endpoint) + return ERR_ENDPOINT_NOT_FOUND; + + WaitIODone(endpoint); + endpoint->Flags = flags; + endpoint->Data = data; + endpoint->Length = length; + endpoint->Callback = callback; + endpoint->UserData = userData; + if (ep == 0) + _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued); + else + _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued); + if (callback) + return IO_PENDING; + return WaitIODone(endpoint); +} + +int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData) +{ + Setup* setup = GetSetup(device); + if (!setup) + return ERR_DEVICE_NOT_FOUND; + + // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call + WaitIODone(_controller.GetEndpoint(device,0)); + + setup->bm_request_type = request_type; + setup->b_request = request; + setup->w_value = value; + setup->w_index = index; + setup->w_length = length; + return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData); +} + +int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) +{ + return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData); +} + +int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) +{ + return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData); +} + +int GetDescriptor(int device, int descType,int descIndex, u8* data, int length) +{ + return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0); +} + +int GetString(int device, int index, char* dst, int length) +{ + u8 buffer[255]; + int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer)); + if (le < 0) + return le; + if (length < 1) + return -1; + length <<= 1; + if (le > length) + le = length; + for (int j = 2; j < le; j += 2) + *dst++ = buffer[j]; + *dst = 0; + return (le>>1)-1; +} + +int SetAddress(int device, int new_addr) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0); +} + +int SetConfiguration(int device, int configNum) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0); +} + +int SetInterface(int device, int ifNum, int altNum) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0); +} + +// HUB stuff +int SetPortFeature(int device, int feature, int index) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0); +} + +int ClearPortFeature(int device, int feature, int index) +{ + return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0); +} + +int SetPortPower(int device, int port) +{ + int r = SetPortFeature(device,PORT_POWER,port); + _controller.DelayMS(20); // 80ms to turn on a hubs power... DESCRIPTOR? todo + return r; +} + +int SetPortReset(int device, int port) +{ + return SetPortFeature(device,PORT_RESET,port); +} + +int GetPortStatus(int device, int port, u32* status) +{ + return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,216 @@ + +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef USBHOST_H +#define USBHOST_H + +#ifndef u8 +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +typedef char s8; +typedef short s16; +typedef char s32; +#endif + +#define ENDPOINT_CONTROL 0 +#define ENDPOINT_ISOCRONOUS 1 +#define ENDPOINT_BULK 2 +#define ENDPOINT_INTERRUPT 3 + +#define DESCRIPTOR_TYPE_DEVICE 1 +#define DESCRIPTOR_TYPE_CONFIGURATION 2 +#define DESCRIPTOR_TYPE_STRING 3 +#define DESCRIPTOR_TYPE_INTERFACE 4 +#define DESCRIPTOR_TYPE_ENDPOINT 5 + +#define DESCRIPTOR_TYPE_HID 0x21 +#define DESCRIPTOR_TYPE_REPORT 0x22 +#define DESCRIPTOR_TYPE_PHYSICAL 0x23 +#define DESCRIPTOR_TYPE_HUB 0x29 + +enum USB_CLASS_CODE +{ + CLASS_DEVICE, + CLASS_AUDIO, + CLASS_COMM_AND_CDC_CONTROL, + CLASS_HID, + CLASS_PHYSICAL = 0x05, + CLASS_STILL_IMAGING, + CLASS_PRINTER, + CLASS_MASS_STORAGE, + CLASS_HUB, + CLASS_CDC_DATA, + CLASS_SMART_CARD, + CLASS_CONTENT_SECURITY = 0x0D, + CLASS_VIDEO = 0x0E, + CLASS_DIAGNOSTIC_DEVICE = 0xDC, + CLASS_WIRELESS_CONTROLLER = 0xE0, + CLASS_MISCELLANEOUS = 0xEF, + CLASS_APP_SPECIFIC = 0xFE, + CLASS_VENDOR_SPECIFIC = 0xFF +}; + +#define DEVICE_TO_HOST 0x80 +#define HOST_TO_DEVICE 0x00 +#define REQUEST_TYPE_STANDARD 0x00 +#define REQUEST_TYPE_CLASS 0x20 +#define REQUEST_TYPE_VENDOR 0x40 +#define RECIPIENT_DEVICE 0x00 +#define RECIPIENT_INTERFACE 0x01 +#define RECIPIENT_ENDPOINT 0x02 +#define RECIPIENT_OTHER 0x03 + +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 +#define SYNCH_FRAME 11 + +/* HID Request Codes */ +#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 + +/* HID Report Types */ +#define HID_REPORT_INPUT 0x01 +#define HID_REPORT_OUTPUT 0x02 +#define HID_REPORT_FEATURE 0x03 + + +// -5 is nak +/* +0010 ACK Handshake +1010 NAK Handshake +1110 STALL Handshake +0110 NYET (No Response Yet) +*/ + +#define IO_PENDING -100 +#define ERR_ENDPOINT_NONE_LEFT -101 +#define ERR_ENDPOINT_NOT_FOUND -102 +#define ERR_DEVICE_NOT_FOUND -103 +#define ERR_DEVICE_NONE_LEFT -104 +#define ERR_HUB_INIT_FAILED -105 +#define ERR_INTERFACE_NOT_FOUND -106 + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; // version + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} DeviceDescriptor; // 16 bytes + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; // Value to use as an argument to select this configuration + u8 iConfiguration; // Index of String Descriptor describing this configuration + u8 bmAttributes; // Bitmap D7 Reserved, set to 1. (USB 1.0 Bus Powered),D6 Self Powered,D5 Remote Wakeup,D4..0 = 0 + u8 bMaxPower; // Maximum Power Consumption in 2mA units +} ConfigurationDescriptor; + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; // Index of String Descriptor Describing this interface +} InterfaceDescriptor; + +typedef struct +{ + u8 bLength; + u8 bDescriptorType; + u8 bEndpointAddress; // Bits 0:3 endpoint, Bits 7 Direction 0 = Out, 1 = In (Ignored for Control Endpoints) + u8 bmAttributes; // Bits 0:1 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt + u16 wMaxPacketSize; + u8 bInterval; // Interval for polling endpoint data transfers. +} EndpointDescriptor; + +typedef struct { + u8 bLength; + u8 bDescriptorType; + u16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + u8 bDescriptorType2; + u16 wDescriptorLength; +} HIDDescriptor; + +//============================================================================ +//============================================================================ + + +void USBInit(); +void USBLoop(); +u8* USBGetBuffer(u32* len); + +// Optional callback for transfers, called at interrupt time +typedef void (*USBCallback)(int device, int endpoint, int status, u8* data, int len, void* userData); + +// Transfers +int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback = 0, void* userData = 0); +int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback = 0, void* userData = 0); +int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback = 0, void* userData = 0); + +// Standard Device methods +int GetDescriptor(int device, int descType, int descIndex, u8* data, int length); +int GetString(int device, int index, char* dst, int length); +int SetAddress(int device, int new_addr); +int SetConfiguration(int device, int configNum); +int SetInterface(int device, int ifNum, int altNum); + +// Implemented to notify app of the arrival of a device +void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utils.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,48 @@ + + +#include "mbed.h" +#include "Utils.h" + +void printfBytes(const char* s, const u8* data, int len) +{ + printf("%s %d:",s,len); + if (len > 256) + len = 256; + while (len-- > 0) + printf(" %02X",*data++); + printf("\r\n"); +} + +void printHexLine(const u8* d, int addr, int len) +{ + printf("%04X ",addr); + int i; + for (i = 0; i < len; i++) + printf("%02X ",d[i]); + for (;i < 16; i++) + printf(" "); + char s[16+1]; + memset(s,0,sizeof(s)); + for (i = 0; i < len; i++) + { + int c = d[i]; + if (c < 0x20 || c > 0x7E) + c = '.'; + s[i] = c; + } + printf("%s\r\n",s); +} + +void printHex(const u8* d, int len) +{ + int addr = 0; + while (len) + { + int count = len; + if (count > 16) + count = 16; + printHexLine(d+addr,addr,count); + addr += 16; + len -= count; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utils.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,37 @@ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +void DelayMS(int ms); + +void printfBytes(const char* label,const u8* data, int len); +void printHex(const u8* d, int len); + +#ifndef min +#define min(_a,_b) ((_a) < (_b) ? (_a) : (_b)) +#endif + +inline int LE16(const u8* d) +{ + return d[0] | (d[1] << 8); +} + +inline u32 BE32(const u8* d) +{ + return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]; +} + +inline void BE32(u32 n, u8* d) +{ + d[0] = (u8)(n >> 24); + d[1] = (u8)(n >> 16); + d[2] = (u8)(n >> 8); + d[3] = (u8)n; +} + +inline void BE16(u32 n, u8* d) +{ + d[0] = (u8)(n >> 8); + d[1] = (u8)n; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hci.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,546 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +Tue Apr 26 2011 Bart Janssens: added HCI connection accept +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Utils.h" +#include "hci.h" +#include "hci_private.h" + +enum hci_callback_evt +{ + NONE, + CONNECT, + DISCONECT, + INQUIRYRESULT +}; + +#define MAX_BLUETOOTH_ADAPTERS 1 + +enum StateMask { + MASK_RESET = 1, + MASK_READ_BUFFER_SIZE = 2, + MASK_READ_BD_ADDR = 4, + MASK_INITED = 8, + MASK_INQUIRY = 16, + MASK_REMOTE_NAME = 32, + MASK_CREATE_CONNECTION = 64 +}; + +int HCI::Open(HCITransport* transport, HCICallback callback) +{ + _transport = transport; + _transport->Set(this); + _callback = callback; + _state = 0; + for (int i = 0; i < MAX_BTDEVICES; i++) + { + _devices[i].Init(); + _devices[i]._transport = transport; + } + return SendCmd(HCI_OP_RESET); +} + +void printf(const BD_ADDR* addr); + +BTDevice* HCI::Find(const BD_ADDR* addr) +{ + for (int i = 0; i < MAX_BTDEVICES; i++) + if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0) + return &_devices[i]; + return 0; +} + +BTDevice* HCI::Find(int handle) +{ + for (int i = 0; i < MAX_BTDEVICES; i++) + if (_devices[i]._state != 0 && handle == _devices[i]._handle) + return &_devices[i]; + return 0; +} +// +bool HCI::Busy() +{ + return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0; +} + +int HCI::Inquiry(int duration) +{ + _state |= MASK_INQUIRY; + u8 buf[5]; + buf[0] = 0x33; + buf[1] = 0x8B; + buf[2] = 0x9E; + buf[3] = duration; + buf[4] = 5; // 5 results + SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf)); + return 0; +} + +int HCI::WriteScanEnable() +{ + +// u8 buf[2]; +// buf[0] = 0x03; +// buf[1] = 0x01; + + u8 buf[1]; + buf[0] = 0x03; + + SendCmd(HCI_OP_WRITE_SCAN_ENABLE,buf,sizeof(buf)); + return 0; +} + +int HCI::AcceptConnection(const BD_ADDR* addr) +{ +// u8 buf[6+4]; +// memset(buf,0,sizeof(buf)); +// memcpy(buf,addr,6); +// buf[7] = 0; + + u8 buf[6+1]; + memset(buf,0,sizeof(buf)); + memcpy(buf,addr,6); + buf[6] = 0; + + SendCmd(HCI_OP_ACCEPT_CONN_REQ,buf,sizeof(buf)); + return 0; +} + +int HCI::SendCmd(int cmd, const u8* params, int len) +{ + u8 b[32]; + b[0] = cmd; + b[1] = (cmd >> 8); + b[2] = len; + if (params) + memcpy(b+3,params,len); + _transport->HCISend(b,len+3); + return 0; +} + +void HCI::OnCommandComplete(int cmd, const u8* data, int len) +{ + // printf("%04X %s",cmd,CmdStr(cmd)); + if (len < 0) + return; + //printfBytes(" complete",data,min(16,len)); + + switch (cmd) + { + // Init phase 0 + case HCI_OP_RESET: // Reset done, init chain to HCI_OP_READ_LOCAL_NAME + SendCmd(HCI_OP_READ_BUFFER_SIZE); + _state |= MASK_RESET; + break; + + // Init phase 1 + case HCI_OP_READ_BUFFER_SIZE: + _acl_mtu = LE16(data); + _sco_mtu = data[2]; + _acl_max_pkt = LE16(data+3); + _sco_max_pkt = LE16(data+5); + SendCmd(HCI_OP_READ_BD_ADDR); + _state |= MASK_READ_BUFFER_SIZE; + break; + + // Init phase 2 + case HCI_OP_READ_BD_ADDR: + _localAddr = *((BD_ADDR*)data); // Local Address + printf("Local Address: "); + printf(&_localAddr); + printf("\r\n"); + + _state |= MASK_READ_BD_ADDR; + _state |= MASK_INITED; + Callback(CALLBACK_READY,data,6); + break; + + // 0CXX + case HCI_OP_READ_LOCAL_NAME: + break; + + case HCI_OP_READ_LOCAL_VERSION: + // params + //SendCmd(HCI_OP_READ_LOCAL_NAME); + break; + + case HCI_OP_READ_LOCAL_COMMANDS: + break; + + case HCI_OP_READ_LOCAL_FEATURES: + //SendCmd(HCI_OP_READ_LOCAL_VERSION); + break; + + case HCI_OP_READ_LOCAL_EXT_FEATURES: + break; + + case HCI_OP_PIN_CODE_REPLY: + printf("Got pin reply\r\n"); + break; + + default: + //printf("Unrecognized Command %04X\r\n",cmd); + break; + } +} + +void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len) +{ + _callback(this,c,data,len); +} + +int HCI::RemoteNameRequest(const BD_ADDR* addr) +{ + _state |= MASK_REMOTE_NAME; + u8 buf[6+4]; + memset(buf,0,sizeof(buf)); + memcpy(buf,addr,6); + buf[7] = 1; + return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf)); +} + +int HCI::CreateConnection(const BD_ADDR* remoteAddr) +{ + _state |= MASK_CREATE_CONNECTION; + u8 buf[6+7]; + memset(buf,0,sizeof(buf)); + memcpy(buf,remoteAddr,6); + buf[6] = 0x18; // DM1,DH1 + buf[7] = 0xCC; // DM3, DH3, DM5, DH5 + buf[8] = 1; // Page Repetition R1 + return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf)); +} + +int HCI::Disconnect(const BD_ADDR* bdaddr) +{ + BTDevice* d = Find(bdaddr); + if (!d) + return ERR_HCI_DEVICE_NOT_FOUND; + int handle = d->_handle; + printf("Disconnect from %d\r\n",handle); + _state |= MASK_CREATE_CONNECTION; + u8 buf[3]; + buf[0] = handle; + buf[1] = (handle >> 8); + buf[2] = 0x13; + return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf)); +} + +void HCI::DisconnectComplete(int handle) +{ + BTDevice* d = Find(handle); + if (!d) + return; + d->_handle = 0; +} + +int HCI::DisconnectAll() +{ + BTDevice* devs[8]; + int count = GetDevices(devs,8); + for (int i = 0; i < count; i++) + Disconnect(&devs[i]->_info.bdaddr); + return 0; +} + +int HCI::PinCodeReply(const u8* data) +{ + u8 b[6+1+16]; + memset(b,0,sizeof(b)); + memcpy(b,data,6); + b[6] = 4; + b[7] = '0'; + b[8] = '0'; + b[9] = '0'; + b[10] = '0'; + return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b)); +} + +void HCI::InquiryResult(const inquiry_info* info) +{ + BTDevice* bt = Find(&info->bdaddr); + if (!bt) // new device + { + for (int i = 0; i < MAX_BTDEVICES; i++) + { + if (_devices[i]._state == 0) + { + bt = _devices + i; + bt->_state = 1; + break; + } + } + if (!bt) + { + printf("HCI::InquiryResult too many devices\r\n"); + return; // Too many devices! + } + } + + bt->_info = *info; +} + +int HCI::GetDevices(BTDevice** devices, int maxDevices) +{ + int j = 0; + for (int i = 0; i < MAX_BTDEVICES; i++) + { + if (_devices[i]._state != 0) + { + devices[j++] = _devices + i; + if (j == maxDevices) + break; + } + } + return j; +} + +void HCI::RemoteName(const BD_ADDR* addr, const char* name) +{ + BTDevice* d = Find(addr); + if (d) + { + strncpy(d->_name,name,sizeof(d->_name)-1); + d->_name[sizeof(d->_name)-1] = 0; + } +} + +void HCI::ConnectComplete(const connection_info* info) +{ + BTDevice* d = Find(&info->bdaddr); + if (!d) + return; + if (info->status == 0) + { + d->_handle = info->handle; + printf("Connected on %04X\r\n",info->handle); + } else + printf("Connection failed with %d\r\n",info->status); +} + +void HCI::ConnectRequest(const request_info* info) +{ + BTDevice* bt = Find(&info->bdaddr); + if (!bt) // new device + { + for (int i = 0; i < MAX_BTDEVICES; i++) + { + if (_devices[i]._state == 0) + { + bt = _devices + i; + bt->_state = 1; + break; + } + } + if (!bt) + { + printf("HCI::ConnectRequest too many devices\r\n"); + return; // Too many devices! + } + } + bt->_info.bdaddr = info->bdaddr; + memcpy(bt->_info.dev_class,info->dev_class,3); + AcceptConnection(&info->bdaddr); +} + +void HCI::HCIRecv(const u8* data, int len) +{ + //printfBytes(EvtStr(data[0]),data,len); + //printfBytes(EvtStr(data[0]),data,min(len,16)); + //printf("HCI Event %02X\r\n",data[0]); + switch (data[0]) + { + case HCI_EV_INQUIRY_COMPLETE: + printfBytes("Inquiry Complete",data,data[1]); + _state &= ~MASK_INQUIRY; + Callback(CALLBACK_INQUIRY_DONE,0,0); + WriteScanEnable(); + break; + + case HCI_EV_INQUIRY_RESULT: + { + const u8* end = data[1] + data + 2; + data += 3; + while (data < end) + { + inquiry_info align; + memcpy(&align,data,sizeof(inquiry_info)); + InquiryResult(&align); + Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info)); + data += 14; + } + } + break; + + case HCI_EV_CONN_COMPLETE: + _state &= ~MASK_CREATE_CONNECTION; + { + connection_info align; + memcpy(&align,data+2,sizeof(connection_info)); + ConnectComplete(&align); + Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info)); + } + break; + + case HCI_EV_CONN_REQUEST: + { + request_info align; + memcpy(&align,data+2,sizeof(request_info)); + ConnectRequest(&align); + } + break; + + case HCI_EV_DISCONN_COMPLETE: + DisconnectComplete(LE16(data+3)); + break; + + case HCI_EV_REMOTE_NAME: + { + BD_ADDR* addr = (BD_ADDR*)(data+3); + const char* name = (const char*)(data + 9); + RemoteName(addr,name); + } + Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1)); // addr is in here too + _state &= ~MASK_REMOTE_NAME; + break; + + case HCI_EV_CMD_STATUS: + { + const char* errs = HCIErrStr(data[2]); + printf("Status %s %s\r\n",CmdStr(LE16(data+4)),errs); + } + break; + + case HCI_EV_CMD_COMPLETE: + OnCommandComplete(data[3] | (data[4] << 8),data+6,data[1]-4); + break; + + case HCI_EV_PIN_CODE_REQ: + PinCodeReply(data+2); + break; + + case HCI_EV_LINK_KEY_REQ: + SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6); + break; + + default: + ; + // printfBytes("HCI Event:",data,data[1]+2); + } +} + +int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr) +{ + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + L2CAPAddr* l2capaddr = (L2CAPAddr*)addr; + BTDevice* bt = Find(&l2capaddr->bdaddr); + if (!bt) + { + printf("Can't open l2cap %d on ",l2capaddr->psm); + printf(&l2capaddr->bdaddr); + printf("\r\n"); + return ERR_HCI_DEVICE_NOT_FOUND; + } + l2capsock->btdevice = bt; + return bt->Open(sock,addr); +} + +int HCI::Create(SocketInternal* sock, SocketAddrHdr* addr) +{ + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + L2CAPAddr* l2capaddr = (L2CAPAddr*)addr; + BTDevice* bt = Find(&l2capaddr->bdaddr); + if (!bt) + { + printf("HCI Create: Can't open l2cap on "); + printf(&l2capaddr->bdaddr); + printf("\r\n"); + return ERR_HCI_DEVICE_NOT_FOUND; + } + l2capsock->btdevice = bt; + //return 0; + return bt->Create(sock,addr); +} + + +int HCI::Accept(SocketInternal* sock, SocketAddrHdr* addr) +{ + + printf("Call to HCI Accept \r\n"); + + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + L2CAPAddr* l2capaddr = (L2CAPAddr*)addr; + BTDevice* bt = Find(&l2capaddr->bdaddr); + if (!bt) + { + //printf("Can't open l2cap %d on ",l2capaddr->psm); + printf("HCI Accept: Can't open l2cap on "); + printf(&l2capaddr->bdaddr); + printf("\r\n"); + return ERR_HCI_DEVICE_NOT_FOUND; + } + //l2capsock->btdevice = bt; + return bt->Open(sock,addr); + +} + +/** +SocketInternal* HCI::Create(SocketInternal* sock) +{ + return sock; +} +**/ + + +int HCI::Send(SocketInternal* sock, const u8* data, int len) +{ + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + return l2capsock->btdevice->Send(sock,data,len); // Pointless double dispatch +} + +int HCI::Close(SocketInternal* sock) +{ + L2CAPSocket* l2capsock = (L2CAPSocket*)sock; + return l2capsock->btdevice->Close(sock); // Pointless double dispatch +} + +void HCI::ACLRecv(const u8* data, int len) +{ + int handle = LE16(data); + BD_ADDR* addr; + BTDevice* d = Find(handle & 0x0FFF); + addr = &d->_info.bdaddr; + + if (d) + d->ACLRecv(addr,data,len); +} + +//=================================================================== +//===================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hci.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,258 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HCI_H_INCLUDED +#define HCI_H_INCLUDED + +#include "Socket.h" + +#pragma pack(1) + +#define ERR_HCI_DEVICE_NOT_FOUND -300 + +class HCI; +class HCITransport; +class BTDevice; + +typedef struct +{ + u8 addr[6]; +} BD_ADDR; + +typedef struct +{ + BD_ADDR bdaddr; + u8 pscan_rep_mode; + u8 pscan_period_mode; + u8 pscan_mode; + u8 dev_class[3]; + u16 clock_offset; +} inquiry_info; + +typedef struct +{ + BD_ADDR bdaddr; + u8 dev_class[3]; + u8 link_type; +} request_info; + +typedef struct +{ + u8 status; + u16 handle; + BD_ADDR bdaddr; + u8 link_type; + u8 encr_mode; +} connection_info; + +// Address struct for creating L2CAP sockets +typedef struct { + SocketAddrHdr hdr; + BD_ADDR bdaddr; + u16 psm; +} L2CAPAddr; + +#pragma pack(4) + +class BTDevice; +typedef struct +{ + public: + SocketInternal si; + BTDevice* btdevice; + u16 scid; + u16 dcid; +} L2CAPSocket; + +#define MAX_HCL_NAME_LENGTH 20 // TODO - BTDevice wants to be a multiple of 4 +#define MAX_PORTS 3 + +// BTDevice encapsulates individual device state +// It provides L2CAP layer sockets + +class BTDevice : public SocketHandler +{ + public: + HCITransport* _transport; + inquiry_info _info; + u16 _handle; // acl connection handle + u8 _state; // connection state + u8 _txid; + char _name[MAX_HCL_NAME_LENGTH]; + + void Init(); + + BD_ADDR* GetAddress() { return &_info.bdaddr; } + + // Called from HCI + void ACLRecv(const BD_ADDR* addr, const u8* data, int len); + + // SocketHandler + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Send(SocketInternal* sock, const u8* data, int len); + virtual int Close(SocketInternal* sock); + // added by Bart Janssens + virtual int Create(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Accept(SocketInternal* sock, SocketAddrHdr* addr); + +private: + L2CAPSocket* SCIDToSocket(int scid); + int Send(const u8* data, int len); + int Send(u8 c, u8 id, u16* params, int count); + int Connect(int scid, int psm); + int Disconnect(int scid, int dcid); + int ConfigureRequest(int dcid); + int ConfigureResponse(u8 rxid, int dcid); + int DisconnectResponse(u8 rxid, int scid, int dcid); + // added by Bart Janssens + int AcceptResponse(u8 rxid, int scid, int dcid); + int RefuseResponse(u8 rxid); + // + void Control(const BD_ADDR* addr, const u8* data, int len); +}; + +enum HCI_CALLBACK_EVENT +{ + CALLBACK_NONE, + CALLBACK_READY, + CALLBACK_INQUIRY_RESULT, + CALLBACK_INQUIRY_DONE, + CALLBACK_REMOTE_NAME, + CALLBACK_CONNECTION_COMPLETE, + CALLBACK_CONNECTION_FAILED +}; + +// L2CAP Protocol/Service Multiplexor (PSM) values + +#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ +#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ +#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ +#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ +#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */ +#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network Encapsulation Protocol*/ +#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */ +#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */ +#define L2CAP_PSM_ESDP 0x0015 /* Extended Service Discovery Profile */ +#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control Transport Protocol */ +#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */ + +/* Connection response results */ +#define L2CAP_CONN_SUCCESS 0x0000 +#define L2CAP_CONN_PND 0x0001 +#define L2CAP_CONN_REF_PSM 0x0002 +#define L2CAP_CONN_REF_SEC 0x0003 +#define L2CAP_CONN_REF_RES 0x0004 +#define L2CAP_CONN_CFG_TO 0x0005 /* Implementation specific result */ + + + +// Callback from inquiry +typedef int (*HCICallback)(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len); + +#define MAX_BTDEVICES 8 + +class HCITransport; +class HCI : public SocketHandler +{ + HCITransport* _transport; + HCICallback _callback; + BD_ADDR _localAddr; + + BTDevice _devices[MAX_BTDEVICES]; + int _deviceCount; + + int _acl_mtu; + int _acl_max_pkt; + int _sco_mtu; + int _sco_max_pkt; + + int _state; + + public: + + // Open a local adapter + int Open(HCITransport* transport, HCICallback callback); + + // Return list of discovered addreses + int GetDevices(BTDevice** devices, int maxDevices); + + // Lookup a device by address or handle + BTDevice* Find(const BD_ADDR* addr); + BTDevice* Find(int handle); + + // Disconnect from a remote device + int Disconnect(const BD_ADDR* addr); + int DisconnectAll(); + + // see what devies are in the system + int Inquiry(int duration = 10); + + // added by Bart Janssens + int WriteScanEnable(); + + int AcceptConnection(const BD_ADDR* addr); + + // get a name, delivered in callback + int RemoteNameRequest(const BD_ADDR* addr); + + // Connect to a remote device + int CreateConnection(const BD_ADDR* remoteAddr); + + bool Busy(); + + // called from transport + void HCIRecv(const u8* data, int len); + + // called from transport + void ACLRecv(const u8* data, int len); + + // SocketHandler methods for maintaining L2CAP sockets + virtual int Open(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Send(SocketInternal* sock, const u8* data, int len); + virtual int Close(SocketInternal* sock); + // added by Bart Janssens + virtual int Create(SocketInternal* sock, SocketAddrHdr* addr); + virtual int Accept(SocketInternal* sock, SocketAddrHdr* addr); + + private: + void InquiryResult(const inquiry_info* info); + void RemoteName(const BD_ADDR* addr, const char* name); + void ConnectComplete(const connection_info* info); + void ConnectRequest(const request_info* info); + void DisconnectComplete(int handle); + int SendCmd(int cmd, const u8* params = 0, int len = 0); + void OnCommandComplete(int cmd, const u8* data, int len); + void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len); + int PinCodeReply(const u8* data); +}; + +class HCITransport +{ +protected: + HCI* _target; +public: + void Set(HCI* target) { _target = target; }; + virtual void HCISend(const u8* data, int len) = 0; + virtual void ACLSend(const u8* data, int len) = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hci_private.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,323 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef HCI_PRIVATE_H_INCLUDED +#define HCI_PRIVATE_H_INCLUDED + +#define HCI_OP_INQUIRY 0x0401 +#define HCI_OP_INQUIRY_CANCEL 0x0402 +#define HCI_OP_EXIT_PERIODIC_INQ 0x0404 +#define HCI_OP_CREATE_CONN 0x0405 +#define HCI_OP_DISCONNECT 0x0406 +#define HCI_OP_ADD_SCO 0x0407 +#define HCI_OP_CREATE_CONN_CANCEL 0x0408 +#define HCI_OP_ACCEPT_CONN_REQ 0x0409 +#define HCI_OP_REJECT_CONN_REQ 0x040a +#define HCI_OP_LINK_KEY_REPLY 0x040b +#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c +#define HCI_OP_PIN_CODE_REPLY 0x040d +#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e +#define HCI_OP_CHANGE_CONN_PTYPE 0x040f +#define HCI_OP_AUTH_REQUESTED 0x0411 +#define HCI_OP_SET_CONN_ENCRYPT 0x0413 +#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 +#define HCI_OP_REMOTE_NAME_REQ 0x0419 +#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a +#define HCI_OP_READ_REMOTE_FEATURES 0x041b +#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c +#define HCI_OP_READ_REMOTE_VERSION 0x041d +#define HCI_OP_SETUP_SYNC_CONN 0x0428 +#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 +#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a + +#define HCI_OP_SNIFF_MODE 0x0803 +#define HCI_OP_EXIT_SNIFF_MODE 0x0804 +#define HCI_OP_ROLE_DISCOVERY 0x0809 +#define HCI_OP_SWITCH_ROLE 0x080b +#define HCI_OP_READ_LINK_POLICY 0x080c +#define a 0x080d +#define HCI_OP_READ_DEF_LINK_POLICY 0x080e +#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f +#define HCI_OP_SNIFF_SUBRATE 0x0811 + + +#define HCI_OP_SET_EVENT_MASK 0x0c01 +#define HCI_OP_RESET 0x0c03 +#define HCI_OP_SET_EVENT_FLT 0x0c05 +#define HCI_OP_WRITE_LOCAL_NAME 0x0c13 +#define HCI_OP_READ_LOCAL_NAME 0x0c14 +#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 +#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18 +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a +#define HCI_OP_READ_AUTH_ENABLE 0x0c1f +#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20 +#define HCI_OP_READ_ENCRYPT_MODE 0x0c21 +#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22 + #define ENCRYPT_DISABLED 0x00 + #define ENCRYPT_P2P 0x01 + #define ENCRYPT_BOTH 0x02 +#define HCI_OP_READ_CLASS_OF_DEV 0x0c23 +#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24 +#define HCI_OP_READ_VOICE_SETTING 0x0c25 +#define HCI_OP_WRITE_VOICE_SETTING 0x0c26 +#define HCI_OP_HOST_BUFFER_SIZE 0x0c33 +#define HCI_OP_READ_SSP_MODE 0x0c55 +#define HCI_OP_WRITE_SSP_MODE 0x0c56 + +#define HCI_OP_READ_LOCAL_VERSION 0x1001 +#define HCI_OP_READ_LOCAL_COMMANDS 0x1002 +#define HCI_OP_READ_LOCAL_FEATURES 0x1003 +#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004 +#define HCI_OP_READ_BUFFER_SIZE 0x1005 +#define HCI_OP_READ_BD_ADDR 0x1009 + +// events +#define HCI_EV_INQUIRY_COMPLETE 0x01 +#define HCI_EV_INQUIRY_RESULT 0x02 +#define HCI_EV_CONN_COMPLETE 0x03 +#define HCI_EV_CONN_REQUEST 0x04 +#define HCI_EV_DISCONN_COMPLETE 0x05 +#define HCI_EV_AUTH_COMPLETE 0x06 +#define HCI_EV_REMOTE_NAME 0x07 +#define HCI_EV_ENCRYPT_CHANGE 0x08 +#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 +#define HCI_EV_REMOTE_FEATURES 0x0b +#define HCI_EV_REMOTE_VERSION 0x0c +#define HCI_EV_QOS_SETUP_COMPLETE 0x0d +#define HCI_EV_CMD_COMPLETE 0x0e +#define HCI_EV_CMD_STATUS 0x0f +#define HCI_EV_ROLE_CHANGE 0x12 +#define HCI_EV_NUM_COMP_PKTS 0x13 +#define HCI_EV_MODE_CHANGE 0x14 +#define HCI_EV_PIN_CODE_REQ 0x16 +#define HCI_EV_LINK_KEY_REQ 0x17 +#define HCI_EV_LINK_KEY_NOTIFY 0x18 +#define HCI_EV_CLOCK_OFFSET 0x1c +#define HCI_EV_PKT_TYPE_CHANGE 0x1d +#define HCI_EV_PSCAN_REP_MODE 0x20 +#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 +#define HCI_EV_REMOTE_EXT_FEATURES 0x23 +#define HCI_EV_SYNC_CONN_COMPLETE 0x2c +#define HCI_EV_SYNC_CONN_CHANGED 0x2d +#define HCI_EV_SNIFF_SUBRATE 0x2e +#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f +#define HCI_EV_IO_CAPA_REQUEST 0x31 +#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 +#define HCI_EV_REMOTE_HOST_FEATURES 0x3d + +/* Possible error codes */ +#define HCI_UNKNOWN_HCI_COMMAND 0x01 +#define HCI_NO_CONNECTION 0x02 +#define HCI_HW_FAILURE 0x03 +#define HCI_PAGE_TIMEOUT 0x04 +#define HCI_AUTHENTICATION_FAILURE 0x05 +#define HCI_KEY_MISSING 0x06 +#define HCI_MEMORY_FULL 0x07 +#define HCI_CONN_TIMEOUT 0x08 +#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09 +#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A +#define HCI_ACL_CONNECTION_EXISTS 0x0B +#define HCI_COMMAND_DISSALLOWED 0x0C +#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D +#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E +#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F +#define HCI_HOST_TIMEOUT 0x10 +#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11 +#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12 +#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13 +#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14 +#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15 +#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16 +#define HCI_REPETED_ATTEMPTS 0x17 +#define HCI_PAIRING_NOT_ALLOWED 0x18 +#define HCI_UNKNOWN_LMP_PDU 0x19 +#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A +#define HCI_SCO_OFFSET_REJECTED 0x1B +#define HCI_SCO_INTERVAL_REJECTED 0x1C +#define HCI_SCO_AIR_MODE_REJECTED 0x1D +#define HCI_INVALID_LMP_PARAMETERS 0x1E +#define HCI_UNSPECIFIED_ERROR 0x1F +#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20 +#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define HCI_LMP_RESPONSE_TIMEOUT 0x22 +#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23 +#define HCI_LMP_PDU_NOT_ALLOWED 0x24 +#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25 +#define HCI_UNIT_KEY_USED 0x26 +#define HCI_QOS_NOT_SUPPORTED 0x27 +#define HCI_INSTANT_PASSED 0x28 +#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29 + +const char* EvtStr(int evt) +{ + switch (evt) + { + case HCI_EV_INQUIRY_COMPLETE: return "HCI_EV_INQUIRY_COMPLETE"; + case HCI_EV_INQUIRY_RESULT: return "HCI_EV_INQUIRY_RESULT"; + case HCI_EV_CONN_COMPLETE: return "HCI_EV_CONN_COMPLETE"; + case HCI_EV_CONN_REQUEST: return "HCI_EV_CONN_REQUEST"; + case HCI_EV_DISCONN_COMPLETE: return "HCI_EV_DISCONN_COMPLETE"; + case HCI_EV_AUTH_COMPLETE: return "HCI_EV_AUTH_COMPLETE"; + case HCI_EV_REMOTE_NAME: return "HCI_EV_REMOTE_NAME"; + case HCI_EV_ENCRYPT_CHANGE: return "HCI_EV_ENCRYPT_CHANGE"; + case HCI_EV_CHANGE_LINK_KEY_COMPLETE : return "HCI_EV_CHANGE_LINK_KEY_COMPLETE"; + case HCI_EV_REMOTE_FEATURES: return "HCI_EV_REMOTE_FEATURES"; + case HCI_EV_REMOTE_VERSION: return "HCI_EV_REMOTE_VERSION"; + case HCI_EV_QOS_SETUP_COMPLETE : return "HCI_EV_QOS_SETUP_COMPLETE"; + case HCI_EV_CMD_COMPLETE: return "HCI_EV_CMD_COMPLETE"; + case HCI_EV_CMD_STATUS: return "HCI_EV_CMD_STATUS"; + case HCI_EV_ROLE_CHANGE: return "HCI_EV_ROLE_CHANGE"; + case HCI_EV_NUM_COMP_PKTS: return "HCI_EV_NUM_COMP_PKTS"; + case HCI_EV_MODE_CHANGE: return "HCI_EV_MODE_CHANGE"; + case HCI_EV_PIN_CODE_REQ: return "HCI_EV_PIN_CODE_REQ"; + case HCI_EV_LINK_KEY_REQ: return "HCI_EV_LINK_KEY_REQ"; + case HCI_EV_LINK_KEY_NOTIFY: return "HCI_EV_LINK_KEY_NOTIFY"; + case HCI_EV_CLOCK_OFFSET: return "HCI_EV_CLOCK_OFFSET"; + case HCI_EV_PKT_TYPE_CHANGE: return "HCI_EV_PKT_TYPE_CHANGE"; + case HCI_EV_PSCAN_REP_MODE: return "HCI_EV_PSCAN_REP_MODE"; + case HCI_EV_INQUIRY_RESULT_WITH_RSSI : return "HCI_EV_INQUIRY_RESULT_WITH_RSSI"; + case HCI_EV_REMOTE_EXT_FEATURES: return "HCI_EV_REMOTE_EXT_FEATURES"; + case HCI_EV_SYNC_CONN_COMPLETE: return "HCI_EV_SYNC_CONN_COMPLETE"; + case HCI_EV_SYNC_CONN_CHANGED: return "HCI_EV_SYNC_CONN_CHANGED"; + case HCI_EV_SNIFF_SUBRATE: return "HCI_EV_SNIFF_SUBRATE"; + case HCI_EV_EXTENDED_INQUIRY_RESULT: return "HCI_EV_EXTENDED_INQUIRY_RESULT"; + case HCI_EV_IO_CAPA_REQUEST: return "HCI_EV_IO_CAPA_REQUEST"; + case HCI_EV_SIMPLE_PAIR_COMPLETE: return "HCI_EV_SIMPLE_PAIR_COMPLETE"; + case HCI_EV_REMOTE_HOST_FEATURES: return "HCI_EV_REMOTE_HOST_FEATURES"; + } + return "Unknown Event"; +} + +const char* CmdStr(int cmd) +{ + switch (cmd) + { + // 0x04XX + case HCI_OP_INQUIRY: return "HCI_OP_INQUIRY"; + case HCI_OP_INQUIRY_CANCEL: return "HCI_OP_INQUIRY_CANCEL"; + case HCI_OP_EXIT_PERIODIC_INQ: return "HCI_OP_EXIT_PERIODIC_INQ"; + case HCI_OP_CREATE_CONN: return "HCI_OP_CREATE_CONN"; + case HCI_OP_DISCONNECT: return "HCI_OP_DISCONNECT"; + case HCI_OP_ADD_SCO: return "HCI_OP_ADD_SCO"; + case HCI_OP_CREATE_CONN_CANCEL: return "HCI_OP_CREATE_CONN_CANCEL"; + case HCI_OP_ACCEPT_CONN_REQ: return "HCI_OP_ACCEPT_CONN_REQ"; + case HCI_OP_REJECT_CONN_REQ: return "HCI_OP_REJECT_CONN_REQ"; + case HCI_OP_LINK_KEY_REPLY: return "HCI_OP_LINK_KEY_REPLY"; + case HCI_OP_LINK_KEY_NEG_REPLY: return "HCI_OP_LINK_KEY_NEG_REPLY"; + case HCI_OP_PIN_CODE_REPLY: return "HCI_OP_PIN_CODE_REPLY"; + case HCI_OP_PIN_CODE_NEG_REPLY: return "HCI_OP_PIN_CODE_NEG_REPLY"; + case HCI_OP_CHANGE_CONN_PTYPE: return "HCI_OP_CHANGE_CONN_PTYPE"; + case HCI_OP_AUTH_REQUESTED: return "HCI_OP_AUTH_REQUESTED"; + case HCI_OP_SET_CONN_ENCRYPT: return "HCI_OP_SET_CONN_ENCRYPT"; + case HCI_OP_CHANGE_CONN_LINK_KEY: return "HCI_OP_CHANGE_CONN_LINK_KEY"; + case HCI_OP_REMOTE_NAME_REQ: return "HCI_OP_REMOTE_NAME_REQ"; + case HCI_OP_REMOTE_NAME_REQ_CANCEL: return "HCI_OP_REMOTE_NAME_REQ_CANCEL"; + case HCI_OP_READ_REMOTE_FEATURES: return "HCI_OP_READ_REMOTE_FEATURES"; + case HCI_OP_READ_REMOTE_EXT_FEATURES: return "HCI_OP_READ_REMOTE_EXT_FEATURES"; + case HCI_OP_READ_REMOTE_VERSION: return "HCI_OP_READ_REMOTE_VERSION"; + case HCI_OP_SETUP_SYNC_CONN: return "HCI_OP_SETUP_SYNC_CONN"; + case HCI_OP_ACCEPT_SYNC_CONN_REQ: return "HCI_OP_ACCEPT_SYNC_CONN_REQ"; + case HCI_OP_REJECT_SYNC_CONN_REQ: return "HCI_OP_REJECT_SYNC_CONN_REQ"; + // 0x0CXX + case HCI_OP_SET_EVENT_MASK: return "HCI_OP_SET_EVENT_MASK"; + case HCI_OP_RESET: return "HCI_OP_RESET"; + case HCI_OP_SET_EVENT_FLT: return "HCI_OP_SET_EVENT_FLT"; + case HCI_OP_WRITE_LOCAL_NAME: return "HCI_OP_WRITE_LOCAL_NAME"; + case HCI_OP_READ_LOCAL_NAME: return "HCI_OP_READ_LOCAL_NAME"; + case HCI_OP_WRITE_CA_TIMEOUT: return "HCI_OP_WRITE_CA_TIMEOUT"; + case HCI_OP_WRITE_PG_TIMEOUT: return "HCI_OP_WRITE_PG_TIMEOUT"; + case HCI_OP_WRITE_SCAN_ENABLE: return "HCI_OP_WRITE_SCAN_ENABLE"; + case HCI_OP_READ_AUTH_ENABLE: return "HCI_OP_READ_AUTH_ENABLE"; + case HCI_OP_WRITE_AUTH_ENABLE: return "HCI_OP_WRITE_AUTH_ENABLE"; + case HCI_OP_READ_ENCRYPT_MODE: return "HCI_OP_READ_ENCRYPT_MODE"; + case HCI_OP_WRITE_ENCRYPT_MODE: return "HCI_OP_WRITE_ENCRYPT_MODE"; + case HCI_OP_READ_CLASS_OF_DEV: return "HCI_OP_READ_CLASS_OF_DEV"; + case HCI_OP_WRITE_CLASS_OF_DEV: return "HCI_OP_WRITE_CLASS_OF_DEV"; + case HCI_OP_READ_VOICE_SETTING: return "HCI_OP_READ_VOICE_SETTING"; + case HCI_OP_WRITE_VOICE_SETTING: return "HCI_OP_WRITE_VOICE_SETTING"; + case HCI_OP_HOST_BUFFER_SIZE: return "HCI_OP_HOST_BUFFER_SIZE"; + case HCI_OP_READ_SSP_MODE: return "HCI_OP_READ_SSP_MODE"; + case HCI_OP_WRITE_SSP_MODE: return "HCI_OP_WRITE_SSP_MODE"; + + // 10xx + case HCI_OP_READ_LOCAL_VERSION: return "HCI_OP_READ_LOCAL_VERSION"; + case HCI_OP_READ_LOCAL_COMMANDS: return "HCI_OP_READ_LOCAL_COMMANDS"; + case HCI_OP_READ_LOCAL_FEATURES: return "HCI_OP_READ_LOCAL_FEATURES"; + case HCI_OP_READ_LOCAL_EXT_FEATURES: return "HCI_OP_READ_LOCAL_EXT_FEATURES"; + case HCI_OP_READ_BUFFER_SIZE: return "HCI_OP_READ_BUFFER_SIZE"; + case HCI_OP_READ_BD_ADDR: return "HCI_OP_READ_BD_ADDR"; + } + return "Unknown Cmd"; +} + +const char* HCIErrStr(int err) +{ + switch (err) + { + case 0: return "OK"; + case HCI_UNKNOWN_HCI_COMMAND: return "HCI_UNKNOWN_HCI_COMMAND"; + case HCI_NO_CONNECTION: return "HCI_NO_CONNECTION"; + case HCI_HW_FAILURE: return "HCI_HW_FAILURE"; + case HCI_PAGE_TIMEOUT: return "HCI_PAGE_TIMEOUT"; + case HCI_AUTHENTICATION_FAILURE: return "HCI_AUTHENTICATION_FAILURE"; + case HCI_KEY_MISSING: return "HCI_KEY_MISSING"; + case HCI_MEMORY_FULL: return "HCI_MEMORY_FULL"; + case HCI_CONN_TIMEOUT: return "HCI_CONN_TIMEOUT"; + case HCI_MAX_NUMBER_OF_CONNECTIONS: return "HCI_CONN_TIMEOUT"; + case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE: return "HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE"; + case HCI_ACL_CONNECTION_EXISTS: return "HCI_ACL_CONNECTION_EXISTS"; + case HCI_COMMAND_DISSALLOWED: return "HCI_COMMAND_DISSALLOWED"; + case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES: return "HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES"; + case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS: return "HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS"; + case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE: return "HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE"; + case HCI_HOST_TIMEOUT: return "HCI_HOST_TIMEOUT"; + case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE: return "HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE"; + case HCI_INVALID_HCI_COMMAND_PARAMETERS: return "HCI_INVALID_HCI_COMMAND_PARAMETERS"; + case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED: return "HCI_OTHER_END_TERMINATED_CONN_USER_ENDED"; + case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES: return "HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES"; + case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF: return "HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF"; + case HCI_CONN_TERMINATED_BY_LOCAL_HOST: return "HCI_CONN_TERMINATED_BY_LOCAL_HOST"; + case HCI_REPETED_ATTEMPTS: return "HCI_REPETED_ATTEMPTS"; + case HCI_PAIRING_NOT_ALLOWED: return "HCI_PAIRING_NOT_ALLOWED"; + case HCI_UNKNOWN_LMP_PDU: return "HCI_UNKNOWN_LMP_PDU"; + case HCI_UNSUPPORTED_REMOTE_FEATURE: return "HCI_UNSUPPORTED_REMOTE_FEATURE"; + case HCI_SCO_OFFSET_REJECTED: return "HCI_SCO_OFFSET_REJECTED"; + case HCI_SCO_INTERVAL_REJECTED: return "HCI_SCO_INTERVAL_REJECTED"; + case HCI_SCO_AIR_MODE_REJECTED: return "HCI_SCO_AIR_MODE_REJECTED"; + case HCI_INVALID_LMP_PARAMETERS: return "HCI_INVALID_LMP_PARAMETERS"; + case HCI_UNSPECIFIED_ERROR: return "HCI_UNSPECIFIED_ERROR"; + case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE: return "HCI_UNSUPPORTED_LMP_PARAMETER_VALUE"; + case HCI_ROLE_CHANGE_NOT_ALLOWED: return "HCI_ROLE_CHANGE_NOT_ALLOWED"; + case HCI_LMP_RESPONSE_TIMEOUT: return "HCI_LMP_RESPONSE_TIMEOUT"; + case HCI_LMP_ERROR_TRANSACTION_COLLISION: return "HCI_LMP_ERROR_TRANSACTION_COLLISION"; + case HCI_LMP_PDU_NOT_ALLOWED: return "HCI_LMP_PDU_NOT_ALLOWED"; + case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE: return "HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE"; + case HCI_UNIT_KEY_USED: return "HCI_UNIT_KEY_USED"; + case HCI_QOS_NOT_SUPPORTED: return "HCI_QOS_NOT_SUPPORTED"; + case HCI_INSTANT_PASSED: return "HCI_INSTANT_PASSED"; + case HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED: return "HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED"; + }; + return "Unknow HCI err"; +}; + + +#endif // HCI_PRIVATE_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,121 @@ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "mbed.h" +#include "USBHost.h" +#include "Utils.h" +#include "FATFileSystem.h" + +int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize); +int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize); +int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize); + +class USBFileSystem : public FATFileSystem +{ + int _device; + u32 _blockSize; + u32 _blockCount; + +public: + USBFileSystem() : FATFileSystem("usb"),_device(0),_blockSize(0),_blockCount(0) + { + } + + void SetDevice(int device) + { + _device = device; + } + + virtual int disk_initialize() + { + return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize); + } + + virtual int disk_write(const char *buffer, int block_number) + { + return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize); + } + + virtual int disk_read(char *buffer, int block_number) + { + return MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize); + } + + virtual int disk_sectors() + { + return _blockCount; + } +}; + +void DumpFS(int depth, int count) +{ + DIR *d = opendir("/usb"); + if (!d) + { + printf("USB file system borked\r\n"); + return; + } + + printf("\nDumping root dir\r\n"); + struct dirent *p; + for(;;) + { + p = readdir(d); + if (!p) + break; + int len = sizeof( dirent); + printf("%s %d\n", p->d_name, len); + } + closedir(d); +} + +int OnDiskInsert(int device) +{ + USBFileSystem fs; + fs.SetDevice(device); + DumpFS(0,0); + return 0; +} + +/* + Simple test shell to exercise mouse,keyboard,mass storage and hubs. + Add 2 15k pulldown resistors between D+/D- and ground, attach a usb socket and have at it. +*/ + +Serial pc(USBTX, USBRX); +int GetConsoleChar() +{ + if (!pc.readable()) + return -1; + char c = pc.getc(); + pc.putc(c); // echo + return c; +} + +void TestShell(); + +int main() +{ + pc.baud(460800); + printf("BlueUSB\nNow get a bunch of usb or bluetooth things and plug them in\r\n"); + TestShell(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/motordriver.cpp Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,142 @@ +/*motor driver libary modified from the following libary, +* +* mbed simple H-bridge motor controller +* Copyright (c) 2007-2010, sford +* +* by Christopher Hasler. +* +* from sford's libary, +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include "motordriver.h" + +#include "mbed.h" + +Motor::Motor(PinName pwm, PinName fwd, PinName rev, bool brakeable): + _pwm(pwm), _fwd(fwd), _rev(rev), _brakeable(brakeable), _sign(0) { + + // Set initial condition of PWM + _pwm.period(0.001); + _pwm = 0; + + // Initial condition of output enables + _fwd = 0; + _rev = 0; +} + +float Motor::speed(float speed) { + float temp = 0; + if (_sign == 0) { + _fwd = (speed > 0.0); + _rev = (speed < 0.0); + temp = abs(speed); + _pwm = temp; + } else if (_sign == 1) { + if (speed < 0) { + _fwd = (speed > 0.0); + _rev = (speed < 0.0); + _pwm = 0; + temp = 0; + } else { + _fwd = (speed > 0.0); + _rev = (speed < 0.0); + temp = abs(speed); + _pwm = temp; + } + } else if (_sign == -1) { + if (speed > 0) { + _fwd = (speed > 0.0); + _rev = (speed < 0.0); + _pwm = 0; + temp = 0; + } else { + _fwd = (speed > 0.0); + _rev = (speed < 0.0); + temp = abs(speed); + _pwm = temp; + } + } + if (speed > 0) + _sign = 1; + else if (speed < 0) { + _sign = -1; + } else if (speed == 0) { + _sign = 0; + } + return temp; +} +// (additions) +void Motor::coast(void) { + _fwd = 0; + _rev = 0; + _pwm = 0; + _sign = 0; +} + +float Motor::stop(float duty) { + if (_brakeable == 1) { + _fwd = 1; + _rev = 1; + _pwm = duty; + _sign = 0; + return duty; + } else + Motor::coast(); + return -1; // error, can't brake +} + +float Motor::state(void) const { + int fwd = _fwd.read(); + int rev = _rev.read(); + float pwm = _pwm.read(); + + if ((fwd == rev) && (pwm > 0)) { + return -2;//braking + } else if (pwm == 0) { + return 2;//coasting + } else if ((fwd == 0) && (rev == 1)) { + return -pwm;//reversing + } else if ((fwd == 1) && (rev == 0)) { + return pwm;//fowards + } else + return -3;//error +} + +//test code, this demonstrates working motor drivers. + +//Motor A(p22, p6, p5, 1); // pwm, fwd, rev, can break +/* +Motor A(p22, p7, p8, 1); // pwm, fwd, rev, can break +Motor B(p21, p5, p6, 1); // pwm, fwd, rev, can break +int main() { + for (float s=-1.0; s < 1.0 ; s += 0.01) { + //A.speed(s); + A.speed(s); + B.speed(s); + wait(0.02); + } + A.stop(0); + B.stop(0); + wait(1); + A.coast(); + B.coast(); +} +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/motordriver.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,91 @@ +/*motor driver libary modified from the following libary, +* +* mbed simple H-bridge motor controller +* Copyright (c) 2007-2010, sford +* +* by Christopher Hasler. +* +* from sford's libary, +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#ifndef MBED_MOTOR_H +#define MBED_MOTOR_H + +#include "mbed.h" + +/** Interface to control a standard DC motor +* with an H-bridge using a PwmOut and 2 DigitalOuts +*/ +class Motor { + public: + +/** Create a motor control interface +* +* @param pwm A PwmOut pin, driving the H-bridge enable line to control the speed +* @param fwd A DigitalOut, set high when the motor should go forward +* @param rev A DigitalOut, set high when the motor should go backwards +* @param set if the motor driver is able to do braking 0 false 1 true. +*/ + Motor(PinName pwm, PinName fwd, PinName rev, bool brakeable = false); + +/** Set the speed of the motor +* +* @param speed The speed of the motor as a normalised value between -1.0 and 1.0. +* @return the applied speed to the motor after checking to ensure motor doesn't switch from forward to reverse without stopping. +*/ + float speed(float speed); + +/** Set the the motor to coast +* +* @param void +* @return motor coasts until another instruction is recived. +*/ + + void coast(void); + +/** Set the motor to dynamicaly brake +* +* @param float 0 - 1.0 provides some control over how hard the motor brakes. +* @return duty applied to motor driver. -1 is error, motor driver can't brake. +*/ + + float stop(float duty); +/** return the current state of the motor +* +* @param void +* @return state of motor, -1 to 1 is speed, -2 is braking, 2 is coasting. -3 is error. +*/ + float state(void) const; + + protected: + mutable PwmOut _pwm; + mutable DigitalOut _fwd; + mutable DigitalOut _rev; + bool _brakeable; // cna the motor driver break + int _sign; //prevents throwing the motor from full foward to full reverse and stuff melting. + +}; + + + + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ps3.h Tue Jul 05 08:25:40 2011 +0000 @@ -0,0 +1,135 @@ +/* +Copyright (c) 2011 Bart Janssens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* Defines for the PS3 Buttons +*/ + + +#define BUTTONSELECT 0 +#define BUTTONLANALOG 1 +#define BUTTONRANALOG 2 +#define BUTTONSTART 3 +#define BUTTONUP 4 +#define BUTTONRIGHT 5 +#define BUTTONDOWN 6 +#define BUTTONLEFT 7 +#define BUTTONL2 8 +#define BUTTONR2 9 +#define BUTTONL1 10 +#define BUTTONR1 11 +#define BUTTONTRIANGEL 12 +#define BUTTONCIRCLE 13 +#define BUTTONCROSS 14 +#define BUTTONSQUARE 15 +#define BUTTONPS 16 + + +/* Defines for the PS3 Joysticks +*/ + +#define LEFTJOYSTICKX 0 +#define LEFTJOYSTICKY 1 +#define RIGHTJOYSTICKX 2 +#define RIGHTJOYSTICKY 3 + + +/* Defines for the PS3 Accelerometers and Gyro +*/ + +#define ACCELOROMETERX 0 +#define ACCELOROMETERY 1 +#define ACCELOROMETERZ 2 +#define GYROMETERZ 3 + +/* Defines for the PS3 LED and Rumble +*/ +#define PS3LED1 0x01 +#define PS3LED2 0x02 +#define PS3LED3 0x04 +#define PS3LED4 0x08 +#define PSRUMBLEHIGH 0x10 +#define PSRUMBLELOW 0x20 + +//Structure which describes the type 01 input report +typedef struct { + u8 ReportType; //Report Type 01 + u8 Reserved1; // Unknown + u16 ButtonState; // Main buttons + u8 PSButtonState; // PS button + u8 Reserved2; // Unknown + u8 LeftStickX; // left Joystick X axis 0 - 255, 128 is mid + u8 LeftStickY; // left Joystick Y axis 0 - 255, 128 is mid + u8 RightStickX; // right Joystick X axis 0 - 255, 128 is mid + u8 RightStickY; // right Joystick Y axis 0 - 255, 128 is mid + u8 Reserved3[4]; // Unknown + u8 PressureUp; // digital Pad Up button Pressure 0 - 255 + u8 PressureRight; // digital Pad Right button Pressure 0 - 255 + u8 PressureDown; // digital Pad Down button Pressure 0 - 255 + u8 PressureLeft; // digital Pad Left button Pressure 0 - 255 + u8 PressureL2; // digital Pad L2 button Pressure 0 - 255 + u8 PressureR2; // digital Pad R2 button Pressure 0 - 255 + u8 PressureL1; // digital Pad L1 button Pressure 0 - 255 + u8 PressureR1; // digital Pad R1 button Pressure 0 - 255 + u8 PressureTriangle; // digital Pad Triangle button Pressure 0 - 255 + u8 PressureCircle; // digital Pad Circle button Pressure 0 - 255 + u8 PressureCross; // digital Pad Cross button Pressure 0 - 255 + u8 PressureSquare; // digital Pad Square button Pressure 0 - 255 + u8 Reserved4[3]; // Unknown + u8 Charge; // charging status ? 02 = charge, 03 = normal + u8 Power; // Battery status ? + u8 Connection; // Connection Type ? + u8 Reserved5[9]; // Unknown + u16 AccelX; // X axis accelerometer Big Endian 0 - 1023 + u16 AccelY; // Y axis accelerometer Big Endian 0 - 1023 + u16 AccelZ; // Z axis accelerometer Big Endian 0 - 1023 + u16 GyroZ; // Z axis Gyro Big Endian 0 - 1023 + +} ps3report; + +class Ps3USB +{ + + + public: + Ps3USB(int device, int configuration, int interfaceNumber); + int Enable(); + int SetPair(u8* bdAddr); + int ShowPair(); + int Led(int i); + int Rumble(u8 duration_right, u8 power_right, u8 duration_left, u8 power_left); + int _count; + + private: + int input_ep; + int output_ep; + int _device; + int _configuration; + int _interfaceNumber; + + u8 ledrumble[48] ; + +}; + +void PS3EventCallback(int device, int endpoint, int status, u8* data, int len, void* userData); +int ParsePs3Result(const u8* data, int len, int count); + +