diff --git a/configure.ac b/configure.ac index 047b3f0..d130337 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AC_MSG_RESULT([$os_win32]) AM_CONDITIONAL([OS_WIN32], [test "$os_win32" = "yes"]) # Checks for USB support. -PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], [have_libusb=yes], [have_libusb=no]) +#PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], [have_libusb=yes], [have_libusb=no]) if test "$have_libusb" = "yes"; then AC_DEFINE([HAVE_LIBUSB], [1], [libusb support]) AC_SUBST([DEPENDENCIES], [libusb-1.0]) diff --git a/examples/Makefile.am b/examples/Makefile.am index d77db45..3037ff5 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,13 +1,16 @@ -AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include +AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src LDADD = $(top_builddir)/src/libdivecomputer.la bin_PROGRAMS = \ + simulator \ universal \ ostc-fwupdate COMMON = common.c common.h \ utils.c utils.h +simulator_SOURCES = simulation.c $(COMMON) + universal_SOURCES = universal.c $(COMMON) ostc_fwupdate_SOURCES = hw_ostc_fwupdate.c $(COMMON) diff --git a/examples/simulation.c b/examples/simulation.c new file mode 100644 index 0000000..e6126b9 --- /dev/null +++ b/examples/simulation.c @@ -0,0 +1,3922 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "checksum.h" +#include "array.h" +#include "utils.h" +#include "serial.h" +#include "irda.h" + +#define SUUNTO_EON_MEMORY_SIZE 0x900 +#define REEFNET_SENSUSULTRA_MEMORY_DATA_SIZE 2080768 + +#define MARES_NEMO_MEMORY_SIZE 0x4000 +#define MARES_NEMO_PACKET_SIZE 0x20 + +#define NAK 0xA8 +#define ACK 0x60 + +#define USEBREAK 1 + +#define MAXSIZE (2 * 1024 * 1024) + +#define DC_FAMILY_DIVESYSTEM_IDIVE (DC_FAMILY_CITIZEN_AQUALAND + 1) +#define DC_FAMILY_COCHRAN_COMMANDER (DC_FAMILY_CITIZEN_AQUALAND + 2) + +static int +error (double percentage) +{ + double random = rand () / (double) RAND_MAX; + + if (random <= percentage) + return 1; + else + return 0; +} + +static int +myrandom (int n) +{ + return rand() / (RAND_MAX / n + 1); +} +/* +static unsigned int +myerror (double percentage, unsigned int n) +{ + double pct = rand() / (double) RAND_MAX; + + if (pct> percentage) + return 0; + + return rand() / (RAND_MAX / n + 1); +} +*/ + +static void +debug (const unsigned char data[], unsigned int size) +{ + message ("size=%u, data=", size); + for (unsigned int i = 0; i < size; ++i) + message ("%02X ", data[i]); + message ("\n"); +} + +static unsigned int +advance (unsigned int position, int offset, int is_spyder) +{ + const unsigned int begin = (is_spyder ? 0x4C : 0x71), end = 0x2000; + + int current = position + offset; + if (current>= end) + return begin + (current - end); + if (current < begin) + return end - (begin - current); + + return current; +} + +static void +send_package (serial_t *device, const unsigned char data[], unsigned int offset, unsigned int len, unsigned char command, int is_spyder) +{ + unsigned char checksum = 0x00; + checksum = checksum_xor_uint8 ((unsigned char*)&command, 1, checksum); + checksum = checksum_xor_uint8 ((unsigned char*)&len, 1, checksum); + + serial_write (device, &command, 1); + serial_write (device, &len, 1); + + unsigned int current = offset; + for (unsigned int i = 0; i < len; ++i) { + serial_write (device, data + current, 1); + checksum = checksum_xor_uint8 (data + current, 1, checksum); + if (current <= (is_spyder ? 0x4C : 0x71)) + current = 0x2000; + current--; + } + serial_write (device, &checksum, 1); + + message ("package: begin=0x%04x, end=0x%04x, len=%i\n", offset, current, len); +} + +static unsigned int +send_next_dive (serial_t *device, const unsigned char data[], unsigned int offset, unsigned char command, int is_spyder) +{ + unsigned int previous = offset; + unsigned int current = offset; + for (unsigned int i = 0; ; ++i) { + if (data[current] == 0x82) { + send_package (device, data, previous, 0, command, is_spyder); + return previous; + } + unsigned int peek = advance (current, (is_spyder ? -2 : -4), is_spyder); + if (i> 0 && data[peek] == 0x80) { + unsigned int len = i % 32; + if (len) + send_package (device, data, previous, len, command, is_spyder); + return current; + } + + if (current <= (is_spyder ? 0x4C : 0x71)) + current = 0x2000; + current--; + + if ((i + 1) % 32 == 0) { + send_package (device, data, previous, 32, command, is_spyder); + previous = current; + } + } +} + + +static void +simulation_raw (serial_t *device, unsigned char data[], unsigned int size) +{ + //serial_write (device, data, size); + for (unsigned int i = 0; i < size; ++i) + serial_write (device, data + i, 1); +} + + +static void +simulation_nemo (serial_t *device, unsigned char data[], unsigned int size) +{ + unsigned char garbage = 0x11; + unsigned char header = 0xEE; + + for (unsigned int i = 0; i < 0x058c; ++i) + serial_write (device, &garbage, 1); + + for (unsigned int i = 0; i < 20; ++i) + serial_write (device, &header, 1); + + unsigned int nbytes = 0; + while (nbytes < MARES_NEMO_MEMORY_SIZE) { + unsigned char crc = checksum_add_uint8 (data + nbytes, MARES_NEMO_PACKET_SIZE, 0x00); + + for (unsigned int i = 0; i < 2; ++i) { + serial_write (device, data + nbytes, MARES_NEMO_PACKET_SIZE); + serial_write (device, &crc, 1); + #ifdef _WIN32 + serial_sleep (device, 10); /* Mares IRIS needs this. */ + #endif + } + + nbytes += MARES_NEMO_PACKET_SIZE; + } +} + + +static void +mares_puck_convert_binary_to_ascii (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize) +{ + assert (osize == 2 * isize); + + const unsigned char ascii[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + for (unsigned int i = 0; i < isize; ++i) { + // Set the most-significant nibble. + unsigned char msn = (input[i]>> 4) & 0x0F; + output[i * 2 + 0] = ascii[msn]; + + // Set the least-significant nibble. + unsigned char lsn = input[i] & 0x0F; + output[i * 2 + 1] = ascii[lsn]; + + unsigned char value = input[i]; + for (unsigned int j = 0; j < 2; ++j) { + unsigned int n = (1 - j) * 4; + unsigned char x = (value>> n) & 0x0F; + output[i * 2 + j] = ascii[x]; + } + } +} + +static void +mares_puck_convert_ascii_to_binary (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize) +{ + assert (isize == 2 * osize); + + for (unsigned int i = 0; i < osize; ++i) { + unsigned char value = 0; + for (unsigned int j = 0; j < 2; ++j) { + unsigned char number = 0; + unsigned char ascii = input[i * 2 + j]; + if (ascii>= '0' && ascii <= '9') + number = ascii - '0'; + else if (ascii>= 'A' && ascii <= 'F') + number = 10 + ascii - 'A'; + else if (ascii>= 'a' && ascii <= 'f') + number = 10 + ascii - 'a'; + else + message ("Invalid charachter."); + + value <<= 4; + value += number; + } + output[i] = value; + } +} + +#define DACOR + +static void +simulation_puck (serial_t *device, unsigned char data[], unsigned int size, int echo) +{ + const unsigned char header = '<', trailer = '>'; + unsigned char ascii[12] = {0}, raw[5] = {0}; +#ifdef DACOR + unsigned char packet[2 * 64 + 2] = {0}; +#else + unsigned char packet[2 * 32 + 2] = {0}; +#endif + unsigned char checksum; + + for (;;) { + serial_read (device, ascii, sizeof (ascii)); + mares_puck_convert_ascii_to_binary (ascii + 1, sizeof (ascii) - 2, raw, sizeof (raw)); + unsigned int command = raw[0]; + unsigned int address = raw[1] + (raw[2] << 8); + unsigned int length = raw[3]; + switch (command) { + case 0x51: + message ("read_memory(%04x,%i)\n", address, length); + #ifdef _WIN32 + serial_sleep (device, 10); /* Mares DRAK needs this. */ + #endif + if (echo) { + serial_write (device, ascii, sizeof (ascii)); /* Dacor needs an echo */ + } + serial_write (device, &header, 1); + mares_puck_convert_binary_to_ascii (data + address, length, packet, 2 * length); + checksum = checksum_add_uint8 (packet, 2 * length, 0x00); + mares_puck_convert_binary_to_ascii (&checksum, 1, packet + 2 * length, 2); + serial_write (device, packet, 2 * length + 2); + serial_write (device, &trailer, 1); + break; + default: + message ("Unknown command 0x%02x\n", command); + break; + } + } +} + +static void +simulation_iconhd (serial_t *device, unsigned char data[], unsigned int size, const unsigned char version[]) +{ + unsigned char command[8] = {0};//, checksum = 0; + unsigned int csize = 0;//, len = 0, address = 0; + //unsigned int offset = 0, ndives = 0; + + const unsigned char eof[] = {0xEA}; + const unsigned char ack[] = {0xAA}; + + unsigned int address = 0, length = 0; + + const unsigned char id[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x63, + 0x6F, 0x6E, 0x20, 0x48, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x2E, 0x31, 0x30, 0x2E, 0x31, 0x31, 0x00, 0x0A, + 0x0B, 0x00, 0x31, 0x31, 0x2D, 0x31, 0x32, 0x2D, 0x30, 0x39, 0x2D, 0x8E, + 0x49, 0x63, 0x6F, 0x6E, 0x20, 0x48, 0x44, 0x20, 0x28, 0x43, 0x29, 0x20, + 0x4D, 0x61, 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 140 bytes + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0xC2: // C2 67 + csize = 2; + serial_read (device, command + 1, csize - 1); + message ("%02X %02X\n", command[0], command[1]); + serial_write (device, ack, sizeof (ack)); + if (version) + serial_write (device, version, sizeof (id)); + else + serial_write (device, id, sizeof (id)); + serial_write (device, eof, sizeof (eof)); + break; + case 0xE7: // E7 42 + 8 byte COMMAND + csize = 2; + serial_read (device, command + 1, csize - 1); + message ("%02X %02X\n", command[0], command[1]); + serial_write (device, ack, sizeof (ack)); + serial_read (device, command, 8); + message ("%02X %02X %02X %02X\n%02X %02X %02X %02X\n", + command[0], command[1], command[2], command[3], + command[4], command[5], command[6], command[7]); + + address = command[0] + (command[1] << 8) + (command[2] << 16) + (command[3] << 24); + length = command[4] + (command[5] << 8) + (command[6] << 16) + (command[7] << 24); + message ("read_memory(0x%08X,0x%08X)\n", address, length); + + { + //serial_write (device, data, size); + unsigned int nbytes = 0; + while (nbytes < length) { + unsigned int len = 1024; + if (nbytes + len> length) + len = length - nbytes; + message ("nbytes=%u, len=%u\n", nbytes, len); + serial_write (device, data + address + nbytes, len); +#ifdef _WIN32 + serial_sleep (device, 10); // For Mares DiveOrganizer +#endif + nbytes += len; + } + serial_write (device, eof, sizeof (eof)); + } + break; + default: + message ("Unknown command 0x%02X\n", command[0]); + break; + } + } +} + +static void +aladin_set_clock (unsigned char data[], long clock_device, long clock_host) +{ + // Clock calibration. + time_t now = time (NULL); + long clock = clock_device + (now - clock_host) * 2; + data[0x7fb + 4] = (clock ) & 0xFF; + data[0x7fa + 4] = (clock>> 8) & 0xFF; + data[0x7f9 + 4] = (clock>> 16) & 0xFF; + data[0x7f8 + 4] = (clock>> 24) & 0xFF; + + message ("clock_host=%lu, now=%lu\n", clock_host, now); + message ("clock_device=%lu, clock=%lu\n", clock_device, clock); + + message ("checksum=%02X %02X\n", data[2048], data[2049]); + + // Checksum + unsigned short checksum = checksum_add_uint16 (data, 2048, 0x0000); + data[2048] = (checksum ) & 0xFF; + data[2049] = (checksum>> 8) & 0xFF; + + message ("checksum=%02X %02X\n", data[2048], data[2049]); +} + + +static void +simulation_aladin (serial_t *device, unsigned char data[], unsigned int size, long clock_device, long clock_host) +{ + const unsigned char header_original[4] = {0xAA, 0xAA, 0xAA, 0x00}; + const unsigned char header_reversed[4] = {'U', 'U', 'U', 0}; + const unsigned char garbage[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + const unsigned char divinglog[2] = {0xFF, 0x00}; + + unsigned char buffer[2050] = {0}; + memcpy (buffer, data, size); + + if (memcmp (data, header_reversed, 4) == 0) { + message ("Header: reversed\n"); + array_reverse_bits (buffer, size); + } else if (memcmp (data, header_original, 4) == 0) { + message ("Header: original\n"); + } else { + message ("Header: unknown\n"); + } + + // Use the device timestamp that is stored in the data. + /*clock_device = + (data[0x7f8 + 4] << 24) + + (data[0x7f9 + 4] << 16) + + (data[0x7fa + 4] << 8) + + data[0x7fb + 4];*/ + + if (clock_device == 0) + clock_host = 757382400; // 1994-01-01 00:00:00 UTC + + aladin_set_clock (buffer, clock_device, clock_host); + + /*unsigned short crc = checksum_add_uint16 (buffer, size, 0x0000); + memcpy (buffer + 2048, &crc, sizeof (crc));*/ + + array_reverse_bits (buffer, sizeof (buffer)); + + // Send some garbage + for (unsigned int i = 0; i < 200; ++i) { + serial_write (device, garbage, 1); + serial_sleep (device, 10); + } + +#if 1 + serial_write (device, buffer, sizeof (buffer)); +#else + for (unsigned int i = 0; i < sizeof (buffer); ++i) { + serial_write (device, buffer + i, 1); + if ((i % 128) == 0) + serial_sleep (device, 1); + } +#endif + + // Diving Log needs this. + serial_write (device, divinglog, sizeof (divinglog)); + + // Garbage + serial_write (device, garbage, sizeof (garbage)); +} + + +static int +test_memomouse (const unsigned char *data, unsigned int size, const unsigned char *fdata, unsigned int fsize, void *userdata) +{ + memcpy (userdata, data + 11, 4); + + return 0; +} + + +static void +memomouse_set_clock (unsigned char data[], unsigned int size, long clock_device, long clock_host) +{ + // Clock calibration. + time_t now = time (NULL); + long clock = clock_device + (now - clock_host) * 2; + data[2 + 1] = (clock ) & 0xFF; + data[2 + 2] = (clock>> 8) & 0xFF; + data[2 + 3] = (clock>> 16) & 0xFF; + data[2 + 4] = (clock>> 24) & 0xFF; + + message ("clock_host=%lu, now=%lu\n", clock_host, now); + message ("clock_device=%lu, clock=%lu\n", clock_device, clock); + + // Checksum + data[size + 2] = checksum_xor_uint8 (data, size + 2, 0x00); +} + + +typedef struct { + unsigned int timestamp; + unsigned int skip, length; +} memomouse_data_t; + + +static int +test_memomouse_length (const unsigned char *data, unsigned int size, const unsigned char *fdata, unsigned int fsize, void *userdata) +{ + //memcpy (userdata, data + 11, 4); + + memomouse_data_t *x = (memomouse_data_t *) userdata; + + unsigned int timestamp = data[11] + (data[12] << 8) + + (data[13] << 16) + (data[14] << 24); + + if (timestamp> x->timestamp) + x->length += size; + else + x->skip += size; + + return 1; +} + + +static void +simulation_memomouse (serial_t *device, unsigned char data[], unsigned int size, long clock_device, long clock_host) +{ + const unsigned char ack = ACK;//, nak = NAK, abc = 0x40; + const unsigned char id[] = {0x50, 0xE0, 0x00, 0x92, 0x62, 0x6A, 0x8C, 0x74, 0x0C, 0x0C, 0x82, 0x50}; + //const unsigned char id_corrupt[] = {0x50, 0xE0, 0x00, 0x0A, 0x62, 0x6A, 0x8C, 0x74, 0x0C, 0x0C, 0x82, 0x1A}; + + // Use the device timestamp that is stored in the data. + //clock_device = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24); + + if (clock_device == 0) + clock_host = 757382400; // 1994-01-01 00:00:00 UTC + + unsigned char timestamp[4] = {0}; + uwatec_memomouse_extract_dives (NULL, data, size, test_memomouse, ×tamp); + + unsigned char command[9] = {0}; + unsigned char packet[128] = {0}; + + unsigned char *package = malloc (size + 3); + if (package == NULL) + return; + + package[0] = (size ) & 0xFF; + package[1] = (size>> 8) & 0xFF; + memcpy (package + 2, data, size); + memcpy (package + 2 + 1, timestamp, 4); + package[size + 2] = checksum_xor_uint8 (package, size + 2, 0x00); + + serial_flush (device, SERIAL_QUEUE_BOTH); + +for (;;) { +start: + message ("Stage 1 (NAK)\n"); + for (;;) { + serial_read (device, command, 1); // NAK + unsigned char abc = command[0]; + array_reverse_bits (&abc, 1); + message ("reply=%02x %02x\n", command[0], abc); + if (command[0] == NAK) + break; + } + + message ("Stage 2 (ID)\n"); + for (;;) { + serial_write (device, id, sizeof (id)); // ID + serial_read (device, command, 1); // ACK + unsigned char abc = command[0]; + array_reverse_bits (&abc, 1); + message ("reply=%02x %02x\n", command[0], abc); + if (command[0] == ACK) + break; + } + + message ("Stage 3 (CMD)\n"); + serial_read (device, command, sizeof (command)); // CMD + serial_write (device, &ack, 1); // ACK + + array_reverse_bits (command, sizeof (command)); + unsigned int xtimestamp = command[4] + (command[5] << 8) + + (command[6] << 16) + (command[7] << 24); + message ("timestamp=%u\n", xtimestamp); + +#if 1 // Timestamp code + + memomouse_data_t x = {0, 0, 0}; + x.timestamp = xtimestamp; + uwatec_memomouse_extract_dives (NULL, data, size, test_memomouse_length, &x); + message ("skip=%u, length=%u\n", x.skip, x.length); + + size = x.length + 5; + package[0] = (size ) & 0xFF; + package[1] = (size>> 8) & 0xFF; + memcpy (package + 2, data, 5); + memcpy (package + 2 + 1, timestamp, 4); + memcpy (package + 2 + 5, data + 5 + x.skip, x.length); + package[size + 2] = checksum_xor_uint8 (package, size + 2, 0x00); + +#endif + + const unsigned int delay = 5000, step = 100; + for (unsigned int i = 0; i < (delay / step); ++i) { + int dsr = serial_get_line (device, SERIAL_LINE_DSR); + int cts = serial_get_line (device, SERIAL_LINE_CTS); + + message ("dsr=%i, cts=%i\n", dsr, cts); + if (dsr == 0) goto start; + + serial_sleep (device, step); + } + + //serial_sleep (device, delay); + + memomouse_set_clock (package, size, clock_device, clock_host); + + message ("Stage 4 (DATA)\n"); +/*for (;;) { + serial_write (device, id, sizeof (id)); // ID + serial_read (device, command, 1); // ACK + message ("reply=%02x\n", command[0]); + if (command[0] == ACK) + break; +}*/ + + // TODO: Send package. +#if 1 + unsigned int i = 0; + unsigned int offset = 0; + while (offset < size + 3) { + /*unsigned int i = 0; + for (;;) { + unsigned int offset = i * 126;*/ + unsigned int len = 126; + if (offset + len> size + 3) + len = size + 3 - offset; + packet[0] = (unsigned char) len; + memcpy (packet + 1, package + offset, len); + packet[len + 1] = checksum_xor_uint8 (packet, len + 1, 0x00); + array_reverse_bits (packet, len + 2); + message ("packet(%u,%u)\n", i, len); + serial_write (device, packet, len + 2); + serial_read (device, command, 1); + switch (command[0]) { + case NAK: + message ("NAK\n"); + // TODO: Send package again. + break; + case ACK: + message ("ACK\n"); + // TODO: Send next package. + offset += len; + i++; + break; + default: + message ("Unknown command %02x\n", command[0]); + break; + } + } +#endif + serial_sleep (device, 5000); +} +} + +static void +sensus_set_clock (unsigned char handshake[], long clock_device, long clock_host) +{ + // Clock calibration. + time_t now = time (NULL); + long clock = clock_device + (now - clock_host); + handshake[8] = (clock ) & 0xFF; + handshake[9] = (clock>> 8) & 0xFF; + handshake[10] = (clock>> 16) & 0xFF; + handshake[11] = (clock>> 24) & 0xFF; +} + + +static void +simulation_sensus (serial_t *device, unsigned char data[], unsigned int size, long clock_device, long clock_host) +{ + unsigned char handshake[12] = {'O', 'K', '1', '1', 16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + unsigned char command[1] = {0}; + unsigned short checksum = checksum_add_uint16 (data, size, 0x00); + + assert (size == 32768); + + int active = 0; + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0x0A: + message ("handshake()\n"); + sensus_set_clock (handshake, clock_device, clock_host); + serial_write (device, handshake, sizeof (handshake)); + active = 1; + break; + case 0x00: + if (active) { + message ("cancel()\n"); + active = 0; + } else { + message ("handshake()\n"); + sensus_set_clock (handshake, clock_device, clock_host); + serial_write (device, handshake, sizeof (handshake)); + active = 1; + } + break; + case 0x40: + message ("dump()\n"); + serial_write (device, "DATA", 4); + for (unsigned int i = 0; i < 32768; i += 512) { + serial_write (device, data + i, 512); + serial_sleep (device, 10); + } + //serial_write (device, data, size); + serial_write (device, &checksum, sizeof (checksum)); + serial_write (device, "END", 3); + active = 0; + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + + +static void +sensuspro_set_clock (unsigned char handshake[], long clock_device, long clock_host) +{ + // Clock calibration. + time_t now = time (NULL); + long clock = clock_device + (now - clock_host); + handshake[6] = (clock ) & 0xFF; + handshake[7] = (clock>> 8) & 0xFF; + handshake[8] = (clock>> 16) & 0xFF; + handshake[9] = (clock>> 24) & 0xFF; + + // Checksum + unsigned short checksum = checksum_crc_ccitt_uint16 (handshake, 10); + handshake[10] = (checksum ) & 0xFF; + handshake[11] = (checksum>> 8) & 0xFF; +} + +static void +simulation_sensuspro (serial_t *device, unsigned char data[], unsigned int size, unsigned char version[], long clock_device, long clock_host) +{ + //unsigned short crc = checksum_crc_ccitt_uint16 (data, size - 2); + + //unsigned short checksum = 0; + unsigned char command[1] = {0}; + unsigned char handshake[] = {0x02, 0xFF, 255, 10, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + /*unsigned short checksum = checksum_crc_ccitt_uint16 (handshake, sizeof (handshake) - 2); + handshake[sizeof (handshake) - 2] = (checksum ) & 0xFF; + handshake[sizeof (handshake) - 1] = (checksum>> 8) & 0xFF;*/ + + if (version) + memcpy (handshake, version, sizeof (handshake) - 2); + + serial_set_timeout (device, 1000); + serial_flush (device, SERIAL_QUEUE_BOTH); + + unsigned int i = 0; + for (;;) { +#if !defined (_WIN32) || !USEBREAK + serial_sleep (device, 1000); +#endif + sensuspro_set_clock (handshake, clock_device, clock_host); +#if defined (_WIN32) && USEBREAK + serial_wait_break (device); +#endif + message ("handshake ()\n"); + serial_write (device, handshake, sizeof (handshake)); + int rc = serial_read (device, command, 1); + /*while (rc == 1 && command[0] == 0x00) { + message ("break ()\n"); + rc = serial_read (device, command, 1); + }*/ + if (rc != 1) + continue; + switch (command[0]) { + case 0xB4: + message ("dump ()\n"); + for (i = 0; i < (size - 2); i += 512) { + message ("i=%u\n", i); + serial_write (device, data + i, 512); + //serial_sleep (device, 10); + } + message ("last=%u\n", i); + serial_write (device, data + size - 2, 2); + //serial_write (device, data, size); + break; + case 0xB5: + serial_read (device, command, 1); + message ("write_interval (%u)\n", command[0]); + handshake[3] = command[0]; + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + + +static void +sensusultra_set_clock (unsigned char handshake[], long devtime, long systime) +{ + // Clock calibration. + time_t now = time (NULL); + long clock = devtime + (now - systime); + handshake[4] = (clock ) & 0xFF; + handshake[5] = (clock>> 8) & 0xFF; + handshake[6] = (clock>> 16) & 0xFF; + handshake[7] = (clock>> 24) & 0xFF; + + // Checksum + unsigned short checksum = checksum_crc_ccitt_uint16 (handshake, 26 - 2); + handshake[26 - 2] = (checksum ) & 0xFF; + handshake[26 - 1] = (checksum>> 8) & 0xFF; +} + + +static int +sensusultra_read (serial_t *device, unsigned char data[], unsigned int size) +{ + const unsigned char prompt[] = {0xA5}; + + for (unsigned int i = 0; i < size; ++i) { + serial_write (device, prompt, sizeof (prompt)); + int rc = serial_read (device, data + i, 1); + if (rc != 1) + return i; + } + + return size; +} + +static void +simulation_sensusultra (serial_t *device, unsigned char data[], unsigned int size, unsigned char version[], long clock_device, long clock_host) +{ + int rc = 0; + unsigned int offset = 0; + unsigned char prompt[] = {0xA5}; + unsigned char command[2] = {0}; + unsigned char handshake[26] = { + 0x01, 0x03, // VERSION + 0x00, 0x01, // SERIAL + //0xFF, 0xFF, // SERIAL + 0x00, 0x00, 0x00, 0x00, // TIME + //devtime & 0xFF, (devtime>> 8) & 0xFF, (devtime>> 16) & 0xFF, (devtime>> 24) & 0xFF, + 0x01, 0x00, // BOOT_COUNT (1) + 0x00, 0x00, 0x00, 0x00, // BOOT_TIME (0) + 0x00, 0x01, // DIVE_COUNT + 0x0a, 0x00, // INTERVAL (10) + 0x57, 0x04, // THRESHOLD (1111) + 0x0F, 0x00, // ENDCOUNT (15) + 0x01, 0x00, // AVERAGING (1) + 0x00, 0x00}; // CRC + unsigned char sense[8] = { + 0x00, 0x00, // VOLTAGE + 0x00, 0x00, // TEMPERATURE + 0x00, 0x00, // PRESSURE + 0x00, 0x00}; // CRC + + if (version) { + memcpy (handshake, version, sizeof (handshake) - 2); + clock_device = array_uint32_le (version + 4); + } + + unsigned short checksum = checksum_crc_ccitt_uint16 (sense, sizeof (sense) - 2); + sense[sizeof (sense) - 2] = (checksum ) & 0xFF; + sense[sizeof (sense) - 1] = (checksum>> 8) & 0xFF; + + serial_flush (device, SERIAL_QUEUE_BOTH); + serial_set_timeout (device, 750); // FIXME: 100ms + + for (;;) { + serial_sleep (device, 1000); + serial_flush (device, SERIAL_QUEUE_BOTH); + message ("handshake()\n"); + sensusultra_set_clock (handshake, clock_device, clock_host); + serial_write (device, handshake, sizeof (handshake)); + rc = sensusultra_read (device, command, 2); + if (rc != 2) + continue; + unsigned short code = command[0] + (command[1] << 8); + unsigned short page = 0, crc = 0, value = 0/*, count = 0*/; + switch (code) { + case 0xB420: + message ("read_user() NOT IMPLEMENTED\n"); + break; + case 0xB421: + message ("read_data()\n"); + page = 0; + while (page < 4064) { + //for (unsigned int i = 0; i < 4064; ++i) { + //serial_sleep (device, 100); + message ("page=%u\n", page); + crc = checksum_crc_ccitt_uint16 (data + size - 512 * (page + 1), 512); + serial_write (device, &page, sizeof (page)); + serial_write (device, data + size - 512 * (page + 1), 512); + serial_write (device, &crc, sizeof (crc)); + serial_write (device, prompt, sizeof (prompt)); + rc = serial_read (device, command, 1); + if (rc != 1) { + // Timeout + message ("response: timeout\n"); + break; + } + if (command[0] == prompt[0]) { + // Accept + message ("response: accept\n"); + page++; + } else if (command[0] == 0x00) { + // Reject + message ("response: reject\n"); + } else { + // Unknown + message ("response: unkown (0x%02x)\n", command[0]); + break; + } + } + break; + case 0xB430: + message ("write_user() NOT IMPLEMENTED\n"); + break; + case 0xB440: + message ("sense()\n"); + serial_write (device, sense, sizeof (sense)); + break; + case 0xB410: + case 0xB411: + case 0xB412: + case 0xB413: + message ("set_parameter()\n"); + rc = sensusultra_read (device, command, 2); + if (rc != 2) + continue; + value = command[0] + (command[1] << 8); + message ("parameter: value=%i\n", value); + offset = 0x10 + 2 * (code - 0xB410); + handshake[offset + 0] = (value ) & 0xFF; + handshake[offset + 1] = (value>> 8) & 0xFF; + break; + default: + message ("Unknown command 0x%04x\n", code); + break; + } + } +} +/* +static void +v2c2_read_command (serial_t *device) +{ + unsigned char command[128] = {0}, checksum = 0; + + for (;;) { + serial_set_timeout (device, -1); + + // Read packet: CMD N(2) DATA(N) CRC + int n = serial_read (device, command + 0, 3); + if (n != 3) { + message ("Ouch!\n"); + continue; + } + + unsigned int ndata = (command[1] << 8) + command[2]; + unsigned int csize = 3 + ndata + 1; + message ("ndata=%u\n", ndata); + + serial_set_timeout (device, 1000); + + n = serial_read (device, command + 3, ndata + 1); + if (n != ndata + 1) { + message ("Ouch!\n"); + continue; + } + + checksum = checksum_xor_uint8 (command, csize - 1, 0x00); + if (command[csize - 1] != checksum) { + message ("Ouch!\n"); + continue; + } + + message ("command="); + for (unsigned int i = 0; i < csize; ++i) { + message ("%02x ", command[i]); + } + message ("\n"); + + } +} +*/ + +static void +simulation_vyper2_or_d9 (serial_t *device, unsigned char data[], unsigned int size, unsigned char id[], int vyper2) +{ + unsigned char command[128] = {0}, checksum = 0; + unsigned int csize = 0, len = 0, address = 0, nparams = 0; + unsigned int isversion = 0; + + unsigned char version[8] = {0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy (version + 3, id, 4); + version[7] = checksum_xor_uint8 (version, 7, 0x00); + + for (;;) { + //v2c2_read_command (device); + + serial_read (device, command, 1); + /*if (!isversion && command[0] != 0x0F) + goto unknown;*/ + switch (command[0]) { + case 0x0F: + csize = 4; + if (vyper2) { + serial_read (device, command + 1, csize - 1); + } else { + serial_write (device, command, 1); + for (unsigned int i = 1; i < csize; ++i) { + serial_read (device, command + i, 1); + serial_write (device, command + i, 1); + } + } + message ("version()\n"); + serial_write (device, version, sizeof (version)); + isversion = 1; + break; + case 0x05: + csize = 7; + if (vyper2) { + serial_read (device, command + 1, csize - 1); + } else { + serial_write (device, command, 1); + for (unsigned int i = 1; i < csize; ++i) { + serial_read (device, command + i, 1); + serial_write (device, command + i, 1); + } + } + nparams = (command[1] << 8) + command[2]; + address = (command[3] << 8) + command[4]; + len = command[5]; + message ("read_memory(%04x,%i)\n", address, len); + if (len < 8) { + message ("Too small!\n"); + break; + } + command[2] += len; + checksum = 0x00; + checksum = checksum_xor_uint8 (command, csize - 1, checksum); + checksum = checksum_xor_uint8 (data + address, len, checksum); + /*if (myrandom (5) == 0) { + message ("Garbage\n"); + unsigned char garbage = 0xFF; + serial_write (device, &garbage, 1); + }*/ + serial_write (device, command, csize - 1); + serial_write (device, data + address, len); + + /*if (myrandom (20) == 0) { + message ("Garbage\n"); + unsigned char garbage = 0xFF; + serial_write (device, &garbage, 1); + } else*/ + serial_write (device, &checksum, 1); + //debug (data + address, len); + break; + case 0x06: + csize = 7 - 1; + if (vyper2) { + serial_read (device, command + 1, csize - 1); + } else { + serial_read (device, command + 1, csize - 1); + } + address = (command[3] << 8) + command[4]; + len = command[5]; + if (vyper2) { + serial_read (device, command + 6, len + 1); + } else { + serial_read (device, command + 6, len); + serial_write (device, command, len + 6); + serial_read (device, command + 6 + len, 1); + serial_write (device, command + 6 + len, 1); + } + csize += len + 1; + message ("write_memory(%04x,%i)\n", address, len); + command[2] -= len; + checksum = 0x00; + checksum = checksum_xor_uint8 (command, 6, checksum); + serial_write (device, command, 6); + serial_write (device, &checksum, 1); + memcpy (data + address, command + 6, len); + //debug (data + address, len); + break; + case 0x20: + csize = 4; + if (vyper2) { + serial_read (device, command + 1, csize - 1); + } else { + serial_write (device, command, 1); + for (unsigned int i = 1; i < csize; ++i) { + serial_read (device, command + i, 1); + serial_write (device, command + i, 1); + } + } + message ("reset_maxdepth()\n"); + serial_write (device, command, csize); + break; + case 0x0B: + csize = 4; + if (vyper2) { + serial_read (device, command + 1, csize - 1); + } else { + serial_write (device, command, 1); + for (unsigned int i = 1; i < csize; ++i) { + serial_read (device, command + i, 1); + serial_write (device, command + i, 1); + } + } + message ("reset()\n"); + serial_write (device, command, csize); + break; + default: + //unknown: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + +//#define FAST + +static void +simulation_vyper (serial_t *device, unsigned char data[], unsigned int size) +{ + unsigned char command[37] = {0}, checksum = 0; + unsigned int csize = 0, len = 0, address = 0; + unsigned int offset = 0, ndives = 0; + + int is_spyder = 0; + if (data[0x24] == 20 || data[0x24] == 30 || data[0x24] == 60) { + if (data[0x16] == 0x01) + if (data[0x17] == 0x01 || data[0x17] == 0x02) + is_spyder = 1; + } + message ("is_spyder=%i\n", is_spyder); + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0x05: + csize = 5; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + len = command[3]; + message ("read_memory(%04x,%i)\n", address, len); + checksum = 0x00; + checksum = checksum_xor_uint8 (command, csize - 1, checksum); + checksum = checksum_xor_uint8 (data + address, len, checksum); +#ifndef FAST + serial_sleep (device, 500); +#endif + serial_write (device, command, csize - 1); + serial_write (device, data + address, len); + serial_write (device, &checksum, 1); + break; + case 0x06: + csize = 4; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + len = command[3]; + serial_read (device, command + 4, len + 1); + csize += len + 1; + message ("write_memory(%04x,%i)\n", address, len); + checksum = 0x00; + checksum = checksum_xor_uint8 (command, 4, checksum); +#ifndef FAST + serial_sleep (device, 500); +#endif + serial_write (device, command, 4); + serial_write (device, &checksum, 1); + memcpy (data + address, command + 4, len); + break; + case 0x07: + csize = 3; + serial_read (device, command + 1, csize - 1); + message ("prepare_write_memory()\n"); +#ifndef FAST + serial_sleep (device, 500); +#endif + serial_write (device, command, csize); + break; + case 0x08: + if (is_spyder) + offset = (data[0x1C] << 8) + data[0x1D] - 1; + else + offset = (data[0x51] << 8) + data[0x52] - 1; + ndives = 0; + case 0x09: + csize = 3; + serial_read (device, command + 1, csize - 1); + message ("read_dive(%i,0x%04x)\n", ndives+1, offset); +#ifndef FAST + serial_sleep (device, 300); +#endif + offset = send_next_dive (device, data, offset, command[0], is_spyder); + ndives++; + break; + case 'A': + csize = 3; + serial_read (device, command + 1, csize - 1); + message ("detect_interface()\n"); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + +static void +simulation_eon (serial_t *device, unsigned char data[], unsigned int size) +{ + unsigned char command[1] = {0}; + unsigned char checksum = checksum_add_uint8 (data, SUUNTO_EON_MEMORY_SIZE /*size*/, 0x00); + + message ("checksum=0x%02x\n", checksum); + message ("checksum=0x%02x\n", data[SUUNTO_EON_MEMORY_SIZE]); + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 'P': + message ("profile()\n"); + for (unsigned int i = 0; i < SUUNTO_EON_MEMORY_SIZE /*size*/; ++i) { + serial_write (device, data + i, 1); + if ((i % 32) == 0) + serial_sleep (device, 10); + } + //serial_write (device, data, size); + serial_write (device, &checksum, 1); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + + +static void +simulation_ostc (serial_t *device, unsigned char data[], unsigned int size) +{ + int n = 0; + unsigned char command[1] = {0}; + unsigned char eeprom0[256] = {0}; + unsigned char eeprom1[256] = {0}; + unsigned char eeprom2[256] = {0}; + unsigned char clock[6] = {0}; + unsigned char md2hash[16] = {0}; + unsigned char temperature[2] = {0}; + + unsigned char preamble[6] = {0}; + unsigned char battery[2] = {0}; + unsigned char firmware[2] = {0}; + + unsigned char pic[] = {0x57}; + unsigned char ack[] = {'K'}; + unsigned char nak[] = {'N'}; + //unsigned char fwdata[0x17F40]; + unsigned char block[69]; + unsigned int blocksize = 0x40; + unsigned int fwsize = 0x17F40; + + memcpy (preamble, data + 1 - 1, sizeof (preamble)); // preamble + memcpy (eeprom0, data + 7 - 1, sizeof (eeprom0)); // eeprom0 + memcpy (battery, data + 263 - 1, sizeof (battery)); // battery + memcpy (firmware, data + 265 - 1, sizeof (firmware)); // firmware + if (size>= 33034 + 256) + memcpy (eeprom1, data + 33034, sizeof (eeprom1)); // firmware + + /* a hw_ostc_dump/foreach + * g,j,m hw_ostc_eeprom_read (device, bank, data, size); + * d,i,n hw_ostc_eeprom_write (device, bank, data, size); + * b,f hw_ostc_parameter_write (device, parameter, data, size); CLOCK/TEMP + * k hw_ostc_tissue_save (device); + * h hw_ostc_tissue_reset (device); + * e hw_ostc_md2_read (device, data, size); + * c hw_ostc_simulate (device, data, size); + */ + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 'a': + message ("read profiles\n"); + for (unsigned int i = 0; i < size; ++i) { + serial_write (device, data + i, 1); + if ((i % 512) == 0) + serial_sleep (device, 10); + } + //serial_write (device, data, size); + break; + case 'b': + message ("write clock\n"); + serial_read (device, clock, sizeof (clock)); + break; + case 'c': + message ("simulator mode\n"); + while (1) { + serial_read (device, command, 1); + message ("depth=%.1fm (%.1fbar)\n", + command[0] - 10.0, command[0] / 10.0); + if (command[0] == 10) + break; + } + break; + case 'd': + message ("write eeprom bank 0\n"); + serial_write (device, command, 1); + for (unsigned int i = 0; i < sizeof (eeprom0) - 4; ++i) { + serial_read (device, eeprom0 + i + 4, 1); + serial_write (device, eeprom0 + i + 4, 1); + } + break; + case 'e': + message ("read MD2 Hash fingerprint\n"); + serial_write (device, firmware, sizeof (firmware)); + serial_write (device, md2hash, sizeof (md2hash)); + break; + case 'f': + message ("write temperature calibration\n"); + serial_write (device, command, 1); + serial_read (device, temperature, sizeof (temperature)); + break; + case 'g': + message ("read eeprom bank 0\n"); + serial_write (device, eeprom0, sizeof (eeprom0)); + break; + case 'h': + message ("reset deco data\n"); + serial_write (device, command, 1); + break; + case 'i': + message ("write eeprom bank 1\n"); + serial_write (device, command, 1); + for (unsigned int i = 0; i < sizeof (eeprom1) - 4; ++i) { + serial_read (device, eeprom1 + i + 4, 1); + serial_write (device, eeprom1 + i + 4, 1); + } + break; + case 'j': + message ("read eeprom bank 1\n"); + serial_write (device, eeprom1, sizeof (eeprom1)); + break; + case 'k': + message ("save tissue data\n"); + serial_write (device, command, 1); + break; + case 'm': + message ("read eeprom bank 2\n"); + serial_write (device, eeprom2, sizeof (eeprom2)); + break; + case 'n': + message ("write eeprom bank 2\n"); + serial_write (device, command, 1); + for (unsigned int i = 0; i < sizeof (eeprom2) - 4; ++i) { + serial_read (device, eeprom2 + i + 4, 1); + serial_write (device, eeprom2 + i + 4, 1); + } + break; + case 0xC1: + message ("fwupdate\n"); + serial_write (device, pic, sizeof(pic)); + serial_write (device, ack, sizeof(ack)); + serial_set_timeout (device, 1000); + while (1) { + n = serial_read (device, block, 4); + if (n != 4) { + message ("timeout\n"); + break; + } + unsigned int address = array_uint24_be(block + 0); + unsigned int length = block[3]; + n = serial_read (device, block + 4, length + 1); + if (n != length + 1) { + message ("nak\n"); + serial_write (device, nak, sizeof(nak)); + continue; + } + unsigned char csum = checksum_add_uint8 (block, 4 + length + 1, 0x00); + message ("address=%06x, length=%u, n=%u, csum=%02x\n", address, length, n, csum); + if (csum != 0 /*|| error(0.25)*/) { + message ("nak\n"); + serial_write (device, nak, sizeof(nak)); + continue; + } + serial_write (device, ack, sizeof(ack)); + } + serial_set_timeout (device, -1); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + + +static void +simulation_ostc3 (serial_t *device, unsigned char data[], unsigned int size, unsigned char id[], unsigned int idsize) +{ + int n = 0; + const unsigned char service[] = {0x4B, 0xAB, 0xCD, 0xEF}; + unsigned char ready[1] = {0x4D}; + unsigned char empty[256] = {0}; + unsigned char command[4] = {0}; + unsigned char clock[6] = {0}; + unsigned char custom[60] = {0}; + unsigned char display[16] = {0}; + unsigned char dive[1] = {0}; + unsigned char hardware[1] = {0}; + unsigned char version[sizeof(custom) + 4] = {0}; + unsigned char fwheader[16+4] = {0}; + //unsigned char fwinfo[16] = {0x16, 0x00, 0x00, 0x09, 0x09, 0x01, 0x30, 0x01, 0x00, 0x09, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}; + unsigned char fwversion[256][4] = {0}; + unsigned char fwid = 0; + + const unsigned int headersize = 256, compactsize = 16; + + //memset(fwversion, 0xFF, sizeof(fwversion)); + memset(empty, 0xFF, sizeof(empty)); + + if (idsize>= sizeof(hardware)) { + memcpy (hardware, id, sizeof(hardware)); + } + +/* + +TYPE CMD ECHO INPUT OUTPUT READY +===================================================== + +init 0xBB N N N 0x4D +exit 0xFF Y N N N +header 0x61 N N data(65536) 0x4D +clock 0x62 Y data(6) N 0x4D +custom 0x63 Y data(60) N 0x4D +dive 0x66 Y data(1) data(n) 0x4D +version 0x69 Y N data(64) 0x4D +display 0x6E Y data(16) N 0x4D +compact 0x6D N N data(4096) 0x4D +*/ + + struct { + unsigned char *data; + unsigned int size; + } dives[256]; + + unsigned int offset = 0; + unsigned int ndives = 0; + while (offset + headersize < size) { + unsigned int marker = array_uint16_le (data + offset); + if (marker != 0xFAFA) + break; + + // Calculate the profile length. + unsigned int length = headersize + array_uint24_le (data + offset + 9) - 3; + + // Workaround for a bug in older firmware versions. + unsigned int firmware = array_uint16_be (data + offset + 0x30); + if (firmware < 93) + length -= 3; + + dives[ndives].data = data + offset; + dives[ndives].size = length; + + offset += length; + ndives++; + } + + message ("ndives=%u\n", ndives); + + unsigned int idx = 0; + unsigned int length = 0, nbytes = 0; + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0xAA: // Init service mode + message ("Init service\n"); + serial_read (device, command + 1, 3); + serial_write (device, service, sizeof(service)); + ready[0] = 0x4C; + break; + case 0xBB: // Init download mode + message ("Init download\n"); + serial_write (device, command, 1); + ready[0] = 0x4D; + break; + case 0xFF: // Exit + message ("Exit\n"); + serial_write (device, command, 1); + break; + case 0x61: // Header + message ("Header\n"); + serial_write (device, command, 1); + for (unsigned int i = 0; i < ndives; ++i) { + idx = ndives - 1 - i; + serial_write (device, dives[idx].data, headersize); + } + for (unsigned int i = ndives; i < 256; ++i) { + serial_write (device, empty, headersize); + } + break; +#if 0 + case 0x6D: // Compact Header + message ("Header\n"); + serial_write (device, command, 1); + serial_write (device, data, compactsize); + for (unsigned int i = 1; i < 256; ++i) { + serial_write (device, empty, compactsize); + } + break; +#endif + case 0x62: // Clock + message ("Clock\n"); + serial_write (device, command, 1); + serial_read (device, clock, sizeof(clock)); + break; + case 0x63: // Custom + message ("Custom\n"); + serial_write (device, command, 1); + serial_read (device, custom, sizeof(custom)); + break; + case 0x66: // Dive + message ("Dive\n"); + serial_write (device, command, 1); + serial_read (device, dive, sizeof(dive)); + idx = ndives - 1 - dive[0]; + serial_write (device, dives[idx].data, dives[idx].size); + break; + case 0x69: // Version + message ("Version\n"); + serial_write (device, command, 1); + serial_write (device, version, sizeof(version)); + break; + case 0x6A: // Hardware + message ("Hardware\n"); + serial_write (device, command, 1); + serial_write (device, hardware, sizeof(hardware)); + break; + case 0x6B: // Firmware info + message ("Firmware info\n"); + serial_write (device, command, 1); + serial_read (device, &fwid, 1); + serial_write (device, fwversion[fwid], sizeof(fwversion[0])); + break; + case 0x6E: // Display + message ("Display\n"); + serial_write (device, command, 1); + serial_read (device, display, sizeof(display)); + break; +#if 0 + case 0x73: // RTE + case 0x74: // Firmware + case 0x76: // Fonts + message ("RTE/Firmware/Fonts (%02x)\n", command[0]); +#else + case 0x73: // Firmware upload + message ("Firmware upload\n"); +#endif + serial_write (device, command, 1); + serial_read (device, fwheader, sizeof(fwheader)); + length = array_uint32_be(fwheader); + fwid = fwheader[4]; + nbytes = 0; + while (nbytes < length) { + unsigned char buffer[4*1024]; + unsigned int len = length - nbytes; + if (len> sizeof(buffer)) { + len = sizeof(buffer); + } + serial_read (device, buffer, len); + nbytes += len; + } + memcpy(fwversion[fwid], fwheader + 12, 4); + message ("Received %u bytes\n", sizeof(fwheader) + nbytes); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + if (command[0] != 0xFF) { + serial_write (device, ready, sizeof(ready)); + } + } +} + +static void +simulation_solution (serial_t *device, unsigned char data[], unsigned int size) +{ + unsigned char command[3] = {0}, reply[3] = {0}; + +for (;;) { + + //PC sends 0xFF + serial_read (device, command, 1); + message ("data=%02x\n", command[0]); + if (command[0] != 0xFF) + message ("Unexpected answer byte(s).\n"); + + //Solution sends 0x3F + reply[0] = 0x3F; + serial_write (device, reply, 1); + //PC sends 0x4D, 0x01,0x01 + serial_read (device, command, 3); + message ("data=%02x %02x %02x\n", command[0], command[1], command[2]); + if (command[0] != 0x4D || command[1] != 0x01 || command[2] != 0x01) + message ("Unexpected answer byte(s).\n"); + + for (unsigned int i = 1; i < 256; ++i) { + message ("Iteration %i (%02x)\n", i, i); + //Solution sends 0x01,i,data[i] + reply[0] = 0x01; + reply[1] = i; + reply[2] = data[i]; + serial_write (device, reply, 3); + //PC sends i + serial_read (device, command, 1); + message ("data=%02x\n", command[0]); + if (command[0] != i) + message ("Unexpected answer byte(s).\n"); + + //Solution sends data[i] + reply[0] = data[i]; + //if (i == 1) + //reply[0] = 0xFF; + serial_write (device, reply, 1); + //PC sends 0x0D + serial_read (device, command, 1); + message ("data=%02x\n", command[0]); + if (command[0] != 0x0D) + message ("Unexpected answer byte(s).\n"); + } + serial_sleep (device, 100); + message("loop end\n"); + //Solution sends 0x02,0x00,0x80 + reply[0] = 0x02; + reply[1] = 0x00; + reply[2] = 0x80; + serial_write (device, reply, 3); + message("marker a\n"); + //PC sends 0x80 + serial_read (device, command, 1); + message ("data=%02x\n", command[0]); + if (command[0] != 0x80) + message ("Unexpected answer byte(s).\n"); + message("marker b\n"); + + //Solution sends 0x80 + reply[0] = 0x80; + serial_write (device, reply, 1); + message("marker c\n"); + //PC sends 0x20 + serial_read (device, command, 1); + message ("data=%02x\n", command[0]); + if (command[0] != 0x20) + message ("Unexpected answer byte(s).\n"); + message("marker d\n"); + + serial_sleep (device, 100); + + //Solution sends 0x3F + reply[0] = 0x3F; + serial_write (device, reply, 1); + message("marker e\n"); + +} + +} + +#if 0 +static int +patch_utc_offset (/*const*/ unsigned char *data, unsigned int size, const unsigned char *fdata, unsigned int fsize, void *userdata) +{ + int utc_offset = * ((int *) userdata); + + //message ("utc=%i\n", utc_offset); + + data[16] = utc_offset * 4; + + //memset (data + 12, 0, 4); + + //message ("utc=%i, %i\n", (signed int)data[16], utc_offset); + + return 1; +} +#endif + +static int +test (const unsigned char *data, unsigned int size, const unsigned char *fdata, unsigned int fsize, void *userdata) +{ + memcpy (userdata, data + 8, 4); + + return 0; +} + + +static void +smart_set_clock (unsigned char data[], long clock_device, long clock_host) +{ + time_t now = time (NULL); + long clock = clock_device + 2 * (now - clock_host); + data[0] = (clock ) & 0xFF; + data[1] = (clock>> 8) & 0xFF; + data[2] = (clock>> 16) & 0xFF; + data[3] = (clock>> 24) & 0xFF; +} + +static int +test_smart_length (const unsigned char *data, unsigned int size, const unsigned char *fdata, unsigned int fsize, void *userdata) +{ + memomouse_data_t *x = (memomouse_data_t *) userdata; + + /*unsigned int timestamp = data[11] + (data[12] << 8) + + (data[13] << 16) + (data[14] << 24);*/ + + unsigned int timestamp = array_uint32_le (data + 8); + + if (timestamp> x->timestamp) + x->length += size; + else + x->skip += size; + + return 1; +} + +static void +simulation_smart (unsigned char data[], unsigned int size, unsigned char model, unsigned int serial, long clock_device, long clock_host) +{ +#ifndef NOIRDA + if (clock_device == 0) + clock_host = 946684800; // 2000年01月01日 00:00:00 UTC + + int rc = 0; + dc_context_t *context = NULL; + irda_t *device = NULL; + unsigned char command[9] = {0}; + unsigned char answer[4] = {0}; + //unsigned int nbytes = 0; + + unsigned char timestamp[4] = {0}; + uwatec_smart_extract_dives (NULL, data, size, test, ×tamp); + +#if 0 + int utc_offset = -7; + uwatec_smart_extract_dives (NULL, data, size, patch_utc_offset, &utc_offset); +#endif + + memomouse_data_t x = {0, 0, 0}; + +begin: + irda_socket_open (&device, context); + irda_socket_bind_lsap (device, 1); + irda_socket_listen (device, 0); + irda_socket_accept (device); + + for (;;) { + memset (command, 0, sizeof (command)); + rc = irda_socket_read (device, command, 1); + if (rc <= 0) + break; + switch (command[0]) { + case 0x13: + message ("Handshake (stage 0).\n"); + message ("rc=%i, command=%02x\n", rc, command[0]); + answer[0] = 0x01; + irda_socket_write (device, answer, 1); + break; + case 0x1B: + message ("Handshake (stage 1).\n"); + message ("rc=%i, command=%02x\n", rc, command[0]); + answer[0] = 0x01; + irda_socket_write (device, answer, 1); + break; + case 0x1C: + message ("Handshake (stage 2).\n"); + rc = irda_socket_read (device, command + 1, 5 - 1); + message ("rc=%i, command=%02x%02x%02x%02x%02x\n", rc, command[0], command[1], command[2], command[3], command[4]); + answer[0] = 0x01; + irda_socket_write (device, answer, 1); + break; + case 0x1A: + message ("Dive Computer Time.\n"); + message ("rc=%i, command=%02x\n", rc, command[0]); + //memcpy (answer, timestamp, 4); + smart_set_clock (answer, clock_device, clock_host); + irda_socket_write (device, answer, 4); + break; + case 0x14: + message ("Serial Number\n"); + message ("rc=%i, command=%02x\n", rc, command[0]); + answer[0] = (serial ) & 0xFF; + answer[1] = (serial>> 8 ) & 0xFF; + answer[2] = (serial>> 16) & 0xFF; + answer[3] = (serial>> 24) & 0xFF; + irda_socket_write (device, answer, 4); + break; + case 0x10: + message ("Dive Computer Model.\n"); + message ("rc=%i, command=%02x\n", rc, command[0]); + answer[0] = model; + irda_socket_write (device, answer, 1); + break; + case 0xC6: + message ("Data Length.\n"); + rc = irda_socket_read (device, command + 1, 9 - 1); + message ("rc=%i, command=%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", rc, + command[0], command[1], command[2], command[3], command[4], + command[5], command[6], command[7], command[8]); +#if 1 + x.timestamp = array_uint32_le (command + 1); + x.length = x.skip = 0; + uwatec_smart_extract_dives (NULL, data, size, test_smart_length, &x); +#else + x.length = size; + x.skip = 0; +#endif + message ("skip=%u, length=%u\n", x.skip, x.length); + answer[0] = (x.length ) & 0xFF; + answer[1] = (x.length>> 8 ) & 0xFF; + answer[2] = (x.length>> 16) & 0xFF; + answer[3] = (x.length>> 24) & 0xFF; + irda_socket_write (device, answer, 4); + break; + case 0xC4: + message ("Data.\n"); + rc = irda_socket_read (device, command + 1, 9 - 1); + message ("rc=%i, command=%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", rc, + command[0], command[1], command[2], command[3], command[4], + command[5], command[6], command[7], command[8]); +#if 1 + x.timestamp = array_uint32_le (command + 1); + x.length = x.skip = 0; + uwatec_smart_extract_dives (NULL, data, size, test_smart_length, &x); +#else + x.length = size; + x.skip = 0; +#endif + answer[0] = ((x.length + 4) ) & 0xFF; + answer[1] = ((x.length + 4)>> 8 ) & 0xFF; + answer[2] = ((x.length + 4)>> 16) & 0xFF; + answer[3] = ((x.length + 4)>> 24) & 0xFF; + irda_socket_write (device, answer, 4); + irda_socket_write (device, data + x.skip, x.length); + /*nbytes = 0; + while (nbytes < size) { + unsigned int len = 32; + if (nbytes + len> size) + len = size - nbytes; + int n = irda_socket_write (device, data + nbytes, len); + if (n < 0) { + message ("FATAL ERROR\n"); + break; + } + nbytes += n; + }*/ + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } + message ("exit\n"); + irda_socket_close (device); + goto begin; +#endif +} + + +static void +simulation_meridian (serial_t *device, unsigned char data[], unsigned int size, unsigned char model, unsigned int serial, long clock_device, long clock_host) +{ + const unsigned char ack = 0x11, nak = 0x66; + unsigned char command[255 + 11]; + unsigned char response[255 + 6]; + unsigned char *answer = response + 5; + + if (clock_device == 0) + clock_host = 946684800; // 2000-01-01 00:00:00 UTC + + for (;;) { + unsigned csize = 0, asize = 0; + + // Read the packet. + serial_read (device, command, 11); + csize = command[7]; + serial_read (device, command + 11, csize + 1); + debug(command, csize + 12); + + // Send the echo. + serial_write (device, command, csize + 12); + + switch (command[11]) { + case 0x13: + message ("Handshake (stage 0).\n"); + answer[0] = 0x01; + asize = 1; + break; + case 0x1B: + message ("Handshake (stage 1).\n"); + answer[0] = 0x01; + asize = 1; + break; + case 0x1C: + message ("Handshake (stage 2).\n"); + answer[0] = 0x01; + asize = 1; + break; + case 0x1A: + message ("Dive Computer Time.\n"); + smart_set_clock (answer, clock_device, clock_host); + asize = 4; + break; + case 0x14: + message ("Serial Number\n"); + answer[0] = (serial ) & 0xFF; + answer[1] = (serial>> 8 ) & 0xFF; + answer[2] = (serial>> 16) & 0xFF; + answer[3] = (serial>> 24) & 0xFF; + asize = 4; + break; + case 0x10: + message ("Dive Computer Model.\n"); + answer[0] = model; + asize = 1; + break; + case 0xC6: + message ("Data Length.\n"); + answer[0] = (size ) & 0xFF; + answer[1] = (size>> 8 ) & 0xFF; + answer[2] = (size>> 16) & 0xFF; + answer[3] = (size>> 24) & 0xFF; + asize = 4; + break; + case 0xC4: + message ("Data.\n"); + answer[0] = ((size + 4) ) & 0xFF; + answer[1] = ((size + 4)>> 8 ) & 0xFF; + answer[2] = ((size + 4)>> 16) & 0xFF; + answer[3] = ((size + 4)>> 24) & 0xFF; + asize = 4; + break; + case 0xFF: + if (command[12] == 0x10) { + message ("Feature Set\n"); + unsigned int feature = 0;//1036746750; + answer[0] = (feature ) & 0xFF; + answer[1] = (feature>> 8 ) & 0xFF; + answer[2] = (feature>> 16) & 0xFF; + answer[3] = (feature>> 24) & 0xFF; + asize = 4; + } + break; + default: + message ("Unknown command 0x%02x\n", command[11]); + continue; + } + + response[0] = ((asize + 1) ) & 0xFF; + response[1] = ((asize + 1)>> 8) & 0xFF; + response[2] = ((asize + 1)>> 16) & 0xFF; + response[3] = ((asize + 1)>> 24) & 0xFF; + response[4] = command[11]; + response[5 + asize] = checksum_xor_uint8 (response, asize + 5, 0x00); + + serial_write (device, &ack, sizeof(ack)); + serial_write (device, response, asize + 6); + + if (command[11] == 0xC4) { + const unsigned int packetsize = 0x80; + + unsigned int nbytes = 0; + while (nbytes < size) { + unsigned int len = size - nbytes; + if (len> packetsize) + len = packetsize; + + unsigned char header[] = { + ((len + 1) ) & 0xFF, + ((len + 1)>> 8) & 0xFF, + ((len + 1)>> 16) & 0xFF, + ((len + 1)>> 24) & 0xFF, + command[11] + }; + unsigned char csum = 0x00; + csum = checksum_xor_uint8 (header, sizeof (header), csum); + csum = checksum_xor_uint8 (data + nbytes, len, csum); + + serial_write (device, header, sizeof (header)); + serial_write (device, data + nbytes, len); + serial_write (device, &csum, sizeof (csum)); + #ifdef WIN32 + serial_sleep (device, 10); + #endif + + nbytes += len; + } + } + } +} + + +#define SKIPNULL 1 + + +static void +simulation_atom2 (serial_t *device, unsigned char data[], unsigned int size, const unsigned char id[]) +{ + unsigned char command[22] = {0}, checksum = 0; + unsigned short checksum16 = 0; + unsigned int csize = 0, address = 0; + + const unsigned char nak = 0xA5, ack = 0x5A; + const double probability = 0;//0.05; + + unsigned char unknown[3] = {0x5A, 0x04, 0xD6}; + unsigned char handshake[3] = {nak, nak, nak}; + unsigned char quit[1] = {nak}; + + unsigned char version[17] = {0}; + memcpy (version, id, 16); + version[16] = checksum_add_uint8 (version, 16, 0x00); +/* + unsigned char dummy[16] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + dc_buffer_t *buffer = dc_buffer_new (0); + dc_buffer_append (buffer, id, 16); + dc_buffer_append (buffer, data, size); + if (size % 0x8000 == 0x8000 - 0x10) + dc_buffer_append (buffer, dummy, sizeof (dummy)); +*/ + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0xA8: // Handshake (A8 99 00) + csize = 3 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("handshake()=%02x %02x %02x\n", command[0], command[1], command[2]); + serial_write (device, handshake, sizeof (handshake)); + break; + case 0x84: // Version (84 00) + csize = 2 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("version()=%02x %02x\n", command[0], command[1]); + if (error (probability)) { + message ("nak()\n"); + serial_write (device, &nak, 1); + } else { + serial_write (device, &ack, 1); + serial_write (device, version, sizeof (version)); + } + break; + case 0xBA: + csize = 2 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("unknown()=%02x %02x\n", command[0], command[1]); + serial_write (device, unknown, sizeof (unknown)); + break; + case 0xB1: // Read (B1 HI LO 00) + //case 0xB4: // Read (B4 HI LO 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("read(%04x,1)=%02x %02x %02x %02x\n", address, command[0], command[1], command[2], command[3]); + if (16 * (address + 1)> size) { + message ("Overflow detected, ignoring command!\n"); + break; + } + if (command[0] == 0xB1) + checksum = checksum_add_uint8 (data + 16 * address, 16, 0x00); + else + checksum = checksum_add_uint8 (data + 16 * address, 128, 0x00); + if (error (probability)) { + message ("nak()\n"); + serial_write (device, &nak, 1); + } else { + serial_write (device, &ack, 1); + if (command[0] == 0xB1) + serial_write (device, data + 16 * address, 16); + else + serial_write (device, data + 16 * address, 128); + serial_write (device, &checksum, 1); + } + break; + case 0xB4: // Read (B4 HI LO 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("read(%04x,8)=%02x %02x %02x %02x\n", address, command[0], command[1], command[2], command[3]); + checksum = checksum_add_uint8 (data + 16 * address, 128, 0x00); + serial_write (device, &ack, 1); + //serial_write (device, data + 16 * address, 128); + //serial_write (device, &checksum, 1); + { + unsigned char tmp[128 + 1]; + memcpy (tmp, data + 16 * address, 128); + memcpy (tmp + 128, &checksum, 1); + serial_write (device, tmp, sizeof (tmp)); + } + break; + case 0xB8: // Read (B8 HI LO 00) - return 256 bytes with 2 byte crc + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("read(%04x,16)=%02x %02x %02x %02x\n", address, command[0], command[1], command[2], command[3]); + checksum16 = checksum_add_uint16 (data + 16 * address, 256, 0x00); + serial_write (device, &ack, 1); + { + unsigned char tmp[256 + 2]; + memcpy (tmp, data + 16 * address, 256); + memcpy (tmp + 256, &checksum16, 2); + serial_write (device, tmp, sizeof (tmp)); + } + break; + case 0xB2: // Write (22+2) + /*csize = 22; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("write(%04x)\n", address); + memcpy (data + address, command + 4, 16); + serial_write (device, &ack, 1); + serial_write (device, &ack, 1);*/ + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("prepare_write(%04x)\n", address); + #if SKIPNULL + if (serial_get_received(device) == 1) { + serial_read (device, command + 1 + csize - 1, 1); + } + #endif + serial_write (device, &ack, 1); + csize = 18 - SKIPNULL; + serial_read (device, command + 4, csize); + message ("write(%04x)\n", address); + memcpy (data + 16 * address, command + 4, 16); + serial_write (device, &ack, 1); + message ("command="); + for (unsigned int i = 0; i < 22; ++i) + message ("%02x ", command[i]); + message ("\n"); + break; + case 0x6A: // Quit (6A 05 A5 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("quit()=%02x %02x %02x %02x\n", command[0], command[1], command[2], command[3]); + serial_write (device, quit, sizeof (quit)); + break; + case 0x91: // Keepalive (91 05 A5 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("keepalive()=%02x %02x %02x %02x\n", command[0], command[1], command[2], command[3]); + serial_write (device, &ack, 1); + break; + default: + if (!SKIPNULL || command[0] != 0x00) + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + +static void +simulation_veo250 (serial_t *device, unsigned char data[], unsigned int size, const unsigned char version[], unsigned int vsize) +{ + unsigned char command[22] = {0}, checksum = 0; + unsigned int csize = 0, address = 0, first = 0, last = 0; + + //const unsigned char garbage[3] = {0xFF, 0xFF, 0xFF}; + + const unsigned char nak = 0xA5, ack = 0x5A; + //const double probability = 0;//0.05; + + const unsigned char init[14] = { + 0x50, 0x50, 0x53, 0x2D, 0x2D, 0x4F, 0x4B, + 0x5F, 0x56, 0x32, 0x2E, 0x30, 0x30, 0x00}; + const unsigned char quit[3] = {0x5A, 0xA5, 0xA5}; + + + unsigned int answer = 0; + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0x55: // Init (55 00) + csize = 2; + serial_read (device, command + 1, csize - 1); + message ("init()\n"); + serial_write (device, init, sizeof (init)); + break; + case 0x98: // Quit (98 00) + csize = 2; + serial_read (device, command + 1, csize - 1); + message ("quit()\n"); + break; + case 0x90: // Version (90 00) + csize = 2; + serial_read (device, command + 1, csize - 1); + message ("version()\n"); + /*if (error (probability)) { + message ("nak()\n"); + serial_write (device, &nak, 1); + } else { + serial_write (device, &ack, 1); + serial_write (device, version, sizeof (version)); + }*/ + //serial_write (device, &garbage, 1); + serial_write (device, &ack, 1); + serial_write (device, version, vsize); + checksum = checksum_add_uint8 (version, vsize, 0x00); + serial_write (device, &checksum, 1); + serial_write (device, &nak, 1); + break; + case 0x20: // Read (6+19) TODO + #if WIN32 + csize = 5; + #else + csize = 6; + #endif + serial_read (device, command + 1, csize - 1); + address = command[2] + (command[1] << 8); + first = command[1] + (command[2] << 8); + last = command[3] + (command[4] << 8); + message ("read(%04x,%04x,%u)=%02x %02x %02x %02x %02x %02x\n", first, last, last - first + 1, + command[0], command[1], command[2], command[3], command[4], command[5]); + if (first> last) { + message ("Bogus command ignored!\n"); + continue; + } + + answer = myrandom (20); + + switch (answer) { + /*case 0: // TIMEOUT + message ("ERROR: Timeout\n"); + break; + case 1: // NAK + message ("ERROR: NAK\n"); + serial_write (device, &nak, 1); + break; + case 2: // GARBAGE + message ("ERROR: Garbage\n"); + serial_write (device, garbage, sizeof (garbage)); + break;*/ + /*case 3: // WRONG PAGE + first += 1; + last += 2; + message ("Wrong page (%04x, %04x)\n", first, last);*/ + default: // ACK + DATA + serial_write (device, &ack, 1); + for (unsigned int i = 0; i < last - first + 1; ++i) { + checksum = checksum_add_uint8 (data + 16 * (first + i), 16, 0x00); + serial_write (device, data + 16 * (first + i), 16); + serial_write (device, &checksum, 1); + //serial_write (device, garbage, 1); + } + serial_write (device, &nak, 1); + break; + } + +#if 0 + csize = 6; + serial_read (device, command + 1, csize - 1); + address = command[1] + (command[2] << 8); + message ("read(%04x)\n", address); + /*checksum = checksum_add_uint8 (data + 16 * address, 16, 0x00); + if (error (probability)) { + message ("nak()\n"); + serial_write (device, &nak, 1); + } else { + serial_write (device, &ack, 1); + serial_write (device, data + 16 * address, 16); + serial_write (device, &checksum, 1); + }*/ + //serial_write (device, version, sizeof (version)); + + checksum = checksum_add_uint8 (data + 16 * address, 16, 0x00); + if (answer) { + serial_write (device, &ack, 1); + serial_write (device, data + 16 * address, 16); + serial_write (device, &checksum, 1); + serial_write (device, &nak, 1); + answer = 0; + } else { + //message ("multi\n"); + serial_write (device, &ack, 1); + //for (unsigned int i = 0; i < 5; ++i) { + serial_write (device, data + 16 * address, 16); + serial_write (device, &checksum, 1); + //} + serial_write (device, &nak, 1); + answer = 1; + } +#endif + break; +#if 0 + case 0xB2: // Write (22+2) + /*csize = 22; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("write(%04x)\n", address); + memcpy (data + address, command + 4, 16); + serial_write (device, &ack, 1); + serial_write (device, &ack, 1);*/ + csize = 4; + serial_read (device, command + 1, csize - 1); + address = (command[1] << 8) + command[2]; + message ("prepare_write(%04x)\n", address); + serial_write (device, &nak, 1); + csize = 18; + serial_read (device, command + 4, csize); + message ("write(%04x)\n", address); + memcpy (data + 16 * address, command + 4, 16); + serial_write (device, &ack, 1); + message ("command="); + for (unsigned int i = 0; i < 22; ++i) + message ("%02x ", command[i]); + message ("\n"); + break; +#endif + case 0x91: // Keepalive (4+3) + csize = 4; + serial_read (device, command + 1, csize - 1); + message ("keepalive()\n"); + serial_write (device, quit, sizeof (quit)); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + + +static void +simulation_vtpro (serial_t *device, unsigned char data[], unsigned int size, const unsigned char version[], dc_buffer_t *logbook) +{ + unsigned char command[22] = {0}, checksum = 0; + unsigned int csize = 0, address = 0, first = 0, last = 0; + + const unsigned char ack = 0x5A, /*nak = 0xA5,*/ end = 0x51;//, garbage = 0xFF; + +/* +AA 00 (init?) +6A 05 A5 00 (quit?) +88 00 (handshake?) +72 03 00 00 (version deel 1?) +72 03 10 00 (version deel 2?) +18 00 (?) +6A 08 00 00 (keepalive?) +34 HI LO HI LO 00 +*/ + + const unsigned char init_mod[] = { + 0x4D, 0x4F, 0x44, 0x2D, 0x2D, 0x4F, 0x4B, + 0x5F, 0x56, 0x32, 0x2E, 0x30, 0x30}; + const unsigned char init_intr[] = { + 0x49, 0x4E, 0x54, 0x52, 0x2D, 0x4F, 0x4B, + 0x5F, 0x56, 0x31, 0x2E, 0x31, 0x31}; + const unsigned char calibrate[] = {0x5A, 0x26, 0x00}; + //const unsigned char calibrate_garbage[] = {0xff, 0xff, 0xff}; + const unsigned char keepalive[] = {0x5A, 0x51}; + const unsigned char unknown2[] = {0x02}; + const unsigned char empty[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + //unsigned int answer = 0; + + for (;;) { + serial_read (device, command, 1); + switch (command[0]) { + case 0xAA: // Init (AA 00) + case 0x20: // Init (20 00) + csize = 2 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("init(0x%02x)\n", command[0]); + if (command[0] == 0xAA) { + serial_write (device, init_mod, sizeof (init_mod)); + } else { + serial_write (device, init_intr, sizeof (init_intr)); + } + break; + case 0x6A: // Quit (6A 05 A5 00) + Keepalive (6A 08 00 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + if (command[1] == 0x05) { + message ("quit()\n"); + } else { + message ("keepalive()\n"); + } + serial_write (device, keepalive, sizeof (keepalive)); + break; + case 0x88: // Version 0 (88 00) + csize = 2 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("version(0)\n"); + checksum = checksum_add_uint4 (version, 8, 0x00); + serial_write (device, &ack, 1); + serial_write (device, version, 8); + serial_write (device, &checksum, 1); + break; + case 0x72: // Version 1 (72 03 00 00) + Version 2 (72 03 10 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + if (command[2] == 0x00) { + message ("version(1)\n"); + checksum = checksum_add_uint4 (version, 8, 0x00); + serial_write (device, &ack, 1); + serial_write (device, version, 8); + serial_write (device, &checksum, 1); + serial_write (device, &end, 1); + } else { + message ("version(2)\n"); + checksum = checksum_add_uint4 (version + 8, 8, 0x00); + serial_write (device, &ack, 1); + serial_write (device, version + 8, 8); + serial_write (device, &checksum, 1); + serial_write (device, &end, 1); + } + break; + case 0x18: // Calibrate (18 00) + csize = 2 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + message ("calibrate()\n"); + //serial_sleep (device, 6000); + serial_write (device, calibrate, sizeof (calibrate)); + break; + case 0x34: // Read (34 HI LO HI LO 00) + csize = 6 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = command[2] + (command[1] << 8); + first = command[2] + (command[1] << 8); + last = command[4] + (command[3] << 8); + //message ("read(%04x)\n", address); + /*message ("read(%04x)=%02x %02x %02x %02x %02x %02x\n", address, + command[0], command[1], command[2], command[3], command[4], command[5]);*/ + message ("read(%04x,%04x,%u)=%02x %02x %02x %02x %02x %02x\n", first, last, last - first + 1, + command[0], command[1], command[2], command[3], command[4], command[5]); + if (first> last || last - first + 1> 32) { + message ("Bogus command ignored!\n"); + continue; + } + serial_write (device, &ack, 1); + for (unsigned int i = 0; i < last - first + 1; ++i) { + checksum = checksum_add_uint8 (data + 16 * (first + i), 16, 0x00); + serial_write (device, data + 16 * (first + i), 16); + serial_write (device, &checksum, 1); + } + break; + case 0x52: // Read table index (52 XX XX 00) + csize = 4 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = command[2] + (command[1] << 8); + message ("read table index(%04x)=%02x %02x %02x\n", address, + command[0], command[1], command[2]); + serial_write (device, &ack, 1); + for (unsigned int i = 0; i < address + 1; ++i) { + if ((i+1) * 8> dc_buffer_get_size(logbook)) { + checksum = checksum_add_uint4 (empty, 8, 0x00); + serial_write (device, empty, 8); + } else { + const unsigned char *p = dc_buffer_get_data(logbook); + checksum = checksum_add_uint4 (p + i * 8, 8, 0x00); + serial_write (device, p + i * 8, 8); + } + serial_write (device, &checksum, 1); + } + break; + case 0x48: // Unknown (48 00) + csize = 2 - SKIPNULL; + serial_read (device, command + 1, csize - 1); + address = command[2] + (command[1] << 8); + message ("unknown()=%02x\n", + command[0]); + serial_write (device, &ack, 1); + serial_write (device, unknown2, sizeof(unknown2)); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + +static void +simulation_seiko (serial_t *device, unsigned char data[], unsigned int size, unsigned char version[]) +{ + const unsigned char trailer = 0x45; + + unsigned char command[3]; + unsigned int csize, address; + + unsigned char id = 0x08; + if (version) { + id = version[0]; + } + + for (;;) { + serial_read (device, command, 1); + serial_write (device, command, 1); + + switch (command[0]) { + case 0x41: + csize = 3; + for (unsigned int i = 1; i < csize; ++i) { + serial_read (device, command + i, 1); + serial_write (device, command + i, 1); + } + message ("0x%02x %02x %02x\n", command[0], command[1], command[2]); + serial_write (device, command, csize); + break; + case 0x44: + csize = 1; + message ("0x%02x\n", command[0]); + serial_write (device, &id, 1); + break; + case 0x0C: + csize = 1; + message ("0x%02x\n", command[0]); + serial_write (device, &trailer, 1); + break; + case 0x52: + csize = 3; + for (unsigned int i = 1; i < csize; ++i) { + serial_read (device, command + i, 1); + serial_write (device, command + i, 1); + } + address = (command[1] << 8) + command[2]; + message ("read(%04x, %u, %u)\n", address, 128, (address * 32) % 128); + serial_write (device, data + address * 32, 128); + serial_write (device, &trailer, 1); + break; + case 0x46: + csize = 1; + message ("0x%02x\n", command[0]); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + +static void +simulation_zeagle (serial_t *device, unsigned char data[], unsigned int size) +{ + const unsigned char header= 0x02, trailer = 0x03, cmd = 0x4D; + + const unsigned char id[] = {0x02, 0x08, 0x00, + 0x41, 0x44, 0x31, 0x31, 0x31, 0x30, 0x33, 0x30, + 0x55, 0x03}; + + unsigned char command[13], length[2], checksum; + unsigned int csize, address, count; +/* +W: 02 08 00 4D 60 61 40 00 00 00 00 B2 03 +R: 08 00 4D 60 61 40 00 00 00 00 B2 03 +R: 02 41 00 4D FF(64) F3 03 + +PACKET := 02 SIZE(2) DATA(SIZE) CRC 03 +CRC := ~SUM8(DATA) + 1 (Two's complement) + +READ_CMD := TYPE ADDR(2) NBYTES(2) 00 00 00 +READ_ANS := TYPE DATA(64) +*/ + for (;;) { + serial_read (device, command, 1); + if (command[0] != 0x02) { + message ("Unknown packet header (%02x)\n", command[0]); + continue; + } + serial_read (device, command + 1, 2); + csize = array_uint16_le (command + 1) + 5; + serial_read (device, command + 3, csize - 3); + //debug (command, csize); + + switch (command[3]) { + case 0x41: + message ("init()\n"); + serial_write (device, command, csize); + serial_write (device, id, sizeof (id)); + break; + case 0x4D: + address = array_uint16_le (command + 4); + count = array_uint16_le (command + 6); + message ("read(%04x, %u)\n", address, count); + length[0] = ((count + 1) ) & 0xFF; + length[1] = ((count + 1)>> 8) & 0xFF; + checksum = ~checksum_add_uint8 (data + address, count, cmd) + 1; + serial_write (device, command, csize); + serial_write (device, &header, 1); + serial_write (device, length, sizeof (length)); + serial_write (device, &cmd, 1); + serial_write (device, data + address, count); + serial_write (device, &checksum, 1); + serial_write (device, &trailer, 1); + break; + default: + message ("Unknown command 0x%02x\n", command[0]); + break; + } + } +} + +/* SLIP special character codes */ +#define END 0xC0 /* indicates end of packet */ +#define ESC 0xDB /* indicates byte stuffing */ +#define ESC_END 0xDC /* ESC ESC_END means END data byte */ +#define ESC_ESC 0xDD /* ESC ESC_ESC means ESC data byte */ + +static int +shearwater_predator_slip_write (serial_t *device, const unsigned char data[], unsigned int size) +{ + int n = 0; + const unsigned char end[] = {END}; + const unsigned char esc_end[] = {ESC, ESC_END}; + const unsigned char esc_esc[] = {ESC, ESC_ESC}; + + /* Send an initial END character to flush out any data that may have + accumulated in the receiver due to line noise. */ +#if 0 + n = serial_write (device, end, sizeof (end)); + if (n != sizeof (end)) { + return -1; + } +#endif + + /* For each byte in the packet, send the appropriate character sequence. */ + for (unsigned int i = 0; i < size; ++i) { + const unsigned char *seq = NULL; + unsigned int len = 0; + switch(data[i]) { + case END: + /* If it's the same code as an END character, we send a special two + character code so as not to make the receiver think we sent an + END. */ + seq = esc_end; + len = sizeof (esc_end); + break; + case ESC: + /* If it's the same code as an ESC character, we send a special two + character code so as not to make the receiver think we sent an + ESC. */ + seq = esc_esc; + len = sizeof (esc_esc); + break; + default: + /* Otherwise, we just send the character. */ + seq = data + i; + len = 1; + break; + } + + n = serial_write (device, seq, len); + if (n != len) { + return -1; + } + } + + /* Tell the receiver that we're done sending the packet. */ + n = serial_write (device, end, sizeof (end)); + if (n != sizeof (end)) { + return -1; + } + + return size; +} + + +static int +shearwater_predator_slip_read (serial_t *device, unsigned char data[], unsigned int size) +{ + unsigned int received = 0; + + /* Sit in a loop reading bytes until we put together a whole packet. + Make sure not to copy them into the packet if we run out of room. */ + while (1) { + unsigned char c = 0; + int n = 0; + + /* Get a character to process. */ + n = serial_read (device, &c, 1); + if (n != 1) { + return -1; + } + + /* Handle byte stuffing if necessary. */ + switch (c) { + case END: + /* If it's an END character then we're done with the packet. */ + /* A minor optimization: if there is no data in the packet, ignore + it. This is meant to avoid bothering IP with all the empty + packets generated by the * duplicate END characters which are in + turn sent to try to detect line noise. */ + if (received) + return received; + else + break; + case ESC: + /* If it's the same code as an ESC character, wait and get another + character and then figure out what to store in the packet based + on that. */ + n = serial_read (device, &c, 1); + if (n != 1) { + return -1; + } + + /* If it's not one of these two, then we have a protocol violation. + The best bet seems to be to leave the byte alone and just stuff + it into the packet. */ + switch (c) { + case ESC_END: + c = END; + break; + case ESC_ESC: + c = ESC; + break; + } + /* Fall-through */ + default: + if (received < size) + data[received] = c; + received++; + } + } + + return received; +} + +static void +simulation_predator (serial_t *device, unsigned char data[], unsigned int size) +{ + unsigned char req_init[] = { + 0x35, 0x00, 0x34, + 0xDD, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x80}; + unsigned char req_block[] = {0x36, 0x00}; + unsigned char req_quit[] = {0x37}; + + unsigned char resp_init[] = { 0x75, 0x10, 0x82 }; + unsigned char resp_block[] = { 0x76, 0 }; // index 1 = block index, index 2+ = divelog data + unsigned char resp_quit[] = { 0x77, 0x00 }; + + unsigned char *pred_buf = data; + unsigned int pred_len = size; + + unsigned char *manifest_buf = data; + unsigned int manifest_len = 0x600; + + unsigned char *dive_buf = data + 0x600; + unsigned int dive_len = size - 0x600; + + unsigned int blocksize = 0x82; + unsigned int nbytes = 0; + unsigned char block = 1; + + for (;;) { + unsigned char packet[254 + 4]; + unsigned char response[254 + 4]; + int n = shearwater_predator_slip_read (device, packet, sizeof (packet)); + if (n < 4 || packet[0] != 0xFF || packet[1] != 0x01 || packet[3] != 0x00) { + message ("Invalid packet.\n"); + continue; + } + debug (packet, n); + n -= 4; + //message ("n=%u.\n", n); + + response[0] = 0x01; + response[1] = 0xFF; + response[2] = 0x00; + response[3] = 0x00; + + if (n == sizeof (req_init) && packet[4] == req_init[0]/*memcmp (packet + 4, req_init, sizeof (req_init)) == 0*/) { + unsigned char *p = packet + 4; + unsigned int compression = p[1]; + unsigned int address = (p[3] << 24) + (p[4] << 16) + (p[5] << 8) + p[6]; + unsigned int length = (p[7] << 16) + (p[8] << 8) + p[9]; + + message ("address=%08x, size=%06x, compression=%02x\n", address, length, compression); + + if (address == 0xDD000000 && length == 0x020080 && compression == 0x00) { + message ("Logbook command.\n"); + data = pred_buf; + size = pred_len; + blocksize = 0x82; + } else if (address == 0xE0000000 && length == 0x600 && compression == 0x00) { + message ("Manifest command.\n"); + data = manifest_buf; + size = manifest_len; + blocksize = 0x82; + } else if (address & 0xC0000000 && length == 0xFFFFFF && compression == 0x10) { + message ("Dive command.\n"); + data = dive_buf; + size = dive_len; + blocksize = 0x92; + } else { + message ("ERROR!\n"); + continue; + } + + response[2] = sizeof (resp_init) + 1; + memcpy (response + 4, resp_init, sizeof (resp_init)); + shearwater_predator_slip_write (device, response, sizeof (resp_init) + 4); + + block = 1; + nbytes = 0; + } else if (n == sizeof (req_block) && memcmp (packet + 4, req_block, sizeof (req_block) - 1) == 0) { + message ("Block command.\n"); + + unsigned int len = blocksize - sizeof (resp_block); + if (nbytes + len> size) { + len = size - nbytes; + } + //message ("len=%u, size=%u\n", len, size); + if (len == 0) { + message ("Zero length!\n"); + continue; + } + + resp_block[1] = block; + response[2] = sizeof (resp_block) + 1 + len; + memcpy (response + 4, resp_block, sizeof (resp_block)); + memcpy (response + 4 + sizeof (resp_block), data + nbytes, len); + shearwater_predator_slip_write (device, response, sizeof (resp_block) + 4 + len); + + block++; + nbytes += len; + } else if (n == sizeof (req_quit) && memcmp (packet + 4, req_quit, sizeof (req_quit)) == 0) { + message ("Quit command.\n"); + response[2] = sizeof (resp_quit) + 1; + memcpy (response + 4, resp_quit, sizeof (resp_quit)); + shearwater_predator_slip_write (device, response, sizeof (resp_quit) + 4); + + block = 1; + nbytes = 0; + } else { + message ("Unknown command.\n"); + } + } +} + +static void +simulation_leonardo (serial_t *device, unsigned char data[], unsigned int size) +{ + + const unsigned char req_dump[] = "{123DBA}"; + const unsigned char resp_dump[] = "{!D5B3}"; + + serial_set_rts(device, 1); + serial_set_dtr(device, 0); + + unsigned char csum_raw[2], csum_ascii[4]; + unsigned int csum = checksum_crc_ccitt_uint16 (data, size); + csum_raw[0] = (csum>> 8) & 0xFF; + csum_raw[1] = (csum ) & 0xFF; + mares_puck_convert_binary_to_ascii (csum_raw, sizeof (csum_raw), csum_ascii, sizeof (csum_ascii)); + + dc_buffer_t *buffer = dc_buffer_new(0); + + for (;;) { + + unsigned char command[20] = {0}; + + unsigned int header = 0, i = 0; + for (;;) { + unsigned char c = 0; + serial_read (device, &c, 1); + + command[i] = c; + + if (c == '{') { + header = 1; + i = 1; + } else if (header) { + i++; + if (c == '}') + break; + } else { + break; + } + } + + debug (command, i); + + if (i < 6 || (i % 2) != 0) { + message ("Ignoring %u bytes.\n", i); + continue; + } + + unsigned char raw[sizeof (command)] = {0}; + mares_puck_convert_ascii_to_binary (command + 1, i - 2, raw, (i - 2) / 2); + + if (i == 8 && memcmp (command, req_dump, sizeof (req_dump) - 1) == 0) { + message ("Dump\n"); + serial_write (device, resp_dump, sizeof (resp_dump) - 1); + unsigned int nbytes = 0; + while (nbytes < size) { + unsigned int len = size - nbytes; + if (len> 4096) + len = 4096; + serial_write (device, data + nbytes, len); +#ifdef _WIN32 + serial_sleep (device, 10); /* Cressi application needs this. */ +#endif + nbytes += len; + } + //serial_write (device, data, size); + serial_write (device, csum_ascii, sizeof (csum_ascii)); + } else if (i == 14) { + unsigned int address = array_uint16_be (raw + 0); + unsigned int length = array_uint16_be (raw + 2); + message ("Read(%04x,%u)\n", address, length); + + dc_buffer_resize(buffer, 1 + length * 2 + 4 + 1); + unsigned char *packet = dc_buffer_get_data(buffer); + packet[0] = '{'; + mares_puck_convert_binary_to_ascii(data + address - 0x1000, length, packet + 1, length * 2); + unsigned int csum = checksum_crc_ccitt_uint16 (packet + 1, length * 2); + csum_raw[0] = (csum>> 8) & 0xFF; + csum_raw[1] = (csum ) & 0xFF; + mares_puck_convert_binary_to_ascii (csum_raw, sizeof (csum_raw), packet + 1 + length * 2, 4); + packet[1 + length * 2 + 4] = '}'; + serial_write (device, packet, dc_buffer_get_size(buffer)); + } else { + message ("Unknown\n"); + } + + } +} + + +static void +simulation_nitekq (serial_t *device, unsigned char data[], unsigned int size, unsigned char version[]) +{ + + const unsigned char header[32] = {0}; + const unsigned char csum[2] = {0}; + + const unsigned int blocksize = 256; + unsigned int address = 0; + unsigned int block = 0; + + for (;;) { + unsigned char c = 0; + serial_read (device, &c, 1); + message ("Command: %02x \'%c\'\n", c, c); + + switch (c) { + case 'H': + if (version) + serial_write (device, version, sizeof(header)); + else + serial_write (device, header, sizeof(header)); + break; + case 'D': + break; + case 'R': + address = 0; + block = 0; + break; + case 'U': + serial_write (device, data, blocksize); + serial_write (device, csum, sizeof(csum)); + break; + case 'B': + message ("Block: %u %04x\n", block, address); + serial_write (device, data + blocksize + address, blocksize); + serial_write (device, csum, sizeof(csum)); + address += blocksize; + block++; + break; + case '<': + serial_write (device, &c, 1); + break; + default: + message ("Unknown command (%02x).\n", c); + } + + + } + +} + +static void +simulation_hyperaqualand (serial_t *device, unsigned char data[], unsigned int size) +{ + const unsigned int blocksize = 32; + unsigned int address = 0; + unsigned int block = 0; + + //serial_set_timeout(device, 1000); + + for (;;) { + unsigned char c = 0; + int n = serial_read (device, &c, 1); + if (n < 1) { + message ("timeout\n"); + address = 0; + block = 0; + continue; + } + message ("Command: %02X\n", c); + + if (c == 0x7F || address + blocksize> size) { + message ("Block: reset\n"); + address = 0; + block = 0; + } else { + message ("Block: %u %04x\n", block, address); + serial_write (device, data + address, blocksize); + address += blocksize; + block++; + } + } + +} + +static void +simulation_idive (serial_t *device, unsigned char data[], unsigned int size, unsigned char version[], unsigned int model) +{ + const unsigned char id_idive[] = { + 0x02, 0x00, 0x6B, 0xFA, 0x32, 0x01, 0x65, 0x04, 0x00, 0x00 + }; + const unsigned char id_ix3m[] = { + 0x24, 0x00, 0x10, 0xD7, 0xC9, 0x01, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0x00, 0xE6, 0x59, 0x82, 0x0E, 0xE6, 0x59, 0x82, 0x0E + }; + unsigned char id[0xFF]; + unsigned char range[4]; + + if (version) { + model = array_uint16_le(version); + } + + message ("model=0x%02x\n", model); + + unsigned int idsize = 0x0A; + unsigned int headersize = 0x32; + unsigned int samplesize = 0x2A; + if (model>= 0x22 && model <= 0x25) { + idsize = 0x1A; + headersize = 0x36; + samplesize = 0x36; + } + + if (version) { + memcpy(id, version, idsize); + } + + unsigned char packet[0xFF + 4]; + unsigned int len = 0; + int n = 0; + + const unsigned char err[] = {0x60}; + unsigned int number = 0; + unsigned int offset = 0; + unsigned int nsamples = 0; + + unsigned int nbytes = 0; + unsigned int ndives = 0; + while (nbytes + headersize < size) { + unsigned int n = array_uint16_le (data + nbytes + 1); + + nbytes += headersize + n * samplesize; + ndives++; + } + + range[0] = 0x01; + range[1] = 0x00; + range[2] = (ndives ) & 0xFF; + range[3] = (ndives>> 8) & 0xFF; + + for (;;) { + n = serial_read (device, packet + 0, 1); + if (n != 1 || packet[0] != 0x55) { + continue; + } + + serial_read (device, packet + 1, 1); + len = packet[1]; + serial_read (device, packet + 2, len + 2); + + //message ("CMD: %02x\n", packet[2]); + unsigned char ack = 0x06; + + switch (packet[2]) { + case 0x10: // ID + case 0x11: // ID (iX3M) + message ("ID\n"); + len = idsize; + memcpy(packet + 3, id, sizeof(id)); + break; + case 0x98: // Range + case 0x78: // Range (iX3M) + message ("RANGE\n"); + if (ndives) { + len = sizeof(range); + memcpy(packet + 3, range, sizeof(range)); + } else { + len = 1; + packet[3] = 0x58; + ack = 0x15; + } + break; + case 0xA0: // Header + case 0x79: // Header (iX3M) + number = array_uint16_le(packet + 3); + message ("HEADER: %u\n", number); + if (number < 1 || number> ndives) { + len = 1; + packet[3] = 0x30; + ack = 0x15; + } else { + offset = 0; + for (unsigned int i = 0; i < ndives - number; ++i) { + unsigned int n = array_uint16_le (data + offset + 1); + offset += headersize + n * samplesize; + } + nsamples = array_uint16_le (data + offset + 1); + len = headersize; + memcpy(packet + 3, data + offset, len); + } + break; + case 0xA8: // Sample + case 0x7A: // Sample (iX3M) + number= array_uint16_le(packet + 3); + message ("SAMPLE: %u\n", number); + if (number < 1 || number> nsamples) { + len = 1; + packet[3] = 0x30; + ack = 0x15; + } else { + len = samplesize; + memcpy(packet + 3, data + offset + headersize + samplesize * (number - 1), len); + } + break; + default: + message ("UNKNOWN: %02x\n", packet[2]); + continue; + } + +#if 0 + if (error(0.05)) { + message ("NAK\n"); + len = 1; + packet[3] = 0x60; + ack = 0x15; + } +#endif + + packet[1] = len + 2; + packet[len + 3] = ack; + unsigned short crc = checksum_crc_ccitt_uint16 (packet, len + 4); + packet[len + 4] = (crc>> 8) & 0xFF; + packet[len + 5] = (crc ) & 0xFF; + serial_write (device, packet, len + 6); + } +} + +static void +simulation_cochran (serial_t *device, unsigned char data[], unsigned int size, unsigned char header[]) +{ + const unsigned int packetsize = 1024; + const unsigned char heartbeat[] = {0xAA}; + unsigned char id[67]; + unsigned char misc[1500]; + unsigned char config[4][512]; + + unsigned int bits = 32; + + unsigned char command[10]; + unsigned int csize = 0; + unsigned int address = 0; + unsigned int length = 0; + int n = 0; + + memset(id, 0xFF, sizeof(id)); + memset(misc, 0xFF, sizeof(misc)); + memset(config, 0xFF, sizeof(config)); + + if (header) { + unsigned int offset = 0; + memcpy(id, header + offset, sizeof(id)); + offset += sizeof(id); +#if 0 + memcpy(misc, header + offset, sizeof(misc)); + offset += sizeof(misc); + for (unsigned int i = 0; i < 4; ++i) { + memcpy(config[i], header + offset, sizeof(config[i])); + offset += sizeof(config[i]); + } +#else + for (unsigned int i = 0; i < 2; ++i) { + memcpy(config[i], header + offset, sizeof(config[i])); + offset += sizeof(config[i]); + } +#endif + } + + if (memcmp(id + 0x3B, "AM\x11""2212\x02", 8) == 0) { + bits = 24; + } + + for (;;) { + serial_set_timeout(device, 1000); + n = serial_read (device, command + 0, 1); + if (n != 1) { + message ("HEARTBEAT\n"); + serial_write (device, heartbeat, sizeof(heartbeat)); + continue; + } + serial_set_timeout(device, -1); + + switch (command[0]) { + case 0x05: // ID + csize = 6; + serial_read (device, command + 1, csize - 1); + message ("ID\n"); + serial_write (device, id, sizeof(id)); + break; + case 0x96: // Config + csize = 2; + serial_read (device, command + 1, csize - 1); + address = command[1]; + message ("CONFIG %u\n", address); + serial_write (device, config[address], sizeof(config[address])); + break; + case 0x89: // Misc + csize = 7; + serial_write (device, heartbeat, sizeof(heartbeat)); + serial_read (device, command + 1, csize - 1); + message ("MISC\n"); + serial_write (device, misc, sizeof(misc)); + break; + case 0x15: // Read + csize = 2 + 2 * (bits / 8); + serial_read (device, command + 1, csize - 1); + if (bits == 24) { + address = array_uint24_le(command + 1); + length = array_uint24_le(command + 4); + } else { + address = array_uint32_le(command + 1); + length = array_uint32_le(command + 5); + } + message ("READ(%08x,%u)\n", address, length); + + unsigned int nbytes = 0; + while (nbytes < length) { + unsigned int len = length - nbytes; + if (len> packetsize) + len = packetsize; + serial_write (device, data + address + nbytes, len); + nbytes += len; + } + break; + default: + message ("UNKNOWN: %02x\n", command[0]); + continue; + } + + + } +} + + +struct { + const char *name; + dc_family_t type; +} +static const g_backends[] = { + {"solution", DC_FAMILY_SUUNTO_SOLUTION}, + {"eon", DC_FAMILY_SUUNTO_EON}, + {"vyper", DC_FAMILY_SUUNTO_VYPER}, + {"vyper2", DC_FAMILY_SUUNTO_VYPER2}, + {"d9", DC_FAMILY_SUUNTO_D9}, + {"aladin", DC_FAMILY_UWATEC_ALADIN}, + {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE}, + {"smart", DC_FAMILY_UWATEC_SMART}, + {"meridian", DC_FAMILY_UWATEC_MERIDIAN}, + {"sensus", DC_FAMILY_REEFNET_SENSUS}, + {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO}, + {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA}, + {"vtpro", DC_FAMILY_OCEANIC_VTPRO}, + {"veo250", DC_FAMILY_OCEANIC_VEO250}, + {"atom2", DC_FAMILY_OCEANIC_ATOM2}, + {"nemo", DC_FAMILY_MARES_NEMO}, + {"puck", DC_FAMILY_MARES_PUCK}, + {"iconhd", DC_FAMILY_MARES_ICONHD}, + {"edy", DC_FAMILY_CRESSI_EDY}, + {"ostc", DC_FAMILY_HW_OSTC}, + {"ostc3", DC_FAMILY_HW_OSTC3}, + {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3}, + {"darwin", DC_FAMILY_MARES_DARWIN}, + {"predator", DC_FAMILY_SHEARWATER_PREDATOR}, + {"leonardo", DC_FAMILY_CRESSI_LEONARDO}, + {"nitekq", DC_FAMILY_DIVERITE_NITEKQ}, + {"aqualand", DC_FAMILY_CITIZEN_AQUALAND}, + {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, + {"cochran", DC_FAMILY_COCHRAN_COMMANDER}, +}; + +static dc_family_t +lookup (const char *name) +{ + unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); + for (unsigned int i = 0; i < nbackends; ++i) { + if (strcmp (name, g_backends[i].name) == 0) + return g_backends[i].type; + + } + + return DC_FAMILY_NULL; +} + +static void +usage (const char *filename) +{ + fprintf (stderr, "Usage:\n\n"); + fprintf (stderr, " %s [options] filename\n\n", filename); + fprintf (stderr, "Options:\n\n"); + fprintf (stderr, " -b backend Backend type (required)\n"); + fprintf (stderr, " -p devname Serial port (required, except for infrared)\n"); + fprintf (stderr, " -d devtime Device clock\n"); + fprintf (stderr, " -s systime System clock\n"); + fprintf (stderr, " -m model Model number\n"); + fprintf (stderr, " -l logfile Set logfile.\n\n"); + + fprintf (stderr, "Supported backends:\n\n"); + unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); + for (unsigned int i = 0; i < nbackends; ++i) { + fprintf (stderr, "%s", g_backends[i].name); + if (i != nbackends - 1) + fprintf (stderr, ", "); + else + fprintf (stderr, "\n\n"); + + } +} + + +static void +get_default_parameters (dc_family_t backend, unsigned int model, const char **filename, long *systime, long *devtime) +{ + switch (backend) { + case DC_FAMILY_SUUNTO_SOLUTION: + *filename = "../../suunto/data/filip/SOLUTION.DMP"; + break; + case DC_FAMILY_SUUNTO_EON: + *filename = "data/eon/nitrox.ebeaule.1.dives.bin"; + break; + case DC_FAMILY_SUUNTO_VYPER: + switch (model) { + case 0x01: // Spyder + *filename = "data/vyper/spyder.roli.bin"; + break; + default: + *filename = "data/vyper/vyper.stasia.bin"; + break; + }; + break; + case DC_FAMILY_SUUNTO_VYPER2: + *filename = "data/vyper2/cobra2.dusty.bin"; + break; + case DC_FAMILY_SUUNTO_D9: + *filename = "data/d9/d9.eric.1.bin"; + break; + case DC_FAMILY_UWATEC_ALADIN: + *filename = "data/aladin/aladin.harry.1.bin"; + break; + case DC_FAMILY_UWATEC_MEMOMOUSE: + *filename = "data/memomouse/memomouse.svp.1.bin"; + break; + case DC_FAMILY_UWATEC_SMART: + switch (model) { + case 0x11: // UWATEC Galileo Sol (peter) + *filename = "data/smart/galileo.peter.bin"; + *systime = 1207211639; + *devtime = 521154354; + break; + case 0x18: // Aladin Smart Tec (rob) + *filename = "data/smart/smarttec.rob.bin"; + *systime = 1209342465; + *devtime = 0x1f4fb2bf; + break; + case 0x1C: // Aladin Smart Z (sven) + *filename = "data/smart/smartz.sven.bin"; + *systime = 1213630630; + *devtime = 0x1fd28c06; + break; + default: + break; + }; + break; + case DC_FAMILY_REEFNET_SENSUS: + *filename = "data/sensus/sensus.steffenreith.bin"; + break; + case DC_FAMILY_REEFNET_SENSUSPRO: + *filename = "data/sensuspro/sensuspro.reefnet.bin"; + break; + case DC_FAMILY_REEFNET_SENSUSULTRA: + *filename = "data/sensusultra/sensusultra.reefnet.bin"; + break; + case DC_FAMILY_OCEANIC_VTPRO: + *filename = "data/vtpro/proplus2.gerbrand.1.bin"; + break; + case DC_FAMILY_OCEANIC_VEO250: + *filename = "data/veo250/veo250.jerry.1a.bin"; + break; + case DC_FAMILY_OCEANIC_ATOM2: + *filename = "data/atom2/atom2.michael.1a.bin"; + break; + case DC_FAMILY_MARES_NEMO: + *filename = "data/nemo/nemo.teemu.1.bin"; + break; + case DC_FAMILY_MARES_PUCK: + *filename = "data/puck/puck.tom.1.bin"; + break; + case DC_FAMILY_MARES_ICONHD: + *filename = "data/iconhd/iconhd.exposure.1.bin"; + break; + case DC_FAMILY_HW_OSTC: + *filename = "data/ostc/ostc.artur.01.bin"; + break; + case DC_FAMILY_CRESSI_EDY: + *filename = "data/edy/edy.gianpaolo.bin"; + break; + default: + break; + } +} + +static dc_buffer_t * +readfile (const char *filename) +{ + // Open the file for reading. + FILE *fp = fopen (filename, "rb"); + if (fp == NULL) + return NULL; + + // Allocate an empty buffer. + dc_buffer_t *buffer = dc_buffer_new (0); + + // Read the file contents. + while (!feof (fp)) { + unsigned char block[1024]; + size_t n = fread (block, 1, sizeof (block), fp); + + dc_buffer_append (buffer, block, n); + } + + // Close the file. + fclose (fp); + + return buffer; +} + +static dc_ticks_t +readtime (const char *filename) +{ + dc_ticks_t ticks = 0; + + // Open the file for reading. + FILE *fp = fopen (filename, "rb"); + if (fp == NULL) + return ticks; + + // Allocate an empty buffer. + unsigned char buffer[8] = {0}; + + // Read the file contents. + size_t n = fread (buffer, 1, sizeof (buffer), fp); + if (n != sizeof (buffer)) + return ticks; + + // Close the file. + fclose (fp); + + ticks += array_uint32_be (buffer); + ticks <<= 32; + ticks += array_uint32_be (buffer + 4); + + return ticks; +} + +int +main (int argc, char *argv[]) +{ + // Default values. + long systime = 0, devtime = 0; + unsigned int model = 0, serial = 0; + unsigned int realistic = 0; + const char *logfile = NULL; + const char *filename = NULL; + const char *devname = NULL; + dc_family_t backend = DC_FAMILY_NULL; + unsigned int delay = 0; + dc_loglevel_t loglevel = DC_LOGLEVEL_WARNING; + + // Parse command-line options. + int opt = 0; + while ((opt = getopt (argc, argv, "b:m:s:d:p:l:w:rvh")) != -1) { + switch (opt) { + case 'b': + backend = lookup (optarg); + break; + case 'm': + model = strtol (optarg, NULL, 0); + break; + case 's': + systime = strtol (optarg, NULL, 0); + break; + case 'd': + devtime = strtol (optarg, NULL, 0); + break; + case 'p': + devname = optarg; + break; + case 'l': + logfile = optarg; + break; + case 'w': + delay = strtol (optarg, NULL, 0); + break; + case 'r': + realistic = 1; + break; + case 'v': + loglevel++; + break; + case 'h': + usage (argv[0]); + return EXIT_SUCCESS; + default: + usage (argv[0]); + return EXIT_FAILURE; + } + } + + if (optind < argc) + filename = argv[optind]; + + if (backend == DC_FAMILY_NULL) { + usage (argv[0]); + return EXIT_FAILURE; + } + + if (filename == NULL) + get_default_parameters (backend, model, &filename, &systime, &devtime); + + message_set_logfile (logfile); + + message ("CONFIGURATION:\n"); + message ("backend=%u\n", backend); + message ("devname=%s\n", devname); + message ("devtime=%u\n", devtime); + message ("systime=%u\n", systime); + message ("model=%u\n", model); + message ("filename=%s\n", filename); + + // Read the input file. + + unsigned int size = MAXSIZE; + unsigned char *data = malloc (size * sizeof (unsigned char)); + memset (data, 0xFF, size); + + FILE *fp = fopen (filename, "rb"); + if (fp != NULL) { + size = fread (data, sizeof (unsigned char), size, fp); + fclose (fp); + } else { + message ("Failed to open the file.\n"); + return EXIT_FAILURE; + } + + message ("size=%u\n", size); + +if (backend == DC_FAMILY_REEFNET_SENSUSULTRA && + size < REEFNET_SENSUSULTRA_MEMORY_DATA_SIZE) +{ + message ("padding=%u\n", REEFNET_SENSUSULTRA_MEMORY_DATA_SIZE - size); + memmove (data + REEFNET_SENSUSULTRA_MEMORY_DATA_SIZE - size, data, size); + memset (data, 0xFF, REEFNET_SENSUSULTRA_MEMORY_DATA_SIZE - size); + size = REEFNET_SENSUSULTRA_MEMORY_DATA_SIZE; +} + + // Read the header file. + + char hdrfile[1024] = {0}; + snprintf (hdrfile, sizeof (hdrfile), "%s.header", filename); + dc_buffer_t *header = readfile (hdrfile); + message ("header=%s, size=%u\n", hdrfile, dc_buffer_get_size (header)); + + // Read the logbook file. + + char logbookfile[1024] = {0}; + snprintf (logbookfile, sizeof (logbookfile), "%s.logbook", filename); + dc_buffer_t *logbook = readfile (logbookfile); + message ("logbook=%s, size=%u\n", logbookfile, dc_buffer_get_size (logbook)); + + // Read the systime file. + + char systimefile[1024] = {0}; + snprintf (systimefile, sizeof (systimefile), "%s.systime", filename); + dc_ticks_t ticks = readtime (systimefile); + message ("systime=%s, ticks=%llu\n", systimefile, ticks); + if (ticks) systime = ticks; + + // Open the serial port. + + dc_context_t *context = NULL; + serial_t *device = NULL; + + dc_context_new(&context); + dc_context_set_loglevel(context, loglevel); + +if (backend != DC_FAMILY_UWATEC_SMART) { + int rc = serial_open (&device, context, devname); + if (rc == -1) { + //message("Error: %i (%s)\n", serial_errcode (), serial_errmsg ()); + return 1; + } + + serial_set_timeout (device, -1); + serial_set_halfduplex (device, realistic); + message ("lines=%u %u\n", serial_get_received (device), serial_get_transmitted (device)); + serial_flush (device, SERIAL_QUEUE_BOTH); + + switch (backend) { + case DC_FAMILY_CRESSI_EDY: + serial_configure (device, 1200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_SUUNTO_SOLUTION: + case DC_FAMILY_SUUNTO_EON: + serial_configure (device, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_SUUNTO_VYPER: + case DC_FAMILY_UWATEC_ALADIN: + serial_configure (device, 2400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_ZEAGLE_N2ITION3: + serial_configure (device, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_SUUNTO_VYPER2: + case DC_FAMILY_SUUNTO_D9: + case DC_FAMILY_UWATEC_MEMOMOUSE: + case DC_FAMILY_OCEANIC_VTPRO: + case DC_FAMILY_OCEANIC_VEO250: + case DC_FAMILY_MARES_NEMO: + case DC_FAMILY_MARES_DARWIN: + case DC_FAMILY_DIVERITE_NITEKQ: + serial_configure (device, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_COCHRAN_COMMANDER: + serial_configure (device, 9600, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_REEFNET_SENSUS: + case DC_FAMILY_REEFNET_SENSUSPRO: + serial_configure (device, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_OCEANIC_ATOM2: + case DC_FAMILY_MARES_PUCK: + serial_configure (device, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_UWATEC_MERIDIAN: + serial_configure (device, 57600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_REEFNET_SENSUSULTRA: + case DC_FAMILY_HW_OSTC: + case DC_FAMILY_HW_OSTC3: + case DC_FAMILY_SHEARWATER_PREDATOR: + case DC_FAMILY_CRESSI_LEONARDO: + case DC_FAMILY_DIVESYSTEM_IDIVE: + serial_configure (device, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + case DC_FAMILY_MARES_ICONHD: + serial_configure (device, 256000, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + break; + default: + break; + } +} + + if (delay) serial_sleep(device, delay); + + unsigned char *version = NULL; + unsigned char version_d9[4] = {0x0E, 0x01, 0x02, 0x0F}; + unsigned char version_d6[4] = {0x0F, 0x01, 0x00, 0x01}; + unsigned char version_v2[4] = {0x10, 0x01, 0x00, 0x04}; + unsigned char version_c2[4] = {0x11, 0x01, 0x00, 0x04}; + unsigned char version_d4[4] = {0x12, 0x01, 0x00, 0x01}; + unsigned char version_va[4] = {0x13, 0x01, 0x00, 0x01}; // Vyper Air + unsigned char version_c3[4] = {0x14, 0x01, 0x00, 0x01}; // Cobra 3 + unsigned char version_he[4] = {0x15, 0x01, 0x00, 0x04}; // HelO2 + + unsigned char version_geo[16] = {'O', 'C', 'E', ' ', 'G', 'E', 'O', ' ', 'R', '1', 'D', ' ', '5', '1', '2', 'K'}; + unsigned char version_vt3[16] = {'O', 'C', 'E', ' ', 'V', 'T', '3', ' ', 'R', '3', 'F', ' ', '5', '1', '2', 'K'}; + unsigned char version_datamask[16] = {'D', 'A', 'T', 'A', 'M', 'A', 'S', 'K', ' ', '2', 'B', ' ', '5', '1', '2', 'K'}; + unsigned char version_atom2[16] = {'2', 'M', ' ', 'A', 'T', 'O', 'M', ' ', 'r', '3', 'C', ' ', '5', '1', '2', 'K'}; + unsigned char version_veo200[16] = {'V', 'E', 'O', ' ', '2', '0', '0', ' ', 'R', '2', 'A', ' ', '2', '5', '6', 'K'}; + unsigned char version_veo250[16] = {'V', 'E', 'O', ' ', '2', '5', '0', ' ', 'R', '2', 'A', ' ', '2', '5', '6', 'K'}; + unsigned char version_veo180nx[16] = {0x56, 0x45, 0x4F, 0x20, 0x32, 0x35, 0x30, 0x20, 0x52, 0x32, 0x42, 0x20, 0x32, 0x35, 0x36, 0x4B}; + //unsigned char version_proplus2[16] = {0x50, 0x52, 0x4F, 0x50, 0x4C, 0x55, 0x53, 0x32, 0x20, 0x32, 0x41, 0x20, 0x32, 0x35, 0x36, 0x4B}; + unsigned char version_vtpro[16] = {0x56, 0x54, 0x50, 0x52, 0x4F, 0x20, 0x20, 0x72, 0x31, 0x41, 0x20, 0x20, 0x32, 0x35, 0x36, 0x4B}; + /*unsigned char version_atmosai[16] = {0x41, 0x54, 0x4D, 0x4F, 0x53, 0x41, 0x49, 0x52, 0x20, 0x32, 0x41, 0x20, 0x32, 0x35, 0x36, 0x4B}; + unsigned char version_f10[16] = {'F', 'R', 'E', 'E', 'W', 'A', 'E', 'R', ' ', '1', 'A', ' ', '5', '1', '2', 'K'}; + unsigned char version_oc1[16] = {'O', 'C', 'W', 'A', 'T', 'C', 'H', ' ', 'R', '1', 'A', ' ', '1', '0', '2', '4'}; + unsigned char version_geo2[16] = "OCEGEO20 1A 512K";*/ + unsigned char version_a300cs[16] = { 'A', 'E', 'R', '3', '0', '0', 'C', 'S', ' ', '1', 'F', ' ', '2', '0', '4', '8' }; + + // Run the simulation. + switch (backend) { + case DC_FAMILY_SUUNTO_SOLUTION: + simulation_solution (device, data, size); + break; + case DC_FAMILY_SUUNTO_EON: + simulation_eon (device, data, size); + break; + case DC_FAMILY_SUUNTO_VYPER: + simulation_vyper (device, data, size); + break; + case DC_FAMILY_SUUNTO_VYPER2: + switch (model) { + case 0x10: // Vyper 2 + version = version_v2; + break; + case 0x11: // Cobra 2 + version = version_c2; + break; + case 0x13: // Vyper Air + version = version_va; + break; + case 0x14: // Cobra 3 + version = version_c3; + break; + case 0x15: // Hel02 + version = version_he; + break; + default: + version = version_v2; + break; + } + if (dc_buffer_get_size (header) == 4) + version = dc_buffer_get_data (header); + simulation_vyper2_or_d9 (device, data, size, version, 1); + break; + case DC_FAMILY_SUUNTO_D9: + version = version_d9; + if (data[0x01] == 'D' && data[0x02] == '9') + version = version_d9; + else if (data[0x01] == 'D' && data[0x02] == '6') + version = version_d6; + else if (data[0x01] == 'D' && data[0x02] == '4') + version = version_d4; + if (dc_buffer_get_size (header) == 4) + version = dc_buffer_get_data (header); + simulation_vyper2_or_d9 (device, data, size, version, 0); + break; + case DC_FAMILY_UWATEC_ALADIN: + simulation_aladin (device, data, size, devtime, systime); + break; + case DC_FAMILY_UWATEC_MEMOMOUSE: + simulation_memomouse (device, data, size, devtime, systime); + break; + case DC_FAMILY_UWATEC_SMART: + if (dc_buffer_get_size (header) == 9) { + const unsigned char *hdr = dc_buffer_get_data (header); + model = hdr[0]; + serial = array_uint32_le (hdr + 1); + if (systime) + devtime = array_uint32_le (hdr + 5); + message ("model=0x%02x, serial=0x%08x, devtime=0x%08x\n", + model, serial, devtime); + } + simulation_smart (data, size, model, serial, devtime, systime); + break; + case DC_FAMILY_UWATEC_MERIDIAN: + if (dc_buffer_get_size (header) == 9) { + const unsigned char *hdr = dc_buffer_get_data (header); + model = hdr[0]; + serial = array_uint32_le (hdr + 1); + if (systime) + devtime = array_uint32_le (hdr + 5); + message ("model=0x%02x, serial=0x%08x, devtime=0x%08x\n", + model, serial, devtime); + } + simulation_meridian (device, data, size, model, serial, devtime, systime); + break; + case DC_FAMILY_REEFNET_SENSUS: + simulation_sensus (device, data, size, devtime, systime); + break; + case DC_FAMILY_REEFNET_SENSUSPRO: + version = NULL; + if (dc_buffer_get_size (header) == 10) + version = dc_buffer_get_data (header); + simulation_sensuspro (device, data, size, version, devtime, systime); + break; + case DC_FAMILY_REEFNET_SENSUSULTRA: + version = NULL; + if (dc_buffer_get_size (header) == 24) + version = dc_buffer_get_data (header); + simulation_sensusultra (device, data, size, version, devtime, systime); + break; + case DC_FAMILY_OCEANIC_VTPRO: + #if defined (PROPLUS2) + version = version_proplus2; + #else + version = version_vtpro; + //version = version_atmosai; + #endif + if (dc_buffer_get_size (header) == 16) + version = dc_buffer_get_data (header); + simulation_vtpro (device, data, size, version, logbook); + break; + case DC_FAMILY_OCEANIC_VEO250: + switch (model) { + case 250: // Veo 250 + version = version_veo250; + break; + case 200: // Veo 200 + version = version_veo200; + break; + case 180: // Veo 180 + version = version_veo180nx; + break; + default: + version = version_veo250; + break; + } + if (dc_buffer_get_size (header) == 16) + version = dc_buffer_get_data (header); + simulation_veo250 (device, data, size, version, 16); + break; + case DC_FAMILY_OCEANIC_ATOM2: + switch (model) { + case 0x4342: // Atom 2 + version = version_atom2; + break; + case 0x4256: // VT3 + case 0x4258: // VT3 + version = version_vt3; + break; + case 0x4344: // GEO + version = version_geo; + break; + case 0x4347: // Datamask + version = version_datamask; + break; + case 0x454C: // A300CS + version = version_a300cs; + break; + default: + version = version_atom2; + break; + } + if (dc_buffer_get_size (header) == 16) + version = dc_buffer_get_data (header); + simulation_atom2 (device, data, size, version); + break; + case DC_FAMILY_MARES_NEMO: + if (size == MARES_NEMO_MEMORY_SIZE) + simulation_nemo (device, data, size); + else + simulation_raw (device, data, size); + break; + case DC_FAMILY_MARES_PUCK: + simulation_puck (device, data, size, 0); + break; + case DC_FAMILY_MARES_DARWIN: + simulation_puck (device, data, size, 1); + break; + case DC_FAMILY_MARES_ICONHD: + if (dc_buffer_get_size (header) == 140) + version = dc_buffer_get_data (header); + simulation_iconhd (device, data, size, version); + break; + case DC_FAMILY_CRESSI_EDY: + if (dc_buffer_get_size (header) == 1) + version = dc_buffer_get_data (header); + simulation_seiko (device, data, size, version); + break; + case DC_FAMILY_HW_OSTC: + simulation_ostc (device, data, size); + break; + case DC_FAMILY_HW_OSTC3: + if (header == NULL) { + unsigned char hwid = model; + header = dc_buffer_new(1); + dc_buffer_append (header, &hwid, 1); + } + simulation_ostc3 (device, data, size, dc_buffer_get_data (header), dc_buffer_get_size (header)); + break; + case DC_FAMILY_ZEAGLE_N2ITION3: + simulation_zeagle (device, data, size); + break; + case DC_FAMILY_SHEARWATER_PREDATOR: + simulation_predator (device, data, size); + break; + case DC_FAMILY_CRESSI_LEONARDO: + simulation_leonardo (device, data, size); + break; + case DC_FAMILY_DIVERITE_NITEKQ: + version = NULL; + if (dc_buffer_get_size (header) == 32) + version = dc_buffer_get_data (header); + simulation_nitekq (device, data, size, version); + break; + case DC_FAMILY_CITIZEN_AQUALAND: + simulation_hyperaqualand (device, data, size); + break; + case DC_FAMILY_DIVESYSTEM_IDIVE: + version = dc_buffer_get_data (header); + simulation_idive (device, data, size, version, model); + break; + case DC_FAMILY_COCHRAN_COMMANDER: + version = dc_buffer_get_data (header); + simulation_cochran (device, data, size, version); + break; + default: + break; + } + + if (backend != DC_FAMILY_UWATEC_SMART) + serial_close (device); + + free (data); + dc_buffer_free (header); + dc_buffer_free (logbook); + + message_set_logfile (NULL); + + return EXIT_SUCCESS; +} diff --git a/examples/utils.c b/examples/utils.c index 9d0768f..d36a6d1 100644 --- a/examples/utils.c +++ b/examples/utils.c @@ -70,6 +70,7 @@ int message (const char* fmt, ...) va_start (ap, fmt); vfprintf (g_logfile, fmt, ap); va_end (ap); + fflush (g_logfile); } va_start (ap, fmt); diff --git a/src/Makefile.am b/src/Makefile.am index 1f52841..4cb258d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,8 +6,7 @@ lib_LTLIBRARIES = libdivecomputer.la libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) libdivecomputer_la_LDFLAGS = \ -version-info $(DC_VERSION_LIBTOOL) \ - -no-undefined \ - -export-symbols libdivecomputer.exp + -no-undefined libdivecomputer_la_SOURCES = \ version.c \ diff --git a/src/irda.c b/src/irda.c index b15d09f..55c5b93 100644 --- a/src/irda.c +++ b/src/irda.c @@ -362,6 +362,108 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa int +irda_socket_bind_name (irda_t *device, const char *name) +{ + if (device == NULL) + return -1; + +#ifdef _WIN32 + SOCKADDR_IRDA peer = {AF_IRDA, 0, 0, 0, 0, 0}; + peer.irdaAddressFamily = AF_IRDA; + if (name) + strncpy (peer.irdaServiceName, name, 25); + else + memset (peer.irdaServiceName, 0x00, 25); +#else + struct sockaddr_irda peer = {0}; + peer.sir_family = AF_IRDA; + peer.sir_lsap_sel = LSAP_ANY; + if (name) + strncpy (peer.sir_name, name, 25); + else + memset (peer.sir_name, 0x00, 25); +#endif + + if (bind (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { + SYSERROR (device->context, ERRNO); + return -1; + } + + return 0; +} + + +int +irda_socket_bind_lsap (irda_t *device, unsigned int lsap) +{ + if (device == NULL) + return -1; + +#ifdef _WIN32 + SOCKADDR_IRDA peer = {AF_IRDA, 0, 0, 0, 0, 0}; + peer.irdaAddressFamily = AF_IRDA; + snprintf (peer.irdaServiceName, 25, "LSAP-SEL%u", lsap); +#else + struct sockaddr_irda peer = {0}; + peer.sir_family = AF_IRDA; + peer.sir_lsap_sel = lsap; + memset (peer.sir_name, 0x00, 25); +#endif + + if (bind (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { + SYSERROR (device->context, ERRNO); + return -1; + } + + return 0; +} + + +int +irda_socket_listen (irda_t *device, int backlog) +{ + if (device == NULL) + return -1; + + if (listen (device->fd, backlog) != 0) { + SYSERROR (device->context, ERRNO); + return -1; + } + + return 0; +} + + +int +irda_socket_accept (irda_t *device) +{ +#ifdef _WIN32 + SOCKADDR_IRDA peer = {0}; + int size = sizeof (peer); +#else + struct sockaddr_irda peer = {0}; + socklen_t size = sizeof (peer); +#endif + + int rc = accept (device->fd, (struct sockaddr *) &peer, &size); + if (rc == -1) { + SYSERROR (device->context, ERRNO); + return -1; + } +/* +#ifdef _WIN32 + closesocket (device->fd); +#else + close (device->fd); +#endif +*/ + + device->fd = rc; + return 0; +} + + +int irda_socket_available (irda_t *device) { if (device == NULL) diff --git a/src/irda.h b/src/irda.h index d83037a..5f9f10c 100644 --- a/src/irda.h +++ b/src/irda.h @@ -45,6 +45,13 @@ int irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int int irda_socket_available (irda_t *device); +int irda_socket_bind_name (irda_t *device, const char *name); +int irda_socket_bind_lsap (irda_t *device, unsigned int lsap); + +int irda_socket_listen (irda_t *device, int backlog); + +int irda_socket_accept (irda_t *device); + int irda_socket_read (irda_t *device, void *data, unsigned int size); int irda_socket_write (irda_t *device, const void *data, unsigned int size); diff --git a/src/irda_dummy.c b/src/irda_dummy.c index 504aee8..c69d125 100644 --- a/src/irda_dummy.c +++ b/src/irda_dummy.c @@ -67,6 +67,34 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa int +irda_socket_bind_name (irda_t *device, const char *name) +{ + return -1; +} + + +int +irda_socket_bind_lsap (irda_t *device, unsigned int lsap) +{ + return -1; +} + + +int +irda_socket_listen (irda_t *device, int backlog) +{ + return -1; +} + + +int +irda_socket_accept (irda_t *device) +{ + return -1; +} + + +int irda_socket_available (irda_t *device) { return -1; diff --git a/src/serial.h b/src/serial.h index 5a9d8ea..4b0c1e2 100644 --- a/src/serial.h +++ b/src/serial.h @@ -111,6 +111,8 @@ int serial_get_transmitted (serial_t *device); int serial_get_line (serial_t *device, int line); +int serial_wait_break (serial_t *device); + int serial_sleep (serial_t *device, unsigned long timeout /* milliseconds */); #ifdef __cplusplus diff --git a/src/serial_posix.c b/src/serial_posix.c index 2b0c3fa..125c809 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -874,6 +874,15 @@ serial_get_line (serial_t *device, int line) return 0; } +int +serial_wait_break (serial_t *device) +{ + if (device == NULL) + return -1; + + return 0; +} + int serial_sleep (serial_t *device, unsigned long timeout) diff --git a/src/serial_win32.c b/src/serial_win32.c index 9d5572c..3424064 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -503,6 +503,34 @@ serial_flush (serial_t *device, int queue) int +serial_wait_break (serial_t *device) +{ + if (device == NULL) + return -1; + + if (!SetCommMask (device->hFile, EV_BREAK)) { + SYSERROR (device->context, GetLastError ()); + return -1; + } + + DWORD mask = 0; + while (WaitCommEvent (device->hFile, &mask, NULL)) { + message ("event=%i\n", mask); + if (mask & EV_BREAK) { + SetCommMask (device->hFile, 0); + return 0; + } + } + + if (!SetCommMask (device->hFile, 0)) { + SYSERROR (device->context, GetLastError ()); + return -1; + } + + return -1; +} + +int serial_send_break (serial_t *device) { if (device == NULL)

AltStyle によって変換されたページ (->オリジナル) /