/* Open Digita Services -- Camera Device Protocol definitions. Copyright (C) 1998, 1999 James C. Thompson Copyright (C) 1998, 1999 Viljo Hakala This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*-------------------------------------------------------------------------- System include files */ #include #if defined(HAVE_CONFIG_H) #include "config.h" #endif #include #if defined(HAVE_FCNTL_H) #include #endif #if defined(HAVE_UNISTD_H) #include #endif #include #include #include #include #include #include #include /*-------------------------------------------------------------------------- Local include files */ #include "ods.h" #include "cameraP.h" /* Start Editing Here: */ typedef struct cmd_format { char * cmd; char * desc; void (*func)(ODSCamera camera); } cmd_format; extern void dump_ptvs(PNameTypeValueStruct *); void tolowers(char *s) { for (; *s; s++) { if (isalpha(*s)) { *s = tolower(*s); } } } unsigned int str2uint(const char *str) { return ((((unsigned int) *str) << 24) | (((unsigned int) *(str + 1)) << 16) | (((unsigned int) *(str + 2)) << 8) | (((unsigned int) *(str + 3)))); } #define Y2K 946677600 /* Sun Jan 1 00:00:00 2000 */ void set_file_utimes(ODSCamera camera, ResFileItem * file) { time_t caltime; struct utimbuf timbuf; UInteger reslength; PNameTypeValueStruct values[100]; unsigned long ptvsdate; unsigned long ptvstime; struct tm vtime; DOSName localfile; unsigned int date_tag = str2uint("date"); unsigned int time_tag = str2uint("time"); memcpy(&localfile, &(file->DOSName), sizeof(DOSName)); tolowers(localfile); odsGetFileTag(camera, (const FileNameStruct *) file, date_tag, &reslength, values, 1); ptvsdate = values[0].Value.UInt; odsGetFileTag(camera, (const FileNameStruct *) file, time_tag, &reslength, values, 1); ptvstime = values[0].Value.UInt; vtime.tm_year = ((ptvsdate >> 4) & 0x0f) * 10 + (ptvsdate & 0x0f); vtime.tm_mon = ((ptvsdate >> 20) & 0x0f) * 10 + ((ptvsdate >> 16) & 0x0f) - 1; vtime.tm_mday = ((ptvsdate >> 12) & 0x0f) * 10 + ((ptvsdate >> 8) & 0x0f) - 1; vtime.tm_hour = ((ptvstime >> 20) & 0x0f) * 10 + ((ptvstime >> 16) & 0x0f); vtime.tm_min = ((ptvstime >> 12) & 0x0f) * 10 + ((ptvstime >> 8) & 0x0f); vtime.tm_sec = ((ptvstime >> 4) & 0x0f) * 10 + (ptvstime & 0x0f); if ( (time((time_t *)NULL)) >= Y2K ) { vtime.tm_year +=100; vtime.tm_mday +=1; } caltime = mktime(&vtime); timbuf.actime = caltime; timbuf.modtime = caltime; utime(localfile, &timbuf); } #define DL_QUANTA 20000 ODSResult get_file_data(ODSCamera camera, ResFileItem *file) { PartialTag tag = {0, 0, 0}; char buffer[DL_QUANTA]; int fd; struct stat st; unsigned int starting_offset = 0; unsigned int target_length = DL_QUANTA; unsigned int length = 0; unsigned int request_length = DL_QUANTA; DOSName localfile; memcpy(&localfile, &(file->DOSName), sizeof(DOSName)); tolowers(localfile); if (file->FileLength < 0) { if (camera->verbosity > 0) { printf("%s: still processing, skipping.\n", localfile); } return kODSNoErr; } /* If the file exists, and has the same length, assume it's already been downloaded, and skip it. This check could stand to be more thorough: access permission, type, etc. */ if (stat(localfile, &st) == 0) { if (st.st_size == file->FileLength) { if (camera->verbosity > 1) { printf("%s: already downloaded, skipping.\n", localfile); } return kODSNoErr; } else { starting_offset = st.st_size; if (camera->verbosity > 1) { printf("%s: continuing from offset %d.\n", localfile, starting_offset); } } } if (camera->verbosity > 1) { printf("%s: size = %ld, flags = %08lx\n", localfile, file->FileLength, file->FileStatus); } else if (camera->verbosity > 0) { printf("%s: size = %ld ", localfile, file->FileLength); fflush(stdout); } fd = open(localfile, O_RDWR | O_CREAT | O_APPEND, 0666); tag.Offset = starting_offset; tag.Length = request_length; while (length < target_length) { ODSResult rc; rc = odsGetFileData(camera, (FileNameStruct *) file, 0, &tag, buffer, 0, 0, 0, 0); while (rc != kODSNoErr) { if (camera->verbosity > 1) { printf("%s: error in download, retrying\n", localfile); } else if (camera->verbosity > 0) { printf("x"); } fflush(stdout); usleep(20000); rc = odsGetFileData(camera, (FileNameStruct *) file, 0, &tag, buffer, 0, 0, 0, 0); } if (tag.Length < request_length) { request_length = tag.Length; } write(fd, buffer, request_length); length += request_length; tag.Offset += request_length; if (camera->verbosity > 1) { printf("%s: %ld bytes of %ld.\n", localfile, tag.Offset, tag.Filesize); } else if (camera->verbosity > 0) { printf("."); fflush(stdout); } request_length = tag.Length; target_length = tag.Filesize - starting_offset; } close(fd); if (camera->verbosity == 1) { printf("\n"); } /* Now that the file has been downloaded, set the access and mod times in it to match the date and time the photo was taken. */ set_file_utimes(camera, file); return kODSNoErr; } void thumb2rgb(int n, unsigned char *thumb, unsigned char *rgb) { int i; for (i = 0; i < n; i++) { double r; double g; double b; int ri; int gi; int bi; double y; double cb; double cr; /* Pull the YCbCr components out of the thumbnail data. */ cb = (double) thumb[0]; y = (double) thumb[1]; cr = (double) thumb[2]; /* Convert to RGB */ r = y + (1.4020 * (cr - 128)); g = y - (0.34414 * (cb - 128)) - (0.71414 * (cr - 128)); b = y + (1.77200 * (cb - 128)); /* Sometimes (maybe because my constants are off a bit) the above conversion will come up with a color component outside the valid 0 -> 255 range. Limit these values to valid values. */ ri = (int) abs(r); gi = (int) abs(g); bi = (int) abs(b); if (ri > 255) ri = 255; if (bi > 255) bi = 255; if (gi > 255) gi = 255; /* Save the converted values in the RGB buffer. */ *rgb++ = ri; *rgb++ = gi; *rgb++ = bi; /* Point to the next YCbCr triple. Note that there's an unused byte (gray value?) stored with each triple, so we skip ahead by four bytes. */ thumb += 4; } } void convert_thumb(const char *localfile, UInteger width, UInteger height, unsigned char *buffer) { int wh = (width * height) / 2; int i; FILE *f; int bufsize = wh * 3; unsigned char *rgb; unsigned char *s; /* Arbitrarily limit the size of the RGB buffer. This leaves room for larger thumbnails in the future, but limits memory problems due to runaway miscalculations. */ if (bufsize > 1024*1024) { printf(" thumbnail too large"); return; } rgb = malloc(bufsize); thumb2rgb(wh, buffer, rgb); if ((f = fopen(localfile, "w")) == 0) { fprintf(stderr, " could not open thumb file for output"); } fprintf(f, "P3\n%ld %ld\n255\n", height, width); for (i = 0, s = rgb; i < wh; i++) { /* Write the RGB values to the PPM file. Each RGB triple represents two pixels. */ unsigned int r = (unsigned int) *s++; unsigned int g = (unsigned int) *s++; unsigned int b = (unsigned int) *s++; fprintf(f, "%d %d %d\n", r, g, b); fprintf(f, "%d %d %d\n", r, g, b); } free(rgb); fclose(f); } ODSResult get_thumb_data(ODSCamera camera, ResFileItem *file) { PartialTag tag = {0, 0, 0}; unsigned char buffer[DL_QUANTA]; char * s; UInteger length; UInteger width; UInteger height; unsigned int request_length = DL_QUANTA; DOSName localfile; ODSResult rc; memcpy(&localfile, &(file->DOSName), sizeof(DOSName)); tolowers(localfile); /* permute the name from .jpg into .ppm */ if (((s = strstr(localfile, ".jpg")) != 0) || ((s = strstr(localfile, ".tif")) != 0)) { strncpy(s, ".ppm", 4); } if (file->FileLength < 0) { if (camera->verbosity > 0) { printf("%s: still processing, skipping.\n", localfile); } return kODSNoErr; } if (camera->verbosity > 0) { printf("%s: ", localfile); fflush(stdout); } tag.Offset = 0; tag.Length = request_length; rc = odsGetFileData(camera, (FileNameStruct *) file, !0, &tag, buffer, &length, &width, &height, 0); while (rc != kODSNoErr) { if (camera->verbosity > 1) { printf("%s: error in download, retrying\n", localfile); } else if (camera->verbosity > 0) { printf("x"); } fflush(stdout); usleep(20000); rc = odsGetFileData(camera, (FileNameStruct *) file, !0, &tag, buffer, &length, &width, &height, 0); } /* convert here */ if (tag.Length == length) { convert_thumb(localfile, width, height, buffer); } if (camera->verbosity > 0) { printf(".\n"); fflush(stdout); } /* Now that the file has been downloaded, set the access and mod times in it to match the date and time the photo was taken. */ set_file_utimes(camera, file); return kODSNoErr; } void get_file_tag(ODSCamera camera, ResFileItem * file) { unsigned int i; UInteger reslength; PNameTypeValueStruct values[100]; printf("**************** %s\n", file->DOSName); odsGetFileTag(camera, (const FileNameStruct *) file, 0, &reslength, values, 100); for (i = 0; i < reslength; i++) { dump_ptvs(values + i); } printf("\n"); } void get_camera_time(ODSCamera camera) { static ClockDateTime clock; unsigned int month; unsigned int day; unsigned int yearmod; unsigned int year; unsigned int hour; unsigned int minute; unsigned int second; odsGetClock(camera, &clock); month = (unsigned int) (clock.ClockDate >> 16); day = (unsigned int) (clock.ClockDate >> 8 & 0xff); yearmod = (unsigned int) (clock.ClockDate & 0xff); year = (yearmod > 0x90) ? yearmod + 0x1900 : yearmod + 0x2000; hour = (unsigned int) (clock.ClockTime >> 16); minute = (unsigned int) (clock.ClockTime >> 8 & 0xff); second = (unsigned int) (clock.ClockTime & 0xff); printf("ClockDate = %08lx\n", clock.ClockDate); printf("ClockTime = %08lx\n", clock.ClockTime); printf("Camera's date: %02x/%02x/%04x time: %02x:%02x:%02x\n", month, day, year, hour, minute, second); } void set_camera_time(ODSCamera camera) { time_t timenow; struct tm *timest; static char asctime[10]; static ClockDateTime clock; unsigned int month; unsigned int day; unsigned int yearmod; unsigned int year; unsigned int hour; unsigned int minute; unsigned int second; if ((timenow=time(NULL)) == -1) { perror("time(): "); } timest = localtime(&timenow); snprintf(asctime,sizeof(asctime), "%02d%02d%02d", timest->tm_mon + 1, timest->tm_mday, timest->tm_year % 100); clock.ClockDate=(unsigned int) strtol(asctime, (char **) NULL, 16); printf("ClockDate = %08lx\n", clock.ClockDate); snprintf(asctime,sizeof(asctime), "%02d%02d%02d", timest->tm_hour, timest->tm_min, timest->tm_sec); clock.ClockTime=(unsigned int) strtol(asctime, (char **) NULL, 16); printf("ClockTime = %08lx\n", clock.ClockTime); odsSetClock(camera, &clock); month = (unsigned int) (clock.ClockDate >> 16); day = (unsigned int) (clock.ClockDate >> 8 & 0xff); yearmod = (unsigned int) (clock.ClockDate & 0xff); year = (yearmod > 0x90) ? yearmod + 0x1900 : yearmod + 0x2000; hour = (unsigned int) (clock.ClockTime >> 16); minute = (unsigned int) (clock.ClockTime >> 8 & 0xff); second = (unsigned int) (clock.ClockTime & 0xff); printf("Set camera's date/time: %02x/%02x/%04x time: %02x:%02x:%02x\n", month, day, year, hour, minute, second); } void get_storage_status(ODSCamera camera) { UInteger taken; UInteger avail; SInteger raw; odsGetStorageStatus(camera, &taken, &avail, &raw); printf("Taken %d pics, space for %d pics, rawcount %d\n", (int) taken, (int) avail, (int) raw); } void del_all_files(ODSCamera camera) { unsigned int i; UInteger reslength; ResFileItem files[1000]; /* BAD: hardcoded number! */ odsGetFileList(camera, 1, 0, &reslength, files, 1000); if (reslength <= 0) { printf("No files to delete\n"); exit(0); } printf("Deleting %d file%s in the camera\n", (int) reslength, reslength > 1 ? "s" : ""); for (i = 0; i < reslength; ++i) { odsEraseFile(camera, (FileNameStruct *) & files[i]); } } void get_file_list(ODSCamera camera) { unsigned int i; UInteger reslength; ResFileItem files[1000]; odsGetFileList(camera, 1, 0, &reslength, files, 1000); printf("%ld file%s in camera...\n", reslength, (reslength == 1) ? "" : "s"); for (i = 0; i < reslength; i++) { get_file_data(camera, files + i); } } void get_thumb_list(ODSCamera camera) { unsigned int i; UInteger reslength; ResFileItem files[1000]; odsGetFileList(camera, 1, 0, &reslength, files, 1000); printf("%ld file%s in camera...\n", reslength, (reslength == 1) ? "" : "s"); for (i = 0; i < reslength; i++) { get_thumb_data(camera, files + i); } } void take_picture(ODSCamera camera) { PNameValueStruct *pnv; BitFlags vendorstatus, systemstatus, capturestatus; union { unsigned long name; char flag[5]; } conv; odsGetCameraStatus(camera, &systemstatus, &capturestatus, &vendorstatus); if (!(pnv = (PNameValueStruct *) malloc(sizeof(PNameValueStruct)))) { #if defined(HAVE_STRERROR) fprintf(stderr, "Couldn't malloc: %s\n", strerror(errno)); #else fprintf(stderr, "Couldn't malloc.\n"); #endif exit(EXIT_FAILURE); } sprintf(conv.flag, "mcap"); swap_long(conv.name); pnv->Name = conv.name; pnv->Data.UInt = 0; /* set mcap to 0: Still image */ odsSetCameraState(camera, pnv); odsStartCapture(camera); /* start the capture sequence */ free(pnv); } void getpowermode(ODSCamera camera) { UInteger powerstate; odsGetPowerMode(camera, &powerstate); if (powerstate) { printf("camera is on\n"); } else { printf("camera is off\n"); } } void power_off(ODSCamera camera) { odsSetPowerMode(camera); } cmd_format supported_cmds[] = { { "delall", "Delete all files in the camera", del_all_files }, { "download", "Download pictures", get_file_list }, { "thumbs", "Download thumbnails", get_thumb_list }, { "gettime", "Get camera's date/time", get_camera_time }, { "settime", "Set camera clock according to computer's clock", set_camera_time }, { "shoot", " Take a picture", take_picture }, { "status", "Show pictures taken, available and raw count", get_storage_status }, { "getpowermode", "Checks if camera is on", getpowermode }, { "poweroff", "Turn the camera off", power_off }, { NULL, NULL, NULL } }; void _ods_list_commands(void) { int i; printf("Currently following commands are supported:\n"); for (i = 0; supported_cmds[i].cmd != NULL; ++i) printf(" %s\t%s\n", supported_cmds[i].cmd, supported_cmds[i].desc); exit(0); } jmp_buf env; void execute_command(int argc, const char *argv[], ODSCamera camera) { int i; int i_found; int count; for (i = 1; i < argc; ++i) { int tries = 0; i_found = 0; for (count = 0; supported_cmds[count].cmd != NULL; ++count) { if (strncasecmp(argv[i], supported_cmds[count].cmd, strlen(supported_cmds[count].cmd)) == 0) { printf("Executing command: %s\n", supported_cmds[count].cmd); i_found++; while (tries < 3) { if (setjmp(env) == 0) { supported_cmds[count].func(camera); break; } else { tries++; odsResetCamera(camera); printf("*** Error in executing command, trying again...\n"); } } } } if (i_found == 0) { printf("*** warning: command \"%s\" not currently supported\n", argv[i] ); } } }