From: Keith Packard Date: Mon, 15 Jul 2019 20:22:15 +0000 (-0700) Subject: ao-tools: Change ao-eeprom into eeprom analysis tool X-Git-Tag: 1.9.1~1^2~68 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=98f7c1c116aab672a29db1f81213cabe2d72ae16 ao-tools: Change ao-eeprom into eeprom analysis tool ao-eeprom used to be a TeleMetrum v0.2 specific tool for fetching eeprom contents from that device. ao-dumpflash handles that case now. ao-eeprom now parses .eeprom files and displays their contents. Signed-off-by: Keith Packard --- diff --git a/ao-tools/ao-eeprom/Makefile.am b/ao-tools/ao-eeprom/Makefile.am index 6c5e0383..d4aca00f 100644 --- a/ao-tools/ao-eeprom/Makefile.am +++ b/ao-tools/ao-eeprom/Makefile.am @@ -5,7 +5,7 @@ AO_EEPROM_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a ao_eeprom_DEPENDENCIES = $(AO_EEPROM_LIBS) -ao_eeprom_LDADD=$(AO_EEPROM_LIBS) $(LIBUSB_LIBS) +ao_eeprom_LDADD=$(AO_EEPROM_LIBS) -ljson-c ao_eeprom_SOURCES = ao-eeprom.c diff --git a/ao-tools/ao-eeprom/ao-eeprom.1 b/ao-tools/ao-eeprom/ao-eeprom.1 index 728f11ed..6257e125 100644 --- a/ao-tools/ao-eeprom/ao-eeprom.1 +++ b/ao-tools/ao-eeprom/ao-eeprom.1 @@ -18,40 +18,32 @@ .\" .TH AO-EEPROM 1 "ao-eeprom" "" .SH NAME -ao-eeprom \- Fetch eeprom contents from TeleMetrum device +ao-eeprom \- Analyze an eeprom log .SH SYNOPSIS .B "ao-eeprom" -[\-T \fItty-device\fP] -[\--tty \fItty-device\fP] -[\-D \fIaltos-device\fP] -[\--device \fIaltos-device\fP] +[\--raw] +[\--csum] +[\--verbose] +[\--len ] +{flight.eeprom} ... .SH OPTIONS .TP -\-T tty-device | --tty tty-device -This selects which tty device the debugger uses to communicate with -the target device. The special name 'BITBANG' directs ao-dbg to use -the cp2103 connection, otherwise this should be a usb serial port -connected to a suitable cc1111 debug node. +\-r | --raw +This option makes ao-eeprom dump the raw bytes of each +log record in hex format. .TP -\-D AltOS-device | --device AltOS-device -Search for a connected device. This requires an argument of one of the -following forms: -.IP -TeleMetrum:2 -.br -TeleMetrum -.br -2 -.IP -Leaving out the product name will cause the tool to select a suitable -product, leaving out the serial number will cause the tool to match -one of the available devices. +\-c | --csum +This option makes ao-eeprom dump records that have checksum errors. By default, +ao-eeprom skips such records. +\-v | --verbose +This option makes ao-eeprom report when records are skipped due to +checksum errors. +\-l | --len #include +#include #include #include -#include "cc-usb.h" -#include "cc.h" - -#define NUM_BLOCK 512 +#include static const struct option options[] = { - { .name = "tty", .has_arg = 1, .val = 'T' }, - { .name = "device", .has_arg = 1, .val = 'D' }, + { .name = "raw", .has_arg = 0, .val = 'r' }, + { .name = "csum", .has_arg = 0, .val = 'c' }, + { .name = "verbose", .has_arg = 0, .val = 'v' }, + { .name = "len", .has_arg = 1, .val = 'l' }, { 0, 0, 0, 0}, }; static void usage(char *program) { - fprintf(stderr, "usage: %s [--tty ] [--device \n", program); + fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len ] {flight.eeprom} ...\n", program); exit(1); } +static bool +ao_csum_valid(uint8_t *d, int len) +{ + uint8_t sum = 0x5a; + int i; + for (i = 0; i < len; i++) + sum += d[i]; + return sum == 0; +} + +static void +ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611) +{ + struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp }; + struct ao_ms5607_value ms5607_value; + + ao_ms5607_convert(&ms5607_sample, &ms5607_value, + &eeprom->ms5607_prom, is_ms5611); + printf(" pres %9u temp %9u (%7.3f kPa %6.2f°C)", + pres, + temp, + ms5607_value.pres / 1000.0, + ms5607_value.temp / 100.0); +} + +#define GRAVITY 9.80665 + +static void +ao_accel(int16_t accel, struct ao_eeprom *eeprom) +{ + double accel_2g = eeprom->config.accel_minus_g - eeprom->config.accel_plus_g; + double accel_scale = GRAVITY * 2.0 / accel_2g; + printf(" accel %6d (%7.2f m/s²)", + accel, (eeprom->config.accel_plus_g - accel) * accel_scale); +} + +static const char *state_names[] = { + "startup", + "idle", + "pad", + "boost", + "fast", + "coast", + "drogue", + "main", + "landed", + "invalid" +}; + +#define NUM_STATE (sizeof state_names/sizeof state_names[0]) + +static const char * +ao_state_name(uint16_t state) +{ + if (state < NUM_STATE) + return state_names[state]; + return "UNKNOWN"; +} + +static void +ao_state(uint16_t state, uint16_t reason) +{ + printf(" state %5u %s reason %5u", + state, ao_state_name(state), reason); +} + +static void +ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2) +{ + printf(" %s %5d", + name, value); + if (r1 && r2 && ref) + printf("(%6.3f V)", + ref * ((double) value / max_adc) * (r1 + r2) / r2); +} + +#if 0 +static uint16_t +uint16(uint8_t *bytes, int off) +{ + return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8); +} + +static int16_t +int16(uint8_t *bytes, int off) +{ + return (int16_t) uint16(bytes, off); +} + +static uint32_t +uint32(uint8_t *bytes, int off) +{ + return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) | + (((uint32_t) bytes[off+2]) << 16) | + (((uint32_t) bytes[off+3]) << 24); +} + +static int32_t +int32(uint8_t *bytes, int off) +{ + return (int32_t) uint32(bytes, off); +} +#endif + +static uint32_t +uint24(uint8_t *bytes, int off) +{ + return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) | + (((uint32_t) bytes[off+2]) << 16); +} + +static int32_t +int24(uint8_t *bytes, int off) +{ + return (int32_t) uint24(bytes, off); +} + int main (int argc, char **argv) { - struct cc_usb *cc; - int block; - uint8_t bytes[2 * 32 * (2 + 8)]; - uint8_t *b; - int i, j; - uint32_t addr; - char *tty = NULL; - char *device = NULL; - int c; - - while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) { + struct ao_eeprom *eeprom; + FILE *file; + int c; + bool raw = false; + bool csum = false; + bool verbose = false; + int arg_len = 0; + char *end; + int ret = 0; + int i; + + while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) { switch (c) { - case 'T': - tty = optarg; + case 'r': + raw = true; break; - case 'D': - device = optarg; + case 'c': + csum = true; + break; + case 'v': + verbose = true; + break; + case 'l': + arg_len = strtol(optarg, &end, 0); + if (!*optarg || *end) + usage(argv[0]); break; default: usage(argv[0]); break; } } - if (!tty) - tty = cc_usbdevs_find_by_arg(device, "TeleMetrum"); - if (!tty) - tty = getenv("ALTOS_TTY"); - if (!tty) - tty="/dev/ttyACM0"; - cc = cc_usb_open(tty); - if (!cc) - exit(1); - for (block = 0; block < NUM_BLOCK; block += 2) { - cc_queue_read(cc, bytes, sizeof (bytes)); - cc_usb_printf(cc, "e %x\ne %x\n", block, block + 1); - cc_usb_sync(cc); - for (i = 0; i < 32 * 2; i++) { - b = bytes + (i * 10); - addr = block * 256 + i * 8; - printf ("%06x", addr); - for (j = 0; j < 8; j++) { - printf (" %02x", b[j+2]); + for (i = optind; i < argc; i++) { + file = fopen(argv[i], "r"); + if (!file) { + perror(argv[i]); + ret++; + continue; + } + eeprom = ao_eeprom_read(file); + fclose(file); + if (!eeprom) { + perror(argv[i]); + ret++; + continue; + } + int len = 0; + bool is_ms5611 = false; + + double sense_r1 = 0.0, sense_r2 = 0.0; + double batt_r1 = 0.0, batt_r2 = 0.0; + double adc_ref = 0.0; + int16_t max_adc = 0; + + switch (eeprom->log_format) { + case AO_LOG_FORMAT_TELEMEGA_OLD: + len = 32; + break; + case AO_LOG_FORMAT_EASYMINI1: + len = 16; + max_adc = 32767; + if (eeprom->serial_number < 1000) + adc_ref = 3.0; + else + adc_ref = 3.3; + batt_r1 = sense_r1 = 100e3; + batt_r2 = sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_TELEMETRUM: + len = 16; + max_adc = 4095; + adc_ref = 3.3; + batt_r1 = 5600; + batt_r2 = 10000; + sense_r1 = 100e3; + sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_TELEMINI2: + len = 16; + break; + case AO_LOG_FORMAT_TELEGPS: + len = 32; + break; + case AO_LOG_FORMAT_TELEMEGA: + len = 32; + max_adc = 4095; + adc_ref = 3.3; + batt_r1 = 5600; + batt_r2 = 10000; + sense_r1 = 100e3; + sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_DETHERM: + len = 16; + break; + case AO_LOG_FORMAT_TELEMINI3: + len = 16; + max_adc = 4095; + adc_ref = 3.3; + batt_r1 = 5600; + batt_r2 = 10000; + sense_r1 = 100e3; + sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_TELEFIRETWO: + len = 32; + break; + case AO_LOG_FORMAT_EASYMINI2: + len = 16; + max_adc = 4095; + adc_ref = 3.3; + batt_r1 = sense_r1 = 100e3; + batt_r2 = sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_TELEMEGA_3: + len = 32; + max_adc = 4095; + adc_ref = 3.3; + batt_r1 = 5600; + batt_r2 = 10000; + sense_r1 = 100e3; + sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_EASYMEGA_2: + len = 32; + max_adc = 4095; + adc_ref = 3.3; + batt_r1 = 5600; + batt_r2 = 10000; + sense_r1 = 100e3; + sense_r2 = 27e3; + break; + case AO_LOG_FORMAT_TELESTATIC: + len = 32; + break; + case AO_LOG_FORMAT_MICROPEAK2: + len = 2; + break; + } + if (arg_len) + len = arg_len; + printf("config major %d minor %d log format %d total %u len %d\n", + eeprom->config.major, + eeprom->config.minor, + eeprom->log_format, + eeprom->len, + len); + uint32_t pos; + for (pos = 0; pos < eeprom->len; pos += len) { + int i; + if (raw) { + printf("%9u", pos); + for (i = 0; i < len; i++) + printf(" %02x", eeprom->data[pos + i]); + } else { + struct ao_log_mega *log_mega; + struct ao_log_mini *log_mini; + struct ao_log_metrum *log_metrum; + struct ao_log_gps *log_gps; + + if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) { + if (verbose) + printf("\tchecksum error at %d\n", pos); + continue; + } + + struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos]; + + printf("type %c tick %5u", log_header->type, log_header->tick); + + switch (eeprom->log_format) { + case AO_LOG_FORMAT_TELEMEGA_OLD: + case AO_LOG_FORMAT_TELEMEGA: + case AO_LOG_FORMAT_TELEMEGA_3: + case AO_LOG_FORMAT_EASYMEGA_2: + log_mega = (struct ao_log_mega *) &eeprom->data[pos]; + switch (log_mega->type) { + case AO_LOG_FLIGHT: + printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u", + eeprom->serial_number, + log_mega->u.flight.flight, + log_mega->u.flight.ground_accel, + log_mega->u.flight.ground_pres); + printf(" along %6d aross %6d through %6d", + log_mega->u.flight.ground_accel_along, + log_mega->u.flight.ground_accel_across, + log_mega->u.flight.ground_accel_through); + printf(" roll %6d pitch %6d yaw %6d", + log_mega->u.flight.ground_roll, + log_mega->u.flight.ground_pitch, + log_mega->u.flight.ground_yaw); + break; + case AO_LOG_STATE: + ao_state(log_mega->u.state.state, + log_mega->u.state.reason); + break; + case AO_LOG_SENSOR: + ao_ms5607(log_mega->u.sensor.pres, + log_mega->u.sensor.temp, + eeprom, is_ms5611); + printf(" accel_x %6d accel_y %6d accel_z %6d", + log_mega->u.sensor.accel_x, + log_mega->u.sensor.accel_y, + log_mega->u.sensor.accel_z); + printf (" gyro_x %6d gyro_y %6d gyro_z %6d", + log_mega->u.sensor.gyro_x, + log_mega->u.sensor.gyro_y, + log_mega->u.sensor.gyro_z); + printf (" mag_x %6d mag_y %6d mag_z %6d", + log_mega->u.sensor.mag_x, + log_mega->u.sensor.mag_y, + log_mega->u.sensor.mag_z); + ao_accel(log_mega->u.sensor.accel, eeprom); + break; + case AO_LOG_TEMP_VOLT: + ao_volts("v_batt", + log_mega->u.volt.v_batt, + max_adc, + adc_ref, + batt_r1, batt_r2); + ao_volts("v_pbatt", + log_mega->u.volt.v_pbatt, + max_adc, + adc_ref, + sense_r1, sense_r2); + printf(" n_sense %1d", + log_mega->u.volt.n_sense); + for (i = 0; i < log_mega->u.volt.n_sense; i++) { + char name[10]; + sprintf(name, "sense%d", i); + ao_volts(name, + log_mega->u.volt.sense[i], + max_adc, + adc_ref, + sense_r1, sense_r2); + } + printf(" pyro %04x", log_mega->u.volt.pyro); + break; + case AO_LOG_GPS_TIME: + printf(" lat %10.7f° lon %10.7f° alt %8d m", + log_mega->u.gps.latitude / 10000000.0, + log_mega->u.gps.longitude/ 10000000.0, + (int32_t) (log_mega->u.gps.altitude_low | + (log_mega->u.gps.altitude_high << 16))); + printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x", + log_mega->u.gps.hour, + log_mega->u.gps.minute, + log_mega->u.gps.second, + log_mega->u.gps.year, + log_mega->u.gps.month, + log_mega->u.gps.day, + log_mega->u.gps.flags); + printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d", + log_mega->u.gps.course, + log_mega->u.gps.ground_speed, + log_mega->u.gps.climb_rate, + log_mega->u.gps.pdop, + log_mega->u.gps.hdop, + log_mega->u.gps.vdop, + log_mega->u.gps.mode); + break; + case AO_LOG_GPS_SAT: + printf(" channels %2d", + log_mega->u.gps_sat.channels); + for (i = 0; i < 12; i++) { + printf(" svid %3d c_n %2d", + log_mega->u.gps_sat.sats[i].svid, + log_mega->u.gps_sat.sats[i].c_n); + } + break; + } + break; + case AO_LOG_FORMAT_EASYMINI1: + case AO_LOG_FORMAT_EASYMINI2: + case AO_LOG_FORMAT_TELEMINI2: + case AO_LOG_FORMAT_TELEMINI3: + log_mini = (struct ao_log_mini *) &eeprom->data[pos]; + switch (log_mini->type) { + case AO_LOG_FLIGHT: + printf(" serial %5u flight %5u ground_pres %9u", + eeprom->serial_number, + log_mini->u.flight.flight, + log_mini->u.flight.ground_pres); + break; + case AO_LOG_STATE: + ao_state(log_mini->u.state.state, + log_mini->u.state.reason); + break; + case AO_LOG_SENSOR: + ao_ms5607(int24(log_mini->u.sensor.pres, 0), + int24(log_mini->u.sensor.temp, 0), + eeprom, is_ms5611); + ao_volts("sense_a", + log_mini->u.sensor.sense_a, max_adc, + adc_ref, sense_r1, sense_r2); + ao_volts("sense_m", + log_mini->u.sensor.sense_m, max_adc, + adc_ref, sense_r1, sense_r2); + ao_volts("v_batt", + log_mini->u.sensor.v_batt, max_adc, + adc_ref, batt_r1, batt_r2); + break; + } /* */ + break; + case AO_LOG_FORMAT_TELEMETRUM: + log_metrum = (struct ao_log_metrum *) &eeprom->data[pos]; + switch (log_metrum->type) { + case AO_LOG_FLIGHT: + printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u ground_temp %9u", + eeprom->serial_number, + log_metrum->u.flight.flight, + log_metrum->u.flight.ground_accel, + log_metrum->u.flight.ground_pres, + log_metrum->u.flight.ground_temp); + break; + case AO_LOG_SENSOR: + ao_ms5607(log_metrum->u.sensor.pres, + log_metrum->u.sensor.temp, + eeprom, is_ms5611); + ao_accel(log_metrum->u.sensor.accel, eeprom); + break; + case AO_LOG_TEMP_VOLT: + ao_volts("v_batt", + log_metrum->u.volt.v_batt, max_adc, + adc_ref, batt_r1, batt_r2); + ao_volts("sense_a", + log_metrum->u.volt.sense_a, max_adc, + adc_ref, sense_r1, sense_r2); + ao_volts("sense_m", + log_metrum->u.volt.sense_m, max_adc, + adc_ref, sense_r1, sense_r2); + break; + case AO_LOG_DEPLOY: + break; + case AO_LOG_STATE: + ao_state(log_metrum->u.state.state, + log_metrum->u.state.reason); + break; + case AO_LOG_GPS_TIME: + printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u", + log_metrum->u.gps_time.hour, + log_metrum->u.gps_time.minute, + log_metrum->u.gps_time.second, + log_metrum->u.gps_time.year, + log_metrum->u.gps_time.month, + log_metrum->u.gps_time.day, + log_metrum->u.gps_time.flags, + log_metrum->u.gps_time.pdop); + break; + case AO_LOG_GPS_SAT: + printf(" channels %2d more %1d", + log_metrum->u.gps_sat.channels, + log_metrum->u.gps_sat.more); + for (i = 0; i < 4; i++) { + printf(" svid %3d c_n %2d", + log_metrum->u.gps_sat.sats[i].svid, + log_metrum->u.gps_sat.sats[i].c_n); + } + break; + case AO_LOG_GPS_POS: + printf(" lat %10.7f° lon %10.7f° alt %8d m", + log_metrum->u.gps.latitude / 10000000.0, + log_metrum->u.gps.longitude/ 10000000.0, + (int32_t) (log_metrum->u.gps.altitude_low | + (log_metrum->u.gps.altitude_high << 16))); + break; + default: + printf(" unknown"); + } + break; + case AO_LOG_FORMAT_TELEGPS: + log_gps = (struct ao_log_gps *) &eeprom->data[pos]; + (void) log_gps; + break; + case AO_LOG_FORMAT_DETHERM: + break; + } } - printf ("\n"); + printf("\n"); } } - cc_usb_close(cc); - exit (0); + return ret; } diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index a33d682d..de6c1946 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -50,5 +50,9 @@ libao_tools_a_SOURCES = \ ao-dfu.h \ ao-selfload.c \ ao-selfload.h \ + ao-eeprom-read.c \ + ao-eeprom-read.h \ + ao-ms5607-convert.c \ + ao-ms5607.h \ ao-verbose.c \ ao-verbose.h diff --git a/ao-tools/lib/ao-eeprom-read.c b/ao-tools/lib/ao-eeprom-read.c new file mode 100644 index 00000000..7ed47151 --- /dev/null +++ b/ao-tools/lib/ao-eeprom-read.c @@ -0,0 +1,258 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao-eeprom-read.h" +#include +#include +#include + +static struct json_object * +ao_eeprom_read_config(FILE *file) +{ + char line[1024]; + struct json_tokener *tok; + struct json_object *obj = NULL; + enum json_tokener_error err; + + tok = json_tokener_new(); + if (!tok) + goto fail_tok; + + for (;;) { + if (fgets(line, sizeof(line), file) == NULL) + goto fail_read; + obj = json_tokener_parse_ex(tok, line, strlen(line)); + err = json_tokener_get_error(tok); + if (err == json_tokener_success) + break; + if (err != json_tokener_continue) + goto fail_read; + } + json_tokener_free(tok); + return obj; +fail_read: + json_tokener_free(tok); +fail_tok: + return NULL; +} + +static int +ao_eeprom_read_byte(FILE *file) +{ + int byte; + if (fscanf(file, "%x", &byte) != 1) + return EOF; + return byte; +} + +static int +ao_eeprom_read_data(FILE *file, struct ao_eeprom *eeprom) +{ + uint8_t *data = NULL, *ndata; + int len = 0; + int size = 0; + int byte; + + data = malloc(size = 64); + if (!data) + goto fail_alloc; + while ((byte = ao_eeprom_read_byte(file)) != EOF) { + if (len == size) { + ndata = realloc(data, size *= 2); + if (!ndata) + goto fail_realloc; + data = ndata; + } + data[len++] = (uint8_t) byte; + } + eeprom->data = data; + eeprom->len = len; + return 1; +fail_realloc: + free(data); +fail_alloc: + return 0; +} + +static int +ao_json_get_int(struct json_object *obj, const char *key, int def) +{ + struct json_object *value; + int i; + + if (!json_object_object_get_ex(obj, key, &value)) + return def; + errno = 0; + i = (int) json_object_get_int(value); + if (errno != 0) + return def; + return i; +} + +static const char * +ao_json_get_string(struct json_object *obj, const char *key, const char *def) +{ + struct json_object *value; + const char *str; + + if (!json_object_object_get_ex(obj, key, &value)) + return def; + errno = 0; + str = json_object_get_string(value); + if (errno) + return def; + if (!str) + return def; + return str; +} + +static int +ao_eeprom_get_pyro(struct ao_config *config, struct json_object *obj) +{ + struct json_object *pyros; + struct json_object *pyro; + int i, p; + + if (!json_object_object_get_ex(obj, "pyros", &pyros)) + return 1; + + if (json_object_get_type(pyros) != json_type_array) + return 0; + + for (i = 0; i < json_object_array_length(pyros); i++) { + pyro = json_object_array_get_idx(pyros, i); + if (pyro) { + p = ao_json_get_int(pyro, "channel", -1); + if (0 <= p && p < AO_PYRO_NUM) { + config->pyro[p].flags = ao_json_get_int(pyro, "flags", 0); + config->pyro[p].accel_less = ao_json_get_int(pyro, "accel_less", 0); + config->pyro[p].accel_greater = ao_json_get_int(pyro, "accel_greater", 0); + config->pyro[p].speed_less = ao_json_get_int(pyro, "speed_less", 0); + config->pyro[p].speed_greater = ao_json_get_int(pyro, "speed_greater", 0); + config->pyro[p].height_less = ao_json_get_int(pyro, "height_less", 0); + config->pyro[p].height_greater = ao_json_get_int(pyro, "height_greater", 0); + config->pyro[p].orient_less = ao_json_get_int(pyro, "orient_less", 0); + config->pyro[p].orient_greater = ao_json_get_int(pyro, "orient_greater", 0); + config->pyro[p].time_less = ao_json_get_int(pyro, "time_less", 0); + config->pyro[p].time_greater = ao_json_get_int(pyro, "time_greater", 0); + config->pyro[p].delay = ao_json_get_int(pyro, "delay", 0); + config->pyro[p].state_less = ao_json_get_int(pyro, "state_less", 0); + config->pyro[p].state_greater_or_equal = ao_json_get_int(pyro, "state_greater_or_equal", 0); + config->pyro[p].motor = ao_json_get_int(pyro, "motor", 0); + } + } + } + return 1; +} + +static int +ao_eeprom_get_ms5607(struct ao_ms5607_prom *ms5607_prom, struct json_object *obj) +{ + struct json_object *ms5607; + + if (!json_object_object_get_ex(obj, "ms5607", &ms5607)) + return 1; + + if (json_object_get_type(ms5607) != json_type_object) + return 0; + + ms5607_prom->reserved = ao_json_get_int(ms5607, "reserved", 0); + ms5607_prom->sens = ao_json_get_int(ms5607, "sens", 0); + ms5607_prom->off = ao_json_get_int(ms5607, "off", 0); + ms5607_prom->tcs = ao_json_get_int(ms5607, "tcs", 0); + ms5607_prom->tco = ao_json_get_int(ms5607, "tco", 0); + ms5607_prom->tref = ao_json_get_int(ms5607, "tref", 0); + ms5607_prom->tempsens = ao_json_get_int(ms5607, "tempsens", 0); + ms5607_prom->crc = ao_json_get_int(ms5607, "crc", 0); + return 1; +} + +static int +ao_eeprom_get_config(struct ao_eeprom *ao_eeprom, struct json_object *obj) +{ + struct ao_config *config = &ao_eeprom->config; + const char *s; + + if (json_object_get_type(obj) != json_type_object) + return 0; + + ao_eeprom->log_format = ao_json_get_int(obj, "log_format", 0); + ao_eeprom->serial_number = ao_json_get_int(obj, "serial", 0); + + config->major = ao_json_get_int(obj, "config_major", 0); + config->minor = ao_json_get_int(obj, "config_minor", 0); + if (config->major == 0 || config->minor == 0) + return 0; + + config->main_deploy = ao_json_get_int(obj, "main_deploy", 250); + config->accel_plus_g = ao_json_get_int(obj, "accel_cal_plus", 0); + + s = ao_json_get_string(obj, "callsign", "N0CALL"); + strncpy(config->callsign, s, sizeof(config->callsign)-1); + + config->apogee_delay = ao_json_get_int(obj, "apogee_delay", 0); + config->accel_minus_g = ao_json_get_int(obj, "accel_cal_minus", 0); + config->radio_cal = ao_json_get_int(obj, "radio_calibration", 0); + config->flight_log_max = ao_json_get_int(obj, "flight_log_max", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->pad_orientation = ao_json_get_int(obj, "pad_orientation", 0); + config->radio_setting = ao_json_get_int(obj, "radio_setting", 0); + config->radio_enable = ao_json_get_int(obj, "radio_enable", 1); + config->frequency = ao_json_get_int(obj, "frequency", 434550); + config->apogee_lockout = ao_json_get_int(obj, "apogee_lockout", 0); + if (!ao_eeprom_get_pyro(config, obj)) + return 0; + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + config->ignite_mode = ao_json_get_int(obj, "ignite_mode", 0); + + if (!ao_eeprom_get_ms5607(&ao_eeprom->ms5607_prom, obj)) + return 0; + + return 1; +} + +struct ao_eeprom * +ao_eeprom_read(FILE *file) +{ + struct ao_eeprom *ao_eeprom; + struct json_object *obj; + int ret; + + ao_eeprom = calloc(1, sizeof (struct ao_eeprom)); + if (!ao_eeprom) + goto fail_ao_eeprom; + + obj = ao_eeprom_read_config(file); + if (!obj) + goto fail_config; + + ret = ao_eeprom_get_config(ao_eeprom, obj); + json_object_put(obj); + if (!ret) + goto fail_config; + + if (!ao_eeprom_read_data(file, ao_eeprom)) + goto fail_data; + + return ao_eeprom; +fail_data: +fail_config: + free(ao_eeprom); +fail_ao_eeprom: + return NULL; +} diff --git a/ao-tools/lib/ao-eeprom-read.h b/ao-tools/lib/ao-eeprom-read.h new file mode 100644 index 00000000..82893f24 --- /dev/null +++ b/ao-tools/lib/ao-eeprom-read.h @@ -0,0 +1,532 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_EEPROM_READ_H_ +#define _AO_EEPROM_READ_H_ + +#include +#include +#include + +#define AO_MAX_CALLSIGN 8 +#define AO_AES_LEN 16 +#define AO_PYRO_NUM 8 + +/* required functions from the underlying log system */ + +#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */ +#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */ +#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */ +#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */ +#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */ +#define AO_LOG_FORMAT_TELEMEGA_OLD 5 /* 32 byte typed telemega records */ +#define AO_LOG_FORMAT_EASYMINI1 6 /* 16-byte MS5607 baro only, 3.0V supply */ +#define AO_LOG_FORMAT_TELEMETRUM 7 /* 16-byte typed telemetrum records */ +#define AO_LOG_FORMAT_TELEMINI2 8 /* 16-byte MS5607 baro only, 3.3V supply, cc1111 SoC */ +#define AO_LOG_FORMAT_TELEGPS 9 /* 32 byte telegps records */ +#define AO_LOG_FORMAT_TELEMEGA 10 /* 32 byte typed telemega records with 32 bit gyro cal */ +#define AO_LOG_FORMAT_DETHERM 11 /* 16-byte MS5607 baro only, no ADC */ +#define AO_LOG_FORMAT_TELEMINI3 12 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */ +#define AO_LOG_FORMAT_TELEFIRETWO 13 /* 32-byte test stand data */ +#define AO_LOG_FORMAT_EASYMINI2 14 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */ +#define AO_LOG_FORMAT_TELEMEGA_3 15 /* 32 byte typed telemega records with 32 bit gyro cal and mpu9250 */ +#define AO_LOG_FORMAT_EASYMEGA_2 16 /* 32 byte typed telemega records with 32 bit gyro cal, mpu9250 rotated 90° and adxl375 */ +#define AO_LOG_FORMAT_TELESTATIC 17 /* 32 byte typed telestatic records */ +#define AO_LOG_FORMAT_MICROPEAK2 18 /* 2-byte baro values with header */ +#define AO_LOG_FORMAT_NONE 127 /* No log at all */ + +enum ao_pyro_flag { + ao_pyro_none = 0x00000000, + + ao_pyro_accel_less = 0x00000001, + ao_pyro_accel_greater = 0x00000002, + + ao_pyro_speed_less = 0x00000004, + ao_pyro_speed_greater = 0x00000008, + + ao_pyro_height_less = 0x00000010, + ao_pyro_height_greater = 0x00000020, + + ao_pyro_orient_less = 0x00000040, + ao_pyro_orient_greater = 0x00000080, + + ao_pyro_time_less = 0x00000100, + ao_pyro_time_greater = 0x00000200, + + ao_pyro_ascending = 0x00000400, + ao_pyro_descending = 0x00000800, + + ao_pyro_after_motor = 0x00001000, + + ao_pyro_delay = 0x00002000, + + ao_pyro_state_less = 0x00004000, + ao_pyro_state_greater_or_equal = 0x00008000, +}; + +struct ao_pyro { + enum ao_pyro_flag flags; + int16_t accel_less, accel_greater; + int16_t speed_less, speed_greater; + int16_t height_less, height_greater; + int16_t orient_less, orient_greater; + int16_t time_less, time_greater; + int16_t delay; + uint8_t state_less, state_greater_or_equal; + int16_t motor; + uint16_t delay_done; + uint8_t _unused; /* was 'fired' */ +}; + +struct ao_config { + uint8_t major; + uint8_t minor; + uint16_t main_deploy; + int16_t accel_plus_g; /* changed for minor version 2 */ + uint8_t _legacy_radio_channel; + char callsign[AO_MAX_CALLSIGN + 1]; + uint8_t apogee_delay; /* minor version 1 */ + int16_t accel_minus_g; /* minor version 2 */ + uint32_t radio_cal; /* minor version 3 */ + uint32_t flight_log_max; /* minor version 4 */ + uint8_t ignite_mode; /* minor version 5 */ + uint8_t pad_orientation; /* minor version 6 */ + uint32_t radio_setting; /* minor version 7 */ + uint8_t radio_enable; /* minor version 8 */ + uint8_t aes_key[AO_AES_LEN]; /* minor version 9 */ + uint32_t frequency; /* minor version 10 */ + uint16_t apogee_lockout; /* minor version 11 */ + struct ao_pyro pyro[AO_PYRO_NUM]; /* minor version 12 */ + uint16_t aprs_interval; /* minor version 13 */ + uint8_t radio_power; /* minor version 14 */ + uint8_t radio_amp; /* minor version 14 */ + int16_t accel_zero_along; /* minor version 15 */ + int16_t accel_zero_across; /* minor version 15 */ + int16_t accel_zero_through; /* minor version 15 */ + uint8_t mid_beep; /* minor version 16 */ + uint16_t tracker_motion; /* minor version 17 */ + uint8_t tracker_interval; /* minor version 17 */ + uint16_t pyro_time; /* minor version 18 */ + uint8_t aprs_ssid; /* minor version 19 */ + uint8_t radio_rate; /* minor version 20 */ + uint32_t send_frequency; /* minor version 21 */ + uint8_t aprs_format; /* minor version 22 */ + uint8_t pad_box; /* minor version 22 */ + uint8_t pad_idle; /* minor version 23 */ +}; + +/* + * ao_log_big.c + */ + +/* + * The data log is recorded in the eeprom as a sequence + * of data packets. + * + * Each packet starts with a 4-byte header that has the + * packet type, the packet checksum and the tick count. Then + * they all contain 2 16 bit values which hold packet-specific + * data. + * + * For each flight, the first packet + * is FLIGHT packet, indicating the serial number of the + * device and a unique number marking the number of flights + * recorded by this device. + * + * During flight, data from the accelerometer and barometer + * are recorded in SENSOR packets, using the raw 16-bit values + * read from the A/D converter. + * + * Also during flight, but at a lower rate, the deployment + * sensors are recorded in DEPLOY packets. The goal here is to + * detect failure in the deployment circuits. + * + * STATE packets hold state transitions as the flight computer + * transitions through different stages of the flight. + */ +#define AO_LOG_FLIGHT 'F' +#define AO_LOG_SENSOR 'A' +#define AO_LOG_TEMP_VOLT 'T' +#define AO_LOG_DEPLOY 'D' +#define AO_LOG_STATE 'S' +#define AO_LOG_GPS_TIME 'G' +#define AO_LOG_GPS_LAT 'N' +#define AO_LOG_GPS_LON 'W' +#define AO_LOG_GPS_ALT 'H' +#define AO_LOG_GPS_SAT 'V' +#define AO_LOG_GPS_DATE 'Y' +#define AO_LOG_GPS_POS 'P' + +#define AO_LOG_POS_NONE (~0UL) + +/* Common header in all log formats */ +struct ao_log_header { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ +}; + +struct ao_log_record { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { + struct { + int16_t ground_accel; /* 4 */ + uint16_t flight; /* 6 */ + } flight; + struct { + int16_t accel; /* 4 */ + int16_t pres; /* 6 */ + } sensor; + struct { + int16_t temp; + int16_t v_batt; + } temp_volt; + struct { + int16_t drogue; + int16_t main; + } deploy; + struct { + uint16_t state; + uint16_t reason; + } state; + struct { + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t flags; + } gps_time; + int32_t gps_latitude; + int32_t gps_longitude; + struct { + uint16_t altitude_low; + int16_t altitude_high; + } gps_altitude; + struct { + uint16_t svid; + uint8_t unused; + uint8_t c_n; + } gps_sat; + struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t extra; + } gps_date; + struct { + uint16_t d0; + uint16_t d1; + } anon; + } u; +}; + +struct ao_log_mega { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + int16_t ground_accel; /* 6 */ + uint32_t ground_pres; /* 8 */ + int16_t ground_accel_along; /* 12 */ + int16_t ground_accel_across; /* 14 */ + int16_t ground_accel_through; /* 16 */ + int16_t pad_18; /* 18 */ + int32_t ground_roll; /* 20 */ + int32_t ground_pitch; /* 24 */ + int32_t ground_yaw; /* 28 */ + } flight; /* 32 */ + struct { + uint16_t flight; /* 4 */ + int16_t ground_accel; /* 6 */ + uint32_t ground_pres; /* 8 */ + int16_t ground_accel_along; /* 12 */ + int16_t ground_accel_across; /* 14 */ + int16_t ground_accel_through; /* 16 */ + int16_t ground_roll; /* 18 */ + int16_t ground_pitch; /* 20 */ + int16_t ground_yaw; /* 22 */ + } flight_old; /* 24 */ + /* AO_LOG_STATE */ + struct { + uint16_t state; + uint16_t reason; + } state; + /* AO_LOG_SENSOR */ + struct { + uint32_t pres; /* 4 */ + uint32_t temp; /* 8 */ + int16_t accel_x; /* 12 */ + int16_t accel_y; /* 14 */ + int16_t accel_z; /* 16 */ + int16_t gyro_x; /* 18 */ + int16_t gyro_y; /* 20 */ + int16_t gyro_z; /* 22 */ + int16_t mag_x; /* 24 */ + int16_t mag_z; /* 26 */ + int16_t mag_y; /* 28 */ + int16_t accel; /* 30 */ + } sensor; /* 32 */ + /* AO_LOG_TEMP_VOLT */ + struct { + int16_t v_batt; /* 4 */ + int16_t v_pbatt; /* 6 */ + int16_t n_sense; /* 8 */ + int16_t sense[10]; /* 10 */ + uint16_t pyro; /* 30 */ + } volt; /* 32 */ + /* AO_LOG_GPS_TIME */ + struct { + int32_t latitude; /* 4 */ + int32_t longitude; /* 8 */ + uint16_t altitude_low; /* 12 */ + uint8_t hour; /* 14 */ + uint8_t minute; /* 15 */ + uint8_t second; /* 16 */ + uint8_t flags; /* 17 */ + uint8_t year; /* 18 */ + uint8_t month; /* 19 */ + uint8_t day; /* 20 */ + uint8_t course; /* 21 */ + uint16_t ground_speed; /* 22 */ + int16_t climb_rate; /* 24 */ + uint8_t pdop; /* 26 */ + uint8_t hdop; /* 27 */ + uint8_t vdop; /* 28 */ + uint8_t mode; /* 29 */ + int16_t altitude_high; /* 30 */ + } gps; /* 32 */ + /* AO_LOG_GPS_SAT */ + struct { + uint16_t channels; /* 4 */ + struct { + uint8_t svid; + uint8_t c_n; + } sats[12]; /* 6 */ + } gps_sat; /* 30 */ + } u; +}; + +#define AO_LOG_MEGA_GPS_ALTITUDE(l) ((int32_t) ((l)->u.gps.altitude_high << 16) | ((l)->u.gps.altitude_low)) +#define AO_LOG_MEGA_SET_GPS_ALTITUDE(l,a) (((l)->u.gps.mode |= AO_GPS_MODE_ALTITUDE_24), \ + ((l)->u.gps.altitude_high = (a) >> 16), \ + (l)->u.gps.altitude_low = (a)) + +struct ao_log_firetwo { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + } flight; /* 6 */ + /* AO_LOG_STATE */ + struct { + uint16_t state; /* 4 */ + uint16_t reason; /* 6 */ + } state; /* 8 */ + /* AO_LOG_SENSOR */ + struct { + uint16_t pressure; /* 4 */ + uint16_t thrust; /* 6 */ + uint16_t thermistor[4]; /* 8 */ + } sensor; /* 24 */ + uint8_t align[28]; /* 4 */ + } u; /* 32 */ +}; + +struct ao_log_telestatic { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + } flight; /* 6 */ + /* AO_LOG_STATE */ + struct { + uint16_t state; /* 4 */ + uint16_t reason; /* 6 */ + } state; /* 8 */ + /* AO_LOG_SENSOR */ + struct { + uint32_t pressure; /* 4 */ + uint32_t pressure2; /* 8 */ + uint32_t thrust; /* 12 */ + uint32_t mass; /* 16 */ + uint16_t t_low; /* 20 */ + uint16_t t_high[4]; /* 22 */ + } sensor; /* 30 */ + uint8_t align[28]; /* 4 */ + } u; /* 32 */ +}; + +struct ao_log_metrum { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + int16_t ground_accel; /* 6 */ + uint32_t ground_pres; /* 8 */ + uint32_t ground_temp; /* 12 */ + } flight; /* 16 */ + /* AO_LOG_STATE */ + struct { + uint16_t state; /* 4 */ + uint16_t reason; /* 6 */ + } state; /* 8 */ + /* AO_LOG_SENSOR */ + struct { + uint32_t pres; /* 4 */ + uint32_t temp; /* 8 */ + int16_t accel; /* 12 */ + } sensor; /* 14 */ + /* AO_LOG_TEMP_VOLT */ + struct { + int16_t v_batt; /* 4 */ + int16_t sense_a; /* 6 */ + int16_t sense_m; /* 8 */ + } volt; /* 10 */ + /* AO_LOG_GPS_POS */ + struct { + int32_t latitude; /* 4 */ + int32_t longitude; /* 8 */ + uint16_t altitude_low; /* 12 */ + int16_t altitude_high; /* 14 */ + } gps; /* 16 */ + /* AO_LOG_GPS_TIME */ + struct { + uint8_t hour; /* 4 */ + uint8_t minute; /* 5 */ + uint8_t second; /* 6 */ + uint8_t flags; /* 7 */ + uint8_t year; /* 8 */ + uint8_t month; /* 9 */ + uint8_t day; /* 10 */ + uint8_t pdop; /* 11 */ + } gps_time; /* 12 */ + /* AO_LOG_GPS_SAT (up to three packets) */ + struct { + uint8_t channels; /* 4 */ + uint8_t more; /* 5 */ + struct { + uint8_t svid; + uint8_t c_n; + } sats[4]; /* 6 */ + } gps_sat; /* 14 */ + uint8_t raw[12]; /* 4 */ + } u; /* 16 */ +}; + +struct ao_log_mini { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + uint16_t r6; + uint32_t ground_pres; /* 8 */ + } flight; + /* AO_LOG_STATE */ + struct { + uint16_t state; /* 4 */ + uint16_t reason; /* 6 */ + } state; + /* AO_LOG_SENSOR */ + struct { + uint8_t pres[3]; /* 4 */ + uint8_t temp[3]; /* 7 */ + int16_t sense_a; /* 10 */ + int16_t sense_m; /* 12 */ + int16_t v_batt; /* 14 */ + } sensor; /* 16 */ + } u; /* 16 */ +}; /* 16 */ + +#define ao_log_pack24(dst,value) do { \ + (dst)[0] = (value); \ + (dst)[1] = (value) >> 8; \ + (dst)[2] = (value) >> 16; \ + } while (0) + +struct ao_log_gps { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + int16_t start_altitude; /* 6 */ + int32_t start_latitude; /* 8 */ + int32_t start_longitude; /* 12 */ + } flight; /* 16 */ + /* AO_LOG_GPS_TIME */ + struct { + int32_t latitude; /* 4 */ + int32_t longitude; /* 8 */ + uint16_t altitude_low; /* 12 */ + uint8_t hour; /* 14 */ + uint8_t minute; /* 15 */ + uint8_t second; /* 16 */ + uint8_t flags; /* 17 */ + uint8_t year; /* 18 */ + uint8_t month; /* 19 */ + uint8_t day; /* 20 */ + uint8_t course; /* 21 */ + uint16_t ground_speed; /* 22 */ + int16_t climb_rate; /* 24 */ + uint8_t pdop; /* 26 */ + uint8_t hdop; /* 27 */ + uint8_t vdop; /* 28 */ + uint8_t mode; /* 29 */ + int16_t altitude_high; /* 30 */ + } gps; /* 31 */ + /* AO_LOG_GPS_SAT */ + struct { + uint16_t channels; /* 4 */ + struct { + uint8_t svid; + uint8_t c_n; + } sats[12]; /* 6 */ + } gps_sat; /* 30 */ + } u; +}; + +struct ao_eeprom { + struct ao_config config; + struct ao_ms5607_prom ms5607_prom; + int log_format; + uint16_t serial_number; + uint8_t *data; + uint32_t len; +}; + +struct ao_eeprom *ao_eeprom_read(FILE *file); + +struct ao_eeprom *ao_eeprom_read_old(FILE *file); + +void ao_eeprom_free_data(struct ao_eeprom *ao_eeprom); + +#endif /* _AO_EEPROM_READ_H_ */ diff --git a/ao-tools/lib/ao-ms5607-convert.c b/ao-tools/lib/ao-ms5607-convert.c new file mode 100644 index 00000000..cc0eee3b --- /dev/null +++ b/ao-tools/lib/ao-ms5607-convert.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +void +ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value, + struct ao_ms5607_prom *prom, bool is_ms5611) +{ + int32_t dT; + int32_t TEMP; + int64_t OFF; + int64_t SENS; + + dT = sample->temp - ((int32_t) prom->tref << 8); + + TEMP = 2000 + (((int64_t) dT * prom->tempsens) >> 23); + + if (is_ms5611) { + OFF = ((int64_t) prom->off << 16) + (((int64_t) prom->tco * dT) >> 7); + SENS = ((int64_t) prom->sens << 15) + (((int64_t) prom->tcs * dT) >> 8); + } else { + OFF = ((int64_t) prom->off << 17) + (((int64_t) prom->tco * dT) >> 6); + SENS = ((int64_t) prom->sens << 16) + (((int64_t) prom->tcs * dT) >> 7); + } + + if (TEMP < 2000) { + int32_t T2 = ((int64_t) dT * (int64_t) dT) >> 31; + int32_t TEMPM = TEMP - 2000; + int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4; + int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM; + if (TEMP < -1500) { + int32_t TEMPP = TEMP + 1500; + /* You'd think this would need a 64-bit int, but + * that would imply a temperature below -327.67°C... + */ + int32_t TEMPP2 = TEMPP * TEMPP; + OFF2 = OFF2 + (int64_t) 15 * TEMPP2; + SENS2 = SENS2 + (int64_t) 8 * TEMPP2; + } + TEMP -= T2; + OFF -= OFF2; + SENS -= SENS2; + } + + value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15; + value->temp = TEMP; +} diff --git a/ao-tools/lib/ao-ms5607.h b/ao-tools/lib/ao-ms5607.h new file mode 100644 index 00000000..a23bb3c6 --- /dev/null +++ b/ao-tools/lib/ao-ms5607.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_MS5607_H_ +#define _AO_MS5607_H_ + +#include +#include + +struct ao_ms5607_prom { + uint16_t reserved; + uint16_t sens; + uint16_t off; + uint16_t tcs; + uint16_t tco; + uint16_t tref; + uint16_t tempsens; + uint16_t crc; +}; + +struct ao_ms5607_sample { + uint32_t pres; /* raw 24 bit sensor */ + uint32_t temp; /* raw 24 bit sensor */ +}; + +struct ao_ms5607_value { + int32_t pres; /* in Pa * 10 */ + int32_t temp; /* in °C * 100 */ +}; + +void +ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value, + struct ao_ms5607_prom *prom, bool is_ms5611); + +#endif /* _AO_MS5607_H_ */