/* 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 */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #include #if defined(HAVE_UNISTD_H) #include #endif #if defined(HAVE_FCNTL_H) #include #endif #include #include /*-------------------------------------------------------------------------- Local include files */ #include "misc.h" #include "nss.h" #include "cameraP.h" /* Start editing here: */ static int read_beacon(int, ODSBeacon *, unsigned long); static void swap_beacon(ODSBeacon *); static int check_beacon(ODSBeacon *); static int write_beacon_ack(int, ODSBeaconAck *); static void swap_beacon_ack(ODSBeaconAck *); static void prepare_beacon_ack(ODSBeaconAck *); static int read_beacon_comp(int, ODSBeaconComp *, unsigned long); static void swap_beacon_comp(ODSBeaconComp *); #if defined(DEBUG) static void dump_beacon(ODSBeacon *); static void dump_beacon_ack(ODSBeaconAck *); static void dump_beacon_comp(ODSBeaconComp *); #endif int nss_open(ODSCamera camera, const char *device, unsigned long req_speed) { ODSBeacon beacon; ODSBeaconAck beacon_ack; ODSBeaconComp beacon_comp; speed_t speed; struct termios tty; #if defined(__BEOS__) /* BeOS uses a blocking mode because its select doesn't work on serial ports. (It turns out that blocking mode doesn't matter on BeOS -- see the notes in misc.c. --jct)*/ camera->fd = open(device, O_RDWR); #else camera->fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); #endif /* Keep the data speed at least 9600, because the camera doesn't communicate well at slower speeds. We have to be able to support at least 9600 anyway, to complete the beacon phase, so it should be safe. */ if (req_speed < 9600) { req_speed = 9600; } /* Open the port */ if (camera->fd < 0) { camera->error = kODSUnixError; return -1; } #if defined(DEBUG) printf("serial port opened\n"); #endif camera->mode = ods_presend; /* Make a copy of the tty settings to restore later. */ tcgetattr(camera->fd, &(camera->tty_original)); /* Put it in raw mode */ memset(&tty, 0, sizeof(tty)); cfmakeraw(&tty); /* A respondent reports that his camera won't begin talking until he sends it a break. Doesn't seem to hurt, so here goes... */ /* Update by vh. Actually this *hurts* some. According to the users' reports ks hasn't worked at first launch, but after the second it does. The break confuses the beacon phase , and I've even experienced it myself on FreeBSD. Example: a5 5a 00 c8 00 02 c9 -- valid beacon signal 00 a5 5a 00 c8 00 02 -- invalid beacon signal Removing tcsendbreak() fixed this. Since tcsendbreak() _helps_ some users it should be left as it's. For now I added a simple check for a bad intro, and restarting the OpenNSS() call. */ tcsendbreak(camera->fd, 4); /* ----- Zeroth phase: toggle the DTR by setting the rate to zero (turning off the port) then setting the rate back to 9600. This will initiate beacon phase from the camera. */ /* off... */ cfsetospeed(&tty, B0); cfsetispeed(&tty, B0); if (tcsetattr(camera->fd, TCSANOW, &tty) == -1) { #if defined(DEBUG) printf("Unable to set port attributes (1).\n"); #endif camera->error = kODSIOError; return -1; } /* ...wait... */ usleep(100000); /* Make sure the input buffer is empty. */ tcflush(camera->fd, TCIOFLUSH); /* ...on. */ cfsetospeed(&tty, B9600); cfsetispeed(&tty, B9600); if (tcsetattr(camera->fd, TCSANOW, &tty) == -1) { #if defined(DEBUG) printf("Unable to set port attributes (2).\n"); #endif camera->error = kODSIOError; return -1; } /* ----- First phase: read the beacon from the camera */ usleep(2000); #if defined(DEBUG) printf("----- \n"); #endif if (!read_beacon(camera->fd, &beacon, camera->timeout)) { close(camera->fd); camera->fd = -1; camera->mode = ods_closed; #if defined(DEBUG) printf("Error reading beacon.\n"); #endif camera->error = kODSIOError; return -1; } swap_beacon(&beacon); #if defined(DEBUG) dump_beacon(&beacon); #endif if (!check_beacon(&beacon) && beacon.intro != 0xa5) { close(camera->fd); camera->fd = -1; camera->mode = ods_closed; camera->error = kODSIOError; return -1; } if (beacon.intro == 0xa5) { tcflush(camera->fd, TCIFLUSH); /* discard invalid bytes in intro (flush received data, but not yet read */ #if defined(DEBUG) printf("discarded irrelevant bytes.\n"); #endif } #if defined(DEBUG) printf("\n----- \n"); #endif /* ----- Second phase: send the beacon acknowledgment to the camera */ beacon_ack.intro = 0x5aa5; beacon_ack.interface_type = 0x55; beacon_ack.cf_reserved = 0; beacon_ack.cf_pod_receive_mode = 0; beacon_ack.cf_host_receive_mode = 0; beacon_ack.data_speed = req_speed; beacon_ack.device_frame_size = 1023; beacon_ack.host_frame_size = 1023; swap_beacon_ack(&beacon_ack); prepare_beacon_ack(&beacon_ack); if (!write_beacon_ack(camera->fd, &beacon_ack)) { close(camera->fd); camera->fd = -1; camera->mode = ods_closed; camera->error = kODSIOError; return -1; } #if defined(DEBUG) swap_beacon_ack(&beacon_ack); dump_beacon_ack(&beacon_ack); #endif #if defined(DEBUG) printf("\n----- \n"); #endif /* ----- Third phase: read the beacon completion from the camera */ if (!read_beacon_comp(camera->fd, &beacon_comp, camera->timeout)) { close(camera->fd); camera->fd = -1; camera->mode = ods_closed; camera->error = kODSIOError; return -1; } swap_beacon_comp(&beacon_comp); /* Pick up the rate and buffer sizes from the completion message. */ camera->data_speed = beacon_comp.data_speed; camera->host_size = beacon_comp.host_frame_size; camera->device_size = beacon_comp.device_frame_size; #if defined(DEBUG) dump_beacon_comp(&beacon_comp); #endif if (beacon_comp.result != 0) { close(camera->fd); camera->fd = -1; camera->mode = ods_closed; camera->error = kODSParamError; return -1; } /* Pause T1 ms */ usleep(100000); /* Change baud rate here */ if (camera->data_speed >= 115200) { speed = B115200; } else if (camera->data_speed >= 57600) { speed = B57600; } else if (camera->data_speed >= 38400) { speed = B38400; } else if (camera->data_speed >= 19200) { speed = B19200; } else { speed = B9600; } cfsetospeed(&tty, speed); cfsetispeed(&tty, speed); tcsetattr(camera->fd, TCSANOW, &tty); /* Pause T1 ms */ usleep(100000); return 0; } int nss_close(ODSCamera camera) { /* Restore its TTY settings */ tcsetattr(camera->fd, TCSANOW, &(camera->tty_original)); /* Close the port and mark it as closed. */ close(camera->fd); camera->fd = -1; return 0; } static int read_beacon(int fd, ODSBeacon * beacon, unsigned long timeout) { int c = read_fully(fd, beacon, sizeof_beacon, timeout); if (c < 0) { fprintf(stderr, "unexpected read failure in read_beacon(), exiting...\n"); exit(1); } return c == sizeof_beacon; } static int check_beacon(ODSBeacon * beacon) { return verify_checksum(beacon, sizeof_beacon); } static void swap_beacon(ODSBeacon * beacon) { swap_short(beacon->intro); swap_short(beacon->vendor_id); swap_short(beacon->device_id); } #if defined(DEBUG) static void dump_beacon(ODSBeacon *beacon) { printf("Beacon: intro = 0x%04hx, vendor = 0x%04hx, device = 0x%04hx\n", beacon->intro, beacon->vendor_id, beacon->device_id); } #endif static int write_beacon_ack(int fd, ODSBeaconAck * beacon_ack) { int c = write_fully(fd, beacon_ack, sizeof_beacon_ack); return c == sizeof_beacon_ack; } static void swap_beacon_ack(ODSBeaconAck * beacon_ack) { swap_short(beacon_ack->intro); swap_long(beacon_ack->data_speed); swap_short(beacon_ack->device_frame_size); swap_short(beacon_ack->host_frame_size); } static void prepare_beacon_ack(ODSBeaconAck * beacon_ack) { set_checksum(beacon_ack, sizeof_beacon_ack); } #if defined(DEBUG) static void dump_beacon_ack(ODSBeaconAck * beacon_ack) { printf("Beacon Ack: intro = %04hx, interface type = %02x\n", beacon_ack->intro, (int) (beacon_ack->interface_type)); printf(" pod receive mode = %d, host receive mode = %d\n", beacon_ack->cf_pod_receive_mode, beacon_ack->cf_host_receive_mode); printf(" data speed = %ld, device frame size = %d, host frame size = %d\n", beacon_ack->data_speed, beacon_ack->device_frame_size, beacon_ack->host_frame_size); } #endif static int read_beacon_comp(int fd, ODSBeaconComp *beacon_comp, unsigned long timeout) { int c = read_fully(fd, beacon_comp, sizeof_beacon_comp, timeout); if (c < 0) { fprintf(stderr, "unexpected read failure in read_beacon_comp(), exiting...\n"); exit(1); } return c == sizeof_beacon_comp; } static void swap_beacon_comp(ODSBeaconComp * beacon_comp) { swap_long(beacon_comp->data_speed); swap_short(beacon_comp->device_frame_size); swap_short(beacon_comp->host_frame_size); } #if defined(DEBUG) static void dump_beacon_comp(ODSBeaconComp * beacon_comp) { printf("Beacon Comp: result = %d\n", beacon_comp->result); printf(" data speed = %ld, device frame size = %d, host frame size = %d\n", beacon_comp->data_speed, beacon_comp->device_frame_size, beacon_comp->host_frame_size); } #endif static int poll_and_reply(ODSCamera camera, const ODSPoll *poll, ODSPollAck *poll_ack, int nak) { unsigned short s; #if defined(DEBUG) printf("poll_and_reply: reading 2 bytes.\n"); #endif if ((read_fully(camera->fd, &s, sizeof(s), camera->timeout) < 0) && nak) { poll_ack->unused = 0; poll_ack->ack = 0; poll_ack->nak = 1; /* reject */ s = *((unsigned short *) poll_ack); swap_short(s); write_fully(camera->fd, &s, sizeof(s)); return 0; } swap_short(s); *((unsigned short *) poll) = s; poll_ack->unused = 0; poll_ack->ack = 1; /* accept */ poll_ack->nak = 0; s = *((unsigned short *) poll_ack); swap_short(s); write_fully(camera->fd, &s, sizeof(s)); return 1; } int nss_receive_packet(ODSCamera camera) { ODSPoll poll; ODSPollAck poll_ack; char *buffer = camera->buffer; unsigned long read_here; if (!poll_and_reply(camera, &poll, &poll_ack, !0)) { /* An error has occurred in polling the camera. What we do next depends on the setting of the error flag in the camera structure. */ if (camera->exit_on_error) { fprintf(stderr, "nss_receive_message: initial poll failure, exiting...\n"); abort(); } usleep(200000); #if defined(DEBUG) printf("nss_receive_message: returning -1\n"); #endif return -1; } ensure_buffer_size(camera, poll.length); #if defined(DEBUG) printf("nss_receive_message: initial poll length = %d\n", poll.length); #endif read_here = read_fully(camera->fd, buffer + camera->bufbytes, poll.length, camera->timeout); if (read_here != poll.length) { #if defined(DEBUG) printf("nss_receive_message: couldn't read initial packet.\n"); #endif /* return -1; */ } camera->bufbytes += read_here; return 0; } int nss_receive_message(ODSCamera camera) { ODSPollAck poll_ack; unsigned long message_len; #if defined(DEBUG) printf("nss_receive_message: entering\n"); #endif if (nss_receive_packet(camera) != 0) { return -1; } /* Copy the overall message length. */ memcpy(&message_len, camera->buffer, sizeof(message_len)); swap_long(message_len); message_len += 4; #if defined(DEBUG) printf("nss_receive_message: size = %ld, already read = %ld\n", message_len, camera->bufbytes); #endif /* Make sure we have enough room to read the entire message. */ ensure_buffer_size(camera, message_len); /* Loop and read the remainder of the message. */ while (camera->bufbytes < message_len) { if (nss_receive_packet(camera) != 0) { return -1; } } read_fully(camera->fd, &poll_ack, 2, camera->timeout); #if defined(DEBUG) printf("nss_receive_message: returning normally\n"); #endif return 0; } static void poll_and_wait(ODSCamera camera, const ODSPoll * poll, ODSPollAck * poll_ack) { unsigned short s = *((unsigned short *) poll); s = swap_short(s); #if defined(DEBUG) printf("poll_and_wait: sending poll\n"); #endif write_fully(camera->fd, &s, sizeof(s)); #if defined(DEBUG) printf("poll_and_wait: reading poll response\n"); #endif if (read_fully(camera->fd, &s, sizeof(s), camera->timeout) < 0) { fprintf(stderr, "poll_and_wait: unexpected read failure, exiting...\n"); exit(1); } s = swap_short(s); *((unsigned short *) poll_ack) = s; } int send_nss_packet(ODSCamera camera, int is_command) { ODSPoll poll; ODSPollAck poll_ack; char * buffer = (char *) camera->buffer + camera->bufused; int bob_flag = (camera->bufused == 0) ? 1 : 0; unsigned long wrote_here; unsigned long to_write; unsigned long remaining; /* Compute first packet size. */ remaining = camera->bufbytes - camera->bufused; to_write = (remaining < camera->device_size) ? remaining : camera->device_size; camera->bufused += to_write; /* Send the first packet. */ poll.poll = 1; poll.cmd_flag = is_command; /* Command */ poll.bob_flag = bob_flag; /* Beginning of buffer? */ poll.eob_flag = /* End of buffer? */ (camera->bufused == camera->bufbytes) ? 1 : 0; poll.length = to_write; poll_and_wait(camera, &poll, &poll_ack); if (poll_ack.nak != 0) { fprintf(stderr, "flush_bytes_send: *** poll NAK.\n"); return 1; } wrote_here = write_fully(camera->fd, buffer, to_write); if (wrote_here != to_write) { #if defined(DEBUG) printf("nss_send_message: couldn't write packet.\n"); #endif return -1; } return 0; } int nss_send_message(ODSCamera camera) { ODSPoll poll; if (send_nss_packet(camera, !0) != 0) { return -1; } while (camera->bufused < camera->bufbytes) { if (send_nss_packet(camera, 0) != 0) { return -1; } } poll.poll = 0; poll.cmd_flag = 0; poll.bob_flag = 0; poll.eob_flag = 0; poll.length = 0; write_fully(camera->fd, &poll, 2); return 0; }