Student project by David Berlin and Boris Dogadov made for the Embedded Systems Workshop course given in Tel-Aviv University on 2010 by Sivan Toledo. Visit the project website for more details: http://davidberlin.co.il/sadna/ .
Dependencies: EthernetNetIf NTPClient_NetServices mbed HTTPServer HTTPClient CyaSSL
Revision 0:3e7d6f496a67, committed 2011-04-17
- Comitter:
- sivan_toledo
- Date:
- Sun Apr 17 21:30:10 2011 +0000
- Child:
- 1:b05231650f32
- Commit message:
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CyaSSL.lib Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/toddouska/code/CyaSSL/#5045d2638c29
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dropbox/Dropbox.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,158 @@ +#include "Dropbox.h" +#include "HTTPClient.h" +#include "HTTPFileSender.h" +#include "base64.h" +#include "url.h" +#include "ctc_hmac.h" +#include "NTPClient.h" +#include "HTTPData.h" + +// NET +NTPClient ntpClient; +HTTPResult result; + +// Dropbox +string consumer_token = "p4t8cn8b3ddci2d"; +string consumer_token_secret = "wtib99x350qo5l6"; +char token[16] = {0}; +char token_secret[16] = {0}; +bool completed = false; +int v = 6000; +char buffer[1024] = {0}; + +extern DigitalOut led1; +extern DigitalOut led3; +extern void USBLoop(); + +Timer timer; + +void request_callback(HTTPResult r) +{ + result = r; + completed = true; +} + +bool dropbox_getToken(char* username, char* password) +{ + HTTPClient client; + HTTPText data; + + /* Request Token */ + printf("Requesting token\r\n"); + + char request[128] = {0}; + sprintf(request, + "http://api.getdropbox.com/0/token?oauth_consumer_key=p4t8cn8b3ddci2d&email=%s&password=%s", + username, + password); + + printf(request); + HTTPResult result = client.get(request, &data); + + if (result != HTTP_OK) + { + printf("R: %d", result); + return false; + } + + const char *dataContent = data.gets(); + + memcpy(token, dataContent + 11, 15); + memcpy(token_secret, dataContent + 40, 15); + + printf("Got token %s %s %s\r\n", dataContent, token, token_secret); + + return true; +} + +bool dropbox_syncTime() +{ + /* Get Time */ + printf("Synchronizing time\r\n"); + Host server(IpAddr(), 123, "0.pool.ntp.org"); + NTPResult result = ntpClient.setTime(server); + + //srand(time(NULL)); + + return (result == NTP_OK); +} + + +bool dropbox_upload(string srcFile, string dstFile) +{ + HTTPClient client; + string dst = dstFile; + + time_t currentTime = time(NULL); + + v++; //= (rand() % 9999999) + 1000; + + //printf("T: %d NONCE: %d\r\n", currentTime, v); + + memset(buffer, 0x00, 1024); + sprintf(buffer, + "POST&http%%3A%%2F%%2Fapi-content.dropbox.com%%2F0%%2Ffiles%%2Fdropbox%%2F&file%%3D%s%%26oauth_consumer_key%%3D%s%%26oauth_nonce%%3D%d%%26oauth_signature_method%%3DHMAC-SHA1%%26oauth_timestamp%%3D%d%%26oauth_token%%3D%s", + dst.c_str(), + consumer_token.c_str(), + v, + currentTime, + token); + + //printf("Sig: %s %d\n\r", buffer, strlen(buffer)); + + string key = consumer_token_secret + "&" + token_secret; + + //printf("Key: %s %d\n\r", key.c_str(), key.size()); + + byte hash[SHA_DIGEST_SIZE]; + Hmac hmac; + HmacSetKey(&hmac, SHA, (const byte*)key.c_str(), key.size()); + HmacUpdate(&hmac, (const byte*)buffer, strlen(buffer)); + HmacFinal(&hmac, hash); + + char sig[128] = {0}; + base64enc((char*)hash, SHA_DIGEST_SIZE, sig); + + char *encodedSig = url_encode(sig); + + memset(buffer, 0x00, 1024); + sprintf(buffer, + "http://api-content.dropbox.com/0/files/dropbox/?file=%s&oauth_consumer_key=%s&oauth_nonce=%d&oauth_timestamp=%d&oauth_token=%s&oauth_signature_method=HMAC-SHA1&oauth_signature=%s", + dst.c_str(), + consumer_token.c_str(), + v, + currentTime, + token, + encodedSig); + + //printf("Req: %s %d\n\r", buffer, strlen(buffer)); + + HTTPFileSender httpFile(srcFile.c_str(), dst.c_str()); + + HTTPText res; + + //client.setTimeout(5000); + + completed = false; + HTTPResult postResult = client.post(buffer, httpFile, &res, request_callback); + + timer.start(); + + while (!completed) + { + led1 = (timer.read_ms() % 250) >= 125; + USBLoop(); + Net::poll(); + } + + timer.stop(); + timer.reset(); + + led1 = 1; + + printf("Res: %s %d %d\n\r", res.gets(), postResult, result); + + free(encodedSig); + + return (result == HTTP_OK); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dropbox/Dropbox.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,8 @@ +#include "mbed.h" +#include <string> + +bool dropbox_getToken(char* username, char* password); + +bool dropbox_syncTime(); + +bool dropbox_upload(string srcFile, string dstFile); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dropbox/HTTPFileSender.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,128 @@ +#include "HTTPFileSender.h" +#include "USBHost.h" + +char HTTPFileSender::header[] = ""; +char HTTPFileSender::footer[] = "\r\n\r\n--R50hrfBj5JYyfR3vF3wR96GPCC9Fd2q2pVMERvEaOE3D8LZTgLLbRpNwXek3--\r\n"; + +HTTPFileSender::HTTPFileSender(const char *fileName, const char *dstFile) +{ + pos = 0; + + printf("Opening %s\n\r", fileName); + + file = fopen(fileName, "r"); + + printf("Opened %d\n\r", file); + + fseek(file, 0L, SEEK_END); + printf("seek1\r\n"); + fileLen = ftell(file); + printf("seek2\r\n"); + fseek(file, 0L, SEEK_SET); + + printf("Size %d\n\r", fileLen); + + /*string dst = dstFile; + string h = ; + memcpy(header, h.c_str(), sizeof(header));*/ + sprintf(header, "--R50hrfBj5JYyfR3vF3wR96GPCC9Fd2q2pVMERvEaOE3D8LZTgLLbRpNwXek3\r\nContent-Disposition: form-data; name=file; filename=%s\r\nContent-type: application/octet-stream\r\n\r\n", dstFile); + + headerSize = strlen(header); + footerSize = strlen(footer); + + totalLen = fileLen + strlen(header) + strlen(footer); +} + +HTTPFileSender::~HTTPFileSender() +{ + fclose(file); + printf("file %d closed\r\n", file); +} + +int HTTPFileSender::read(char* buf, int len) +{ + //printf("read requested %d bytes from file %d\n\r", len, file); + + int dataSent = 0; + + //printf("Header: %d, Footer: %d\r\n", headerSize, footerSize); + + if (pos >= totalLen) + { + printf("End of file\n\r"); + return 0; + } + + if (pos < headerSize) + { + int bytesToCopy = headerSize - pos; + memcpy(buf, header + pos, bytesToCopy); + + dataSent += bytesToCopy; + pos += bytesToCopy; + + //printf("transfer header %d\r\n", bytesToCopy); + } + + //printf("Before content: %d %d\r\n", pos, dataSent); + + if (pos >= headerSize && + pos < (headerSize + fileLen)) + { + int bytesRead = fread(buf + dataSent, 1, len - dataSent, file); + + dataSent += bytesRead; + pos += bytesRead; + + // printf("transfer content %d\r\n", bytesRead); + } + + // printf("Before footer: %d %d\n\r", pos, dataSent); + + if (dataSent < len && + pos >= (headerSize + fileLen) && + pos < (headerSize + fileLen + footerSize)) + { + int posInFooter = pos - fileLen - headerSize; + int bytesToCopy = min(footerSize - posInFooter, len - dataSent); + + memcpy(buf + dataSent, footer + posInFooter, bytesToCopy); + + dataSent += bytesToCopy; + pos += bytesToCopy; + + // printf("transfer footer %d\r\n", bytesToCopy); + } + + //printf("After: %d %d\r\n", pos, dataSent); + + //int result = fread(buf, 1, len, file); + + //printf("read %s %d bytes\r\n", buf, dataSent); + if (pos % 1024 == 0) printf("read %d bytes pos %d\r\n", dataSent, pos); + + return dataSent; +} + +string HTTPFileSender::getDataType() +{ + // printf("data type read\n\r"); + return "multipart/form-data; boundary=R50hrfBj5JYyfR3vF3wR96GPCC9Fd2q2pVMERvEaOE3D8LZTgLLbRpNwXek3"; +} + +int HTTPFileSender::getDataLen() +{ + // printf("get data len %d\n\r", totalLen); + return totalLen; +} + +void HTTPFileSender::clear() { } + +int HTTPFileSender::write(const char* buf, int len) { return 0; } + +void HTTPFileSender::setDataType(const string& type) { } + +bool HTTPFileSender::getIsChunked() { return false; } +void HTTPFileSender::setIsChunked(bool chunked) { } + +void HTTPFileSender::setDataLen(int len) { } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dropbox/HTTPFileSender.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,34 @@ +#include "HTTPData.h" +//#include "HTTPText.h" +#include "HTTPClient.h" + +class HTTPFileSender : public HTTPData +{ + public: + HTTPFileSender(const char *fileName, const char* dstFile); + virtual ~HTTPFileSender(); + virtual void clear(); + virtual int read(char* buf, int len); + virtual int write(const char* buf, int len); + + virtual string getDataType(); //Internet media type for Content-Type header + virtual void setDataType(const string& type); //Internet media type from Content-Type header + + virtual bool getIsChunked(); //For Transfer-Encoding header + virtual void setIsChunked(bool chunked); //From Transfer-Encoding header + + virtual int getDataLen(); //For Content-Length header + virtual void setDataLen(int len); //From Content-Length header, or if the transfer is chunked, next chunk length + private: + FILE *file; + + int pos; + int totalLen; + int fileLen; + + int headerSize; + int footerSize; + + static char header[256]; + static char footer[128]; +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dropbox/base64.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,59 @@ + + /* + Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + + #include "base64.h" + //Originaly from Rolf's iputil.c + + #ifdef __cplusplus + extern "C" { + #endif + + #include <string.h> + + unsigned int base64enc_len(const char *str) { + return (((strlen(str)-1)/3)+1)<<2; + } + + void base64enc(const char *input, unsigned int length, char *output) { + static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned int c, c1, c2, c3; + for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) { + c1 = ((((unsigned char)*((unsigned char *)&input[i])))); + c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0; + c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0; + + c = ((c1 & 0xFC) >> 2); + output[j+0] = base64[c]; + c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4); + output[j+1] = base64[c]; + c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6); + output[j+2] = (length>i+1)?base64[c]:'='; + c = (c3 & 0x3F); + output[j+3] = (length>i+2)?base64[c]:'='; + } + output[(((length-1)/3)+1)<<2] = '\0'; + } + + #ifdef __cplusplus + } + #endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Dropbox/base64.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,68 @@ + + /* + Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + + #ifndef BASE64_H + #define BASE64_H + + #include <string> + using std::string; + + #ifdef __cplusplus + extern "C" { + #endif + + //Originaly from Rolf's iputil.h + + unsigned int base64enc_len(const char *str); + + void base64enc(const char *input, unsigned int length, char *output); + + #ifdef __cplusplus + } + #endif + + + class Base64 + { + public: + static string encode(const string& str) + { + char* out = new char[ base64enc_len(str.c_str()) ]; + base64enc(str.c_str(), str.length(), out); + string res(out); + delete[] out; + return res; + } + + static string encode(const char* buf, int len) + { + char* out = new char[len]; + base64enc(buf, len, out); + string res(out); + delete[] out; + return res; + } + }; + + #endif /* LWIP_UTILS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EthernetNetIf.lib Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mamezu/code/EthernetNetIf/#0f6c82fcde82
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Sun Apr 17 21:30:10 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/HTTPClient.lib Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mamezu/code/HTTPClient/#62fac7f06c8d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPServer.lib Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/donatien/code/HTTPServer/#d753966e4d97
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HttpHandlerSetup.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,193 @@ +#include "HttpHandlerSetup.h" + +bool ReadSettings(char* username, char* password) +{ + //printf("ReadSettings start\r\n"); + FILE* settingsFile = fopen("/usb/DBSet.txt", "r"); + if (settingsFile) + { + //printf("before fseek %d\n\r", settingsFile); + fseek(settingsFile, 9L, SEEK_SET); + fgets(username, 32, settingsFile); + fseek(settingsFile, 9L, SEEK_CUR); + fgets(password, 32, settingsFile); + + + int len = strlen(username); username[len - 2] = 0; // remove /r/n + //printf("ReadSettings %s, %s, %d, %d, %s\r\n", username, password, len, ftell(settingsFile), data); + + fclose(settingsFile); + } + + return settingsFile != 0; +} + +HttpHandlerSetup::HttpHandlerSetup(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : + HTTPRequestHandler(rootPath, path, pTCPSocket) +{ + //printf("HttpHandlerSetup()"); +} + +HttpHandlerSetup::~HttpHandlerSetup() +{ +} + +void HttpHandlerSetup::doGetPageWelcome() +{ + //printf("doGetPageWelcome()-start\r\n"); + const char* resp = + "<html><body>" + "<p><span style=\"color: #a9a9a9\"><span style=\"font-size: 12px\">DropBox Sync Setup</span></span></p><p>" + "<p><a href=\"/Setup\">Setup</a></p>" + "<p><a href=\"/UsbBrowser/root/\">DiskOnKey browser</a></p>" + "</form><p> </p>" + "<p><strong><span style=\"color: #000080\">BDDB Ltd.</span></strong></p>" + "</body>" + "</html>"; + + int len = strlen(resp); + setContentLen(len); + respHeaders()["Connection"] = "close"; + writeData(resp, len); +} + +void HttpHandlerSetup::UpdateSettingsFile() +{ + if (m_WasDataRead) + { + return; + } + + char buffer[256]; + int dataLength = dataLen(); + int readBytes = readData(buffer, 45 + dataLength); + + if (readBytes > 0) + { + int offset = readBytes > dataLength ? 45 : 0; // Inconsistency id data reading + char* c1 = strchr(buffer, '&'); + char* c2 = strchr(buffer + offset, '=') + 1; + char* c3 = strchr(c1, '=') + 1; + int lenU = c1 - c2; + int lenP = readBytes - (c3 - buffer); + + char* c2_fixed = strstr(c2, "%40"); + if (c2_fixed) // case @ is replaced by %40 + { + c2_fixed[0] = '@'; + memcpy(c2_fixed + 1, c2_fixed + 3, lenU - (c2_fixed - c2) - 3); + lenU -= 2; + printf(c2); + } + + FILE* settingsFile = fopen("/usb/DBSet.txt", "w"); + if (settingsFile) + { + fwrite("USERNAME=", 1, 9, settingsFile); + fwrite(c2, 1, lenU, settingsFile); + fwrite("\r\nPASSWORD=", 1, 11, settingsFile); + fwrite(c3, 1, lenP, settingsFile); + fclose(settingsFile); + + //printf("Updated %s, %s\r\n", c2, c3); + } + m_WasDataRead = true; + } + + //printf("readBytes %d\r\n", readBytes); +} + +void HttpHandlerSetup::doGet() +{ + //printf("Setup path %s\r\n", path()); + if (path().size() <= 1) + { + doGetPageWelcome(); + return; + } + + //printf("doGet()-start %s, %s\r\n", Username, Password); + const char* resp1 = + "<html><body>" + "<p><span style=\"color: #a9a9a9\"><span style=\"font-size: 12px\">DropBox Sync Setup</span></span></p><p>" + "<form method=\"post\" action=\"\">" + "Username: <input type=\"text\" name=\"Username\" value=\""; + const char* resp2 = "\" /><br />Password: <input type=\"text\" name=\"Password\" value=\""; + const char* resp3 = + "\" /><br /><input type=\"submit\" value=\"Submit\" />" + "</form><p> </p>" + "<p><strong><span style=\"color: #000080\">BDDB Ltd</span></strong></p>" + "</body>" + "</html>"; + + char username[32]="invalid", password[32]="error"; + ReadSettings(username, password); + + int l1 = strlen(resp1), l2 = strlen(resp2), l3 = strlen(resp3); + int p = strlen(password), u = strlen(username); + + respHeaders()["Connection"] = "close"; + + setContentLen(l1 + l2 + l3 + p + u); + int t1 = writeData(resp1, l1); + int t2 = writeData(username, u); + int t3 = writeData(resp2, l2); + int t4 = writeData(password,p); + int t5 = writeData(resp3, l3); + + m_WasDataRead = false; + printf("doGet()-end\r\n"); +} + +void HttpHandlerSetup::doPost() +{/* + map<string,string>::iterator it = reqHeaders().begin(); + printf("printing %s\n\r", path()); + while (it != reqHeaders().end()) + { + printf("%s --- %s\r\n", it->first, it->second); + it++; + } + */ + printf("doPost()-start\r\n"); + UpdateSettingsFile(); + + const char* resp = + "<html><body>" + "<p><span style=\"color: #0080FF\"><span style=\"font-size: 14px\">Password changed</span></span></p><p>" + "<FORM><INPUT TYPE=\"button\" VALUE=\"Back\" onClick=\"history.go(-1);return true;\"></FORM>" + "</form><p> </p>" + "<p><strong><span style=\"color: #000080\">BDDB Ltd.</span></strong></p>" + "</body>" + "</html>"; + const int length = strlen(resp); + setContentLen(length); + respHeaders()["Connection"] = "keep-alive"; + writeData(resp, length); + + printf("doPost()-end\r\n"); +} + +void HttpHandlerSetup::doHead() +{ + printf("onHead\r\n"); +} + +void HttpHandlerSetup::onReadable() //Data has been read +{ + printf("onReadable\r\n"); + UpdateSettingsFile(); +} + +void HttpHandlerSetup::onWriteable() //Data has been written & buf is free +{ +// printf("onWriteable() password: %s, username:%s \r\n", Password, Username); + printf("onWriteable\r\n"); + //close(); //Data written, we can close the connection +} + +void HttpHandlerSetup::onClose() //Connection is closing +{ + printf("onClose\r\n"); + //Nothing to do +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HttpHandlerSetup.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,32 @@ +#include "HTTPServer.h" + +#ifndef HTTP_HANDLER_SETUP +#define HTTP_HANDLER_SETUP + +bool ReadSettings(char* username, char* password); + +class HttpHandlerSetup : public HTTPRequestHandler +{ +public: + HttpHandlerSetup(const char* rootPath, const char* path, TCPSocket* pTcpSocket); + virtual ~HttpHandlerSetup(); + + static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTcpSocket) { return new HttpHandlerSetup(rootPath, path, pTcpSocket); } +protected: + + virtual void doGet(); + virtual void doPost(); + virtual void doHead(); + + virtual void onReadable(); //Data has been read + virtual void onWriteable(); //Data has been written & buf is free + virtual void onClose(); //Connection is closing + +private: + void doGetPageWelcome(); + void UpdateSettingsFile(); + + bool m_WasDataRead; +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HttpHandlerUsbBrowser.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,130 @@ +#include "HttpHandlerUsbBrowser.h" +#include "USBHost.h" +#include "Utils.h" +#include "UsbStorage.h" + +HttpHandlerUsbBrowser::HttpHandlerUsbBrowser(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : + HTTPRequestHandler(rootPath, path, pTCPSocket) +{ + //printf("HttpHandlerUsbBrowser()"); +} + +HttpHandlerUsbBrowser::~HttpHandlerUsbBrowser() +{ +} + +void HttpHandlerUsbBrowser::doGet() +{ + int cmpRes = path().compare(0, 5, "/root"); + printf("doGet path:%d\r\n", cmpRes); + + DIR* d = 0; + FILE* f = 0; + + char usbFullPath[256] = "/usb"; + if (cmpRes == 0) + { + path().copy(usbFullPath + 4, 252, 5); + int usbFullPathLen = strlen(usbFullPath); + if (usbFullPath[usbFullPathLen - 1] == '/') usbFullPath[usbFullPathLen - 1] = 0; + + d = opendir(usbFullPath); + //printf("after open dir\r\n"); + + if (!d) f = fopen(usbFullPath, "r"); + //printf("after open file\r\n"); + } + + if (!d && !f) + { + printf("return no data\r\n"); + respHeaders()["Connection"] = "close"; + writeData("<html><body>No Data or Invalid Path</html></body>", 49); + setContentLen(49); + return; + } + + const char* resp1 = + "<html><body>" + "<p><span style=\"color: #a9a9a9\"><span style=\"font-size: 12px\">DropBox Sync Flash-Explorer</span></span></p>"; + + const char* resp2 = + "</form><p> </p>" + "<p><strong><span style=\"color: #000080\">BDDB Ltd.</span></strong></p>" + "</body>" + "</html>"; + + int l1 = strlen(resp1), l2 = strlen(resp2); + int length = l1 + l2; + + int t1 = writeData(resp1, l1); + + if (d) + { + printf("\nDumping root dir\n\r"); + struct dirent *dir = readdir(d); + while (dir) + { + int len = sizeof(dirent); + printf("%s %d\n\r", dir->d_name, len); + + int nameLen = strlen(dir->d_name); + + writeData("<p><a href=\"", 12); + writeData(dir->d_name, nameLen); + writeData("/\">", 3); + writeData(dir->d_name, nameLen); + writeData("</a></p>", 8); + length += nameLen * 2 + 23; + + dir = readdir(d); + } + closedir(d); + } + else if (f) + { + printf("dumping file \r\n"); + while (fgets(usbFullPath, 256, f) && length <= 4096) + { + // printf("%s\r\n", usbFullPath); + int len = strlen(usbFullPath); + writeData(usbFullPath, len); + + length += len; + } + + fclose(f); + } + + int t3 = writeData(resp2, l2); + respHeaders()["Connection"] = "close"; + setContentLen(length); + + printf("doGet()-end length %d\r\n", length); +} + +void HttpHandlerUsbBrowser::doPost() +{ + printf("doPost()\r\n"); +} + +void HttpHandlerUsbBrowser::doHead() +{ + printf("onHead\r\n"); +} + +void HttpHandlerUsbBrowser::onReadable() //Data has been read +{ + printf("onReadable\r\n"); +} + +void HttpHandlerUsbBrowser::onWriteable() //Data has been written & buf is free +{ + printf("onWriteable\r\n"); + close(); //Data written, we can close the connection +} + +void HttpHandlerUsbBrowser::onClose() //Connection is closing +{ + //Nothing to do +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HttpHandlerUsbBrowser.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,20 @@ +#include "HTTPServer.h" + +class HttpHandlerUsbBrowser : public HTTPRequestHandler +{ +public: + HttpHandlerUsbBrowser(const char* rootPath, const char* path, TCPSocket* pTcpSocket); + virtual ~HttpHandlerUsbBrowser(); + + static inline HTTPRequestHandler* inst(const char* rootPath, const char* path, TCPSocket* pTcpSocket) { return new HttpHandlerUsbBrowser(rootPath, path, pTcpSocket); } + +protected: + + virtual void doGet(); + virtual void doPost(); + virtual void doHead(); + + virtual void onReadable(); //Data has been read + virtual void onWriteable(); //Data has been written & buf is free + virtual void onClose(); //Connection is closing +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MassStorage/MassStorage.cpp Sun Apr 17 21:30:10 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/MassStorage/UsbStorage.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,45 @@ +#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) + { + //printf("disk_readA\r\n"); + int r = MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize); + //printf("disk_readB\r\n"); + return r; + } + + virtual int disk_sectors() + { + return _blockCount; + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NTPClient.lib Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/donatien/code/NTPClient/#7c3f1199256a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/AutoEvents.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,154 @@ + +/* +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" + +#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) + +u8 auto_mouse[4]; // buttons,dx,dy,scroll +u8 auto_keyboard[8]; // modifiers,reserved,keycode1..keycode6 +u8 auto_joystick[4]; // x,y,buttons,throttle + +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; + 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) +{ + 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); + 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; + default: + printf("Interrupt endpoint %02X %08X\n",ed->bEndpointAddress,evt); + break; + } + if (dst) + { + printf("Auto Event for %02X %08X\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\n",i,(const char*)buffer); + } + +// Walk descriptors and create endpoints for a given device +int StartAutoEvent(int device, int configuration, int interfaceNumber) +{ + 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; +} + +// Implemented in main.cpp +int OnDiskInsert(int device); + +void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc) +{ + printf("LoadDevice %d %02X:%02X:%02X\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol); + char s[128]; + for (int i = 1; i < 3; i++) + { + if (GetString(device,i,s,sizeof(s)) < 0) + break; + printf("%d: %s\n",i,s); + } + + switch (interfaceDesc->bInterfaceClass) + { + case CLASS_MASS_STORAGE: + if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50) + OnDiskInsert(device); // it's SCSI! + break; + default: + StartAutoEvent(device,1,0); + break; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1090 @@ + +/* +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\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\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\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\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next); + //LOG("%04X ED %08X %08X %08X\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\n",ep,endpoint->TDHead.Control); + + if (status != 0) + { + LOG("ProcessDoneQueue status %02X %d\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========\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\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\n\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)\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)\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\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\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\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\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; + + LPC_USB->HcRhDescriptorB |= 0xFFFF; + + 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; +} + +void Disconnect() +{ +_controller.Disconnect(0,1); +} + +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; +} + +void ClearPortPower() +{ + LPC_USB->HcRhPortStatus1 |= ConnectStatusChange; +} + +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); +} + +void Reset() +{ + LPC_USB->HcCommandStatus |= 1; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.h Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,205 @@ + +/* +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_CLASS 0x20 +#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 + +// -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); + +int SetPortReset(int device, int port); +int GetPortStatus(int device, int port, u32* status); +int SetPortPower(int device, int port); +void ClearPortPower(); +void Reset(); +// 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/USBHost/Utils.cpp Sun Apr 17 21:30:10 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("\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\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/USBHost/Utils.h Sun Apr 17 21:30:10 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/main.cpp Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,217 @@ +/* +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 "UsbStorage.h" + +#include "EthernetNetIf.h" +#include "HTTPClient.h" +#include "Dropbox.h" +#include "HTTPServer.h" +#include "HttpHandlerSetup.h" +#include "HttpHandlerUsbBrowser.h" +#include "HTTPFileSender.h" +#include "base64.h" +#include "url.h" +#include "ctc_hmac.h" +#include "NTPClient.h" +#include "HTTPData.h" + +void test_dropbox(); + +// USB +Serial pc(USBTX, USBRX); +USBFileSystem fs; +int usbDevice = -1; + +// NET +EthernetNetIf* eth; + +// LED +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); + +int OnDiskInsert(int device) +{ + printf("\r\nOnDiskInsert\r\n"); + + usbDevice = device; + fs.SetDevice(usbDevice); + + return 0; +} + + +bool setup_eth() +{ + printf("\r\nSetting up...\r\n"); + + EthernetErr ethErr = eth->setup(); + if(ethErr) + { + printf("Error %d in setup.\n", ethErr); + return false; + } + printf("\r\nSetup OK\r\n"); + + return true; +} + +bool setup_httpServer(HTTPServer& svr) +{ + svr.addHandler<HttpHandlerUsbBrowser>("/UsbBrowser"); + svr.addHandler<HttpHandlerSetup>("/"); + svr.bind(80); + + printf("Http Server initialized\r\n"); + + return true; +} + +bool upload_files(char* username, char* password) +{ + DIR *d = opendir("/usb/DROPBOX"); //TODO - global + int totalFiles = -1; + if (d) + { + char filenameSrc[64] = "/usb/DROPBOX/"; + char filenameDst[32] = "USBSYNC_"; //TODO - remove? + int c = 0; + + printf("Synchronize Start\n\r"); + if (!dropbox_syncTime()) + { + printf("Failed to sync time"); + led3 = 1; + return totalFiles; + } + if (!dropbox_getToken(username, password)) + { + printf("Failed getting token\r\n"); + led3 = 1; + return totalFiles; + } + + struct dirent *p = readdir(d); + while (p) + { + strcpy(filenameSrc + 13, p->d_name); + strcpy(filenameDst + 8, p->d_name); + printf("Uploading %s to %s\r\n", filenameSrc, filenameDst); + + dropbox_upload(filenameSrc, filenameDst); + c++; + p = readdir(d); + } + + closedir(d); + + totalFiles = c; + printf("Synchronizing finished (%d)\n\r", totalFiles); + led2 = 1; + + return totalFiles; + } + else + { + led3 = 1; + printf("Failed opening /usb/DROPBOX/\r\n"); + return totalFiles; + } +} + +int main() +{ + bool ethSetup = false, httpSetup = false; + USBInit(); + HTTPServer svr; + + int i = 0; + + led3 = 0; // clear error LED + + for (;;) + { + if (i++ % 500000 == 0) printf("looping\r\n"); //TODO replace with time + + USBLoop(); + Net::poll(); + + if (!ethSetup) + { + eth = new EthernetNetIf(); + ethSetup = setup_eth(); + + if (!ethSetup) + { + delete eth; + eth = 0; + } + + httpSetup = false; + } + + if (ethSetup && !httpSetup) + { + httpSetup = setup_httpServer(svr); + } + + // Cehck if Ethernet setup and USB-Disk connected + if (usbDevice >= 0 && ethSetup) + { + usbDevice = -1; + + led1 = 1; + led2 = 0; + + // Read username/password + char username[32] = {0}; + char password[32] = {0}; + if (!ReadSettings(username, password)) + { + printf("Failed opening /usb/DBSet.txt\r\n"); + led3 = 1; + continue; + } + + // Start synchronizing + int totalFiles = upload_files(username, password); + + FILE* logFile = fopen("/usb/dbLog.txt", "a+"); + if (logFile) + { + if (totalFiles >= 0) + fprintf(logFile, "%d Synchronizing successfull %d files\r\n", time(NULL), totalFiles); + else + fputs("Synchronizing failed\r\n", logFile); //TODO whats this? + + fclose(logFile); + } + + led1 = 0; + ClearPortPower(); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sun Apr 17 21:30:10 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0