#include "libexf1.h" // gcc -o ExF1Ctrl exf1ctrl.c libexf1.c exf1api.c -lusb /* Command observations: * Byte 1-4 = Number of bytes in packet. * Byte 5-6 = Command idx. for broken up commands: 0x0001, 0x0002 ... * Byte 7-8 = Command. * Byte 9-12 = Command number: 0x00000000 - 0xFFFFFFFF. * Byte 13-14 = Parameter 1. * Byte 15-16 = Parameter 2. * Byte 17-18 = Parameter 3. * Byte 19-20 = Parameter 4. */ /* Ack observations: * Byte 1-4 = Number of bytes in packet. * Byte 5-6 = Ack idx. Ends with 0x0003. * Byte 7-8 = Ack. 0x2001 = OK, 0x0002 = More data on the way. * Byte 9-12 = Command number: 0x00000000 - 0xFFFFFFFF. * Byte 13-14 = Parameter 1. * Byte 15-16 = Parameter 2. * Byte 17-18 = Parameter 3. * Byte 19-20 = Parameter 4. * Byte 21-22 = Parameter 5. * Byte 23-24 = Parameter 6. */ /* Command 0x1016 is used to configure camera settings. * Byte 1-4 = Setting address. * Byte 5-6 = Setting. * * Examples: * * Manual exposure: * Exposure = 0x0000500E, 0x0001 = M, 0x0002 = Auto, etc. * ShutterSpe = 0x0000500D, 0x0023 = 1/40, 0x002B = 1/250, etc. * Aperture = 0x00005007, 0x0001 = F2.7, 0x0002 = F3.0, etc. * * Still image: * Image size = 0x00005003, Size is written in ASCII. * Quality = 0x00005004, 0x0001 = Economy, 0x0002 = Normal, etc. * WB = 0x00005005, 0x0002 = Auto WB, 0x0004 = Daylight, etc. * Metering = 0x0000500B, 0x0002 = Center weighted, 0x0003 = Set multi, etc. * Flash = 0x0000500C, 0x0001 = Auto flash, 0x0002 = Flash off, etc. * ISO = 0x0000500F, 0xFFFF = Auto, 0x0064 = 100, 0x00C8 = 200, etc. * EV = 0x00005010, 0x0000 = -2.0EV, 0x0001 = -1.7EV, etc. * Storage = 0x0000D002, 0x0000 = Save to SD, 0x0001 = Save to PC. * Rec light = 0x0000D008, 0x0000 = Off, 0x0001 = On * Movie mode = 0x0000D00B, 0x0001 = HD, 0x0002 = HS * * Continues shutter: * High-speed = 0x0000D00F, 0x0001 = 1fps, 0x000C = 30fps, etc * UpperLimit = 0x0000D010, 0x0001 = 3fps, 0x0002 = 5fps, etc. * * Prerecord Still Image: * CS shot = 0x0000D011, 0x001E = 30, 0x0028 = 40, etc. * * Movie: * HD setting = 0x0000D00C, 0x0000 = FHD, 0x0001 = HD * HS setting = 0x0000D00D, 0x0000 = 300fps, 0x0001 = 600fps, etc. * * Focus = 0x0000500A, 0x0002 = AF, 0x0003 = Macro focus, etc. * */ /* Command 0x1014 / 0x1015 reads out a camera setting. * Byte 1-4 = Setting address. * * 1. packet = Setting? * 2. packet = ACK? */ usb_dev_handle *dev = NULL; char tmp[BUF_SIZE]; char img[IMG_BUF_SIZE]; PTP_DEVICE_INFO deviceInfo; PTP_DEVICE_PROPERTY deviceProperty; PTP_OBJECT_INFO objectInfo; DWORD_DATA_SET *objectHandles; PTP_CONTAINER *rx; DWORD zoomSetting; DWORD focusSetting; DWORD USB_CMD_ID = 0xFFFFFFFF; void exf1Cmd(WORD cmd, ...) { DWORD dwordVal; WORD wordVal; char *pString; va_list ap; va_start(ap, cmd); switch(cmd){ case CMD_WRITE: dwordVal = va_arg(ap, int); // Address wordVal = va_arg(ap, int); // Value. usbTx(cmd, TYPE_CMD, sizeof(dwordVal),(DWORD) dwordVal, 0); usbTx(cmd, TYPE_DATA, sizeof(wordVal), (DWORD) wordVal, 0); usbRx(); if (dwordVal == ADDR_FUNCTIONALITY) { //do usbRxEvent(); //while (rx->code != EVT_DEVICE_INFO_CHANGED); } break; case CMD_READ: break; case CMD_MOVIE_RESET: case CMD_CS_RELEASE: case CMD_MOVIE_RELEASE: case CMD_STILL_START: case CMD_MOVIE_START: dwordVal = va_arg(ap, int); usbTx(cmd, TYPE_CMD, sizeof(dwordVal), (DWORD) dwordVal, 0); if (dwordVal) { // PreRecordEnabled... do usbGetStatus(); while (usbRx() < 0); } else usbRx(); break; case CMD_CS_PRESS: case CMD_SHUTTER: case CMD_HALF_PRESS: usbTx(cmd, TYPE_CMD, 0, 0, 0); usbRxEvent(); usbRx(); break; case CMD_STILL_RESET: case CMD_MOVIE_PRESS: case CMD_CLOSE_SESSION: case CMD_HALF_RELEASE: case CMD_STILL_STOP: case CMD_MOVIE_STOP: usbTx(cmd, TYPE_CMD, 0, 0, 0); usbRx(); break; case CMD_CF_PRESS: case CMD_CZ_PRESS: dwordVal = va_arg(ap, int); usbTx(cmd, TYPE_CMD, 2*sizeof(dwordVal), (DWORD) dwordVal, 0); usbRx(); break; case CMD_CF_RELEASE: case CMD_CZ_RELEASE: case CMD_ZOOM: case CMD_FOCUS: dwordVal = va_arg(ap, int); usbTx(cmd, TYPE_CMD, 2*sizeof(dwordVal), (DWORD) dwordVal, 0); while (usbRxEvent() > 0); usbRx(); while (usbRxEvent() > 0); break; case CMD_OPEN_SESSION: USB_CMD_ID = 0; dwordVal = va_arg(ap, int); usbTx(cmd, TYPE_CMD, sizeof(dwordVal), (DWORD) dwordVal, 0); usbRx(); break; case CMD_GET_STILL_HANDLES: case CMD_GET_MOVIE_HANDLES: case CMD_GET_DEVICE_INFO: usbTx(cmd, TYPE_CMD, 0, 0, 0); usbRx(); usbRx(); break; case CMD_GET_OBJECT_INFO: dwordVal = va_arg(ap, int); usbTx(cmd, TYPE_CMD, 2*sizeof(DWORD), dwordVal, 0xFFFFFFFF); usbRx(); usbRx(); break; case CMD_GET_PROP_DESC: dwordVal = va_arg(ap, int); usbTx(cmd, TYPE_CMD, sizeof(dwordVal), (DWORD) dwordVal, 0); usbRx(); usbRx(); break; case CMD_GET_THUMBNAIL: case CMD_GET_OBJECT: wordVal = va_arg(ap, int); // File/memory destination. dwordVal = va_arg(ap, int); // objectHandle usbTx(cmd, TYPE_CMD, sizeof(DWORD), dwordVal, 0); switch (wordVal) { case TO_FILE: pString = (char *) va_arg(ap, int); if (usbRxToFile(pString) < 0); usbRxToFile(pString); break; case TO_MEM: break; } usbRx(); break; default: printf("Unsupported command type!\n"); } va_end(ap); USB_CMD_ID++; } void usbTx(WORD cmd, WORD cmdType, int nCmdParameterBytes, DWORD cmdParameter1, DWORD cmdParameter2) { PTP_CONTAINER tx; int packetSize = 12 + nCmdParameterBytes; tx.length = packetSize; tx.type = cmdType; tx.code = cmd; tx.trans_id = USB_CMD_ID; if (nCmdParameterBytes == 2) { tx.payload.word_params.param1 = 0xFFFF & cmdParameter1; } else if (nCmdParameterBytes == 4) { tx.payload.dword_params.param1 = cmdParameter1; } else if (nCmdParameterBytes == 8) { tx.payload.dword_params.param1 = cmdParameter1; tx.payload.dword_params.param2 = cmdParameter2; } /* int i; char *pTx = (char *) &tx; for (i=0; i 0) { /* printf("usbRx: 0x%04X 0x%04X\n", rx->code, rx->type); char *pTx = rx->payload.data; for (i=0; ilength-12; i++) printf("%02X-", 0xFF & *(pTx + i)); printf("\n"); */ switch (rx->type) { case TYPE_DATA: switch (rx->code) { case CMD_GET_DEVICE_INFO: setDeviceInfo(rx->payload.data); printDeviceInfo(); break; case CMD_GET_PROP_DESC: setDeviceProperty(rx->payload.data); printDeviceProperty(); break; case CMD_GET_OBJECT_INFO: setObjectInfo(rx->payload.data); //printObjectInfo(); break; case CMD_GET_STILL_HANDLES: case CMD_GET_MOVIE_HANDLES: free(objectHandles); getDwordDataSet(&objectHandles, rx->payload.data); //printDwordDataSet("ObjectHandles : ", objectHandles); break; default: printf("Unhandled data package (usbRx): 0x%04X 0x%04X ", rx->code, rx->type); char *pTx = rx->payload.data; for (i=0; ilength-12; i++) printf("%02X-", 0xFF & *(pTx + i)); printf("\n"); } break; case TYPE_RESPONSE: if (rx->code != CMD_OK) printf("Ack = %02X.\n", rx->code); break; /* case TYPE_EVENT: printf("Read an event message.\n"); //usbRx(); if (usb_interrupt_read(dev, EP_INT, tmp, 16, TIME_OUT) < 0) printf(" Error: interrupt read failed!\n"); bytesRead = rx->code; break; * */ default: printf("Unknown message type: 0x%04x\n", 0xFFFF & rx->type); } } else if (bytesRead != -116) { printf("Error: Bulk read failed! %d %s\n", bytesRead, usb_strerror()); } return bytesRead; } int usbRxToFile(char *fileName) { FILE *pFile; int bytesRead = usb_bulk_read(dev, EP_IN, img, IMG_BUF_SIZE, TIME_OUT); int bytesRemaining = -1, objectSize = 0; rx = (PTP_CONTAINER *) img; if (bytesRead > 0) { switch (rx->type) { case TYPE_DATA: objectSize = rx->length-12; pFile = fopen(fileName, "wb"); fwrite(rx->payload.data, 1, bytesRead-12, pFile); printf("> Transferring %d bytes... \n", objectSize); for (bytesRemaining = rx->length - bytesRead; bytesRemaining > 0; bytesRemaining -= bytesRead) { do bytesRead = usb_bulk_read(dev, EP_IN, img, IMG_BUF_SIZE, TIME_OUT); while (bytesRead < 0); fwrite(img, 1, bytesRead, pFile); } fclose (pFile); printf("> %s saved to disk. \n", fileName); break; case TYPE_RESPONSE: if (rx->code != CMD_OK) printf("Ack = %02X.\n", rx->code); break; default: printf("Unhandled data package (usbRxToFile): 0x%04X 0x%04X\n", rx->type, rx->code); char *pTx = rx->payload.data; int i; for (i=0; ilength-12; i++) printf("%02X-", 0xFF & *(pTx + i)); printf("\n"); break; } } return bytesRemaining; } int usbRxEvent(){ int bytesRead = usb_interrupt_read(dev, EP_INT, tmp, 24, TIME_OUT/5); rx = (PTP_CONTAINER *) tmp; if (bytesRead > 0) { /* printf("usbRxEvent: 0x%04X 0x%04X\n", rx->code, rx->type); char *pTx = rx->payload.data; for (i=0; ilength-12; i++) printf("%02X-", 0xFF & *(pTx + i)); printf("\n"); */ if (rx->type == TYPE_EVENT) { switch (rx->code) { case EVT_FOCUS_CHANGED: focusSetting = rx->payload.dword_params.param1; break; case EVT_FOCUS_OK: case EVT_DEVICE_INFO_CHANGED: break; case EVT_ZOOM_CHANGED: zoomSetting = rx->payload.dword_params.param1; break; default: printf("Unhandled event code: 0x%04x\n", rx->code); } } else printf("Not an event message!\n"); } else if (bytesRead != -116 && bytesRead != -110) printf(" Error: interrupt read failed: %s!, %i\n", usb_strerror(),bytesRead ); return bytesRead; } void usbGetStatus() { char statusBytes[2]; if (usb_control_msg(dev, 0x82, 0x00, 0x00, 0x81, statusBytes, 0x2, TIME_OUT) < 0) printf("error: cmd write 1 failed\n"); if (usb_control_msg(dev, 0x82, 0x00, 0x00, 0x2, statusBytes, 0x2, TIME_OUT) < 0) printf("error: cmd write 2 failed\n"); } WORD getStringDataSet(STRING_DATA_SET **dst, char *src) { WORD byteSize; STRING_DATA_SET *sds = (STRING_DATA_SET *) src; byteSize = (sds->noItems) * sizeof(WORD) + 1; *dst = malloc(byteSize); memcpy(*dst, sds, byteSize); return byteSize; } DWORD getWordDataSet(WORD_DATA_SET **dst, char *src) { DWORD byteSize; WORD_DATA_SET *wds = (WORD_DATA_SET *) src; byteSize = (wds->noItems + 2) * sizeof(WORD); *dst = malloc(byteSize); memcpy(*dst, wds, byteSize); return byteSize; } DWORD getDwordDataSet(DWORD_DATA_SET **dst, char *src) { DWORD byteSize; DWORD_DATA_SET *wds = (DWORD_DATA_SET *) src; byteSize = (wds->noItems + 1) * sizeof(DWORD); *dst = malloc(byteSize); memcpy(*dst, wds, byteSize); return byteSize; } void setDeviceInfo(char *pData) { // Free up old data sets. free(deviceInfo.vendorExtensionDesc); free(deviceInfo.operationsSupported); free(deviceInfo.eventsSupported); free(deviceInfo.devicePropertiesSupported); free(deviceInfo.captureFormats); free(deviceInfo.imageFormats); free(deviceInfo.manufacturer); free(deviceInfo.model); free(deviceInfo.deviceVersion); free(deviceInfo.serialNumber); // Retrieve new device info from packet. deviceInfo.standardVersion = GET_WORD (pData); pData += sizeof(WORD); deviceInfo.vendorExtensionID = GET_DWORD(pData); pData += sizeof(DWORD); deviceInfo.vendorExtensionVersion = GET_WORD (pData); pData += sizeof(WORD); pData += getStringDataSet(&deviceInfo.vendorExtensionDesc, pData); deviceInfo.functionalMode = GET_WORD (pData); pData += sizeof(WORD); pData += getWordDataSet(&deviceInfo.operationsSupported, pData); pData += getWordDataSet(&deviceInfo.eventsSupported, pData); pData += getWordDataSet(&deviceInfo.devicePropertiesSupported, pData); pData += getWordDataSet(&deviceInfo.captureFormats, pData); pData += getWordDataSet(&deviceInfo.imageFormats, pData); pData += getStringDataSet(&deviceInfo.manufacturer, pData); pData += getStringDataSet(&deviceInfo.model, pData); pData += getStringDataSet(&deviceInfo.deviceVersion, pData); pData += getStringDataSet(&deviceInfo.serialNumber, pData); } void printStringDataSet(char *pDescrition, STRING_DATA_SET *pDataSet) { int i; printf("%s", pDescrition); for (i=0; inoItems; i++) printf("%c", pDataSet->data[i]); printf("\n"); } void printWordDataSet(char *pDescrition, WORD_DATA_SET *pDataSet) { int i; printf("%s", pDescrition); for (i=0; inoItems; i++) printf("0x%04X, ", pDataSet->data[i]); printf("\n"); } void printDwordDataSet(char *pDescrition, DWORD_DATA_SET *pDataSet) { int i; printf("%s", pDescrition); for (i=0; inoItems; i++) printf("0x%08X, ", pDataSet->data[i]); printf("\n"); } void printDeviceInfo() { printStringDataSet("Manufacturer : ", deviceInfo.manufacturer); printStringDataSet("Model : ", deviceInfo.model); printStringDataSet("DeviceVersion : ", deviceInfo.deviceVersion); printStringDataSet("SerialNumber : ", deviceInfo.serialNumber); printf("ExtensionID : 0x%08X\n", deviceInfo.vendorExtensionID); printStringDataSet("Description : ", deviceInfo.vendorExtensionDesc); printf("Version : 0x%04X\n", deviceInfo.vendorExtensionVersion); printWordDataSet("Properties : ", deviceInfo.devicePropertiesSupported); printWordDataSet("CaptureFormats: ", deviceInfo.captureFormats); printWordDataSet("ImageFormats : ", deviceInfo.imageFormats); } void printEnumDataSet(char *pDescrition, ENUM_FORM *pDataSet, WORD dataType) { int i; printf("%s", pDescrition); switch (dataType) { case DATA_TYPE_CHAR: for (i=0; inumberOfValues; i++) printf("0x%02X, ", *(char *)pDataSet->supportedValue[i]); break; case DATA_TYPE_WORD: for (i=0; inumberOfValues; i++) printf("0x%04X, ", *(WORD *)pDataSet->supportedValue[i]); break; case DATA_TYPE_DWORD: for (i=0; inumberOfValues; i++) printf("0x%08X, ", *(DWORD *)pDataSet->supportedValue[i]); break; case DATA_TYPE_STRING: for (i=0; inumberOfValues; i++) { printStringDataSet("", (STRING_DATA_SET *)pDataSet->supportedValue[i]); } break; } printf("\n"); } void setDeviceProperty(char *pData) { int i; // Free up old data sets. free(deviceProperty.defaultValue); free(deviceProperty.currentValue); switch (deviceProperty.formFlag) { case PROPERTY_FORM_RANGE: free(deviceProperty.form.rangeForm.maximumValue); free(deviceProperty.form.rangeForm.minimumValue); free(deviceProperty.form.rangeForm.stepSize); break; case PROPERTY_FORM_ENUM: for (i=0; i 4) { // Calculate package size; packetSize = 12 + 4*(int)(nCmdParameters / 4); //printf("PacketSize=%d\n", packetSize); // Assuming big endianess here! pCmdBuffer = cmdBuffer; pCmdBuffer += 0; SET_DWORD(pCmdBuffer, packetSize); // Number of bytes in USB packet. pCmdBuffer += 4; SET_WORD (pCmdBuffer, cmdIndex); // Command index. pCmdBuffer += 2; SET_WORD (pCmdBuffer, cmd); // Command. pCmdBuffer += 2; SET_DWORD(pCmdBuffer, USB_CMD_ID); // Command number. pCmdBuffer += 4; pCmdParameters = cmdParameters; for (i=12; inext) { for(dev = bus->devices; dev; dev = dev->next) { if(dev->descriptor.idVendor == MY_VID && dev->descriptor.idProduct == MY_PID) { printf("hledani USB %i %i", i, device_num); if( i == device_num ) return usb_open(dev); else i++; } } } return NULL; }