#include "MTP.h"
#include "usb.h"
#include <string.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
struct MTPHeader {
union{
byte lenL; // 0
word lenW;
uint32_t lenD;
byte lenB[4];
};
byte typeL,typeH; // 4
byte opL,opH; // 6
uint32_t transid; // 8
};
static struct{
MTPHeader h;
uint32_t params[3]; // 12
}bulkcs;
word eefill; // Füllstand des EEPROM = Dateilänge
namespace MTP {
static void outc(const byte*p,byte len) {
usbSend(p,len);
}
static void out1(byte b) {
outc(&b,1);
}
static void out2(word w) {
out1(w);
out1(w>>8);
}
static void out4(word w) {
out2(w);
out2(0);
}
static void out0(byte len) {
usbSend(0,len);
}
static void out8(word w) {
out2(w);
out0(6);
}
static void outHeader(word len) {
out4(len+12);
out2(2); // type
outc(&bulkcs.h.opL,6); // operation + transaction ID
}
static void outFlush() {
usbFlush();
}
static void outDescriptor() {
outHeader(11+10+20);
out0(11);
out4(3); // Only needed capabilities (Windows 10)
out2(0x100B); // DeleteObject // required otherwise files are deletion protected, and write protected after copying to local storage
out2(0x100C); // SendObjectInfo // required otherwise files cannot be added
out2(0x100D); // SendObject // same as above
out0(20);
outFlush();
}
static void outStorageIDs() {
outHeader(8);
out4(1); // 1 entry
out4(1); // 1 storage
outFlush();
}
static void outStorageInfo() {
outHeader(2+2+2+8+8+4+1+1);
out2(3); // storage type (fixed RAM)
out2(1); // filesystem type (generic flat)
out2(0); // access capability (read-write)
out8(1024); // max capacity (bytes)
out8(1024-eefill); // free space (bytes)
out4(0); // free space (objects)
out0(2); // 2 identifier, jetzt kommt "Festspeicher"
outFlush();
}
static void outObjectHandles() {
outHeader(8);
out4(1);
out4(1);
outFlush();
}
static void outObjectInfo(byte) {
static const PROGMEM char name[]="eeprom";
outHeader(4+4+4+40+1+(sizeof name<<1)+3);
out4(1); // Logical Storage ID
out4(0x3000); // undefiniert
out4(eefill); // size
out0(40); // Info für Bilder
out1(sizeof name);
for (byte i=0;i<sizeof name;i++) out2(pgm_read_byte(name+i));
out0(3); // date captured, date modified, keywords: all undefined
outFlush();
}
static void GetObject(byte) {
outHeader(eefill);
for (word i=0; i<eefill; i++) out1(eeprom_read_byte((byte*)i));
outFlush(); // Short-Packet
}
static void usbSkipString() {
byte n;
usbRecv(&n,1);
usbRecv(0,n+n);
}
static bool SendObjectInfo() {
usbRecv(0,20); // Header, Dateityp ignorieren
usbRecv(&eefill,2);
usbRecv(0,42); // Krimskrams dazwischen ignorieren
usbSkipString(); // name
usbSkipString(); // ctime
usbSkipString(); // mtime
usbSkipString(); // keywords
return eefill<=1024;
}
// Datei überschreiben: Jetzt kommen die Daten, und Dateilänge sollte gleich sein.
static bool SendObject() {
word size;
usbRecv(&size,2);
usbRecv(0,10);
size-=12;
if (size!=eefill) return false;
for (word i=0; i<size; i++) {
byte b;
usbRecv(&b,1);
eeprom_write_byte((byte*)i,b);
}
return true;
}
static void handleCommand() {
byte p1 = 0;
byte retcode = 1; // Ok
if (bulkcs.h.opH!=0x10) retcode=5;
else switch (bulkcs.h.opL) {
case 1: outDescriptor(); break; // GetDescription
case 2: break; // OpenSession
case 3: break; // CloseSession
case 4: outStorageIDs(); break; // GetStorageIDs
case 5: outStorageInfo(); break; // GetStorageInfo
case 6: p1 = 1; break; // GetNumObjects
case 7: outObjectHandles(); break; // GetObjectHandles
case 8: outObjectInfo(bulkcs.params[0]);break;// GetObjectInfo
case 9: GetObject(bulkcs.params[0]); break; // GetObject
case 11: break; // DeleteObject
case 12: // SendObjectInfo
if (!SendObjectInfo()) retcode=12; // store_fill
else bulkcs.params[2] = 1/*handle*/;
bulkcs.h.lenL = 12 + 3*4; // 3 Parameter
goto ex1;
case 13: // SendObject
if (!SendObject()) retcode=21; // no_valid_objectinfo
bulkcs.h.lenL = 12;
// Events werden (zumindest unter Windows 10) nun doch nicht mehr benötigt.
// Kann man sich also sparen.
break;
default:
retcode = 5; // operation not supported
}
bulkcs.h.lenL = 16; // Standard: Rückgabe 1 Parameter
bulkcs.params[0] = p1;
ex1: // für mehr als 1 Parameter
bulkcs.h.typeL = 3; // Antwort
bulkcs.h.opL = retcode;
bulkcs.h.opH = 0x20;
usbSend(&bulkcs,bulkcs.h.lenL);
usbFlush();
}
// Einzige exportierte Funktion
void pollUSB() {
if (usbRecvPoll()) {
PORTD&=~0x20; // TX
usbRecv(&bulkcs,8);
if (bulkcs.h.typeL==1 // "command", alles andere: STALL (Protokollfehler)
// && bulkcs.h.typeH==0x10
&& bulkcs.h.lenD<=sizeof bulkcs
&& bulkcs.h.lenL>=12) {
usbRecv(&bulkcs.h.transid,bulkcs.h.lenL-8); // Rest des Kommandos abholen
handleCommand();
}else{
// eelog(&bulkcs,8); // Murks!
UEINTX=0; // aufs nächste ganze USB-Paket synchronisieren
}
PORTD|= 0x20;
}
}
}/*namespace*/
Detected encoding: UTF-8 | 0
|