Initial Commit - Copy from Altus Metrum AltOS

This commit is contained in:
2024-06-25 19:03:04 +02:00
commit 13fc49c923
2048 changed files with 1206748 additions and 0 deletions

60
ao-tools/lib/Makefile.am Normal file
View File

@@ -0,0 +1,60 @@
noinst_LIBRARIES = libao-tools.a
AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
libao_tools_a_uneeded = \
cc-log.c
libao_tools_a_SOURCES = \
ccdbg-command.c \
ccdbg-debug.c \
ccdbg-debug.h \
ccdbg-flash.c \
ccdbg.h \
ccdbg-io.c \
ccdbg-manual.c \
ccdbg-memory.c \
ccdbg-rom.c \
ccdbg-state.c \
cc-analyse.c \
cc-convert.c \
cc-dsp.c \
cc-integrate.c \
cc-mega.c \
cc-period.c \
cc-process.c \
cc-usb.c \
cc-usb.h \
cc.h \
cc-usbdev.c \
cc-util.c \
cc-bitbang.c \
cc-bitbang.h \
cc-logfile.c \
cc-telem.c \
cc-telemetry.c \
cc-telemetry.h \
cp-usb-async.c \
cp-usb-async.h \
i0.c \
chbevl.c \
mconf.h \
cephes.h \
ao-atmosphere.c \
ao-atmosphere.h \
ao-hex.c \
ao-hex.h \
ao-editaltos.c \
ao-editaltos.h \
ao-elf.c \
ao-elf.h \
ao-dfu.c \
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

View File

@@ -0,0 +1,175 @@
/*
* Copyright © 2019 Keith Packard <keithp@keithp.com>
*
* 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 <math.h>
#include "ao-atmosphere.h"
#define GRAVITY 9.80665
/*
* Pressure Sensor Model, version 1.1
*
* written by Holly Grimes
*
* Uses the International Standard Atmosphere as described in
* "A Quick Derivation relating altitude to air pressure" (version 1.03)
* from the Portland State Aerospace Society, except that the atmosphere
* is divided into layers with each layer having a different lapse rate.
*
* Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
* at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
*
* Height measurements use the local tangent plane. The postive z-direction is up.
*
* All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
* The lapse rate is given in Kelvin/meter, the gas constant for air is given
* in Joules/(kilogram-Kelvin).
*/
#define GRAVITATIONAL_ACCELERATION (-GRAVITY)
#define AIR_GAS_CONSTANT 287.053
#define NUMBER_OF_LAYERS 7
#define MAXIMUM_ALTITUDE 84852.0
#define MINIMUM_PRESSURE 0.3734
#define LAYER0_BASE_TEMPERATURE 288.15
#define LAYER0_BASE_PRESSURE 101325
/* lapse rate and base altitude for each layer in the atmosphere */
static const double lapse_rate[] = {
-0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
};
static const double base_altitude[] = {
0, 11000, 20000, 32000, 47000, 51000, 71000
};
/* outputs atmospheric pressure associated with the given altitude.
* altitudes are measured with respect to the mean sea level
*/
double
ao_altitude_to_pressure(double altitude)
{
double base_temperature = LAYER0_BASE_TEMPERATURE;
double base_pressure = LAYER0_BASE_PRESSURE;
double pressure;
double base; /* base for function to determine pressure */
double exponent; /* exponent for function to determine pressure */
int layer_number; /* identifies layer in the atmosphere */
double delta_z; /* difference between two altitudes */
if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
return 0;
/* calculate the base temperature and pressure for the atmospheric layer
associated with the inputted altitude */
for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
if (lapse_rate[layer_number] == 0.0) {
exponent = GRAVITATIONAL_ACCELERATION * delta_z
/ AIR_GAS_CONSTANT / base_temperature;
base_pressure *= exp(exponent);
}
else {
base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
exponent = GRAVITATIONAL_ACCELERATION /
(AIR_GAS_CONSTANT * lapse_rate[layer_number]);
base_pressure *= pow(base, exponent);
}
base_temperature += delta_z * lapse_rate[layer_number];
}
/* calculate the pressure at the inputted altitude */
delta_z = altitude - base_altitude[layer_number];
if (lapse_rate[layer_number] == 0.0) {
exponent = GRAVITATIONAL_ACCELERATION * delta_z
/ AIR_GAS_CONSTANT / base_temperature;
pressure = base_pressure * exp(exponent);
}
else {
base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
exponent = GRAVITATIONAL_ACCELERATION /
(AIR_GAS_CONSTANT * lapse_rate[layer_number]);
pressure = base_pressure * pow(base, exponent);
}
return pressure;
}
/* outputs the altitude associated with the given pressure. the altitude
returned is measured with respect to the mean sea level */
double
ao_pressure_to_altitude(double pressure)
{
double next_base_temperature = LAYER0_BASE_TEMPERATURE;
double next_base_pressure = LAYER0_BASE_PRESSURE;
double altitude;
double base_pressure;
double base_temperature;
double base; /* base for function to determine base pressure of next layer */
double exponent; /* exponent for function to determine base pressure
of next layer */
double coefficient;
int layer_number; /* identifies layer in the atmosphere */
int delta_z; /* difference between two altitudes */
if (pressure < 0) /* illegal pressure */
return -1;
if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
return MAXIMUM_ALTITUDE;
/* calculate the base temperature and pressure for the atmospheric layer
associated with the inputted pressure. */
layer_number = -1;
do {
layer_number++;
base_pressure = next_base_pressure;
base_temperature = next_base_temperature;
delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
if (lapse_rate[layer_number] == 0.0) {
exponent = GRAVITATIONAL_ACCELERATION * delta_z
/ AIR_GAS_CONSTANT / base_temperature;
next_base_pressure *= exp(exponent);
}
else {
base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
exponent = GRAVITATIONAL_ACCELERATION /
(AIR_GAS_CONSTANT * lapse_rate[layer_number]);
next_base_pressure *= pow(base, exponent);
}
next_base_temperature += delta_z * lapse_rate[layer_number];
}
while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
/* calculate the altitude associated with the inputted pressure */
if (lapse_rate[layer_number] == 0.0) {
coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
* base_temperature;
altitude = base_altitude[layer_number]
+ coefficient * log(pressure / base_pressure);
}
else {
base = pressure / base_pressure;
exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
/ GRAVITATIONAL_ACCELERATION;
coefficient = base_temperature / lapse_rate[layer_number];
altitude = base_altitude[layer_number]
+ coefficient * (pow(base, exponent) - 1);
}
return altitude;
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright © 2019 Keith Packard <keithp@keithp.com>
*
* 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_ATMOSPHERE_H_
#define _AO_ATMOSPHERE_H_
double
ao_altitude_to_pressure(double altitude);
double
ao_pressure_to_altitude(double pressure);
#endif /* _AO_ATMOSPHERE_H_ */

203
ao-tools/lib/ao-dfu.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* Copyright © 2016 Keith Packard <keithp@keithp.com>
*
* 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 <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "ao-hex.h"
#include "ao-dfu.h"
static uint32_t dfu_crc;
static FILE *dfu_file;
static int dfu_failed;
static int dfu_error;
static uint32_t update_crc(uint32_t crc, uint8_t byte)
{
int j;
uint32_t mask;
crc = crc ^ byte;
for (j = 0; j < 8; j++) {
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
return crc;
}
static void dfu_init(FILE *file)
{
dfu_crc = 0xffffffff;
dfu_file = file;
dfu_failed = 0;
dfu_error = 0;
}
static int dfu_fini(void)
{
if (fflush(dfu_file) == EOF) {
if (!dfu_failed) {
dfu_failed = 1;
dfu_error = errno;
}
}
if (dfu_failed)
errno = dfu_error;
return !dfu_failed;
}
static void dfu_8(uint8_t byte) {
if (putc(byte, dfu_file) == EOF) {
if (!dfu_failed) {
dfu_failed = 1;
dfu_error = errno;
}
}
dfu_crc = update_crc(dfu_crc, byte);
}
static void dfu_pad(int len) {
while (len--)
dfu_8(0);
}
static void dfu_string(char *string) {
char c;
while ((c = *string++))
dfu_8((uint8_t) c);
}
static void dfu_string_pad(char *string, int len) {
char c;
while ((c = *string++)) {
dfu_8((uint8_t) c);
len--;
}
dfu_pad(len);
}
static void dfu_block(uint8_t *bytes, int len) {
while (len--)
dfu_8(*bytes++);
}
static void dfu_lsb16(uint16_t value) {
dfu_8(value);
dfu_8(value>>8);
}
static void dfu_lsb32(uint32_t value) {
dfu_8(value);
dfu_8(value >> 8);
dfu_8(value >> 16);
dfu_8(value >> 24);
}
static uint32_t dfu_image_size(struct ao_hex_image *image) {
return 8 + image->length;
}
static uint32_t dfu_images_size(int num_image, struct ao_hex_image images[])
{
uint32_t size = 0;
int i;
for (i = 0; i < num_image; i++)
size += dfu_image_size(&images[i]);
return size;
}
static void dfu_image(struct ao_hex_image *image)
{
dfu_lsb32(image->address);
dfu_lsb32(image->length);
dfu_block(image->data, image->length);
}
static void dfu_target(char *name, int num_image, struct ao_hex_image images[])
{
uint32_t images_size = dfu_images_size(num_image, images);
int i;
dfu_string("Target");
dfu_8(0);
if (name) {
dfu_8(1);
dfu_pad(3);
dfu_string_pad(name, 255);
} else {
dfu_8(0);
dfu_pad(3);
dfu_pad(255);
}
dfu_lsb32(images_size);
dfu_lsb32(num_image);
for (i = 0; i < num_image; i++)
dfu_image(&images[i]);
}
static uint32_t dfu_target_size(int num_image, struct ao_hex_image images[])
{
return 274 + dfu_images_size(num_image, images);
}
static uint32_t
dfu_size(int num_image, struct ao_hex_image images[])
{
uint32_t size = 0;
size += 11; /* DFU Prefix */
size += dfu_target_size(num_image, images);
return size;
}
int
ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[])
{
uint32_t total_size;
total_size = dfu_size(num_image, images);
dfu_init(file);
/* DFU Prefix */
dfu_string(DFU_SIGNATURE);
dfu_8(0x01);
dfu_lsb32(total_size);
dfu_8(0x01);
dfu_target("ST...", num_image, images);
/* DFU Suffix */
dfu_lsb16(info->bcdDevice);
dfu_lsb16(info->idProduct);
dfu_lsb16(info->idVendor);
dfu_lsb16(DFU_SPEC_VERSION);
dfu_string("UFD");
dfu_8(16);
dfu_lsb32(dfu_crc);
return dfu_fini();
}

36
ao-tools/lib/ao-dfu.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyright © 2016 Keith Packard <keithp@keithp.com>
*
* 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_DFU_H_
#define _AO_DFU_H_
struct ao_dfu_info {
uint16_t bcdDevice;
uint16_t idProduct;
uint16_t idVendor;
};
#define DFU_SIGNATURE "DfuSe"
#define DFU_SPEC_VERSION 0x011a
#define DFU_TARGET_SIGNATURE "Target"
int
ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[]);
#endif /* _AO_DFU_H_ */

237
ao-tools/lib/ao-editaltos.c Normal file
View File

@@ -0,0 +1,237 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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 <string.h>
#include <stdlib.h>
#include "ao-editaltos.h"
struct ao_sym ao_symbols[] = {
[AO_ROMCONFIG_VERSION_INDEX] = {
.name = "ao_romconfig_version",
.required = 1
},
[AO_ROMCONFIG_CHECK_INDEX] = {
.name = "ao_romconfig_check",
.required = 1
},
[AO_SERIAL_NUMBER_INDEX] = {
.name = "ao_serial_number",
.required = 1
},
[AO_RADIO_CAL_INDEX] = {
.name = "ao_radio_cal",
.required = 0
},
[AO_USB_DESCRIPTORS_INDEX] = {
.name = "ao_usb_descriptors",
.required = 0
},
};
#define NUM_SYMBOLS 5
int ao_num_symbols = NUM_SYMBOLS;
/*
* Edit the to-be-written memory block
*/
static bool
rewrite(struct ao_hex_image *load, unsigned address, uint8_t *data, int length)
{
if (address < load->address || load->address + load->length < address + length)
return false;
memcpy(&load->data[address - load->address], data, length);
return true;
}
/*
* Find the symbols needed to correctly load the program
*/
bool
ao_editaltos_find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
struct ao_sym *symbols, int num_symbols)
{
int f, s;
for (f = 0; f < num_file_symbols; f++) {
for (s = 0; s < num_symbols; s++) {
if (strcmp(symbols[s].name, file_symbols[f].name) == 0) {
symbols[s].addr = file_symbols[f].addr;
symbols[s].found = true;
}
}
}
for (s = 0; s < num_symbols; s++)
if (!symbols[s].found && symbols[s].required)
return false;
return true;
}
bool
ao_editaltos(struct ao_hex_image *image,
uint16_t serial,
uint32_t cal)
{
uint8_t *serial_ucs2;
int serial_ucs2_len;
uint8_t serial_int[2];
unsigned int s;
int i;
int string_num;
uint8_t cal_int[4];
/* Write the config values into the flash image
*/
serial_int[0] = serial & 0xff;
serial_int[1] = (serial >> 8) & 0xff;
if (!rewrite(image, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
AO_SERIAL_NUMBER);
return false;
}
if (AO_USB_DESCRIPTORS) {
uint32_t usb_descriptors = AO_USB_DESCRIPTORS - image->address;
string_num = 0;
while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
if (image->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
++string_num;
if (string_num == 4)
break;
}
usb_descriptors += image->data[usb_descriptors];
}
if (usb_descriptors >= image->length || image->data[usb_descriptors] == 0 ) {
fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
return false;
}
serial_ucs2_len = image->data[usb_descriptors] - 2;
serial_ucs2 = malloc(serial_ucs2_len);
if (!serial_ucs2) {
fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
return false;
}
s = serial;
for (i = serial_ucs2_len / 2; i; i--) {
serial_ucs2[i * 2 - 1] = 0;
serial_ucs2[i * 2 - 2] = (s % 10) + '0';
s /= 10;
}
if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len)) {
fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
return false;
}
}
if (cal && AO_RADIO_CAL) {
cal_int[0] = cal & 0xff;
cal_int[1] = (cal >> 8) & 0xff;
cal_int[2] = (cal >> 16) & 0xff;
cal_int[3] = (cal >> 24) & 0xff;
if (!rewrite(image, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
fprintf(stderr, "Cannot rewrite radio calibration at %08x\n", AO_RADIO_CAL);
return false;
}
}
return true;
}
static uint16_t
read_le16(uint8_t *src)
{
return (uint16_t) src[0] | ((uint16_t) src[1] << 8);
}
bool
ao_heximage_usb_id(struct ao_hex_image *image, struct ao_usb_id *id)
{
uint32_t usb_descriptors;
if (!AO_USB_DESCRIPTORS)
return false;
usb_descriptors = AO_USB_DESCRIPTORS - image->address;
while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
if (image->data[usb_descriptors+1] == AO_USB_DESC_DEVICE) {
break;
}
usb_descriptors += image->data[usb_descriptors];
}
/*
* check to make sure there's at least 0x12 (size of a USB
* device descriptor) available
*/
if (usb_descriptors >= image->length || image->data[usb_descriptors] != 0x12)
return false;
id->vid = read_le16(image->data + usb_descriptors + 8);
id->pid = read_le16(image->data + usb_descriptors + 10);
return true;
}
uint16_t *
ao_heximage_usb_product(struct ao_hex_image *image)
{
uint32_t usb_descriptors;
int string_num;
uint16_t *product;
uint8_t product_len;
if (!AO_USB_DESCRIPTORS)
return NULL;
usb_descriptors = AO_USB_DESCRIPTORS - image->address;
string_num = 0;
while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
if (image->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
++string_num;
if (string_num == 3)
break;
}
usb_descriptors += image->data[usb_descriptors];
}
/*
* check to make sure there's at least 0x12 (size of a USB
* device descriptor) available
*/
if (usb_descriptors >= image->length || image->data[usb_descriptors] == 0)
return NULL;
product_len = image->data[usb_descriptors] - 2;
if (usb_descriptors < product_len + 2)
return NULL;
product = malloc (product_len + 2);
if (!product)
return NULL;
memcpy(product, image->data + usb_descriptors + 2, product_len);
product[product_len/2] = 0;
return product;
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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_EDITALTOS_H_
#define _AO_EDITALTOS_H_
#include <stdint.h>
#include <stdbool.h>
#include "ao-hex.h"
extern struct ao_sym ao_symbols[];
extern int ao_num_symbols;
#define AO_USB_DESC_DEVICE 1
#define AO_USB_DESC_STRING 3
#define AO_ROMCONFIG_VERSION_INDEX 0
#define AO_ROMCONFIG_CHECK_INDEX 1
#define AO_SERIAL_NUMBER_INDEX 2
#define AO_RADIO_CAL_INDEX 3
#define AO_USB_DESCRIPTORS_INDEX 4
#define AO_ROMCONFIG_VERSION (ao_symbols[AO_ROMCONFIG_VERSION_INDEX].addr)
#define AO_ROMCONFIG_CHECK (ao_symbols[AO_ROMCONFIG_CHECK_INDEX].addr)
#define AO_SERIAL_NUMBER (ao_symbols[AO_SERIAL_NUMBER_INDEX].addr)
#define AO_RADIO_CAL (ao_symbols[AO_RADIO_CAL_INDEX].addr)
#define AO_USB_DESCRIPTORS (ao_symbols[AO_USB_DESCRIPTORS_INDEX].addr)
struct ao_editaltos_funcs {
uint16_t (*get_uint16)(void *closure, uint32_t addr);
uint32_t (*get_uint32)(void *closure, uint32_t addr);
};
struct ao_usb_id {
uint16_t vid;
uint16_t pid;
};
bool
ao_editaltos_find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
struct ao_sym *symbols, int num_symbols);
bool
ao_editaltos(struct ao_hex_image *image,
uint16_t serial,
uint32_t radio_cal);
bool
ao_heximage_usb_id(struct ao_hex_image *image, struct ao_usb_id *id);
uint16_t *
ao_heximage_usb_product(struct ao_hex_image *image);
#endif /* _AO_EDITALTOS_H_ */

View File

@@ -0,0 +1,258 @@
/*
* Copyright © 2017 Keith Packard <keithp@keithp.com>
*
* 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 <json-c/json.h>
#include <string.h>
#include <errno.h>
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;
}

View File

@@ -0,0 +1,567 @@
/*
* Copyright © 2017 Keith Packard <keithp@keithp.com>
*
* 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 <stdint.h>
#include <stdio.h>
#include <ao-ms5607.h>
#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_TELEMEGA_4 19 /* 32 byte typed telemega records with 32 bit gyro cal and Bmx160 */
#define AO_LOG_FORMAT_EASYMOTOR 20 /* 16 byte typed easymotor records with pressure sensor and adxl375 */
#define AO_LOG_FORMAT_TELEMEGA_5 21 /* 32 byte typed telemega records with 32 bit gyro cal, mpu6000 and mmc5983 */
#define AO_LOG_FORMAT_TELEMEGA_6 22 /* 32 byte typed telemega records with 32 bit gyro cal, bmi088 and mmc5983 */
#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_log_motor {
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 */
int16_t ground_accel_along; /* 8 */
int16_t ground_accel_across; /* 10 */
int16_t ground_accel_through; /* 12 */
int16_t ground_motor_pressure; /* 14 */
} flight; /* 16 */
/* AO_LOG_STATE */
struct {
uint16_t state; /* 4 */
uint16_t reason; /* 6 */
} state;
/* AO_LOG_SENSOR */
struct {
uint16_t pressure; /* 4 */
uint16_t v_batt; /* 6 */
int16_t accel; /* 8 */
int16_t accel_across; /* 10 */
int16_t accel_along; /* 12 */
int16_t accel_through; /* 14 */
} sensor; /* 16 */
} 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_ */

325
ao-tools/lib/ao-elf.c Normal file
View File

@@ -0,0 +1,325 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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 <err.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ao-elf.h"
#include "ao-hex.h"
#include "ao-verbose.h"
/*
* Look through the Elf file for symbols that can be adjusted before
* the image is written to the device
*/
static struct ao_sym *
load_symbols (Elf *e, int *num_symbolsp)
{
Elf_Scn *scn;
Elf_Data *symbol_data = NULL;
GElf_Shdr shdr;
GElf_Sym sym;
int i, symbol_count;
char *symbol_name;
size_t shstrndx;
struct ao_sym *symbols = NULL;
struct ao_sym *symbol;
int num_symbols = 0;
int size_symbols = 0;
if (elf_getshdrstrndx(e, &shstrndx) < 0)
return false;
/*
* Find the symbols
*/
scn = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
if (gelf_getshdr(scn, &shdr) != &shdr)
return false;
if (shdr.sh_type == SHT_SYMTAB) {
symbol_data = elf_getdata(scn, NULL);
symbol_count = shdr.sh_size / shdr.sh_entsize;
break;
}
}
if (!symbol_data)
return NULL;
for (i = 0; i < symbol_count; i++) {
gelf_getsym(symbol_data, i, &sym);
symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
if (!symbol_name[0])
continue;
if (num_symbols == size_symbols) {
struct ao_sym *new_symbols;
int new_size;
if (!size_symbols)
new_size = 16;
else
new_size = size_symbols * 2;
new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
if (!new_symbols)
goto bail;
symbols = new_symbols;
size_symbols = new_size;
}
symbol = &symbols[num_symbols];
memset(symbol, 0, sizeof (struct ao_sym));
symbol->name = strdup(symbol_name);
if (!symbol->name)
goto bail;
symbol->addr = sym.st_value;
ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
num_symbols++;
}
*num_symbolsp = num_symbols;
return symbols;
bail:
for (i = 0; i < num_symbols; i++)
free(symbols[i].name);
free(symbols);
return NULL;
}
static uint32_t
round4(uint32_t a) {
return (a + 3) & ~3;
}
static struct ao_hex_image *
new_load (uint32_t addr, uint32_t len)
{
struct ao_hex_image *new;
len = round4(len);
new = calloc (1, sizeof (struct ao_hex_image) + len);
if (!new)
abort();
new->address = addr;
new->length = len;
return new;
}
static void
load_paste(struct ao_hex_image *into, struct ao_hex_image *from)
{
if (from->address < into->address || into->address + into->length < from->address + from->length)
abort();
memcpy(into->data + from->address - into->address, from->data, from->length);
}
/*
* Make a new load structure large enough to hold the old one and
* the new data
*/
static struct ao_hex_image *
expand_load(struct ao_hex_image *from, uint32_t address, uint32_t length)
{
struct ao_hex_image *new;
if (from) {
uint32_t from_last = from->address + from->length;
uint32_t last = address + length;
if (address > from->address)
address = from->address;
if (last < from_last)
last = from_last;
length = last - address;
if (address == from->address && length == from->length)
return from;
}
new = new_load(address, length);
if (from) {
load_paste(new, from);
free (from);
}
return new;
}
/*
* Create a new load structure with data from the existing one
* and the new data
*/
static struct ao_hex_image *
load_write(struct ao_hex_image *from, uint32_t address, uint32_t length, void *data)
{
struct ao_hex_image *new;
new = expand_load(from, address, length);
memcpy(new->data + address - new->address, data, length);
return new;
}
#define DBG 0
/*
* Construct a large in-memory block for all
* of the loaded sections of the program
*/
static struct ao_hex_image *
get_load(Elf *e)
{
Elf_Scn *scn;
size_t shstrndx;
GElf_Shdr shdr;
Elf_Data *data;
size_t nphdr;
size_t p;
GElf_Phdr phdr;
GElf_Addr sh_paddr;
struct ao_hex_image *load = NULL;
#if DBG
char *section_name;
#endif
size_t nshdr;
size_t s;
if (elf_getshdrstrndx(e, &shstrndx) < 0)
return 0;
if (elf_getphdrnum(e, &nphdr) < 0)
return 0;
if (elf_getshdrnum(e, &nshdr) < 0)
return 0;
/*
* As far as I can tell, all of the phdr sections should
* be flashed to memory
*/
for (p = 0; p < nphdr; p++) {
/* Find this phdr */
gelf_getphdr(e, p, &phdr);
if (phdr.p_type != PT_LOAD)
continue;
/* Get the associated file section */
#if DBG
fprintf (stderr, "offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
(uint32_t) phdr.p_offset,
(uint32_t) phdr.p_vaddr,
(uint32_t) phdr.p_paddr,
(uint32_t) phdr.p_filesz,
(uint32_t) phdr.p_memsz);
#endif
for (s = 0; s < nshdr; s++) {
scn = elf_getscn(e, s);
if (!scn) {
fprintf (stderr, "getscn failed\n");
abort();
}
if (gelf_getshdr(scn, &shdr) != &shdr) {
fprintf (stderr, "gelf_getshdr failed\n");
abort();
}
#if DBG
section_name = elf_strptr(e, shstrndx, shdr.sh_name);
#endif
if (shdr.sh_size != 0 && shdr.sh_type != SHT_NOBITS && (shdr.sh_flags & SHF_ALLOC) &&
phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz)
{
sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
#if DBG
fprintf (stderr, "\tsize %08x rom %08x exec %08x %s\n",
(uint32_t) shdr.sh_size,
(uint32_t) sh_paddr,
(uint32_t) shdr.sh_addr,
section_name);
#endif
data = elf_getdata(scn, NULL);
/* Write the section data into the memory block */
load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf);
}
}
}
return load;
}
/*
* Open the specified ELF file and
* check for the symbols we need
*/
struct ao_hex_image *
ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols)
{
int fd;
Elf *e;
size_t shstrndx;
struct ao_hex_image *image;
if (elf_version(EV_CURRENT) == EV_NONE)
return NULL;
fd = open(name, O_RDONLY, 0);
if (fd < 0)
return NULL;
e = elf_begin(fd, ELF_C_READ, NULL);
if (!e)
return NULL;
if (elf_kind(e) != ELF_K_ELF)
return NULL;
if (elf_getshdrstrndx(e, &shstrndx) != 0)
return NULL;
if (symbols)
*symbols = load_symbols(e, num_symbols);
image = get_load(e);
if (!image) {
fprintf (stderr, "Cannot create memory image from file\n");
return NULL;
}
return image;
}

29
ao-tools/lib/ao-elf.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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_ELF_H_
#define _AO_ELF_H_
#include <stdbool.h>
#include <gelf.h>
#include "ao-hex.h"
struct ao_hex_image *
ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols);
#endif /* _AO_ELF_H_ */

651
ao-tools/lib/ao-hex.c Normal file
View File

@@ -0,0 +1,651 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "ao-hex.h"
#include "ao-verbose.h"
struct ao_hex_input {
FILE *file;
int line;
char *name;
};
enum ao_hex_read_state {
read_marker,
read_length,
read_address,
read_type,
read_data,
read_checksum,
read_newline,
read_white,
read_done,
};
static void
ao_hex_error(struct ao_hex_input *input, char *format, ...)
{
va_list ap;
va_start(ap, format);
fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
}
static void
ao_hex_free(struct ao_hex_record *record)
{
if (!record) return;
free(record);
}
static struct ao_hex_record *
ao_hex_alloc(uint8_t length)
{
struct ao_hex_record *record;
record = calloc(1, sizeof(struct ao_hex_record) + length);
record->length = length;
return record;
}
static int
ishex(char c)
{
return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
}
static int
fromhex(char c)
{
if (isdigit(c))
return c - '0';
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
if ('A' <= c && c <= 'F')
return c - 'A' + 10;
abort();
return 0;
}
static uint8_t
ao_hex_checksum(struct ao_hex_record *record)
{
uint8_t checksum = 0;
int i;
checksum += record->length;
checksum += record->address >> 8;
checksum += record->address & 0xff;
checksum += record->type;
for (i = 0; i < record->length; i++)
checksum += record->data[i];
return -checksum;
}
static struct ao_hex_record *
ao_hex_read_record(struct ao_hex_input *input)
{
struct ao_hex_record *record = NULL;
enum ao_hex_read_state state = read_marker;
char c;
int nhexbytes = 0;
uint32_t hex = 0;
uint32_t ndata = 0;
uint8_t checksum;
while (state != read_done) {
c = getc(input->file);
if (c == EOF && state != read_white && state != read_marker) {
ao_hex_error(input, "Unexpected EOF");
goto bail;
}
if (c == ' ')
continue;
if (c == '\n')
input->line++;
switch (state) {
case read_marker:
if (c == EOF)
return NULL;
if (c != ':') {
ao_hex_error(input, "Missing ':'");
goto bail;
}
state = read_length;
nhexbytes = 2;
hex = 0;
break;
case read_length:
case read_address:
case read_type:
case read_data:
case read_checksum:
if (!ishex(c)) {
ao_hex_error(input, "Non-hex char '%c'",
c);
goto bail;
}
hex = hex << 4 | fromhex(c);
--nhexbytes;
if (nhexbytes != 0)
break;
switch (state) {
case read_length:
record = ao_hex_alloc(hex);
if (!record) {
ao_hex_error(input, "Out of memory");
goto bail;
}
state = read_address;
nhexbytes = 4;
break;
case read_address:
record->address = hex;
state = read_type;
nhexbytes = 2;
break;
case read_type:
record->type = hex;
state = read_data;
nhexbytes = 2;
ndata = 0;
break;
case read_data:
record->data[ndata] = hex;
ndata++;
nhexbytes = 2;
break;
case read_checksum:
record->checksum = hex;
state = read_newline;
break;
default:
break;
}
if (state == read_data)
if (ndata == record->length) {
nhexbytes = 2;
state = read_checksum;
}
hex = 0;
break;
case read_newline:
if (c != '\n' && c != '\r') {
ao_hex_error(input, "Missing newline");
goto bail;
}
state = read_white;
break;
case read_white:
if (!isspace(c)) {
if (c == '\n')
input->line--;
if (c != EOF)
ungetc(c, input->file);
state = read_done;
}
break;
case read_done:
break;
}
}
checksum = ao_hex_checksum(record);
if (checksum != record->checksum) {
ao_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
record->checksum, checksum);
goto bail;
}
return record;
bail:
ao_hex_free(record);
return NULL;
}
void
ao_hex_file_free(struct ao_hex_file *hex)
{
int i;
if (!hex)
return;
for (i = 0; i < hex->nrecord; i++)
ao_hex_free(hex->records[i]);
free(hex);
}
struct ao_hex_file *
ao_hex_file_read(FILE *file, char *name)
{
struct ao_hex_input input;
struct ao_hex_file *hex = NULL, *newhex;
struct ao_hex_record *record;
int srecord = 1;
int done = 0;
hex = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *), 1);
if (!hex)
return NULL;
input.name = name;
input.line = 1;
input.file = file;
while (!done) {
record = ao_hex_read_record(&input);
if (!record) {
if (feof(input.file)) {
done = 1;
break;
} else
goto bail;
}
if (hex->nrecord == srecord) {
srecord *= 2;
newhex = realloc(hex,
sizeof (struct ao_hex_file) +
srecord * sizeof (struct ao_hex_record *));
if (!newhex)
goto bail;
hex = newhex;
}
hex->records[hex->nrecord++] = record;
}
return hex;
bail:
ao_hex_file_free(hex);
return NULL;
}
static struct ao_sym *
load_symbols(struct ao_hex_file *hex,
int *num_symbolsp)
{
uint32_t extended_addr;
uint32_t addr;
int i;
struct ao_hex_record *record;
struct ao_sym *symbols = NULL;
struct ao_sym *symbol;
int num_symbols = 0;
int size_symbols = 0;
extended_addr = 0;
for (i = 0; i < hex->nrecord; i++) {
record = hex->records[i];
switch (record->type) {
case AO_HEX_RECORD_NORMAL:
addr = extended_addr + record->address;
break;
case AO_HEX_RECORD_EOF:
break;
case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
if (record->length != 2)
goto bail;
extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
break;
case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
if (record->length != 2)
goto bail;
extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
break;
case AO_HEX_RECORD_SYMBOL:
addr = extended_addr + record->address;
if (num_symbols == size_symbols) {
struct ao_sym *new_symbols;
int new_size;
if (!size_symbols)
new_size = 16;
else
new_size = size_symbols * 2;
new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
if (!new_symbols)
goto bail;
symbols = new_symbols;
size_symbols = new_size;
}
symbol = &symbols[num_symbols];
memset(symbol, 0, sizeof (struct ao_sym));
symbol->name = calloc(record->length + 1, 1);
if (!symbol->name)
goto bail;
memcpy(symbol->name, record->data, record->length);
symbol->addr = addr;
ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
num_symbols++;
break;
}
}
*num_symbolsp = num_symbols;
return symbols;
bail:
for (i = 0; i < num_symbols; i++)
free(symbols[i].name);
free(symbols);
return NULL;
}
static void
ao_hex_record_set_checksum(struct ao_hex_record *record)
{
uint8_t cksum = 0;
int i;
cksum += record->length;
cksum += record->address >> 8;
cksum += record->address;
cksum += record->type;
for (i = 0; i < record->length; i++)
cksum += record->data[i];
record->checksum = -cksum;
}
struct ao_hex_image *
ao_hex_image_create(struct ao_hex_file *hex)
{
struct ao_hex_image *image;
struct ao_hex_record *record;
int i;
uint32_t addr;
uint32_t base, bound;
uint32_t offset;
uint32_t extended_addr;
int length;
/* Find the address bounds of the file
*/
base = 0xffffffff;
bound = 0x0;
extended_addr = 0;
for (i = 0; i < hex->nrecord; i++) {
uint32_t r_bound;
record = hex->records[i];
switch (record->type) {
case AO_HEX_RECORD_NORMAL:
addr = extended_addr + record->address;
r_bound = addr + record->length;
if (addr < base)
base = addr;
if (r_bound > bound)
bound = r_bound;
break;
case AO_HEX_RECORD_EOF:
break;
case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
if (record->length != 2)
return NULL;
extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
break;
case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
if (record->length != 2)
return NULL;
extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
break;
case AO_HEX_RECORD_SYMBOL:
break;
}
}
length = bound - base;
image = calloc(sizeof(struct ao_hex_image) + length, 1);
if (!image)
return NULL;
image->address = base;
image->length = length;
memset(image->data, 0xff, length);
extended_addr = 0;
for (i = 0; i < hex->nrecord; i++) {
record = hex->records[i];
switch (record->type) {
case AO_HEX_RECORD_NORMAL:
addr = extended_addr + record->address;
offset = addr - base;
memcpy(image->data + offset, record->data, record->length);
break;
case AO_HEX_RECORD_EOF:
break;
case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
break;
case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
break;
case AO_HEX_RECORD_SYMBOL:
break;
}
}
return image;
}
void
ao_hex_image_free(struct ao_hex_image *image)
{
free(image);
}
static uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
static uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
struct ao_hex_image *
ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b)
{
struct ao_hex_image *n;
uint32_t base, bound;
uint32_t length;
base = min(a->address, b->address);
bound = max(a->address + a->length, b->address + b->length);
length = bound - base;
n = calloc (sizeof (struct ao_hex_image) + length, 1);
if (!n)
return NULL;
n->address = base;
n->length = length;
memset(n->data, 0xff, length);
memcpy(n->data + a->address - n->address, a->data, a->length);
memcpy(n->data + b->address - n->address, b->data, b->length);
return n;
}
int
ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b)
{
if (a->length != b->length)
return 0;
if (memcmp(a->data, b->data, a->length) != 0)
return 0;
return 1;
}
struct ao_hex_image *
ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp)
{
FILE *file;
struct ao_hex_file *hex_file;
struct ao_hex_image *hex_image;
file = fopen (filename, "r");
if (!file)
return NULL;
hex_file = ao_hex_file_read(file, filename);
fclose(file);
if (!hex_file)
return NULL;
hex_image = ao_hex_image_create(hex_file);
if (!hex_image)
return NULL;
if (symbols)
*symbols = load_symbols(hex_file, num_symbolsp);
ao_hex_file_free(hex_file);
return hex_image;
}
#define BYTES_PER_RECORD 32
static struct ao_hex_file *
ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_symbols)
{
/* split data into n-byte-sized chunks */
uint32_t data_records = (image->length + BYTES_PER_RECORD-1) / BYTES_PER_RECORD;
/* extended address and data for each block, EOF, address and data for each symbol */
uint32_t total_records = data_records * 2 + 1 + num_symbols * 2;
uint32_t offset;
uint32_t address;
uint32_t length;
char *name;
struct ao_hex_file *hex_file;
int nrecord = 0;
int s;
struct ao_hex_record *record;
hex_file = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *) * total_records, 1);
if (!hex_file)
return NULL;
/* Add the data
*/
for (offset = 0; offset < image->length; offset += BYTES_PER_RECORD) {
uint32_t address = image->address + offset;
uint32_t length = image->length - offset;
if (length > BYTES_PER_RECORD)
length = BYTES_PER_RECORD;
record = calloc(sizeof (struct ao_hex_record) + 2, 1);
record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
record->address = 0;
record->length = 2;
record->data[0] = address >> 24;
record->data[1] = address >> 16;
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
record = calloc(sizeof (struct ao_hex_record) + length, 1);
record->type = AO_HEX_RECORD_NORMAL;
record->address = address;
record->length = length;
memcpy(record->data, image->data + offset, length);
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
}
/* Stick an EOF after the data
*/
record = calloc(1,sizeof (struct ao_hex_record) + 2);
record->type = AO_HEX_RECORD_EOF;
record->address = 0;
record->length = 0;
record->data[0] = 0;
record->data[1] = 0;
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
/* Add the symbols
*/
for (s = 0; s < num_symbols; s++) {
name = symbols[s].name;
address = symbols[s].addr;
length = strlen (name);
record = calloc(sizeof (struct ao_hex_record) + 2, 1);
record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
record->address = 0;
record->length = 2;
record->data[0] = address >> 24;
record->data[1] = address >> 16;
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
record = calloc(sizeof (struct ao_hex_record) + length, 1);
record->type = AO_HEX_RECORD_SYMBOL;
record->address = address;
record->length = length;
memcpy(record->data, name, length);
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
}
hex_file->nrecord = nrecord;
return hex_file;
}
static bool
ao_hex_write_record(FILE *file, struct ao_hex_record *record)
{
int i;
fputc(':', file);
fprintf(file, "%02x", record->length);
fprintf(file, "%04x", record->address);
fprintf(file, "%02x", record->type);
for (i = 0; i < record->length; i++)
fprintf(file, "%02x", record->data[i]);
fprintf(file, "%02x", record->checksum);
fputc('\n', file);
return true;
}
bool
ao_hex_save(FILE *file, struct ao_hex_image *image,
struct ao_sym *symbols, int num_symbols)
{
struct ao_hex_file *hex_file;
int i;
bool ret = false;
hex_file = ao_hex_file_create(image, symbols, num_symbols);
if (!hex_file)
goto create_failed;
for (i = 0; i < hex_file->nrecord; i++) {
if (!ao_hex_write_record(file, hex_file->records[i]))
goto write_failed;
}
ret = true;
if (fflush(file) != 0)
ret = false;
write_failed:
ao_hex_file_free(hex_file);
create_failed:
return ret;
}

85
ao-tools/lib/ao-hex.h Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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_HEX_H_
#define _AO_HEX_H_
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#define AO_HEX_RECORD_NORMAL 0x00
#define AO_HEX_RECORD_EOF 0x01
#define AO_HEX_RECORD_EXTENDED_ADDRESS_4 0x02
#define AO_HEX_RECORD_EXTENDED_ADDRESS_8 0x04
#define AO_HEX_RECORD_SYMBOL 0xfe
/* Intel hex file format data
*/
struct ao_hex_record {
uint8_t length;
uint16_t address;
uint8_t type;
uint8_t checksum;
uint8_t data[0];
};
struct ao_hex_file {
int nrecord;
struct ao_hex_record *records[0];
};
struct ao_hex_image {
uint32_t address;
uint32_t length;
uint8_t data[0];
};
struct ao_sym {
unsigned addr;
char *name;
bool required;
bool found;
};
struct ao_hex_file *
ao_hex_file_read(FILE *file, char *name);
void
ao_hex_file_free(struct ao_hex_file *hex);
struct ao_hex_image *
ao_hex_image_create(struct ao_hex_file *hex);
void
ao_hex_image_free(struct ao_hex_image *image);
struct ao_hex_image *
ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols);
struct ao_hex_image *
ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b);
int
ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b);
bool
ao_hex_save(FILE *file, struct ao_hex_image *image,
struct ao_sym *symbols, int num_symbols);
#endif /* _AO_HEX_H_ */

View File

@@ -0,0 +1,63 @@
/*
* Copyright © 2012 Keith Packard <keithp@keithp.com>
*
* 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 <ao-ms5607.h>
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;
}

50
ao-tools/lib/ao-ms5607.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* Copyright © 2012 Keith Packard <keithp@keithp.com>
*
* 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 <stdint.h>
#include <stdbool.h>
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_ */

197
ao-tools/lib/ao-selfload.c Normal file
View File

@@ -0,0 +1,197 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <string.h>
#include "ao-hex.h"
#include "ao-selfload.h"
#include "ao-verbose.h"
#define TRACE(...) ao_printf(AO_VERBOSE_SELF, __VA_ARGS__)
static void
ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256])
{
int byte;
cc_usb_sync(cc);
cc_usb_printf(cc, "R %x\n", address);
for (byte = 0; byte < 0x100; byte++) {
block[byte] = cc_usb_getchar(cc);
}
TRACE ("\nread %08x\n", address);
for (byte = 0; byte < 0x100; byte++) {
TRACE (" %02x", block[byte]);
if ((byte & 0xf) == 0xf)
TRACE ("\n");
}
}
static void
ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256])
{
int byte;
cc_usb_sync(cc);
cc_usb_printf(cc, "W %x\n", address);
TRACE ("write %08x\n", address);
for (byte = 0; byte < 0x100; byte++) {
TRACE (" %02x", block[byte]);
if ((byte & 0xf) == 0xf)
TRACE ("\n");
}
for (byte = 0; byte < 0x100; byte++) {
cc_usb_printf(cc, "%c", block[byte]);
}
}
struct ao_hex_image *
ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length)
{
struct ao_hex_image *image;
int pages;
int page;
uint32_t base = address & ~0xff;
uint32_t bound = (address + length + 0xff) & ~0xff;
image = calloc(sizeof (struct ao_hex_image) + (bound - base), 1);
image->address = base;
image->length = bound - base;
pages = image->length / 0x100;
for (page = 0; page < pages; page++)
ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100);
return image;
}
bool
ao_self_write(struct cc_usb *cc, struct ao_hex_image *image)
{
uint8_t block[256];
uint8_t check[256];
uint32_t base, bound, length, address;
uint32_t pages;
uint32_t page;
base = image->address & ~0xff;
bound = (image->address + image->length + 0xff) & ~0xff;
address = base;
length = bound - base;
pages = length / 0x100;
printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout);
for (page = 0; page < pages; page++) {
uint32_t start, stop;
address = base + page * 0x100;
if (address < image->address || address + 0x100 > image->address + image->length) {
ao_self_block_read(cc, address, block);
}
start = address;
stop = address + 0x100;
if (start < image->address)
start = image->address;
if (stop > image->address + image->length)
stop = image->address + image->length;
memset(block, 0xff, 0x100);
memcpy(block + start - address, image->data + start - image->address, stop - start);
ao_self_block_write(cc, address, block);
ao_self_block_read(cc, address, check);
if (memcmp(block, check, 0x100) != 0) {
fprintf(stderr, "Block at 0x%08x doesn't match\n", address);
return 0;
}
putchar('.'); fflush(stdout);
}
printf("done\n");
cc_usb_printf(cc,"a\n");
return 1;
}
/*
* Read a 16-bit value from the USB target
*/
uint16_t
ao_self_get_uint16(struct cc_usb *cc, uint32_t addr)
{
struct ao_hex_image *hex = ao_self_read(cc, addr, 2);
uint16_t v;
uint8_t *data;
if (!hex)
return 0;
data = hex->data + addr - hex->address;
v = data[0] | (data[1] << 8);
free(hex);
return v;
}
uint32_t
ao_self_get_uint32(struct cc_usb *cc, uint32_t addr)
{
struct ao_hex_image *hex = ao_self_read(cc, addr, 4);
uint32_t v;
uint8_t *data;
if (!hex)
return 0;
data = hex->data + addr - hex->address;
v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
free(hex);
return v;
}
bool
ao_self_get_usb_id(struct cc_usb *cc, struct ao_usb_id *id)
{
struct ao_hex_image *hex;
bool ret;
if (!AO_USB_DESCRIPTORS)
return false;
hex = ao_self_read(cc, AO_USB_DESCRIPTORS, 512);
if (!hex)
return false;
ret = ao_heximage_usb_id(hex, id);
free(hex);
return ret;
}
uint16_t *
ao_self_get_usb_product(struct cc_usb *cc)
{
struct ao_hex_image *hex;
uint16_t *ret;
if (!AO_USB_DESCRIPTORS)
return NULL;
hex = ao_self_read(cc, AO_USB_DESCRIPTORS, 512);
if (!hex)
return NULL;
ret = ao_heximage_usb_product(hex);
free(hex);
return ret;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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_SELFLOAD_H_
#define _AO_SELFLOAD_H_
#include <stdbool.h>
#include "ao-hex.h"
#include "cc-usb.h"
#include "ao-editaltos.h"
struct ao_hex_image *
ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length);
bool
ao_self_write(struct cc_usb *cc, struct ao_hex_image *image);
uint16_t
ao_self_get_uint16(struct cc_usb *cc, uint32_t addr);
uint32_t
ao_self_get_uint32(struct cc_usb *cc, uint32_t addr);
bool
ao_self_get_usb_id(struct cc_usb *cc, struct ao_usb_id *id);
uint16_t *
ao_self_get_usb_product(struct cc_usb *cc);
uint16_t *
ao_self_get_usb_product(struct cc_usb *cc);
#endif /* _AO_SELFLOAD_H_ */

37
ao-tools/lib/ao-verbose.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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 "ao-verbose.h"
#include <stdio.h>
uint32_t ao_verbose;
void
ao_printf(uint32_t verbose, const char *format, ...)
{
va_list args;
if (!(ao_verbose & verbose))
return;
va_start(args, format);
vprintf(format, args);
va_end(args);
}

33
ao-tools/lib/ao-verbose.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright © 2013 Keith Packard <keithp@keithp.com>
*
* 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_VERBOSE_H_
#define _AO_VERBOSE_H_
#include <stdint.h>
#include <stdarg.h>
extern uint32_t ao_verbose;
#define AO_VERBOSE_EXE 1
#define AO_VERBOSE_SELF 2
void
ao_printf(uint32_t verbose, const char *format, ...);
#endif /* _AO_VERBOSE_H_ */

268
ao-tools/lib/cc-analyse.c Normal file
View File

@@ -0,0 +1,268 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <math.h>
void
cc_timedata_limits(struct cc_timedata *d, double min_time, double max_time, int *start, int *stop)
{
int i;
*start = -1;
for (i = 0; i < d->num; i++) {
if (*start < 0 && min_time <= d->data[i].time)
*start = i;
if (d->data[i].time <= max_time)
*stop = i;
}
}
int
cc_timedata_min(struct cc_timedata *d, double min_time, double max_time)
{
int i;
int set = 0;
int min_i = -1;
double min;
if (d->num == 0)
return -1;
for (i = 0; i < d->num; i++)
if (min_time <= d->data[i].time && d->data[i].time <= max_time)
if (!set || d->data[i].value < min) {
min_i = i;
min = d->data[i].value;
set = 1;
}
return min_i;
}
int
cc_timedata_min_mag(struct cc_timedata *d, double min_time, double max_time)
{
int i;
int set = 0;
int min_i = -1;
double min;
if (d->num == 0)
return -1;
for (i = 0; i < d->num; i++)
if (min_time <= d->data[i].time && d->data[i].time <= max_time)
if (!set || fabs(d->data[i].value) < min) {
min_i = i;
min = fabs(d->data[i].value);
set = 1;
}
return min_i;
}
int
cc_timedata_max(struct cc_timedata *d, double min_time, double max_time)
{
int i;
double max;
int max_i = -1;
int set = 0;
if (d->num == 0)
return -1;
for (i = 0; i < d->num; i++)
if (min_time <= d->data[i].time && d->data[i].time <= max_time)
if (!set || d->data[i].value > max) {
max_i = i;
max = d->data[i].value;
set = 1;
}
return max_i;
}
int
cc_timedata_max_mag(struct cc_timedata *d, double min_time, double max_time)
{
int i;
double max;
int max_i = -1;
int set = 0;
if (d->num == 0)
return -1;
for (i = 0; i < d->num; i++)
if (min_time <= d->data[i].time && d->data[i].time <= max_time)
if (!set || fabs(d->data[i].value) > max) {
max_i = i;
max = fabs(d->data[i].value);
set = 1;
}
return max_i;
}
double
cc_timedata_average(struct cc_timedata *td, double start_time, double stop_time)
{
int i;
double prev_time;
double next_time;
double interval;
double sum = 0.0;
double period = 0.0;
prev_time = start_time;
for (i = 0; i < td->num; i++) {
if (start_time <= td->data[i].time && td->data[i].time <= stop_time) {
if (i < td->num - 1 && td->data[i+1].time < stop_time)
next_time = (td->data[i].time + td->data[i+1].time) / 2.0;
else
next_time = stop_time;
interval = next_time - prev_time;
sum += td->data[i].value * interval;
period += interval;
prev_time = next_time;
}
}
return sum / period;
}
int
cc_perioddata_limits(struct cc_perioddata *d, double min_time, double max_time, int *start, int *stop)
{
double start_d, stop_d;
if (d->num == 0)
return 0;
start_d = ceil((min_time - d->start) / d->step);
if (start_d < 0)
start_d = 0;
stop_d = floor((max_time - d->start) / d->step);
if (stop_d >= d->num)
stop_d = d->num - 1;
if (stop_d < start_d)
return 0;
*start = (int) start_d;
*stop = (int) stop_d;
return 1;
}
int
cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time)
{
int i;
double min;
int min_i;
int start, stop;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
min = d->data[start];
min_i = start;
for (i = start + 1; i <= stop; i++)
if (d->data[i] < min) {
min = d->data[i];
min_i = i;
}
return min_i;
}
int
cc_perioddata_min_mag(struct cc_perioddata *d, double min_time, double max_time)
{
int start, stop;
int i;
double min;
int min_i;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
min = d->data[start];
min_i = start;
for (i = start + 1; i <= stop; i++)
if (fabs(d->data[i]) < min) {
min = fabs(d->data[i]);
min_i = i;
}
return min_i;
}
int
cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time)
{
int start, stop;
int i;
double max;
int max_i;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
max = d->data[start];
max_i = start;
for (i = start + 1; i <= stop; i++)
if (d->data[i] > max) {
max = d->data[i];
max_i = i;
}
return max_i;
}
int
cc_perioddata_max_mag(struct cc_perioddata *d, double min_time, double max_time)
{
int start, stop;
int i;
double max;
int max_i;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
max = d->data[start];
max_i = start;
for (i = start + 1; i <= stop; i++)
if (fabs(d->data[i]) > max) {
max = fabs(d->data[i]);
max_i = i;
}
return max_i;
}
double
cc_perioddata_average(struct cc_perioddata *d, double min_time, double max_time)
{
int start, stop;
int i;
double sum = 0.0;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return 0.0;
for (i = start; i <= stop; i++)
sum += d->data[i];
return sum / (stop - start + 1);
}
double
cc_perioddata_average_mag(struct cc_perioddata *d, double min_time, double max_time)
{
int start, stop;
int i;
double sum = 0.0;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return 0.0;
for (i = start; i <= stop; i++)
sum += fabs(d->data[i]);
return sum / (stop - start + 1);
}

237
ao-tools/lib/cc-bitbang.c Normal file
View File

@@ -0,0 +1,237 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 <time.h>
#include <stdio.h>
#include <stdlib.h>
#include "ccdbg-debug.h"
#include "cc-bitbang.h"
#include "cp-usb-async.h"
struct cc_bitbang {
struct cp_usb_async *cp_async;
};
static uint32_t cc_clock_us = CC_CLOCK_US;
static uint32_t cc_reset_us = CC_RESET_US;
void
cc_bitbang_set_clock(uint32_t us)
{
cc_clock_us = us;
}
void
cc_bitbang_half_clock(struct cc_bitbang *bb)
{
struct timespec req, rem;
req.tv_sec = (cc_clock_us / 2) / 1000000;
req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000;
nanosleep(&req, &rem);
}
void
cc_bitbang_wait_reset(struct cc_bitbang *bb)
{
struct timespec req, rem;
cc_bitbang_sync(bb);
req.tv_sec = (cc_reset_us) / 1000000;
req.tv_nsec = ((cc_reset_us) % 1000000) * 1000;
nanosleep(&req, &rem);
}
struct cc_bitbang *
cc_bitbang_open(void)
{
struct cc_bitbang *bb;
bb = calloc(sizeof (struct cc_bitbang), 1);
if (!bb) {
perror("calloc");
return NULL;
}
bb->cp_async = cp_usb_async_open();
if (!bb->cp_async) {
free (bb);
return NULL;
}
return bb;
}
void
cc_bitbang_close(struct cc_bitbang *bb)
{
cp_usb_async_close(bb->cp_async);
free (bb);
}
void
cc_bitbang_debug_mode(struct cc_bitbang *bb)
{
/* force two rising clocks while holding RESET_N low */
ccdbg_debug(CC_DEBUG_COMMAND, "#\n");
ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n");
ccdbg_debug(CC_DEBUG_COMMAND, "#\n");
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N);
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA );
cc_bitbang_wait_reset(bb);
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA );
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA );
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA );
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N);
cc_bitbang_wait_reset(bb);
}
void
cc_bitbang_reset(struct cc_bitbang *bb)
{
ccdbg_debug(CC_DEBUG_COMMAND, "#\n");
ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n");
ccdbg_debug(CC_DEBUG_COMMAND, "#\n");
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N);
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA );
cc_bitbang_wait_reset(bb);
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA );
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA );
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA );
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N);
cc_bitbang_wait_reset(bb);
}
int
cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value)
{
cp_usb_async_write(bb->cp_async, mask, value);
return 0;
}
void
cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep)
{
cp_usb_async_read(bb->cp_async, valuep);
}
void
cc_bitbang_sync(struct cc_bitbang *bb)
{
cp_usb_async_sync(bb->cp_async);
}
static char
is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit)
{
if (mask&bit) {
if (get&bit)
return on;
else
return '.';
} else
return '-';
}
void
cc_bitbang_print(char *format, uint8_t mask, uint8_t set)
{
ccdbg_debug (CC_DEBUG_BITBANG, format,
is_bit(set, mask, 'C', CC_CLOCK),
is_bit(set, mask, 'D', CC_DATA),
is_bit(set, mask, 'R', CC_RESET_N));
}
void
cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set)
{
cc_bitbang_write(bb, mask, set);
cc_bitbang_print("%c %c %c\n", mask, set);
cc_bitbang_half_clock(bb);
}
void
cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit)
{
if (bit) bit = CC_DATA;
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N);
cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N);
}
void
cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte)
{
int bit;
ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte);
for (bit = 7; bit >= 0; bit--) {
cc_bitbang_send_bit(bb, (byte >> bit) & 1);
if (bit == 3)
ccdbg_debug(CC_DEBUG_BITBANG, "\n");
}
cc_bitbang_sync(bb);
}
void
cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes)
{
while (nbytes--)
cc_bitbang_send_byte(bb, *bytes++);
}
void
cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit)
{
uint8_t mask = first ? CC_DATA : 0;
cc_bitbang_send(bb, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N);
cc_bitbang_read(bb, bit);
cc_bitbang_send(bb, CC_CLOCK| CC_RESET_N, CC_RESET_N);
}
void
cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep)
{
uint8_t byte = 0;
uint8_t bits[8];
int bit;
ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n");
for (bit = 0; bit < 8; bit++) {
cc_bitbang_recv_bit(bb, first, &bits[bit]);
first = 0;
}
cc_bitbang_sync(bb);
for (bit = 0; bit < 8; bit++) {
byte = byte << 1;
byte |= (bits[bit] & CC_DATA) ? 1 : 0;
cc_bitbang_print("#\t%c %c %c\n", CC_DATA, bits[bit]);
if (bit == 3)
ccdbg_debug(CC_DEBUG_BITBANG, "\n");
}
ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte);
*bytep = byte;
}
void
cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes)
{
int i;
int first = 1;
for (i = 0; i < nbytes; i++) {
cc_bitbang_recv_byte(bb, first, &bytes[i]);
first = 0;
}
}

94
ao-tools/lib/cc-bitbang.h Normal file
View File

@@ -0,0 +1,94 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 _CC_BITBANG_H_
#define _CC_BITBANG_H_
#include <stdint.h>
#define CC_CLOCK 0x1
#define CC_DATA 0x2
#define CC_RESET_N 0x4
#define CC_CLOCK_US (2)
/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground
* and a 2.7k resistor to the reset line. This takes about 6us
* to settle, so we'll wait longer than that after changing the reset line
*/
#define CC_RESET_US (12)
struct cc_bitbang;
void
cc_bitbang_set_clock(uint32_t us);
void
cc_bitbang_half_clock(struct cc_bitbang *bb);
void
cc_bitbang_wait_reset(struct cc_bitbang *bb);
struct cc_bitbang *
cc_bitbang_open(void);
void
cc_bitbang_close(struct cc_bitbang *bb);
void
cc_bitbang_debug_mode(struct cc_bitbang *bb);
void
cc_bitbang_reset(struct cc_bitbang *bb);
int
cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value);
void
cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep);
void
cc_bitbang_sync(struct cc_bitbang *bb);
void
cc_bitbang_print(char *format, uint8_t mask, uint8_t set);
void
cc_bitbang_print(char *format, uint8_t mask, uint8_t set);
void
cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set);
void
cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit);
void
cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte);
void
cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes);
void
cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit);
void
cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep);
void
cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes);
#endif /* _CC_BITBANG_H_ */

305
ao-tools/lib/cc-convert.c Normal file
View File

@@ -0,0 +1,305 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <math.h>
/*
* Pressure Sensor Model, version 1.1
*
* written by Holly Grimes
*
* Uses the International Standard Atmosphere as described in
* "A Quick Derivation relating altitude to air pressure" (version 1.03)
* from the Portland State Aerospace Society, except that the atmosphere
* is divided into layers with each layer having a different lapse rate.
*
* Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
* at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
*
* Height measurements use the local tangent plane. The postive z-direction is up.
*
* All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
* The lapse rate is given in Kelvin/meter, the gas constant for air is given
* in Joules/(kilogram-Kelvin).
*/
#define GRAVITATIONAL_ACCELERATION -9.80665
#define AIR_GAS_CONSTANT 287.053
#define NUMBER_OF_LAYERS 7
#define MAXIMUM_ALTITUDE 84852.0
#define MINIMUM_PRESSURE 0.3734
#define LAYER0_BASE_TEMPERATURE 288.15
#define LAYER0_BASE_PRESSURE 101325
/* lapse rate and base altitude for each layer in the atmosphere */
static const double lapse_rate[NUMBER_OF_LAYERS] = {
-0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
};
static const int base_altitude[NUMBER_OF_LAYERS] = {
0, 11000, 20000, 32000, 47000, 51000, 71000
};
/* outputs atmospheric pressure associated with the given altitude. altitudes
are measured with respect to the mean sea level */
double
cc_altitude_to_pressure(double altitude)
{
double base_temperature = LAYER0_BASE_TEMPERATURE;
double base_pressure = LAYER0_BASE_PRESSURE;
double pressure;
double base; /* base for function to determine pressure */
double exponent; /* exponent for function to determine pressure */
int layer_number; /* identifies layer in the atmosphere */
int delta_z; /* difference between two altitudes */
if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
return 0;
/* calculate the base temperature and pressure for the atmospheric layer
associated with the inputted altitude */
for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
if (lapse_rate[layer_number] == 0.0) {
exponent = GRAVITATIONAL_ACCELERATION * delta_z
/ AIR_GAS_CONSTANT / base_temperature;
base_pressure *= exp(exponent);
}
else {
base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
exponent = GRAVITATIONAL_ACCELERATION /
(AIR_GAS_CONSTANT * lapse_rate[layer_number]);
base_pressure *= pow(base, exponent);
}
base_temperature += delta_z * lapse_rate[layer_number];
}
/* calculate the pressure at the inputted altitude */
delta_z = altitude - base_altitude[layer_number];
if (lapse_rate[layer_number] == 0.0) {
exponent = GRAVITATIONAL_ACCELERATION * delta_z
/ AIR_GAS_CONSTANT / base_temperature;
pressure = base_pressure * exp(exponent);
}
else {
base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
exponent = GRAVITATIONAL_ACCELERATION /
(AIR_GAS_CONSTANT * lapse_rate[layer_number]);
pressure = base_pressure * pow(base, exponent);
}
return pressure;
}
double
cc_altitude_to_temperature(double altitude)
{
double base_temperature = LAYER0_BASE_TEMPERATURE;
double temperature;
int layer_number; /* identifies layer in the atmosphere */
double delta_z; /* difference between two altitudes */
/* calculate the base temperature for the atmospheric layer
associated with the inputted altitude */
for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
base_temperature += delta_z * lapse_rate[layer_number];
}
/* calculate the pressure at the inputted altitude */
delta_z = altitude - base_altitude[layer_number];
temperature = base_temperature + lapse_rate[layer_number] * delta_z;
return temperature - 273.15;
}
/* outputs the altitude associated with the given pressure. the altitude
returned is measured with respect to the mean sea level */
double
cc_pressure_to_altitude(double pressure)
{
double next_base_temperature = LAYER0_BASE_TEMPERATURE;
double next_base_pressure = LAYER0_BASE_PRESSURE;
double altitude;
double base_pressure;
double base_temperature;
double base; /* base for function to determine base pressure of next layer */
double exponent; /* exponent for function to determine base pressure
of next layer */
double coefficient;
int layer_number; /* identifies layer in the atmosphere */
int delta_z; /* difference between two altitudes */
if (pressure < 0) /* illegal pressure */
return -1;
if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
return MAXIMUM_ALTITUDE;
/* calculate the base temperature and pressure for the atmospheric layer
associated with the inputted pressure. */
layer_number = -1;
do {
layer_number++;
base_pressure = next_base_pressure;
base_temperature = next_base_temperature;
delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
if (lapse_rate[layer_number] == 0.0) {
exponent = GRAVITATIONAL_ACCELERATION * delta_z
/ AIR_GAS_CONSTANT / base_temperature;
next_base_pressure *= exp(exponent);
}
else {
base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
exponent = GRAVITATIONAL_ACCELERATION /
(AIR_GAS_CONSTANT * lapse_rate[layer_number]);
next_base_pressure *= pow(base, exponent);
}
next_base_temperature += delta_z * lapse_rate[layer_number];
}
while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
/* calculate the altitude associated with the inputted pressure */
if (lapse_rate[layer_number] == 0.0) {
coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
* base_temperature;
altitude = base_altitude[layer_number]
+ coefficient * log(pressure / base_pressure);
}
else {
base = pressure / base_pressure;
exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
/ GRAVITATIONAL_ACCELERATION;
coefficient = base_temperature / lapse_rate[layer_number];
altitude = base_altitude[layer_number]
+ coefficient * (pow(base, exponent) - 1);
}
return altitude;
}
/*
* Values for our MP3H6115A pressure sensor
*
* From the data sheet:
*
* Pressure range: 15-115 kPa
* Voltage at 115kPa: 2.82
* Output scale: 27mV/kPa
*
*
* 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
* 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
*/
double
cc_barometer_to_pressure(double count)
{
return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
}
double
cc_barometer_to_altitude(double baro)
{
double Pa = cc_barometer_to_pressure(baro);
return cc_pressure_to_altitude(Pa);
}
static const double count_per_mss = 27.0;
double
cc_accelerometer_to_acceleration(double accel, double ground_accel)
{
return (ground_accel - accel) / count_per_mss;
}
/* Value for the CC1111 built-in temperature sensor
* Output voltage at 0°C = 0.755V
* Coefficient = 0.00247V/°C
* Reference voltage = 1.25V
*
* temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
* = (value - 19791.268) / 32768 * 1.25 / 0.00247
*/
double
cc_thermometer_to_temperature(double thermo)
{
return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
}
double
cc_battery_to_voltage(double battery)
{
return battery / 32767.0 * 5.0;
}
double
cc_ignitor_to_voltage(double ignite)
{
return ignite / 32767 * 15.0;
}
static inline double sqr(double a) { return a * a; }
void
cc_great_circle (double start_lat, double start_lon,
double end_lat, double end_lon,
double *dist, double *bearing)
{
const double rad = M_PI / 180;
const double earth_radius = 6371.2 * 1000; /* in meters */
double lat1 = rad * start_lat;
double lon1 = rad * -start_lon;
double lat2 = rad * end_lat;
double lon2 = rad * -end_lon;
// double d_lat = lat2 - lat1;
double d_lon = lon2 - lon1;
/* From http://en.wikipedia.org/wiki/Great-circle_distance */
double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) +
sqr(cos(lat1) * sin(lat2) -
sin(lat1) * cos(lat2) * cos(d_lon)));
double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon);
double d = atan2(vdn,vdd);
double course;
if (cos(lat1) < 1e-20) {
if (lat1 > 0)
course = M_PI;
else
course = -M_PI;
} else {
if (d < 1e-10)
course = 0;
else
course = acos((sin(lat2)-sin(lat1)*cos(d)) /
(sin(d)*cos(lat1)));
if (sin(lon2-lon1) > 0)
course = 2 * M_PI-course;
}
*dist = d * earth_radius;
*bearing = course * 180/M_PI;
}

146
ao-tools/lib/cc-dsp.c Normal file
View File

@@ -0,0 +1,146 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include "cephes.h"
#include <math.h>
#include <stdlib.h>
static inline double sqr (double x) { return x * x; }
/*
* Kaiser Window digital filter
*/
#if 0
/* not used in this program */
static double highpass (double n, double m, double wc)
{
double alpha = m/2;
double dist;
dist = n - alpha;
if (dist == 0)
return (M_PI/2 - wc) / M_PI;
return -sin(dist * (M_PI/2-wc)) / (M_PI * dist);
}
#endif
static double lowpass (double n, double m, double wc)
{
double alpha = m/2;
double dist;
dist = n - alpha;
if (dist == 0)
return wc / M_PI;
return sin (wc * dist) / (M_PI * dist);
}
static double kaiser (double n, double m, double beta)
{
double alpha = m / 2;
return i0 (beta * sqrt (1 - sqr((n - alpha) / alpha))) / i0(beta);
}
static double beta (double A)
{
if (A > 50)
return 0.1102 * (A - 8.7);
else if (A >= 21)
return 0.5842 * pow((A - 21), 0.4) + 0.07886 * (A - 21);
else
return 0.0;
}
static int M (double A, double delta_omega)
{
if (A > 21)
return ceil ((A - 7.95) / (2.285 * delta_omega));
else
return ceil(5.79 / delta_omega);
}
struct filter_param {
double omega_pass;
double delta_omega;
double A;
double beta;
int M;
} filter_param_t;
static struct filter_param
filter (double omega_pass, double omega_stop, double error)
{
struct filter_param p;
p.omega_pass = omega_pass;
p.delta_omega = omega_stop - omega_pass;
p.A = -20 * log10 (error);
p.beta = beta (p.A);
p.M = M (p.A, p.delta_omega);
if ((p.M & 1) == 1)
p.M++;
return p;
}
static double *
make_low_pass_filter(double omega_pass, double omega_stop, double error, int *length_p)
{
struct filter_param p = filter(omega_pass, omega_stop, error);
int length;
int n;
double *lpf;
length = p.M + 1;
lpf = calloc (length, sizeof(double));
for (n = 0; n < length; n++)
lpf[n] = lowpass(n, p.M, omega_pass) * kaiser(n, p.M, p.beta);
*length_p = length;
return lpf;
}
static double *
convolve(double *d, int d_len, double *e, int e_len)
{
int w = (e_len - 1) / 2;
int n;
double *con = calloc (d_len, sizeof (double));
for (n = 0; n < d_len; n++) {
double v = 0;
int o;
for (o = -w; o <= w; o++) {
int p = n + o;
double sample = p < 0 ? d[0] : p >= d_len ? d[d_len-1] : d[p];
v += sample * e[o + w];
}
con[n] = v;
}
return con;
}
double *
cc_low_pass(double *data, int data_len, double omega_pass, double omega_stop, double error)
{
int fir_len;
double *fir = make_low_pass_filter(omega_pass, omega_stop, error, &fir_len);
double *result;
result = convolve(data, data_len, fir, fir_len);
free(fir);
return result;
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <stdlib.h>
struct cc_timedata *
cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), double a)
{
struct cc_timedata *r;
int n;
r = calloc (1, sizeof (struct cc_timedata));
r->num = d->num;
r->size = d->num;
r->data = calloc (r->size, sizeof (struct cc_timedataelt));
r->time_offset = d->time_offset;
for (n = 0; n < d->num; n++) {
r->data[n].time = d->data[n].time;
r->data[n].value = f(d->data[n].value, a);
}
return r;
}
struct cc_timedata *
cc_timedata_integrate(struct cc_timedata *d, double min_time, double max_time)
{
struct cc_timedata *i;
int n, m;
int start, stop;
cc_timedata_limits(d, min_time, max_time, &start, &stop);
i = calloc (1, sizeof (struct cc_timedata));
i->num = stop - start + 1;
i->size = i->num;
i->data = calloc (i->size, sizeof (struct cc_timedataelt));
i->time_offset = d->data[start].time;
for (n = 0; n < i->num; n++) {
m = n + start;
i->data[n].time = d->data[m].time;
if (n == 0) {
i->data[n].value = 0;
} else {
i->data[n].value = i->data[n-1].value +
(d->data[m].value + d->data[m-1].value) / 2 *
((d->data[m].time - d->data[m-1].time) / 100.0);
}
}
return i;
}
struct cc_perioddata *
cc_perioddata_differentiate(struct cc_perioddata *i)
{
struct cc_perioddata *d;
int n;
d = calloc (1, sizeof (struct cc_perioddata));
d->num = i->num;
d->start = i->start;
d->step = i->step;
d->data = calloc (d->num, sizeof(double));
for (n = 1; n < d->num; n++)
d->data[n] = (i->data[n] - i->data[n-1]) / (i->step / 100.0);
d->data[0] = d->data[1];
return d;
}

122
ao-tools/lib/cc-log.c Normal file
View File

@@ -0,0 +1,122 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <gconf/gconf-client.h>
#include "cc.h"
static char *cc_file_dir;
#define ALTOS_DIR_PATH "/apps/aoview/log_dir"
#define DEFAULT_DIR "AltOS"
static void
cc_file_save_conf(void)
{
GConfClient *gconf_client;
g_type_init();
gconf_client = gconf_client_get_default();
if (gconf_client)
{
gconf_client_set_string(gconf_client,
ALTOS_DIR_PATH,
cc_file_dir,
NULL);
g_object_unref(G_OBJECT(gconf_client));
}
}
static void
cc_file_load_conf(void)
{
char *file_dir;
GConfClient *gconf_client;
g_type_init();
gconf_client = gconf_client_get_default();
if (gconf_client)
{
file_dir = gconf_client_get_string(gconf_client,
ALTOS_DIR_PATH,
NULL);
g_object_unref(G_OBJECT(gconf_client));
if (file_dir)
cc_file_dir = strdup(file_dir);
}
}
void
cc_set_log_dir(char *dir)
{
cc_file_dir = strdup(dir);
cc_file_save_conf();
}
char *
cc_get_log_dir(void)
{
cc_file_load_conf();
if (!cc_file_dir) {
cc_file_dir = cc_fullname(getenv("HOME"), DEFAULT_DIR);
cc_file_save_conf();
}
return cc_file_dir;
}
char *
cc_make_filename(int serial, int flight, char *ext)
{
char base[50];
char seq[20];
struct tm tm;
time_t now;
char *full;
int r;
int sequence;
now = time(NULL);
(void) localtime_r(&now, &tm);
cc_mkdir(cc_get_log_dir());
sequence = 0;
for (;;) {
if (sequence)
snprintf(seq, sizeof(seq), "-seq-%03d", sequence);
else
seq[0] = '\0';
snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d%s.%s",
tm.tm_year + 1900,
tm.tm_mon + 1,
tm.tm_mday,
serial,
flight,
seq,
ext);
full = cc_fullname(cc_get_log_dir(), base);
r = access(full, F_OK);
if (r < 0)
return full;
free(full);
sequence++;
}
}

337
ao-tools/lib/cc-logfile.c Normal file
View File

@@ -0,0 +1,337 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
timedata_add(struct cc_timedata *data, double time, double value)
{
struct cc_timedataelt *newdata;
int newsize;
if (data->size == data->num) {
if (data->size == 0)
newdata = malloc((newsize = 256) * sizeof (struct cc_timedataelt));
else
newdata = realloc (data->data, (newsize = data->size * 2)
* sizeof (struct cc_timedataelt));
if (!newdata)
return 0;
data->size = newsize;
data->data = newdata;
}
time += data->time_offset;
if (data->num && data->data[data->num-1].time > time) {
data->time_offset += 65536;
time += 65536;
}
data->data[data->num].time = time;
data->data[data->num].value = value;
data->num++;
return 1;
}
static void
timedata_free(struct cc_timedata *data)
{
if (data->data)
free(data->data);
}
static int
gpsdata_add(struct cc_gpsdata *data, struct cc_gpselt *elt)
{
struct cc_gpselt *newdata;
int newsize;
if (data->size == data->num) {
if (data->size == 0)
newdata = malloc((newsize = 256) * sizeof (struct cc_gpselt));
else
newdata = realloc (data->data, (newsize = data->size * 2)
* sizeof (struct cc_gpselt));
if (!newdata)
return 0;
data->size = newsize;
data->data = newdata;
}
elt->time += data->time_offset;
if (data->num && data->data[data->num-1].time > elt->time) {
data->time_offset += 65536;
elt->time += 65536;
}
data->data[data->num] = *elt;
data->num++;
return 1;
}
static int
gpssat_add(struct cc_gpsdata *data, struct cc_gpssat *sat)
{
int i, j;
int reuse = 0;
int newsizesats;
struct cc_gpssats *newsats;
for (i = data->numsats; --i >= 0;) {
if (data->sats[i].sat[0].time == sat->time) {
reuse = 1;
break;
}
if (data->sats[i].sat[0].time < sat->time)
break;
}
if (!reuse) {
if (data->numsats == data->sizesats) {
if (data->sizesats == 0)
newsats = malloc((newsizesats = 256) * sizeof (struct cc_gpssats));
else
newsats = realloc (data->sats, (newsizesats = data->sizesats * 2)
* sizeof (struct cc_gpssats));
if (!newsats)
return 0;
data->sats = newsats;
data->sizesats = newsizesats;
}
i = data->numsats++;
data->sats[i].nsat = 0;
}
j = data->sats[i].nsat;
if (j < 12) {
data->sats[i].sat[j] = *sat;
data->sats[i].nsat = j + 1;
}
return 1;
}
static void
gpsdata_free(struct cc_gpsdata *data)
{
if (data->data)
free(data->data);
}
#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_POS_NONE (~0UL)
#define GPS_TIME 1
#define GPS_LAT 2
#define GPS_LON 4
#define GPS_ALT 8
static int
read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int *ground_pres_count)
{
char type;
int tick;
int a, b;
static struct cc_gpselt gps;
static int gps_valid;
struct cc_gpssat sat;
int serial;
if (sscanf(line, "serial-number %u", &serial) == 1) {
f->serial = serial;
return 1;
}
if (sscanf(line, "%c %x %x %x", &type, &tick, &a, &b) != 4)
return 0;
switch (type) {
case AO_LOG_FLIGHT:
f->ground_accel = a;
f->ground_pres = 0;
f->flight = b;
*ground_pres = 0;
*ground_pres_count = 0;
break;
case AO_LOG_SENSOR:
timedata_add(&f->accel, tick, a);
timedata_add(&f->pres, tick, b);
if (*ground_pres_count < 20) {
*ground_pres += b;
(*ground_pres_count)++;
if (*ground_pres_count >= 20)
f->ground_pres = *ground_pres / *ground_pres_count;
}
break;
case AO_LOG_TEMP_VOLT:
timedata_add(&f->temp, tick, a);
timedata_add(&f->volt, tick, b);
break;
case AO_LOG_DEPLOY:
timedata_add(&f->drogue, tick, a);
timedata_add(&f->main, tick, b);
break;
case AO_LOG_STATE:
timedata_add(&f->state, tick, a);
break;
case AO_LOG_GPS_TIME:
/* the flight computer writes TIME first, so reset
* any stale data before adding this record
*/
gps.time = tick;
gps.hour = (a & 0xff);
gps.minute = (a >> 8) & 0xff;
gps.second = (b & 0xff);
gps.flags = (b >> 8) & 0xff;
gps_valid = GPS_TIME;
break;
case AO_LOG_GPS_LAT:
gps.lat = ((int32_t) (a + (b << 16))) / 10000000.0;
gps_valid |= GPS_LAT;
break;
case AO_LOG_GPS_LON:
gps.lon = ((int32_t) (a + (b << 16))) / 10000000.0;
gps_valid |= GPS_LON;
break;
case AO_LOG_GPS_ALT:
gps.alt = (int16_t) a;
gps_valid |= GPS_ALT;
break;
case AO_LOG_GPS_SAT:
sat.time = tick;
sat.svid = a;
sat.c_n = (b >> 8) & 0xff;
gpssat_add(&f->gps, &sat);
break;
case AO_LOG_GPS_DATE:
f->year = 2000 + (a & 0xff);
f->month = (a >> 8) & 0xff;
f->day = (b & 0xff);
break;
default:
return 0;
}
if (gps_valid == 0xf) {
gps_valid = 0;
gpsdata_add(&f->gps, &gps);
}
return 1;
}
static const char *state_names[] = {
"startup",
"idle",
"pad",
"boost",
"fast",
"coast",
"drogue",
"main",
"landed",
"invalid"
};
static enum ao_flight_state
state_name_to_state(char *state_name)
{
enum ao_flight_state state;
for (state = ao_flight_startup; state < ao_flight_invalid; state++)
if (!strcmp(state_names[state], state_name))
return state;
return ao_flight_invalid;
}
static int
read_telem(const char *line, struct cc_flightraw *f)
{
struct cc_telem telem;
struct cc_gpselt gps;
struct cc_gpssat sat;
int s;
if (!cc_telem_parse(line, &telem))
return 0;
f->ground_accel = telem.ground_accel;
f->ground_pres = telem.ground_pres;
f->flight = 0;
timedata_add(&f->accel, telem.tick, telem.flight_accel);
timedata_add(&f->pres, telem.tick, telem.flight_pres);
timedata_add(&f->temp, telem.tick, telem.temp);
timedata_add(&f->volt, telem.tick, telem.batt);
timedata_add(&f->drogue, telem.tick, telem.drogue);
timedata_add(&f->main, telem.tick, telem.main);
timedata_add(&f->state, telem.tick, state_name_to_state(telem.state));
if (telem.gps.gps_locked) {
f->year = telem.gps.gps_time.year;
f->month = telem.gps.gps_time.month;
f->day = telem.gps.gps_time.day;
gps.time = telem.tick;
gps.lat = telem.gps.lat;
gps.lon = telem.gps.lon;
gps.alt = telem.gps.alt;
gps.hour = telem.gps.gps_time.hour;
gps.minute = telem.gps.gps_time.minute;
gps.second = telem.gps.gps_time.second;
gpsdata_add(&f->gps, &gps);
}
for (s = 0; s < telem.gps_tracking.channels; s++) {
sat.time = telem.tick;
sat.svid = telem.gps_tracking.sats[s].svid;
sat.c_n = telem.gps_tracking.sats[s].c_n0;
gpssat_add(&f->gps, &sat);
}
return 1;
}
struct cc_flightraw *
cc_log_read(FILE *file)
{
struct cc_flightraw *f;
char line[8192];
double ground_pres = 0.0;
int ground_pres_count = 0;
f = calloc(1, sizeof (struct cc_flightraw));
if (!f)
return NULL;
while (fgets(line, sizeof (line), file)) {
if (read_eeprom(line, f, &ground_pres, &ground_pres_count))
continue;
if (read_telem(line, f))
continue;
fprintf (stderr, "invalid line: %s", line);
}
return f;
}
void
cc_flightraw_free(struct cc_flightraw *raw)
{
timedata_free(&raw->accel);
timedata_free(&raw->pres);
timedata_free(&raw->temp);
timedata_free(&raw->volt);
timedata_free(&raw->main);
timedata_free(&raw->drogue);
timedata_free(&raw->state);
gpsdata_free(&raw->gps);
free(raw);
}

161
ao-tools/lib/cc-mega.c Normal file
View File

@@ -0,0 +1,161 @@
/*
* Copyright © 2012 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <string.h>
#include <ctype.h>
static const char *
parse_hex(const char *data, int *result)
{
char d[12];
int x;
int i;
while (isspace (*data))
data++;
for (i = 0; i < sizeof (d) - 1 && isxdigit(*data); i++)
d[i] = *data++;
d[i] = '\0';
if (sscanf(d, "%x", &x) != 1)
return NULL;
*result = x;
return data;
}
static const char *
parse_uint16(const char *data, uint16_t *result)
{
int x;
data = parse_hex(data, &x);
*result =x;
return data;
}
static const char *
parse_uint8(const char *data, uint8_t *result)
{
int x;
data = parse_hex(data, &x);
*result =x;
return data;
}
static int
parse_eeprom(const char *input_line, struct ao_log_mega *l) {
const char *line;
int b;
if (input_line[1] != ' ')
return 0;
if (!isupper(input_line[0]))
return 0;
l->type = input_line[0];
l->is_config = 0;
line = input_line + 2;
line = parse_uint16(line, &l->tick);
for (b = 0; b < 28; b++) {
if (!line)
return 0;
line = parse_uint8(line, &l->u.bytes[b]);
}
return 1;
}
#define YUP(t) do { \
l->u.config_int.kind = (t); \
l->is_config = 1; \
return 1; \
} while (0);
static int
parse_config(const char *input_line, struct ao_log_mega *l) {
if (sscanf (input_line, "Config version: %d.%d",
&l->u.config_int.data[0],
&l->u.config_int.data[1]))
YUP(AO_CONFIG_CONFIG);
if (sscanf (input_line, "Main deploy: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MAIN);
if (sscanf (input_line, "Apogee delay: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_APOGEE);
if (sscanf (input_line, "Apogee lockout: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_LOCKOUT);
if (sscanf (input_line, "Frequency: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_FREQUENCY);
if (sscanf (input_line, "Radio enable: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_RADIO_ENABLE);
if (sscanf (input_line, "Accel cal +1g: %d -1g: %d",
&l->u.config_int.data[0],
&l->u.config_int.data[1]))
YUP(AO_CONFIG_ACCEL_CAL);
if (sscanf (input_line, "Radio cal: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_RADIO_CAL);
if (sscanf (input_line, "Max flight log: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MAX_LOG);
if (sscanf (input_line, "Ignite mode: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_IGNITE_MODE);
if (sscanf (input_line, "Pad orientation: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_PAD_ORIENTATION);
if (sscanf (input_line, "serial-number %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_SERIAL_NUMBER);
if (sscanf (input_line, "log-format %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_LOG_FORMAT);
if (sscanf (input_line, "ms5607 reserved: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_RESERVED);
if (sscanf (input_line, "ms5607 sens: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_SENS);
if (sscanf (input_line, "ms5607 off: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_OFF);
if (sscanf (input_line, "ms5607 tcs: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_TCS);
if (sscanf (input_line, "ms5607 tco: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_TCO);
if (sscanf (input_line, "ms5607 tref: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_TREF);
if (sscanf (input_line, "ms5607 tempsens: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_TEMPSENS);
if (sscanf (input_line, "ms5607 crc: %d",
&l->u.config_int.data[0]))
YUP(AO_CONFIG_MS5607_CRC);
return 0;
}
int
cc_mega_parse(const char *input_line, struct ao_log_mega *l) {
return parse_eeprom(input_line, l) || parse_config(input_line, l);
}

57
ao-tools/lib/cc-period.c Normal file
View File

@@ -0,0 +1,57 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <stdlib.h>
#include <math.h>
struct cc_perioddata *
cc_period_make(struct cc_timedata *td, double start_time, double stop_time)
{
int len = stop_time - start_time + 1;
struct cc_perioddata *pd;
int i, j;
double t;
pd = calloc(1, sizeof (struct cc_perioddata));
pd->start = start_time;
pd->step = 1;
pd->num = len;
pd->data = calloc(len, sizeof(double));
j = 0;
for (i = 0; i < pd->num; i++) {
t = start_time + i * pd->step;
while (j < td->num - 1 && fabs(t - td->data[j].time) >= fabs(t - td->data[j+1].time))
j++;
pd->data[i] = td->data[j].value;
}
return pd;
}
struct cc_perioddata *
cc_period_low_pass(struct cc_perioddata *raw, double omega_pass, double omega_stop, double error)
{
struct cc_perioddata *filtered;
filtered = calloc (1, sizeof (struct cc_perioddata));
filtered->start = raw->start;
filtered->step = raw->step;
filtered->num = raw->num;
filtered->data = cc_low_pass(raw->data, raw->num, omega_pass, omega_stop, error);
return filtered;
}

167
ao-tools/lib/cc-process.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
static void
cook_timed(struct cc_timedata *td, struct cc_perioddata *pd,
double start_time, double stop_time,
double omega_pass, double omega_stop, double error)
{
struct cc_perioddata *unfiltered, *filtered;
unfiltered = cc_period_make(td, start_time, stop_time);
filtered = cc_period_low_pass (unfiltered, omega_pass, omega_stop, error);
*pd = *filtered;
free (filtered);
free (unfiltered->data);
free (unfiltered);
}
static double
barometer_to_altitude(double b, double pad_alt)
{
return cc_barometer_to_altitude(b) - pad_alt;
}
struct cc_flightcooked *
cc_flight_cook(struct cc_flightraw *raw)
{
struct cc_flightcooked *cooked;
double flight_start = 0;
double flight_stop = 0;
int start_set = 0;
int stop_set = 0;
int i;
struct cc_timedata *accel;
struct cc_timedata *accel_speed;
struct cc_timedata *accel_pos;
struct cc_timedata *pres;
struct cc_perioddata *pres_speed;
struct cc_perioddata *pres_accel;
if (raw->accel.num == 0)
return NULL;
cooked = calloc (1, sizeof (struct cc_flightcooked));
/*
* Find flight start and stop times by looking at
* state transitions. The stop time is set to the time
* of landing, which may be long after it landed (due to radio
* issues). Refine this value by looking through the sensor data
*/
for (i = 0; i < raw->state.num; i++) {
if (!start_set && raw->state.data[i].value > ao_flight_pad) {
flight_start = raw->state.data[i].time - 10;
start_set = 1;
}
if (!stop_set && raw->state.data[i].value > ao_flight_main) {
flight_stop = raw->state.data[i].time;
stop_set = 1;
}
}
if (!start_set || flight_start < raw->accel.data[0].time)
flight_start = raw->accel.data[0].time;
if (stop_set) {
for (i = 0; i < raw->accel.num - 1; i++) {
if (raw->accel.data[i+1].time >= flight_stop) {
flight_stop = raw->accel.data[i].time;
break;
}
}
} else {
flight_stop = raw->accel.data[raw->accel.num-1].time;
}
cooked->flight_start = flight_start;
cooked->flight_stop = flight_stop;
/* Integrate the accelerometer data to get speed and position */
accel = cc_timedata_convert(&raw->accel, cc_accelerometer_to_acceleration, raw->ground_accel);
cooked->accel = *accel;
free(accel);
accel_speed = cc_timedata_integrate(&cooked->accel, flight_start - 10, flight_stop);
accel_pos = cc_timedata_integrate(accel_speed, flight_start - 10, flight_stop);
#define ACCEL_OMEGA_PASS (2 * M_PI * 20 / 100)
#define ACCEL_OMEGA_STOP (2 * M_PI * 30 / 100)
#define BARO_OMEGA_PASS (2 * M_PI * .5 / 100)
#define BARO_OMEGA_STOP (2 * M_PI * 1 / 100)
#define FILTER_ERROR (1e-8)
cook_timed(&cooked->accel, &cooked->accel_accel,
flight_start, flight_stop,
ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR);
cook_timed(accel_speed, &cooked->accel_speed,
flight_start, flight_stop,
ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR);
free(accel_speed->data); free(accel_speed);
cook_timed(accel_pos, &cooked->accel_pos,
flight_start, flight_stop,
ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR);
free(accel_pos->data); free(accel_pos);
/* Filter the pressure data */
pres = cc_timedata_convert(&raw->pres, barometer_to_altitude,
cc_barometer_to_altitude(raw->ground_pres));
cooked->pres = *pres;
free(pres);
cook_timed(&cooked->pres, &cooked->pres_pos,
flight_start, flight_stop,
BARO_OMEGA_PASS, BARO_OMEGA_STOP, FILTER_ERROR);
/* differentiate twice to get to acceleration */
pres_speed = cc_perioddata_differentiate(&cooked->pres_pos);
pres_accel = cc_perioddata_differentiate(pres_speed);
cooked->pres_speed = *pres_speed;
free(pres_speed);
cooked->pres_accel = *pres_accel;
free(pres_accel);
/* copy state */
cooked->state.num = raw->state.num;
cooked->state.size = raw->state.num;
cooked->state.data = calloc(cooked->state.num, sizeof (struct cc_timedataelt));
memcpy(cooked->state.data, raw->state.data, cooked->state.num * sizeof (struct cc_timedataelt));
cooked->state.time_offset = raw->state.time_offset;
return cooked;
}
#define if_free(x) ((x) ? free(x) : (void) 0)
void
cc_flightcooked_free(struct cc_flightcooked *cooked)
{
if_free(cooked->accel_accel.data);
if_free(cooked->accel_speed.data);
if_free(cooked->accel_pos.data);
if_free(cooked->pres_pos.data);
if_free(cooked->pres_speed.data);
if_free(cooked->pres_accel.data);
if_free(cooked->gps_lat.data);
if_free(cooked->gps_lon.data);
if_free(cooked->gps_alt.data);
if_free(cooked->state.data);
if_free(cooked->accel.data);
if_free(cooked->pres.data);
free(cooked);
}

213
ao-tools/lib/cc-telem.c Normal file
View File

@@ -0,0 +1,213 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <string.h>
#include <stdlib.h>
static void
cc_parse_string(char *target, int len, char *source)
{
strncpy(target, source, len-1);
target[len-1] = '\0';
}
static void
cc_parse_int(int *target, char *source)
{
*target = strtol(source, NULL, 0);
}
static void
cc_parse_hex(int *target, char *source)
{
*target = strtol(source, NULL, 16);
}
static void
cc_parse_pos(double *target, char *source)
{
int deg;
double min;
char dir;
double r;
if (sscanf(source, "%d°%lf'%c", &deg, &min, &dir) != 3) {
*target = 0;
return;
}
r = deg + min / 60.0;
if (dir == 'S' || dir == 'W')
r = -r;
*target = r;
}
#define PARSE_MAX_WORDS 512
int
cc_telem_parse(const char *input_line, struct cc_telem *telem)
{
char *saveptr;
char *raw_words[PARSE_MAX_WORDS];
char **words;
int version = 0;
int nword;
char line_buf[8192], *line;
int tracking_pos;
/* avoid smashing our input parameter */
strncpy (line_buf, input_line, sizeof (line_buf)-1);
line_buf[sizeof(line_buf) - 1] = '\0';
line = line_buf;
for (nword = 0; nword < PARSE_MAX_WORDS; nword++) {
raw_words[nword] = strtok_r(line, " \t\n", &saveptr);
line = NULL;
if (raw_words[nword] == NULL)
break;
}
if (nword < 36)
return FALSE;
words = raw_words;
if (strcmp(words[0], "VERSION") == 0) {
cc_parse_int(&version, words[1]);
words += 2;
nword -= 2;
}
if (strcmp(words[0], "CALL") != 0)
return FALSE;
cc_parse_string(telem->callsign, sizeof (telem->callsign), words[1]);
cc_parse_int(&telem->serial, words[3]);
if (version >= 2) {
cc_parse_int(&telem->flight, words[5]);
words += 2;
nword -= 2;
} else
telem->flight = 0;
cc_parse_int(&telem->rssi, words[5]);
if (version <= 2) {
/* Older telemetry versions mis-computed the rssi value */
telem->rssi = (telem->rssi + 74) / 2 - 74;
}
cc_parse_string(telem->state, sizeof (telem->state), words[9]);
cc_parse_int(&telem->tick, words[10]);
cc_parse_int(&telem->accel, words[12]);
cc_parse_int(&telem->pres, words[14]);
cc_parse_int(&telem->temp, words[16]);
cc_parse_int(&telem->batt, words[18]);
cc_parse_int(&telem->drogue, words[20]);
cc_parse_int(&telem->main, words[22]);
cc_parse_int(&telem->flight_accel, words[24]);
cc_parse_int(&telem->ground_accel, words[26]);
cc_parse_int(&telem->flight_vel, words[28]);
cc_parse_int(&telem->flight_pres, words[30]);
cc_parse_int(&telem->ground_pres, words[32]);
if (version >= 1) {
cc_parse_int(&telem->accel_plus_g, words[34]);
cc_parse_int(&telem->accel_minus_g, words[36]);
words += 4;
nword -= 4;
} else {
telem->accel_plus_g = telem->ground_accel;
telem->accel_minus_g = telem->ground_accel + 530;
}
cc_parse_int(&telem->gps.nsat, words[34]);
if (strcmp (words[36], "unlocked") == 0) {
telem->gps.gps_connected = 1;
telem->gps.gps_locked = 0;
telem->gps.gps_time.year = telem->gps.gps_time.month = telem->gps.gps_time.day = 0;
telem->gps.gps_time.hour = telem->gps.gps_time.minute = telem->gps.gps_time.second = 0;
telem->gps.lat = telem->gps.lon = 0;
telem->gps.alt = 0;
tracking_pos = 37;
} else if (nword >= 40) {
telem->gps.gps_locked = 1;
telem->gps.gps_connected = 1;
if (version >= 2) {
sscanf(words[36], "%d-%d-%d",
&telem->gps.gps_time.year,
&telem->gps.gps_time.month,
&telem->gps.gps_time.day);
words += 1;
nword -= 1;
} else {
telem->gps.gps_time.year = telem->gps.gps_time.month = telem->gps.gps_time.day = 0;
}
sscanf(words[36], "%d:%d:%d", &telem->gps.gps_time.hour, &telem->gps.gps_time.minute, &telem->gps.gps_time.second);
cc_parse_pos(&telem->gps.lat, words[37]);
cc_parse_pos(&telem->gps.lon, words[38]);
sscanf(words[39], "%dm", &telem->gps.alt);
tracking_pos = 46;
} else {
telem->gps.gps_connected = 0;
telem->gps.gps_locked = 0;
telem->gps.gps_time.year = telem->gps.gps_time.month = telem->gps.gps_time.day = 0;
telem->gps.gps_time.hour = telem->gps.gps_time.minute = telem->gps.gps_time.second = 0;
telem->gps.lat = telem->gps.lon = 0;
telem->gps.alt = 0;
tracking_pos = -1;
}
if (nword >= 46) {
telem->gps.gps_extended = 1;
sscanf(words[40], "%lfm/s", &telem->gps.ground_speed);
sscanf(words[41], "%d", &telem->gps.course);
sscanf(words[42], "%lfm/s", &telem->gps.climb_rate);
sscanf(words[43], "%lf", &telem->gps.hdop);
sscanf(words[44], "%d", &telem->gps.h_error);
sscanf(words[45], "%d", &telem->gps.v_error);
} else {
telem->gps.gps_extended = 0;
telem->gps.ground_speed = 0;
telem->gps.course = 0;
telem->gps.climb_rate = 0;
telem->gps.hdop = 0;
telem->gps.h_error = 0;
telem->gps.v_error = 0;
}
if (tracking_pos >= 0 && nword >= tracking_pos + 2 && strcmp(words[tracking_pos], "SAT") == 0) {
int c, n, pos;
int per_sat;
int state;
if (version >= 2)
per_sat = 2;
else
per_sat = 3;
cc_parse_int(&n, words[tracking_pos + 1]);
pos = tracking_pos + 2;
if (nword >= pos + n * per_sat) {
telem->gps_tracking.channels = n;
for (c = 0; c < n; c++) {
cc_parse_int(&telem->gps_tracking.sats[c].svid,
words[pos + 0]);
if (version < 2)
cc_parse_hex(&state, words[pos + 1]);
cc_parse_int(&telem->gps_tracking.sats[c].c_n0,
words[pos + per_sat - 1]);
pos += per_sat;
}
} else {
telem->gps_tracking.channels = 0;
}
} else {
telem->gps_tracking.channels = 0;
}
return TRUE;
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright © 2011 Keith Packard <keithp@keithp.com>
*
* 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 "cc.h"
#include <string.h>
static int
parse_byte(char *data, uint8_t *byte)
{
char d[3];
int x;
d[0] = data[0];
d[1] = data[1];
d[2] = '\0';
if (sscanf(d, "%x", &x) != 1)
return FALSE;
*byte = x;
return TRUE;
}
int
cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry)
{
uint8_t *byte;
char *data;
uint8_t hex[35];
int i;
if (strncmp(input_line, "TELEM", 5) != 0)
return FALSE;
data = strchr (input_line, ' ');
if (!data)
return FALSE;
data++;
byte = hex;
for (i = 0; i < 35; i++) {
if (!parse_byte(data, byte))
return FALSE;
data += 2;
byte++;
}
if (hex[0] != 34)
return FALSE;
memcpy(telemetry, hex+1, 34);
return TRUE;
}
uint8_t
cc_telemetry_cksum(const union ao_telemetry_all *telemetry)
{
const uint8_t *x = (const uint8_t *) telemetry;
int i;
uint8_t sum = 0x5a;
for (i = 0; i < 34; i++)
sum += x[i];
return sum;
}
void
cc_telemetry_unparse(const union ao_telemetry_all *telemetry, char output_line[CC_TELEMETRY_BUFSIZE])
{
uint8_t hex[36];
int i;
int p;
hex[0] = 34;
memcpy(hex+1, telemetry, 34);
hex[35] = cc_telemetry_cksum(telemetry);
strcpy(output_line, "TELEM ");
p = strlen(output_line);
for (i = 0; i < 36; i++) {
sprintf(output_line + p, "%02x", hex[i]);
p += 2;
}
}

338
ao-tools/lib/cc-telemetry.h Normal file
View File

@@ -0,0 +1,338 @@
/*
* Copyright © 2011 Keith Packard <keithp@keithp.com>
*
* 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 _CC_TELEMETRY_H_
#define _CC_TELEMETRY_H_
/*
* ao_telemetry.c
*/
#define AO_MAX_CALLSIGN 8
#define AO_MAX_VERSION 8
#define AO_MAX_TELEMETRY 128
struct ao_telemetry_generic {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t payload[27]; /* 5 */
uint8_t rssi; /* 32 */
uint8_t status; /* 33 */
/* 34 */
};
#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
#define AO_TELEMETRY_SENSOR_TELEMINI 0x02
#define AO_TELEMETRY_SENSOR_TELENANO 0x03
struct ao_telemetry_sensor {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t state; /* 5 flight state */
int16_t accel; /* 6 accelerometer (TM only) */
int16_t pres; /* 8 pressure sensor */
int16_t temp; /* 10 temperature sensor */
int16_t v_batt; /* 12 battery voltage */
int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */
int16_t sense_m; /* 16 main continuity sense (TM/Tm) */
int16_t acceleration; /* 18 m/s² * 16 */
int16_t speed; /* 20 m/s * 16 */
int16_t height; /* 22 m */
int16_t ground_pres; /* 24 average pres on pad */
int16_t ground_accel; /* 26 average accel on pad */
int16_t accel_plus_g; /* 28 accel calibration at +1g */
int16_t accel_minus_g; /* 30 accel calibration at -1g */
/* 32 */
};
#define AO_TELEMETRY_CONFIGURATION 0x04
struct ao_telemetry_configuration {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t device; /* 5 device type */
uint16_t flight; /* 6 flight number */
uint8_t config_major; /* 8 Config major version */
uint8_t config_minor; /* 9 Config minor version */
uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */
uint16_t main_deploy; /* 12 Main deploy alt in meters */
uint16_t flight_log_max; /* 14 Maximum flight log size in kB */
char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */
char version[AO_MAX_VERSION]; /* 24 Software version */
/* 32 */
};
#define AO_TELEMETRY_LOCATION 0x05
#define AO_GPS_MODE_NOT_VALID 'N'
#define AO_GPS_MODE_AUTONOMOUS 'A'
#define AO_GPS_MODE_DIFFERENTIAL 'D'
#define AO_GPS_MODE_ESTIMATED 'E'
#define AO_GPS_MODE_MANUAL 'M'
#define AO_GPS_MODE_SIMULATED 'S'
#define AO_GPS_MODE_ALTITUDE_24 (1 << 0) /* reports 24-bits of altitude */
struct ao_telemetry_location {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t flags; /* 5 Number of sats and other flags */
int16_t altitude_low; /* 6 GPS reported altitude (m) */
int32_t latitude; /* 8 latitude (degrees * 10⁷) */
int32_t longitude; /* 12 longitude (degrees * 10⁷) */
uint8_t year; /* 16 (- 2000) */
uint8_t month; /* 17 (1-12) */
uint8_t day; /* 18 (1-31) */
uint8_t hour; /* 19 (0-23) */
uint8_t minute; /* 20 (0-59) */
uint8_t second; /* 21 (0-59) */
uint8_t pdop; /* 22 (m * 5) */
uint8_t hdop; /* 23 (m * 5) */
uint8_t vdop; /* 24 (m * 5) */
uint8_t mode; /* 25 */
uint16_t ground_speed; /* 26 cm/s */
int16_t climb_rate; /* 28 cm/s */
uint8_t course; /* 30 degrees / 2 */
int8_t altitude_high; /* 31 */
/* 32 */
};
typedef int32_t gps_alt_t;
#define AO_TELEMETRY_LOCATION_ALTITUDE(l) \
((l)->altitude_low | (((l)->mode & AO_GPS_MODE_ALTITUDE_24) ? \
((gps_alt_t) (l)->altitude_high << 16) : 0))
#define AO_TELEMETRY_SATELLITE 0x06
struct ao_telemetry_satellite_info {
uint8_t svid;
uint8_t c_n_1;
};
#define AO_TELEMETRY_SATELLITE_MAX_SAT 12
struct ao_telemetry_satellite {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t channels; /* 5 number of reported sats */
struct ao_telemetry_satellite_info sats[AO_TELEMETRY_SATELLITE_MAX_SAT]; /* 6 */
uint8_t unused[2]; /* 30 */
/* 32 */
};
#define AO_TELEMETRY_COMPANION 0x07
#define AO_COMPANION_MAX_CHANNELS 12
struct ao_telemetry_companion {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t board_id; /* 5 */
uint8_t update_period; /* 6 */
uint8_t channels; /* 7 */
uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */
/* 32 */
};
#define AO_TELEMETRY_MEGA_SENSOR_MPU 0x08 /* Invensense IMU */
#define AO_TELEMETRY_MEGA_SENSOR_BMX160 0x12 /* BMX160 IMU */
struct ao_telemetry_mega_sensor {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t orient; /* 5 angle from vertical */
int16_t accel; /* 6 Z axis */
int32_t pres; /* 8 Pa * 10 */
int16_t temp; /* 12 °C * 100 */
int16_t accel_x; /* 14 */
int16_t accel_y; /* 16 */
int16_t accel_z; /* 18 */
int16_t gyro_x; /* 20 */
int16_t gyro_y; /* 22 */
int16_t gyro_z; /* 24 */
int16_t mag_x; /* 26 */
int16_t mag_z; /* 30 */
int16_t mag_y; /* 28 */
/* 32 */
};
#define AO_TELEMETRY_MEGA_DATA 0x09
struct ao_telemetry_mega_data {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t state; /* 5 flight state */
int16_t v_batt; /* 6 battery voltage */
int16_t v_pyro; /* 8 pyro battery voltage */
int8_t sense[6]; /* 10 continuity sense */
int32_t ground_pres; /* 16 average pres on pad */
int16_t ground_accel; /* 20 average accel on pad */
int16_t accel_plus_g; /* 22 accel calibration at +1g */
int16_t accel_minus_g; /* 24 accel calibration at -1g */
int16_t acceleration; /* 26 m/s² * 16 */
int16_t speed; /* 28 m/s * 16 */
int16_t height; /* 30 m */
/* 32 */
};
#define AO_TELEMETRY_METRUM_SENSOR 0x0A
struct ao_telemetry_metrum_sensor {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t state; /* 5 flight state */
int16_t accel; /* 6 Z axis */
int32_t pres; /* 8 Pa * 10 */
int16_t temp; /* 12 °C * 100 */
int16_t acceleration; /* 14 m/s² * 16 */
int16_t speed; /* 16 m/s * 16 */
int16_t height; /* 18 m */
int16_t v_batt; /* 20 battery voltage */
int16_t sense_a; /* 22 apogee continuity sense */
int16_t sense_m; /* 24 main continuity sense */
uint8_t pad[6]; /* 26 */
/* 32 */
};
#define AO_TELEMETRY_METRUM_DATA 0x0B
struct ao_telemetry_metrum_data {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t pad5[3]; /* 5 */
int32_t ground_pres; /* 8 average pres on pad */
int16_t ground_accel; /* 12 average accel on pad */
int16_t accel_plus_g; /* 14 accel calibration at +1g */
int16_t accel_minus_g; /* 16 accel calibration at -1g */
uint8_t pad18[14]; /* 18 */
/* 32 */
};
#define AO_TELEMETRY_MINI 0x10
#define AO_TELEMETRY_MINI3 0x11
struct ao_telemetry_mini {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t state; /* 5 flight state */
int16_t v_batt; /* 6 battery voltage */
int16_t sense_a; /* 8 apogee continuity */
int16_t sense_m; /* 10 main continuity */
int32_t pres; /* 12 Pa * 10 */
int16_t temp; /* 16 °C * 100 */
int16_t acceleration; /* 18 m/s² * 16 */
int16_t speed; /* 20 m/s * 16 */
int16_t height; /* 22 m */
int32_t ground_pres; /* 24 average pres on pad */
int32_t pad28; /* 28 */
/* 32 */
};
/* #define AO_SEND_ALL_BARO */
#define AO_TELEMETRY_BARO 0x80
/*
* This packet allows the full sampling rate baro
* data to be captured over the RF link so that the
* flight software can be tested using 'real' data.
*
* Along with this telemetry packet, the flight
* code is modified to send full-rate telemetry all the time
* and never send an RDF tone; this ensure that the full radio
* link is available.
*/
struct ao_telemetry_baro {
uint16_t serial; /* 0 */
uint16_t tick; /* 2 */
uint8_t type; /* 4 */
uint8_t samples; /* 5 number samples */
int16_t baro[12]; /* 6 samples */
/* 32 */
};
union ao_telemetry_all {
struct ao_telemetry_generic generic;
struct ao_telemetry_sensor sensor;
struct ao_telemetry_configuration configuration;
struct ao_telemetry_location location;
struct ao_telemetry_satellite satellite;
struct ao_telemetry_companion companion;
struct ao_telemetry_mega_sensor mega_sensor;
struct ao_telemetry_mega_data mega_data;
struct ao_telemetry_metrum_sensor metrum_sensor;
struct ao_telemetry_metrum_data metrum_data;
struct ao_telemetry_mini mini;
struct ao_telemetry_baro baro;
};
#define CC_TELEMETRY_HEADER "TELEM"
/* "TELEM " 1 byte length 32 data bytes 1 rssi 1 status 1 checksum 1 null */
#define CC_TELEMETRY_BUFSIZE (6 + (1 + 32 + 3) * 2 + 1)
int
cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry);
uint8_t
cc_telemetry_cksum(const union ao_telemetry_all *telemetry);
void
cc_telemetry_unparse(const union ao_telemetry_all *telemetry, char output_line[CC_TELEMETRY_BUFSIZE]);
#endif

502
ao-tools/lib/cc-usb.c Normal file
View File

@@ -0,0 +1,502 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include "ccdbg-debug.h"
#include "cc-usb.h"
#define CC_NUM_HEX_READ 64
/*
* AltOS has different buffer sizes for in/out packets
*/
#define CC_IN_BUF 65536
#define CC_OUT_BUF 64
#define DEFAULT_TTY "/dev/ttyACM0"
struct cc_hex_read {
uint8_t *buf;
int len;
};
struct cc_usb {
int fd;
uint8_t in_buf[CC_IN_BUF];
int in_pos;
int in_count;
uint8_t out_buf[CC_OUT_BUF];
int out_count;
struct cc_hex_read hex_buf[CC_NUM_HEX_READ];
int hex_count;
int show_input;
int remote;
};
#define NOT_HEX 0xff
static uint8_t
cc_hex_nibble(uint8_t c)
{
if ('0' <= c && c <= '9')
return c - '0';
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
if ('A' <= c && c <= 'F')
return c - 'A' + 10;
return NOT_HEX;
}
/*
* Take raw input bytes, parse them as hex
* and write them to the waiting buffer
*/
static void
cc_handle_hex_read(struct cc_usb *cc)
{
uint8_t h, l;
int hex_pos;
hex_pos = 0;
while (hex_pos < cc->hex_count && cc->in_pos < cc->in_count) {
/*
* Skip to next hex character
*/
while (cc->in_pos < cc->in_count &&
cc_hex_nibble(cc->in_buf[cc->in_pos]) == NOT_HEX)
cc->in_pos++;
/*
* Make sure we have two characters left
*/
if (cc->in_count - cc->in_pos < 2)
break;
/*
* Parse hex number
*/
h = cc_hex_nibble(cc->in_buf[cc->in_pos]);
l = cc_hex_nibble(cc->in_buf[cc->in_pos+1]);
if (h == NOT_HEX || l == NOT_HEX) {
fprintf(stderr, "hex read error\n");
break;
}
cc->in_pos += 2;
/*
* Store hex number
*/
*cc->hex_buf[hex_pos].buf++ = (h << 4) | l;
if (--cc->hex_buf[hex_pos].len <= 0)
hex_pos++;
}
/* Move pending hex reads to the start of the array */
if (hex_pos) {
memmove(cc->hex_buf, cc->hex_buf + hex_pos,
(cc->hex_count - hex_pos) * sizeof (cc->hex_buf[0]));
cc->hex_count -= hex_pos;
}
}
static void
cc_usb_dbg(int indent, uint8_t *bytes, int len)
{
static int eol = 1;
int i;
uint8_t c;
ccdbg_debug(CC_DEBUG_BITBANG, "<<<%d bytes>>>", len);
while (len--) {
c = *bytes++;
if (eol) {
for (i = 0; i < indent; i++)
ccdbg_debug(CC_DEBUG_BITBANG, " ");
eol = 0;
}
switch (c) {
case '\r':
ccdbg_debug(CC_DEBUG_BITBANG, "\\r");
break;
case '\n':
eol = 1;
ccdbg_debug(CC_DEBUG_BITBANG, "\\n\n");
break;
default:
if (c < ' ' || c > '~')
ccdbg_debug(CC_DEBUG_BITBANG, "\\%02x", c);
else
ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
}
}
}
int cc_default_timeout = 5000;
/*
* Flush pending writes, fill pending reads
*/
static int
_cc_usb_sync(struct cc_usb *cc, int wait_for_input, int write_timeout)
{
int ret;
struct pollfd fds;
int timeout;
fds.fd = cc->fd;
for (;;) {
if (cc->hex_count || cc->out_count)
timeout = write_timeout;
else if (wait_for_input && cc->in_pos == cc->in_count)
timeout = wait_for_input;
else
timeout = 0;
fds.events = 0;
/* Move remaining bytes to the start of the input buffer */
if (cc->in_pos) {
memmove(cc->in_buf, cc->in_buf + cc->in_pos,
cc->in_count - cc->in_pos);
cc->in_count -= cc->in_pos;
cc->in_pos = 0;
}
if (cc->in_count < CC_IN_BUF)
fds.events |= POLLIN;
if (cc->out_count)
fds.events |= POLLOUT;
ret = poll(&fds, 1, timeout);
if (ret == 0) {
if (timeout)
return -1;
break;
}
if (ret < 0) {
perror("poll");
return -1;
}
if (fds.revents & POLLIN) {
ret = read(cc->fd, cc->in_buf + cc->in_count,
CC_IN_BUF - cc->in_count);
if (ret > 0) {
cc_usb_dbg(24, cc->in_buf + cc->in_count, ret);
cc->in_count += ret;
if (cc->hex_count)
cc_handle_hex_read(cc);
if (cc->show_input && cc->in_count) {
write(2, cc->in_buf, cc->in_count);
cc->in_count = 0;
}
} else if (ret <= 0) {
perror("read");
return -1;
}
}
if (fds.revents & POLLOUT) {
ret = write(cc->fd, cc->out_buf,
cc->out_count);
if (ret > 0) {
cc_usb_dbg(0, cc->out_buf, ret);
memmove(cc->out_buf,
cc->out_buf + ret,
cc->out_count - ret);
cc->out_count -= ret;
} else if (ret < 0)
perror("write");
}
}
return 0;
}
void
cc_usb_sync(struct cc_usb *cc)
{
if (_cc_usb_sync(cc, 0, cc_default_timeout) < 0) {
fprintf(stderr, "USB link timeout\n");
exit(1);
}
}
void
cc_usb_printf(struct cc_usb *cc, char *format, ...)
{
char buf[1024], *b;
va_list ap;
int ret, this_time;
/* sprintf to a local buffer */
va_start(ap, format);
ret = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (ret > sizeof(buf)) {
fprintf(stderr, "printf overflow for format %s\n",
format);
}
/* flush local buffer to the wire */
b = buf;
while (ret > 0) {
this_time = ret;
if (this_time > CC_OUT_BUF - cc->out_count)
this_time = CC_OUT_BUF - cc->out_count;
memcpy(cc->out_buf + cc->out_count, b, this_time);
cc->out_count += this_time;
ret -= this_time;
b += this_time;
while (cc->out_count >= CC_OUT_BUF)
cc_usb_sync(cc);
}
}
int
cc_usb_getchar_timeout(struct cc_usb *cc, int timeout)
{
while (cc->in_pos == cc->in_count) {
if (_cc_usb_sync(cc, timeout, cc_default_timeout) < 0) {
fprintf(stderr, "USB link timeout\n");
exit(1);
}
}
return cc->in_buf[cc->in_pos++];
}
int
cc_usb_getchar(struct cc_usb *cc)
{
return cc_usb_getchar_timeout(cc, cc_default_timeout);
}
void
cc_usb_getline(struct cc_usb *cc, char *line, int max)
{
int c;
while ((c = cc_usb_getchar(cc)) != '\n') {
switch (c) {
case '\r':
break;
default:
if (max > 1) {
*line++ = c;
max--;
}
break;
}
}
*line++ = '\0';
}
int
cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len)
{
int this_len;
int ret = len;
while (len) {
this_len = len;
if (this_len > 8)
this_len = 8;
len -= this_len;
cc_usb_printf(cc, "P");
while (this_len--)
cc_usb_printf (cc, " %02x", (*bytes++) & 0xff);
cc_usb_printf(cc, "\n");
}
return ret;
}
void
cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len)
{
struct cc_hex_read *hex_buf;
/* At the start of a command sequence, flush any pending input */
if (cc->hex_count == 0) {
cc_usb_sync(cc);
cc->in_count = 0;
}
while (cc->hex_count >= CC_NUM_HEX_READ)
cc_usb_sync(cc);
hex_buf = &cc->hex_buf[cc->hex_count++];
hex_buf->buf = buf;
hex_buf->len = len;
}
int
cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *buf, int len)
{
cc_queue_read(cc, buf, len);
cc_usb_printf(cc, "G %x\n", len);
return len;
}
int
cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len)
{
cc_usb_printf(cc, "O %x %x\n", len, addr);
while (len--)
cc_usb_printf(cc, "%02x", *bytes++);
cc_usb_sync(cc);
return 0;
}
int
cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len)
{
int i;
cc_queue_read(cc, bytes, len);
cc_usb_printf(cc, "I %x %x\n", len, addr);
cc_usb_sync(cc);
for (i = 0; i < len; i++) {
if ((i & 15) == 0) {
if (i)
ccdbg_debug(CC_DEBUG_MEMORY, "\n");
ccdbg_debug(CC_DEBUG_MEMORY, "\t%04x", addr + i);
}
ccdbg_debug(CC_DEBUG_MEMORY, " %02x", bytes[i]);
}
ccdbg_debug(CC_DEBUG_MEMORY, "\n");
return 0;
}
int
cc_usb_debug_mode(struct cc_usb *cc)
{
cc_usb_sync(cc);
cc_usb_printf(cc, "D\n");
return 1;
}
int
cc_usb_reset(struct cc_usb *cc)
{
cc_usb_sync(cc);
cc_usb_printf(cc, "R\n");
return 1;
}
void
cc_usb_open_remote(struct cc_usb *cc, int freq, char *call)
{
if (!cc->remote) {
fprintf (stderr, "freq %dkHz\n", freq);
fprintf (stderr, "call %s\n", call);
cc_usb_printf(cc, "\nc F %d\nc c %s\np\nE 0\n", freq, call);
do {
cc->in_count = cc->in_pos = 0;
_cc_usb_sync(cc, 100, cc_default_timeout);
} while (cc->in_count > 0);
cc->remote = 1;
}
}
void
cc_usb_close_remote(struct cc_usb *cc)
{
if (cc->remote) {
cc_usb_printf(cc, "~");
cc->remote = 0;
}
}
static struct termios save_termios;
#include <errno.h>
struct cc_usb *
cc_usb_open(char *tty)
{
struct cc_usb *cc;
struct termios termios;
int i;
if (!tty)
tty = DEFAULT_TTY;
cc = calloc (sizeof (struct cc_usb), 1);
if (!cc)
return NULL;
i = 0;
for (;;) {
cc->fd = open(tty, O_RDWR | O_NONBLOCK);
if (cc->fd >= 0)
break;
i++;
if (errno == EBUSY || errno == EPERM || errno == EACCES) {
fprintf(stderr, "open failed, pausing");
perror(tty);
if (i < 20) {
sleep(3);
continue;
}
}
perror(tty);
free (cc);
return NULL;
}
tcgetattr(cc->fd, &termios);
save_termios = termios;
cfmakeraw(&termios);
cfsetospeed(&termios, B9600);
cfsetispeed(&termios, B9600);
tcsetattr(cc->fd, TCSAFLUSH, &termios);
cc_usb_printf(cc, "\nE 0\n");
do {
cc->in_count = cc->in_pos = 0;
_cc_usb_sync(cc, 100, cc_default_timeout);
} while (cc->in_count > 0);
return cc;
}
void
cc_usb_close(struct cc_usb *cc)
{
cc_usb_close_remote(cc);
cc_usb_sync(cc);
tcsetattr(cc->fd, TCSAFLUSH, &save_termios);
close (cc->fd);
free (cc);
}
int
cc_usb_write(struct cc_usb *cc, void *buf, int c)
{
uint8_t *b;
int this_time;
b = buf;
cc->show_input = 1;
while (c > 0) {
this_time = c;
if (this_time > CC_OUT_BUF - cc->out_count)
this_time = CC_OUT_BUF - cc->out_count;
memcpy(cc->out_buf + cc->out_count, b, this_time);
cc->out_count += this_time;
c -= this_time;
b += this_time;
while (cc->out_count >= CC_OUT_BUF) {
_cc_usb_sync(cc, 0, -1);
}
}
return 1;
}

79
ao-tools/lib/cc-usb.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 _CC_USB_H_
#define _CC_USB_H_
#include <stdint.h>
struct cc_usb;
extern int cc_default_timeout;
struct cc_usb *
cc_usb_open(char *tty);
void
cc_usb_close(struct cc_usb *cc);
int
cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len);
int
cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *bytes, int len);
int
cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len);
int
cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len);
int
cc_usb_debug_mode(struct cc_usb *cc);
int
cc_usb_reset(struct cc_usb *cc);
void
cc_usb_sync(struct cc_usb *cc);
void
cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len);
int
cc_usb_getchar_timeout(struct cc_usb *cc, int timeout);
int
cc_usb_getchar(struct cc_usb *cc);
void
cc_usb_getline(struct cc_usb *cc, char *line, int max);
void
cc_usb_printf(struct cc_usb *cc, char *format, ...);
int
cc_usb_write(struct cc_usb *cc, void *buf, int c);
void
cc_usb_open_remote(struct cc_usb *cc, int freq, char *call);
void
cc_usb_close_remote(struct cc_usb *cc);
#endif /* _CC_USB_H_ */

338
ao-tools/lib/cc-usbdev.c Normal file
View File

@@ -0,0 +1,338 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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.
*/
#define _GNU_SOURCE
#include "cc.h"
#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *
load_string(char *dir, char *file)
{
char *full = cc_fullname(dir, file);
char line[4096];
char *r;
FILE *f;
int rlen;
f = fopen(full, "r");
free(full);
if (!f)
return NULL;
r = fgets(line, sizeof (line), f);
fclose(f);
if (!r)
return NULL;
rlen = strlen(r);
if (r[rlen-1] == '\n')
r[rlen-1] = '\0';
return strdup(r);
}
static int
load_hex(char *dir, char *file)
{
char *line;
char *end;
long i;
line = load_string(dir, file);
if (!line)
return -1;
i = strtol(line, &end, 16);
free(line);
if (end == line)
return -1;
return i;
}
static int
load_dec(char *dir, char *file)
{
char *line;
char *end;
long i;
line = load_string(dir, file);
if (!line)
return -1;
i = strtol(line, &end, 10);
free(line);
if (end == line)
return -1;
return i;
}
static int
dir_filter_tty_colon(const struct dirent *d)
{
return strncmp(d->d_name, "tty:", 4) == 0;
}
static int
dir_filter_tty(const struct dirent *d)
{
return strncmp(d->d_name, "tty", 3) == 0;
}
static char *
usb_tty(char *sys)
{
char *base;
int num_configs;
int config;
struct dirent **namelist;
int interface;
int num_interfaces;
char endpoint_base[64];
char *endpoint_full;
char *tty_dir;
int ntty;
char *tty;
base = cc_basename(sys);
num_configs = load_hex(sys, "bNumConfigurations");
num_interfaces = load_hex(sys, "bNumInterfaces");
for (config = 1; config <= num_configs; config++) {
for (interface = 0; interface < num_interfaces; interface++) {
sprintf(endpoint_base, "%s:%d.%d",
base, config, interface);
endpoint_full = cc_fullname(sys, endpoint_base);
/* Check for tty:ttyACMx style names
*/
ntty = scandir(endpoint_full, &namelist,
dir_filter_tty_colon,
alphasort);
if (ntty > 0) {
free(endpoint_full);
tty = cc_fullname("/dev", namelist[0]->d_name + 4);
free(namelist);
return tty;
}
/* Check for tty/ttyACMx style names
*/
tty_dir = cc_fullname(endpoint_full, "tty");
ntty = scandir(tty_dir, &namelist,
dir_filter_tty,
alphasort);
free (tty_dir);
if (ntty > 0) {
tty = cc_fullname("/dev", namelist[0]->d_name);
free(endpoint_full);
free(namelist);
return tty;
}
/* Check for ttyACMx style names
*/
ntty = scandir(endpoint_full, &namelist,
dir_filter_tty,
alphasort);
free(endpoint_full);
if (ntty > 0) {
tty = cc_fullname("/dev", namelist[0]->d_name);
free(namelist);
return tty;
}
}
}
return NULL;
}
static struct cc_usbdev *
usb_scan_device(char *sys)
{
struct cc_usbdev *usbdev;
usbdev = calloc(1, sizeof (struct cc_usbdev));
if (!usbdev)
return NULL;
usbdev->sys = strdup(sys);
usbdev->manufacturer = load_string(sys, "manufacturer");
usbdev->product = load_string(sys, "product");
usbdev->serial = load_dec(sys, "serial");
usbdev->idProduct = load_hex(sys, "idProduct");
usbdev->idVendor = load_hex(sys, "idVendor");
usbdev->tty = usb_tty(sys);
return usbdev;
}
static void
usbdev_free(struct cc_usbdev *usbdev)
{
free(usbdev->sys);
free(usbdev->manufacturer);
free(usbdev->product);
/* this can get used as a return value */
if (usbdev->tty)
free(usbdev->tty);
free(usbdev);
}
#define USB_DEVICES "/sys/bus/usb/devices"
static int
dir_filter_dev(const struct dirent *d)
{
const char *n = d->d_name;
char c;
while ((c = *n++)) {
if (isdigit(c))
continue;
if (c == '-')
continue;
if (c == '.' && n != d->d_name + 1)
continue;
return 0;
}
return 1;
}
static int
is_am(int idVendor, int idProduct) {
if (idVendor == 0xfffe)
return 1;
if (idVendor == 0x0403 && idProduct == 0x6015)
return 1;
return 0;
}
struct cc_usbdevs *
cc_usbdevs_scan(int non_tty)
{
int e;
struct dirent **ents;
char *dir;
struct cc_usbdev *dev;
struct cc_usbdevs *devs;
int n;
devs = calloc(1, sizeof (struct cc_usbdevs));
if (!devs)
return NULL;
n = scandir (USB_DEVICES, &ents,
dir_filter_dev,
alphasort);
if (!n)
return 0;
for (e = 0; e < n; e++) {
dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
dev = usb_scan_device(dir);
free(dir);
if (is_am(dev->idVendor, dev->idProduct) && (non_tty || dev->tty)) {
if (devs->dev)
devs->dev = realloc(devs->dev,
(devs->ndev + 1) * sizeof (struct usbdev *));
else
devs->dev = malloc (sizeof (struct usbdev *));
devs->dev[devs->ndev++] = dev;
}
}
free(ents);
return devs;
}
void
cc_usbdevs_free(struct cc_usbdevs *usbdevs)
{
int i;
if (!usbdevs)
return;
for (i = 0; i < usbdevs->ndev; i++)
usbdev_free(usbdevs->dev[i]);
free(usbdevs);
}
static char *
match_dev(char *product, int serial)
{
struct cc_usbdevs *devs;
struct cc_usbdev *dev;
int i;
char *tty = NULL;
devs = cc_usbdevs_scan(FALSE);
if (!devs)
return NULL;
for (i = 0; i < devs->ndev; i++) {
dev = devs->dev[i];
if (product && strncmp (product, dev->product, strlen(product)) != 0)
continue;
if (serial && serial != dev->serial)
continue;
break;
}
if (i < devs->ndev) {
tty = devs->dev[i]->tty;
devs->dev[i]->tty = NULL;
}
cc_usbdevs_free(devs);
return tty;
}
char *
cc_usbdevs_find_by_arg(char *arg, char *default_product)
{
char *product;
int serial;
char *end;
char *colon;
char *tty;
if (arg)
{
/* check for <serial> */
serial = strtol(arg, &end, 0);
if (end != arg) {
if (*end != '\0')
return NULL;
product = NULL;
} else {
/* check for <product>:<serial> */
colon = strchr(arg, ':');
if (colon) {
product = strndup(arg, colon - arg);
serial = strtol(colon + 1, &end, 0);
if (*end != '\0')
return NULL;
} else {
product = arg;
serial = 0;
}
}
} else {
product = NULL;
serial = 0;
}
tty = NULL;
if (!product && default_product)
tty = match_dev(default_product, serial);
if (!tty)
tty = match_dev(product, serial);
if (product && product != arg)
free(product);
return tty;
}

81
ao-tools/lib/cc-util.c Normal file
View File

@@ -0,0 +1,81 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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.
*/
#define _GNU_SOURCE
#include "cc.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
char *
cc_fullname (char *dir, char *file)
{
char *new;
int dlen = strlen (dir);
int flen = strlen (file);
int slen = 0;
if (dir[dlen-1] != '/')
slen = 1;
new = malloc (dlen + slen + flen + 1);
if (!new)
return 0;
strcpy(new, dir);
if (slen)
strcat (new, "/");
strcat(new, file);
return new;
}
char *
cc_basename(char *file)
{
char *b;
b = strrchr(file, '/');
if (!b)
return file;
return b + 1;
}
int
cc_mkdir(char *dir)
{
char *slash;
char *d;
char *part;
d = dir;
for (;;) {
slash = strchr (d, '/');
if (!slash)
slash = d + strlen(d);
if (!*slash)
break;
part = strndup(dir, slash - dir);
if (!access(part, F_OK))
if (mkdir(part, 0777) < 0)
return -errno;
free(part);
d = slash + 1;
}
return 0;
}

652
ao-tools/lib/cc.h Normal file
View File

@@ -0,0 +1,652 @@
/*
* Copyright © 2009 Keith Packard <keithp@keithp.com>
*
* 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 _CC_H_
#define _CC_H_
#include <stdio.h>
#include <stdint.h>
#include "cc-telemetry.h"
char *
cc_fullname (char *dir, char *file);
char *
cc_basename(char *file);
int
cc_mkdir(char *dir);
struct cc_usbdev {
char *sys;
char *tty;
char *manufacturer;
char *product;
int serial; /* AltOS always uses simple integer serial numbers */
int idProduct;
int idVendor;
};
struct cc_usbdevs {
struct cc_usbdev **dev;
int ndev;
};
void
cc_usbdevs_free(struct cc_usbdevs *usbdevs);
struct cc_usbdevs *
cc_usbdevs_scan(int non_tty);
char *
cc_usbdevs_find_by_arg(char *arg, char *default_product);
void
cc_set_log_dir(char *dir);
char *
cc_get_log_dir(void);
char *
cc_make_filename(int serial, int flight, char *ext);
/*
* For sequential data which are not evenly spaced
*/
struct cc_timedataelt {
double time;
double value;
};
struct cc_timedata {
int num;
int size;
struct cc_timedataelt *data;
double time_offset;
};
/*
* For GPS data
*/
struct cc_gpselt {
double time;
int hour;
int minute;
int second;
int flags;
double lat;
double lon;
double alt;
};
#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
#define SIRF_SAT_CODE_LOCKED (1 << 5)
#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
struct cc_gpssat {
double time;
uint16_t svid;
uint8_t c_n;
};
struct cc_gpssats {
int nsat;
struct cc_gpssat sat[12];
};
struct cc_gpsdata {
int num;
int size;
struct cc_gpselt *data;
double time_offset;
int numsats;
int sizesats;
struct cc_gpssats *sats;
};
/*
* For sequential data which are evenly spaced
*/
struct cc_perioddata {
int num;
double start;
double step;
double *data;
};
enum ao_flight_state {
ao_flight_startup = 0,
ao_flight_idle = 1,
ao_flight_pad = 2,
ao_flight_boost = 3,
ao_flight_fast = 4,
ao_flight_coast = 5,
ao_flight_drogue = 6,
ao_flight_main = 7,
ao_flight_landed = 8,
ao_flight_invalid = 9
};
struct cc_flightraw {
int flight;
int serial;
double ground_accel;
double ground_pres;
int year, month, day;
struct cc_timedata accel;
struct cc_timedata pres;
struct cc_timedata temp;
struct cc_timedata volt;
struct cc_timedata main;
struct cc_timedata drogue;
struct cc_timedata state;
struct cc_gpsdata gps;
};
struct cc_flightraw *
cc_log_read(FILE *file);
void
cc_flightraw_free(struct cc_flightraw *raw);
struct cc_flightcooked {
double flight_start;
double flight_stop;
struct cc_perioddata accel_accel;
struct cc_perioddata accel_speed;
struct cc_perioddata accel_pos;
struct cc_perioddata pres_pos;
struct cc_perioddata pres_speed;
struct cc_perioddata pres_accel;
struct cc_perioddata gps_lat;
struct cc_perioddata gps_lon;
struct cc_perioddata gps_alt;
/* unfiltered, but converted */
struct cc_timedata pres;
struct cc_timedata accel;
struct cc_timedata state;
};
/*
* Telemetry data contents
*/
struct cc_gps_time {
int year;
int month;
int day;
int hour;
int minute;
int second;
};
struct cc_gps {
int nsat;
int gps_locked;
int gps_connected;
struct cc_gps_time gps_time;
double lat; /* degrees (+N -S) */
double lon; /* degrees (+E -W) */
int alt; /* m */
int gps_extended; /* has extra data */
double ground_speed; /* m/s */
int course; /* degrees */
double climb_rate; /* m/s */
double hdop; /* unitless? */
int h_error; /* m */
int v_error; /* m */
};
#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
#define SIRF_SAT_CODE_LOCKED (1 << 5)
#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
struct cc_gps_sat {
int svid;
int c_n0;
};
struct cc_gps_tracking {
int channels;
struct cc_gps_sat sats[12];
};
struct cc_telem {
char callsign[16];
int serial;
int flight;
int rssi;
char state[16];
int tick;
int accel;
int pres;
int temp;
int batt;
int drogue;
int main;
int flight_accel;
int ground_accel;
int flight_vel;
int flight_pres;
int ground_pres;
int accel_plus_g;
int accel_minus_g;
struct cc_gps gps;
struct cc_gps_tracking gps_tracking;
};
int
cc_telem_parse(const char *input_line, struct cc_telem *telem);
struct ao_log_mega {
char type; /* 0 */
uint8_t is_config; /* 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 */
} flight; /* 12 */
/* 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_y; /* 26 */
int16_t mag_z; /* 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 */
int16_t altitude; /* 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 pad; /* 21 */
} gps; /* 22 */
/* AO_LOG_GPS_SAT */
struct {
uint16_t channels; /* 4 */
struct {
uint8_t svid;
uint8_t c_n;
} sats[12]; /* 6 */
} gps_sat; /* 30 */
struct {
uint32_t kind;
int32_t data[6];
} config_int;
struct {
uint32_t kind;
char string[24];
} config_str;
/* Raw bytes */
uint8_t bytes[28];
} u;
};
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;
};
#define AO_CONFIG_CONFIG 1
#define AO_CONFIG_MAIN 2
#define AO_CONFIG_APOGEE 3
#define AO_CONFIG_LOCKOUT 4
#define AO_CONFIG_FREQUENCY 5
#define AO_CONFIG_RADIO_ENABLE 6
#define AO_CONFIG_ACCEL_CAL 7
#define AO_CONFIG_RADIO_CAL 8
#define AO_CONFIG_MAX_LOG 9
#define AO_CONFIG_IGNITE_MODE 10
#define AO_CONFIG_PAD_ORIENTATION 11
#define AO_CONFIG_SERIAL_NUMBER 12
#define AO_CONFIG_LOG_FORMAT 13
#define AO_CONFIG_MS5607_RESERVED 14
#define AO_CONFIG_MS5607_SENS 15
#define AO_CONFIG_MS5607_OFF 16
#define AO_CONFIG_MS5607_TCS 17
#define AO_CONFIG_MS5607_TCO 18
#define AO_CONFIG_MS5607_TREF 19
#define AO_CONFIG_MS5607_TEMPSENS 20
#define AO_CONFIG_MS5607_CRC 21
#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_CONFIG 'c'
#define AO_GPS_NUM_SAT_MASK (0xf << 0)
#define AO_GPS_NUM_SAT_SHIFT (0)
#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
#define AO_GPS_COURSE_VALID (1 << 7)
#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 5 /* 32 byte typed telemega records */
#define AO_LOG_FORMAT_EASYMINI 6 /* 16-byte MS5607 baro only, 3.0V supply */
#define AO_LOG_FORMAT_TELEMETRUM 7 /* 16-byte typed telemetrum records */
#define AO_LOG_FORMAT_TELEMINI 8 /* 16-byte MS5607 baro only, 3.3V supply */
#define AO_LOG_FORMAT_TELEGPS 9 /* 32 byte telegps records */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
int
cc_mega_parse(const char *input_line, struct ao_log_mega *l);
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/* Conversion functions */
double
cc_pressure_to_altitude(double pressure);
double
cc_altitude_to_pressure(double altitude);
double
cc_altitude_to_temperature(double altitude);
double
cc_barometer_to_pressure(double baro);
double
cc_barometer_to_altitude(double baro);
double
cc_accelerometer_to_acceleration(double accel, double ground_accel);
double
cc_thermometer_to_temperature(double thermo);
double
cc_battery_to_voltage(double battery);
double
cc_ignitor_to_voltage(double ignite);
void
cc_great_circle (double start_lat, double start_lon,
double end_lat, double end_lon,
double *dist, double *bearing);
void
cc_timedata_limits(struct cc_timedata *d, double min_time, double max_time, int *start, int *stop);
int
cc_timedata_min(struct cc_timedata *d, double min_time, double max_time);
int
cc_timedata_min_mag(struct cc_timedata *d, double min_time, double max_time);
int
cc_timedata_max(struct cc_timedata *d, double min_time, double max_time);
int
cc_timedata_max_mag(struct cc_timedata *d, double min_time, double max_time);
double
cc_timedata_average(struct cc_timedata *d, double min_time, double max_time);
double
cc_timedata_average_mag(struct cc_timedata *d, double min_time, double max_time);
int
cc_perioddata_limits(struct cc_perioddata *d, double min_time, double max_time, int *start, int *stop);
int
cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time);
int
cc_perioddata_min_mag(struct cc_perioddata *d, double min_time, double max_time);
int
cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time);
int
cc_perioddata_max_mag(struct cc_perioddata *d, double min_time, double max_time);
double
cc_perioddata_average(struct cc_perioddata *d, double min_time, double max_time);
double
cc_perioddata_average_mag(struct cc_perioddata *d, double min_time, double max_time);
double *
cc_low_pass(double *data, int data_len, double omega_pass, double omega_stop, double error);
struct cc_perioddata *
cc_period_make(struct cc_timedata *td, double start_time, double stop_time);
struct cc_perioddata *
cc_period_low_pass(struct cc_perioddata *raw, double omega_pass, double omega_stop, double error);
struct cc_timedata *
cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), double a);
struct cc_timedata *
cc_timedata_integrate(struct cc_timedata *d, double min_time, double max_time);
struct cc_perioddata *
cc_perioddata_differentiate(struct cc_perioddata *i);
struct cc_flightcooked *
cc_flight_cook(struct cc_flightraw *raw);
void
cc_flightcooked_free(struct cc_flightcooked *cooked);
#endif /* _CC_H_ */

View File

@@ -0,0 +1,176 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
uint8_t
ccdbg_chip_erase(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read8(dbg, CC_CHIP_ERASE, NULL, 0);
}
uint8_t
ccdbg_wr_config(struct ccdbg *dbg, uint8_t config)
{
return ccdbg_cmd_write_read8(dbg, CC_WR_CONFIG, &config, 1);
}
uint8_t
ccdbg_rd_config(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read8(dbg, CC_RD_CONFIG, NULL, 0);
}
uint16_t
ccdbg_get_pc(struct ccdbg *dbg)
{
uint16_t pc1, pc2;
pc1 = ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0);
pc2 = ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0);
if (pc1 != pc2)
fprintf (stderr, "Invalid pc %04x != %04x\n",
pc1, pc2);
return pc2;
}
uint8_t
ccdbg_read_status(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read8(dbg, CC_READ_STATUS, NULL, 0);
}
uint8_t
ccdbg_set_hw_brkpnt(struct ccdbg *dbg, uint8_t number, uint8_t enable, uint16_t addr)
{
uint8_t data[3];
data[0] = (number << 3) | (enable << 2);
data[1] = (addr >> 8);
data[2] = addr;
return ccdbg_cmd_write_read8(dbg, CC_SET_HW_BRKPNT, data, 3);
}
uint8_t
ccdbg_halt(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read8(dbg, CC_HALT, NULL, 0);
}
uint8_t
ccdbg_resume(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read8(dbg, CC_RESUME, NULL, 0);
}
uint8_t
ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes)
{
return ccdbg_cmd_write_read8(dbg, CC_DEBUG_INSTR(nbytes), instr, nbytes);
}
void
ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes)
{
static uint8_t discard;
ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes),
instr, nbytes, &discard);
}
void
ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes,
uint8_t *reply)
{
return ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes),
instr, nbytes, reply);
}
uint8_t
ccdbg_step_instr(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read8(dbg, CC_STEP_INSTR, NULL, 0);
}
uint8_t
ccdbg_step_replace(struct ccdbg *dbg, uint8_t *instr, int nbytes)
{
return ccdbg_cmd_write_read8(dbg, CC_STEP_REPLACE(nbytes), instr, nbytes);
}
uint16_t
ccdbg_get_chip_id(struct ccdbg *dbg)
{
return ccdbg_cmd_write_read16(dbg, CC_GET_CHIP_ID, NULL, 0);
}
/*
* Execute a sequence of instructions
*/
uint8_t
ccdbg_execute(struct ccdbg *dbg, uint8_t *inst)
{
uint8_t status = 0;
while(inst[0] != 0) {
uint8_t len = inst[0];
int i;
ccdbg_debug(CC_DEBUG_INSTRUCTIONS, "\t%02x", inst[1]);
for (i = 0; i < len - 1; i++)
ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " %02x", inst[i+2]);
ccdbg_debug_instr_queue(dbg, inst+1, len, &status);
for (; i < 3; i++)
ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " ");
ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " -> %02x\n", status);
inst += len + 1;
}
ccdbg_sync(dbg);
return status;
}
static uint8_t jump_mem[] = {
3, LJMP, 0xf0, 0x00,
#define PC_HIGH 2
#define PC_LOW 3
0
};
uint8_t
ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc)
{
jump_mem[PC_HIGH] = pc >> 8;
jump_mem[PC_LOW] = pc & 0xff;
return ccdbg_execute(dbg, jump_mem);
}
uint8_t
ccdbg_execute_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
{
uint16_t pc;
uint8_t status;
if (image->address < 0xf000) {
fprintf(stderr, "Cannot execute program starting at 0x%04x\n", image->address);
return -1;
}
ccdbg_write_hex_image(dbg, image, 0);
ccdbg_set_pc(dbg, image->address);
pc = ccdbg_get_pc(dbg);
ccdbg_debug(CC_DEBUG_EXECUTE, "pc starts at 0x%04x\n", pc);
status = ccdbg_resume(dbg);
ccdbg_debug(CC_DEBUG_EXECUTE, "resume status: 0x%02x\n", status);
return 0;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
#include <stdarg.h>
int
ccdbg_level = 0;
void
ccdbg_add_debug(int level)
{
ccdbg_level |= level;
}
void
ccdbg_clear_debug(int level)
{
ccdbg_level &= ~level;
}
static int initialized;
void
ccdbg_debug(int level, char *format, ...)
{
va_list ap;
if (!initialized) {
char *level;
initialized = 1;
level = getenv("CCDEBUG");
if (level)
ccdbg_level |= strtoul(level, NULL, 0);
}
if (ccdbg_level & level) {
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
}
}
void
ccdbg_flush(int level)
{
if (ccdbg_level & level)
fflush(stdout);
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 _CCDBG_DEBUG_H_
#define _CCDBG_DEBUG_H_
/* Debug levels
*/
#define CC_DEBUG_BITBANG 0x00000001
#define CC_DEBUG_COMMAND 0x00000002
#define CC_DEBUG_INSTRUCTIONS 0x00000004
#define CC_DEBUG_EXECUTE 0x00000008
#define CC_DEBUG_FLASH 0x00000010
#define CC_DEBUG_MEMORY 0x00000020
#define CC_DEBUG_USB_ASYNC 0x00000040
/* ccdbg-debug.c */
void
ccdbg_debug(int level, char *format, ...);
void
ccdbg_add_debug(int level);
void
ccdbg_clear_debug(int level);
void
ccdbg_flush(int level);
#endif /* _CCDBG_DEBUG_H_ */

351
ao-tools/lib/ccdbg-flash.c Normal file
View File

@@ -0,0 +1,351 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
/* From SWRA124 section 3.1.6 */
static uint8_t flash_page[] = {
MOV_direct_data, P1DIR, 0x02,
MOV_direct_data, P1, 0xFF,
MOV_direct_data, FADDRH, 0,
#define FLASH_ADDR_HIGH 8
MOV_direct_data, FADDRL, 0,
#define FLASH_ADDR_LOW 11
MOV_DPTR_data16, 0, 0,
#define RAM_ADDR_HIGH 13
#define RAM_ADDR_LOW 14
MOV_Rn_data(7), 0,
#define FLASH_WORDS_HIGH 16
MOV_Rn_data(6), 0,
#define FLASH_WORDS_LOW 18
MOV_direct_data, FWT, 0x20,
#define FLASH_TIMING 21
MOV_direct_data, FCTL, FCTL_ERASE,
/* eraseWaitLoop: */
MOV_A_direct, FCTL,
JB, ACC(FCTL_BUSY_BIT), 0xfb,
MOV_direct_data, P1, 0xfd,
MOV_direct_data, FCTL, FCTL_WRITE,
/* writeLoop: */
MOV_Rn_data(5), 2,
/* writeWordLoop: */
MOVX_A_atDPTR,
INC_DPTR,
MOV_direct_A, FWDATA,
DJNZ_Rn_rel(5), 0xfa, /* writeWordLoop */
/* writeWaitLoop: */
MOV_A_direct, FCTL,
JB, ACC(FCTL_SWBSY_BIT), 0xfb, /* writeWaitLoop */
DJNZ_Rn_rel(6), 0xf1, /* writeLoop */
DJNZ_Rn_rel(7), 0xef, /* writeLoop */
MOV_direct_data, P1DIR, 0x00,
MOV_direct_data, P1, 0xFF,
TRAP,
};
#define FLASH_RAM 0xf000
#if 0
static uint8_t flash_erase_page[] = {
3, MOV_direct_data, FADDRH, 0,
#define ERASE_PAGE_HIGH 3
3, MOV_direct_data, FADDRL, 0,
#define ERASE_PAGE_LOW 7
3, MOV_direct_data, FWT, 0x2A,
3, MOV_direct_data, FCTL, FCTL_ERASE,
0
};
static uint8_t flash_read_control[] = {
2, MOV_A_direct, FCTL,
0
};
#endif
#if 0
static uint8_t flash_control_clear[] = {
3, MOV_direct_data, FCTL, 0,
2, MOV_A_direct, FCTL,
0
};
#endif
#if 0
static uint8_t
ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr)
{
uint16_t page_addr = addr >> 1;
uint8_t status;
uint8_t old[0x10], new[0x10];
int i;
ccdbg_read_memory(dbg, addr, old, 0x10);
flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8;
flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff;
status = ccdbg_execute(dbg, flash_erase_page);
ccdbg_debug(CC_DEBUG_FLASH, "erase status 0x%02x\n", status);
do {
status = ccdbg_execute(dbg, flash_read_control);
ccdbg_debug(CC_DEBUG_FLASH, "fctl 0x%02x\n", status);
} while (status & FCTL_BUSY);
ccdbg_read_memory(dbg, addr, new, 0x10);
for (i = 0; i < 0x10; i++)
ccdbg_debug(CC_DEBUG_FLASH, "0x%02x -> 0x%02x\n", old[i], new[i]);
status = ccdbg_execute(dbg, flash_control_clear);
ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status);
return 0;
}
#endif
#if 0
static uint8_t flash_write[] = {
MOV_direct_data, P1DIR, 0x02,
MOV_direct_data, P1, 0xFD,
MOV_A_direct, FCTL,
JB, ACC(FCTL_BUSY_BIT), 0xf1,
MOV_direct_data, FCTL, 0x20,
MOV_direct_data, FADDRH, 0,
#define WRITE_PAGE_HIGH 16
MOV_direct_data, FADDRL, 0,
#define WRITE_PAGE_LOW 19
MOV_direct_data, FCTL, FCTL_WRITE,
MOV_direct_data, FWDATA, 0,
#define WRITE_BYTE_0 25
MOV_direct_data, FWDATA, 0,
#define WRITE_BYTE_1 28
MOV_A_direct, FCTL,
JB, ACC(FCTL_SWBSY_BIT), 0xf1,
MOV_direct_data, P1, 0xFF,
TRAP,
};
#endif
static uint8_t
ccdbg_clock_init(struct ccdbg *dbg)
{
static uint8_t set_clkcon_fast[] = {
3, MOV_direct_data, CLKCON, 0x00,
0
};
static uint8_t get_sleep[] = {
2, MOV_A_direct, SLEEP,
0
};
uint8_t status;
ccdbg_execute(dbg, set_clkcon_fast);
do {
status = ccdbg_execute(dbg, get_sleep);
} while (!(status & 0x40));
return 0;
}
#if 0
static uint8_t
ccdbg_flash_write_word(struct ccdbg *dbg, uint16_t addr, uint8_t data[2])
{
uint16_t page_addr = addr >> 1;
uint8_t check[2];
uint8_t status;
int i;
flash_write[WRITE_PAGE_HIGH] = page_addr >> 8;
flash_write[WRITE_PAGE_LOW] = page_addr & 0xff;
flash_write[WRITE_BYTE_0] = data[0];
flash_write[WRITE_BYTE_1] = data[1];
ccdbg_debug(CC_DEBUG_FLASH, "upload flash write\n");
ccdbg_write_memory(dbg, 0xf000, flash_write, sizeof(flash_write));
ccdbg_set_pc(dbg, 0xf000);
ccdbg_resume(dbg);
for (;;) {
status = ccdbg_read_status(dbg);
ccdbg_debug(CC_DEBUG_FLASH, "waiting for write 0x%02x\n", status);
if ((status & CC_STATUS_CPU_HALTED) != 0)
break;
sleep (1);
}
status = ccdbg_execute(dbg, flash_control_clear);
ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status);
ccdbg_read_memory(dbg, addr, check, 2);
for (i = 0; i < 2; i++)
ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", data[i], check[i]);
return 0;
}
#endif
#define TIMERS_OFF 0x08
#define DMA_PAUSE 0x04
#define TIMER_SUSPEND 0x02
#define SEL_FLASH_INFO_PAGE 0x01
#if 0
static uint8_t
ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock)
{
uint8_t config;
uint8_t bytes[2];
uint8_t old[1], new[1];
config = ccdbg_rd_config(dbg);
ccdbg_wr_config(dbg, config|SEL_FLASH_INFO_PAGE);
bytes[0] = lock;
bytes[1] = 0;
ccdbg_flash_erase_page(dbg, 0);
ccdbg_read_memory(dbg, 0, old, 1);
ccdbg_flash_write_word(dbg, 0, bytes);
ccdbg_read_memory(dbg, 0, new, 1);
ccdbg_debug(CC_DEBUG_FLASH, "flash lock 0x%02x -> 0x%02x\n", old[0], new[0]);
ccdbg_wr_config(dbg, config & ~SEL_FLASH_INFO_PAGE);
return 0;
}
#endif
uint8_t
ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
{
uint16_t flash_prog;
uint16_t flash_len;
uint8_t fwt;
uint16_t flash_addr;
uint16_t flash_word_addr;
uint16_t flash_words;
uint8_t flash_words_high, flash_words_low;
uint16_t ram_addr;
uint8_t status;
uint16_t remain, this_time, start;
uint8_t verify[0x400];
int times;
ccdbg_clock_init(dbg);
if (image->address + image->length > 0x8000) {
fprintf(stderr, "cannot flash image from 0x%04x to 0x%04x\n",
image->address, image->address + image->length);
return 1;
}
if (image->address & 0x3ff) {
fprintf(stderr, "flash image must start on page boundary\n");
return 1;
}
ram_addr = 0xf000;
flash_prog = 0xf400;
fwt = 0x20;
flash_page[FLASH_TIMING] = fwt;
ccdbg_debug(CC_DEBUG_FLASH, "Upload %d flash program bytes to 0x%04x\n",
sizeof (flash_page), flash_prog);
ccdbg_write_memory(dbg, flash_prog, flash_page, sizeof(flash_page));
remain = image->length;
start = 0;
while (remain) {
this_time = remain;
if (this_time > 0x400)
this_time = 0x400;
ccdbg_debug(CC_DEBUG_FLASH, "Upload %d bytes at 0x%04x\n", this_time, ram_addr);
ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time);
#if 0
ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in ram\n", this_time);
ccdbg_read_memory(dbg, ram_addr, verify, this_time);
if (memcmp (image->data + start, verify, this_time) != 0) {
fprintf(stderr, "ram verify failed\n");
return 1;
}
#endif
flash_addr = image->address + start;
flash_word_addr = flash_addr >> 1;
flash_len = this_time + (this_time & 1);
flash_words = flash_len >> 1;
flash_words_low = flash_words & 0xff;
flash_words_high = flash_words >> 8;
/* The flash code above is lame */
if (flash_words_low)
flash_words_high++;
ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_HIGH, flash_word_addr >> 8);
ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_LOW, flash_word_addr & 0xff);
ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_HIGH, ram_addr >> 8);
ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_LOW, ram_addr & 0xff);
ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_HIGH, flash_words_high);
ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words_low);
ccdbg_set_pc(dbg, flash_prog);
ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n",
this_time, flash_addr);
status = ccdbg_resume(dbg);
for (times = 0; times < 10; times++) {
status = ccdbg_read_status(dbg);
ccdbg_debug(CC_DEBUG_FLASH, ".");
ccdbg_flush(CC_DEBUG_FLASH);
if ((status & CC_STATUS_CPU_HALTED) != 0)
break;
usleep(10000);
}
ccdbg_debug(CC_DEBUG_FLASH, "\n");
if (times == 10) {
fprintf(stderr, "flash page timed out\n");
return 1;
}
ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in flash\n", this_time);
ccdbg_read_memory(dbg, flash_addr, verify, this_time);
if (memcmp (image->data + start, verify, this_time) != 0) {
int i;
fprintf(stderr, "flash verify failed\n");
for (i = 0; i < this_time; i++) {
if (image->data[start + i] != verify[i])
fprintf(stderr, "0x%04x: 0x%02x != 0x%02x\n",
start + i, image->data[start+i], verify[i]);
}
return 1;
}
remain -= this_time;
start += this_time;
}
return 0;
}

144
ao-tools/lib/ccdbg-io.c Normal file
View File

@@ -0,0 +1,144 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
#include <time.h>
#include "cc-usb.h"
#include "cc-bitbang.h"
struct ccdbg *
ccdbg_open(char *tty)
{
struct ccdbg *dbg;
dbg = calloc(sizeof (struct ccdbg), 1);
if (!dbg) {
perror("calloc");
return NULL;
}
if (!tty)
tty = getenv("ALTOS_TTY");
if (!tty)
tty="/dev/ttyACM0";
if (!strcmp(tty, "BITBANG")) {
dbg->bb = cc_bitbang_open();
if (!dbg->bb) {
free(dbg);
return NULL;
}
} else {
dbg->usb = cc_usb_open(tty);
if (!dbg->usb) {
free(dbg);
return NULL;
}
}
return dbg;
}
void
ccdbg_close(struct ccdbg *dbg)
{
if (dbg->usb)
cc_usb_close(dbg->usb);
if (dbg->bb)
cc_bitbang_close(dbg->bb);
free (dbg);
}
void
ccdbg_debug_mode(struct ccdbg *dbg)
{
if (dbg->usb)
cc_usb_debug_mode(dbg->usb);
else if (dbg->bb)
cc_bitbang_debug_mode(dbg->bb);
}
void
ccdbg_reset(struct ccdbg *dbg)
{
if (dbg->usb)
cc_usb_reset(dbg->usb);
else if (dbg->bb)
cc_bitbang_reset(dbg->bb);
}
void
ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes)
{
if (dbg->usb)
cc_usb_send_bytes(dbg->usb, bytes, nbytes);
else if (dbg->bb)
cc_bitbang_send_bytes(dbg->bb, bytes, nbytes);
}
void
ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes)
{
if (dbg->usb)
cc_usb_recv_bytes(dbg->usb, bytes, nbytes);
else if (dbg->bb)
cc_bitbang_recv_bytes(dbg->bb, bytes, nbytes);
}
void
ccdbg_sync(struct ccdbg *dbg)
{
if (dbg->usb)
cc_usb_sync(dbg->usb);
else if (dbg->bb)
cc_bitbang_sync(dbg->bb);
}
void
ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len)
{
ccdbg_send_bytes(dbg, &cmd, 1);
ccdbg_send_bytes(dbg, data, len);
}
uint8_t
ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len)
{
uint8_t byte[1];
ccdbg_cmd_write(dbg, cmd, data, len);
ccdbg_recv_bytes(dbg, byte, 1);
ccdbg_sync(dbg);
return byte[0];
}
uint16_t
ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len)
{
uint8_t byte[2];
ccdbg_cmd_write(dbg, cmd, data, len);
ccdbg_recv_bytes(dbg, byte, 2);
ccdbg_sync(dbg);
return (byte[0] << 8) | byte[1];
}
void
ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd,
uint8_t *data, int len,
uint8_t *reply)
{
ccdbg_cmd_write(dbg, cmd, data, len);
ccdbg_recv_bytes(dbg, reply, 1);
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
#include "cc-bitbang.h"
/*
* Manual bit-banging to debug the low level protocol
*/
static void
get_bit(char *line, int i, char on, uint8_t bit, uint8_t *bits, uint8_t *masks)
{
if (line[i] == on) {
*bits |= bit;
*masks |= bit;
return;
}
if (line[i] == '.') {
*masks |= bit;
return;
}
if (line[i] == '-') {
return;
}
fprintf(stderr, "bad line %s\n", line);
exit (1);
}
void
ccdbg_manual(struct ccdbg *dbg, FILE *input)
{
char line[80];
uint8_t set, mask;
if (dbg->bb == NULL) {
fprintf(stderr, "Must use bitbang API for manual mode\n");
return;
}
while (fgets(line, sizeof line, input)) {
if (line[0] == '#' || line[0] == '\n') {
printf ("%s", line);
continue;
}
set = 0;
mask = 0;
get_bit(line, 0, 'C', CC_CLOCK, &set, &mask);
get_bit(line, 2, 'D', CC_DATA, &set, &mask);
get_bit(line, 4, 'R', CC_RESET_N, &set, &mask);
if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) {
uint8_t read;
cc_bitbang_read(dbg->bb, &read);
cc_bitbang_sync(dbg->bb);
cc_bitbang_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read);
if ((set & CC_CLOCK) == 0)
printf ("\t%d", (read&CC_DATA) ? 1 : 0);
printf ("\n");
}
cc_bitbang_send(dbg->bb, mask, set);
cc_bitbang_sync(dbg->bb);
}
}

179
ao-tools/lib/ccdbg-memory.c Normal file
View File

@@ -0,0 +1,179 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
/*
* Read and write arbitrary memory through the debug port
*/
static uint8_t memory_init[] = {
3, MOV_DPTR_data16, 0, 0,
#define HIGH_START 2
#define LOW_START 3
0,
};
static uint8_t write8[] = {
2, MOV_A_data, 0,
#define DATA_BYTE 2
1, MOVX_atDPTR_A,
1, INC_DPTR,
0
};
static uint8_t read8[] = {
1, MOVX_A_atDPTR,
1, INC_DPTR,
0,
};
uint8_t
ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes)
{
int i, nl = 0;
struct ccstate state;
if (dbg->usb)
return cc_usb_write_memory(dbg->usb, addr, bytes, nbytes);
ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP);
memory_init[HIGH_START] = addr >> 8;
memory_init[LOW_START] = addr;
(void) ccdbg_execute(dbg, memory_init);
for (i = 0; i < nbytes; i++) {
write8[DATA_BYTE] = *bytes++;
ccdbg_execute(dbg, write8);
if ((i & 0xf) == 0xf) {
ccdbg_debug(CC_DEBUG_MEMORY, ".");
ccdbg_flush(CC_DEBUG_MEMORY);
nl = 1;
}
if ((i & 0xff) == 0xff) {
ccdbg_debug(CC_DEBUG_MEMORY, "\n");
nl = 0;
}
}
ccdbg_state_restore(dbg, &state);
if (nl)
ccdbg_debug(CC_DEBUG_MEMORY, "\n");
return 0;
}
uint8_t
ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes)
{
int i, nl = 0;
struct ccstate state;
if (ccdbg_rom_contains(dbg, addr, nbytes)) {
ccdbg_rom_replace_xmem(dbg, addr, bytes, nbytes);
return 0;
}
if (dbg->usb)
return cc_usb_read_memory(dbg->usb, addr, bytes, nbytes);
ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP);
memory_init[HIGH_START] = addr >> 8;
memory_init[LOW_START] = addr;
(void) ccdbg_execute(dbg, memory_init);
for (i = 0; i < nbytes; i++) {
*bytes++ = ccdbg_execute(dbg, read8);
if ((i & 0xf) == 0xf) {
ccdbg_debug(CC_DEBUG_MEMORY, ".");
ccdbg_flush(CC_DEBUG_MEMORY);
nl = 1;
}
if ((i & 0xff) == 0xff) {
ccdbg_debug(CC_DEBUG_MEMORY, "\n");
nl = 0;
}
}
ccdbg_state_replace_xmem(dbg, &state, addr, bytes, nbytes);
ccdbg_state_restore(dbg, &state);
if (nl)
ccdbg_debug(CC_DEBUG_MEMORY, "\n");
return 0;
}
uint8_t
ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte)
{
return ccdbg_write_memory(dbg, addr, &byte, 1);
}
uint8_t
ccdbg_write_hex_image(struct ccdbg *dbg, struct ao_hex_image *image, uint16_t offset)
{
ccdbg_write_memory(dbg, image->address + offset, image->data, image->length);
return 0;
}
struct ao_hex_image *
ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length)
{
struct ao_hex_image *image;
image = calloc(sizeof(struct ao_hex_image) + length, 1);
image->address = address;
image->length = length;
memset(image->data, 0xff, length);
ccdbg_read_memory(dbg, address, image->data, length);
return image;
}
static uint8_t sfr_read[] = {
2, MOV_A_direct, 0,
#define SFR_READ_ADDR 2
0,
};
static uint8_t sfr_write[] = {
3, MOV_direct_data, 0, 0,
#define SFR_WRITE_ADDR 2
#define SFR_WRITE_DATA 3
0,
};
uint8_t
ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes)
{
int i;
struct ccstate state;
ccdbg_state_save(dbg, &state, CC_STATE_ACC);
for (i = 0; i < nbytes; i++) {
sfr_read[SFR_READ_ADDR] = addr + i;
*bytes++ = ccdbg_execute(dbg, sfr_read);
}
ccdbg_state_replace_sfr(dbg, &state, addr, bytes, nbytes);
ccdbg_state_restore(dbg, &state);
return 0;
}
uint8_t
ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes)
{
int i;
for (i = 0; i < nbytes; i++) {
sfr_write[SFR_WRITE_ADDR] = addr + i;
sfr_write[SFR_WRITE_DATA] = *bytes++;
ccdbg_execute(dbg, sfr_write);
}
return 0;
}

63
ao-tools/lib/ccdbg-rom.c Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
uint8_t
ccdbg_set_rom(struct ccdbg *dbg, struct ao_hex_image *rom)
{
if (dbg->rom)
ao_hex_image_free(dbg->rom);
dbg->rom = rom;
return 0;
}
uint8_t
ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes)
{
struct ao_hex_image *rom = dbg->rom;
if (!rom)
return 0;
if (addr < rom->address || rom->address + rom->length < addr + nbytes)
return 0;
return 1;
}
uint8_t
ccdbg_rom_replace_xmem(struct ccdbg *dbg,
uint16_t addr, uint8_t *bytes, int nbytes)
{
struct ao_hex_image *rom = dbg->rom;
if (!rom)
return 0;
if (rom->address < addr + nbytes && addr < rom->address + rom->length) {
int start, stop;
start = addr;
if (addr < rom->address)
start = rom->address;
stop = addr + nbytes;
if (rom->address + rom->length < stop)
stop = rom->address + rom->length;
memcpy(bytes + start - addr, rom->data + start - rom->address,
stop - start);
return 1;
}
return 0;
}

128
ao-tools/lib/ccdbg-state.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 "ccdbg.h"
static uint8_t save_acc[] = {
1, NOP,
0
};
static uint8_t save_sfr[] = {
2, MOV_A_direct, 0,
#define SAVE_SFR_ADDR 2
0,
};
struct sfr_state {
uint8_t address;
uint16_t mask;
char *name;
};
static struct sfr_state sfrs[CC_STATE_NSFR] = {
{ SFR_DPL0, CC_STATE_DP, "dpl0" },
{ SFR_DPH0, CC_STATE_DP, "dph0" },
{ SFR_DPL1, CC_STATE_DP, "dpl1" },
{ SFR_DPH1, CC_STATE_DP, "dph1" },
{ PSW(0), CC_STATE_PSW, "psw" },
};
uint8_t
ccdbg_state_save(struct ccdbg *dbg, struct ccstate *state, unsigned int mask)
{
int i;
mask |= CC_STATE_ACC;
if (mask & CC_STATE_ACC)
state->acc = ccdbg_execute(dbg, save_acc);
for (i = 0; i < CC_STATE_NSFR; i++) {
if (sfrs[i].mask & mask) {
save_sfr[SAVE_SFR_ADDR] = sfrs[i].address;
state->sfr[i] = ccdbg_execute(dbg, save_sfr);
}
}
state->mask = mask;
return 0;
}
static uint8_t restore_sfr[] = {
3, MOV_direct_data, 0, 0,
#define RESTORE_SFR_ADDR 2
#define RESTORE_SFR_DATA 3
0
};
static uint8_t restore_acc[] = {
2, MOV_A_data, 0,
#define RESTORE_ACC_DATA 2
0
};
uint8_t
ccdbg_state_restore(struct ccdbg *dbg, struct ccstate *state)
{
int i;
for (i = CC_STATE_NSFR - 1; i >= 0; i--) {
if (sfrs[i].mask & state->mask) {
restore_sfr[RESTORE_SFR_ADDR] = sfrs[i].address;
restore_sfr[RESTORE_SFR_DATA] = state->sfr[i];
ccdbg_execute(dbg, restore_sfr);
}
}
if (state->mask & CC_STATE_ACC) {
restore_acc[RESTORE_ACC_DATA] = state->acc;
ccdbg_execute(dbg, restore_acc);
}
state->mask = 0;
return 0;
}
static void
ccdbg_state_replace(uint16_t sfr_addr, uint8_t sfr, char *name,
uint16_t addr, uint8_t *bytes, int nbytes)
{
sfr_addr += 0xdf00;
if (addr <= sfr_addr && sfr_addr < addr + nbytes) {
fprintf(stderr, "replacing %s at 0x%04x - read 0x%02x saved 0x%02x\n",
name, sfr_addr, bytes[sfr_addr - addr], sfr);
bytes[sfr_addr - addr] = sfr;
}
}
void
ccdbg_state_replace_xmem(struct ccdbg *dbg, struct ccstate *state,
uint16_t addr, uint8_t *bytes, int nbytes)
{
int i;
if (state->mask & CC_STATE_ACC)
ccdbg_state_replace(ACC(0), state->acc, "acc",
addr, bytes, nbytes);
for (i = 0; i < CC_STATE_NSFR; i++)
if (state->mask & sfrs[i].mask)
ccdbg_state_replace(sfrs[i].address, state->sfr[i],
sfrs[i].name, addr, bytes, nbytes);
}
void
ccdbg_state_replace_sfr(struct ccdbg *dbg, struct ccstate *state,
uint8_t addr, uint8_t *bytes, int nbytes)
{
ccdbg_state_replace_xmem(dbg, state, (uint16_t) addr + 0xdf00, bytes, nbytes);
}

302
ao-tools/lib/ccdbg.h Normal file
View File

@@ -0,0 +1,302 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 _CCDBG_H_
#define _CCDBG_H_
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "ccdbg-debug.h"
#include "cc-bitbang.h"
#include "cc-usb.h"
#include "ao-hex.h"
/* 8051 instructions
*/
#define NOP 0x00
#define MOV_direct_data 0x75
#define LJMP 0x02
#define MOV_Rn_data(n) (0x78 | (n))
#define DJNZ_Rn_rel(n) (0xd8 | (n))
#define MOV_A_direct 0xe5
#define MOV_direct1_direct2 0x85
#define MOV_direct_A 0xf5
#define MOV_DPTR_data16 0x90
#define MOV_A_data 0x74
#define MOVX_atDPTR_A 0xf0
#define MOVX_A_atDPTR 0xe0
#define INC_DPTR 0xa3
#define TRAP 0xa5
#define SJMP 0x80
#define JB 0x20
/* 8051 special function registers
*/
#define SFR_P0 0x80
#define SFR_SP 0x81
#define SFR_DPL0 0x82
#define SFR_DPH0 0x83
#define SFR_DPL1 0x84
#define SFR_DPH1 0x85
/* flash controller */
#define FWT 0xAB
#define FADDRL 0xAC
#define FADDRH 0xAD
#define FCTL 0xAE
# define FCTL_BUSY 0x80
# define FCTL_BUSY_BIT 7
# define FCTL_SWBSY 0x40
# define FCTL_SWBSY_BIT 6
# define FCTL_CONTRD 0x10
# define FCTL_WRITE 0x02
# define FCTL_ERASE 0x01
#define FWDATA 0xAF
#define SLEEP 0xBE
/* clock controller */
#define CLKCON 0xC6
#define CLKCON_OSC32K 0x80
#define CLKCON_OSC 0x40
#define CLKCON_TICKSPD 0x38
#define CLKCON_CLKSPD 0x07
/* I/O pins */
#define P0 0x80
#define P1 0x90
#define P2 0xA0
#define P0DIR 0xFD
#define P1DIR 0xFE
#define P2DIR 0xFF
/* Bit-addressable accumulator */
#define ACC(bit) (0xE0 | (bit))
/* Bit-addressable status word */
#define PSW(bit) (0xD0 | (bit))
struct ccdbg {
struct cc_bitbang *bb;
struct cc_usb *usb;
struct ao_hex_image *rom;
};
#define CC_STATE_ACC 0x1
#define CC_STATE_PSW 0x2
#define CC_STATE_DP 0x4
#define CC_STATE_NSFR 5
struct ccstate {
uint16_t mask;
uint8_t acc;
uint8_t sfr[CC_STATE_NSFR];
};
/* CC1111 debug port commands
*/
#define CC_CHIP_ERASE 0x14
#define CC_WR_CONFIG 0x1d
#define CC_RD_CONFIG 0x24
# define CC_CONFIG_TIMERS_OFF (1 << 3)
# define CC_CONFIG_DMA_PAUSE (1 << 2)
# define CC_CONFIG_TIMER_SUSPEND (1 << 1)
# define CC_SET_FLASH_INFO_PAGE (1 << 0)
#define CC_GET_PC 0x28
#define CC_READ_STATUS 0x34
# define CC_STATUS_CHIP_ERASE_DONE (1 << 7)
# define CC_STATUS_PCON_IDLE (1 << 6)
# define CC_STATUS_CPU_HALTED (1 << 5)
# define CC_STATUS_POWER_MODE_0 (1 << 4)
# define CC_STATUS_HALT_STATUS (1 << 3)
# define CC_STATUS_DEBUG_LOCKED (1 << 2)
# define CC_STATUS_OSCILLATOR_STABLE (1 << 1)
# define CC_STATUS_STACK_OVERFLOW (1 << 0)
#define CC_SET_HW_BRKPNT 0x3b
# define CC_HW_BRKPNT_N(n) ((n) << 3)
# define CC_HW_BRKPNT_N_MASK (0x3 << 3)
# define CC_HW_BRKPNT_ENABLE (1 << 2)
#define CC_HALT 0x44
#define CC_RESUME 0x4c
#define CC_DEBUG_INSTR(n) (0x54|(n))
#define CC_STEP_INSTR 0x5c
#define CC_STEP_REPLACE(n) (0x64|(n))
#define CC_GET_CHIP_ID 0x68
/* ccdbg-command.c */
void
ccdbg_debug_mode(struct ccdbg *dbg);
void
ccdbg_reset(struct ccdbg *dbg);
uint8_t
ccdbg_chip_erase(struct ccdbg *dbg);
uint8_t
ccdbg_wr_config(struct ccdbg *dbg, uint8_t config);
uint8_t
ccdbg_rd_config(struct ccdbg *dbg);
uint16_t
ccdbg_get_pc(struct ccdbg *dbg);
uint8_t
ccdbg_read_status(struct ccdbg *dbg);
uint8_t
ccdbg_set_hw_brkpnt(struct ccdbg *dbg, uint8_t number, uint8_t enable, uint16_t addr);
uint8_t
ccdbg_halt(struct ccdbg *dbg);
uint8_t
ccdbg_resume(struct ccdbg *dbg);
uint8_t
ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes);
void
ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes);
void
ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes,
uint8_t *reply);
uint8_t
ccdbg_step_instr(struct ccdbg *dbg);
uint8_t
ccdbg_step_replace(struct ccdbg *dbg, uint8_t *instr, int nbytes);
uint16_t
ccdbg_get_chip_id(struct ccdbg *dbg);
uint8_t
ccdbg_execute(struct ccdbg *dbg, uint8_t *inst);
uint8_t
ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc);
uint8_t
ccdbg_execute_hex_image(struct ccdbg *dbg, struct ao_hex_image *image);
/* ccdbg-flash.c */
uint8_t
ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image);
/* ccdbg-io.c */
struct ccdbg *
ccdbg_open(char *tty);
void
ccdbg_close(struct ccdbg *dbg);
void
ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len);
uint8_t
ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len);
void
ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd,
uint8_t *data, int len, uint8_t *reply);
uint16_t
ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len);
void
ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes);
void
ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes);
void
ccdbg_sync(struct ccdbg *dbg);
/* ccdbg-manual.c */
void
ccdbg_manual(struct ccdbg *dbg, FILE *input);
/* ccdbg-memory.c */
uint8_t
ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes);
uint8_t
ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes);
uint8_t
ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte);
uint8_t
ccdbg_write_hex_image(struct ccdbg *dbg, struct ao_hex_image *image, uint16_t offset);
struct ao_hex_image *
ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length);
uint8_t
ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes);
uint8_t
ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes);
/* ccdbg-rom.c */
uint8_t
ccdbg_set_rom(struct ccdbg *dbg, struct ao_hex_image *rom);
uint8_t
ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes);
uint8_t
ccdbg_rom_replace_xmem(struct ccdbg *dbg,
uint16_t addrp, uint8_t *bytesp, int nbytes);
/* ccdbg-state.c */
uint8_t
ccdbg_state_save(struct ccdbg *dbg, struct ccstate *state, unsigned int mask);
uint8_t
ccdbg_state_restore(struct ccdbg *dbg, struct ccstate *state);
void
ccdbg_state_replace_xmem(struct ccdbg *dbg, struct ccstate *state,
uint16_t addr, uint8_t *bytes, int nbytes);
void
ccdbg_state_replace_sfr(struct ccdbg *dbg, struct ccstate *state,
uint8_t addr, uint8_t *bytes, int nbytes);
#endif /* _CCDBG_H_ */

123
ao-tools/lib/cephes.h Normal file
View File

@@ -0,0 +1,123 @@
/*
* This file comes from the cephes math library, which was
* released under the GPLV2+ license as a part of the Debian labplot
* package (I've included the GPLV2 license reference here to make
* this clear) - Keith Packard <keithp@keithp.com>
*
* Cephes Math Library Release 2.0: April, 1987
* Copyright 1984, 1987 by Stephen L. Moshier
* Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*
* 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.
*/
/*
* Prototypes of Cephes functions
*/
#ifndef _CEPHES_H_
#define _CEPHES_H_
/* Variable for error reporting. See mtherr.c. */
extern int merror;
#if 0
extern int airy ( double x, double *ai, double *aip, double *bi, double *bip );
extern double beta ( double a, double b );
extern double lbeta ( double a, double b );
extern double chdtrc ( double df, double x );
extern double chdtr ( double df, double x );
extern double chdtri ( double df, double y );
extern double dawsn ( double xx );
extern double ellie ( double phi, double m );
extern double ellik ( double phi, double m );
extern double ellpe ( double x );
extern double ellpk ( double x );
extern double expn ( int n, double x );
extern double fac ( int i );
extern double fdtrc ( int ia, int ib, double x );
extern double fdtr ( int ia, int ib, double x );
extern double fdtri ( int ia, int ib, double y );
extern double frexp ( double x, int *pw2 );
extern double ldexp ( double x, int pw2 );
extern int fresnl ( double xxa, double *ssa, double *cca );
extern double gdtr ( double a, double b, double x );
extern double gdtrc ( double a, double b, double x );
extern double hyp2f0 ( double a, double b, double x, int type, double *err );
extern double hyp2f1 ( double a, double b, double c, double x );
extern double hyperg ( double a, double b, double x );
#endif
extern double i0 ( double x );
extern double i0e ( double x );
#if 0
extern double i1 ( double x );
extern double i1e ( double x );
extern double iv ( double v, double x );
extern double igamc ( double a, double x );
extern double igam ( double a, double x );
extern double igami ( double a, double y0_ );
extern double incbet ( double aa, double bb, double xx );
extern double incbi ( double aa, double bb, double yy0 );
extern double jv ( double n, double x );
extern double k0 ( double x );
extern double k0e ( double x );
extern double k1 ( double x );
extern double k1e ( double x );
extern double kn ( int nn, double x );
extern int mtherr ( char *name, int code );
extern double ndtr ( double a );
extern double ndtri ( double y0_ );
extern double pdtrc ( int k, double m );
extern double pdtr ( int k, double m );
extern double pdtri ( int k, double y );
extern double psi ( double x );
extern void revers ( double y[], double x[], int n );
extern double true_gamma ( double x );
extern double rgamma ( double x );
extern int shichi ( double x, double *si, double *ci );
extern int sici ( double x, double *si, double *ci );
extern double spence ( double x );
extern double stdtr ( int k, double t );
extern double stdtri ( int k, double p );
extern double onef2 ( double a, double b, double c, double x, double *err );
extern double threef0 ( double a, double b, double c, double x, double *err );
extern double struve ( double v, double x );
extern double log1p ( double x );
extern double expm1 ( double x );
extern double cosm1 ( double x );
extern double yv ( double v, double x );
extern double zeta ( double x, double q );
extern double zetac ( double x );
#endif
extern double chbevl ( double x, void *P, int n );
#if 0
extern double polevl ( double x, void *P, int n );
extern double p1evl ( double x, void *P, int n );
/* polyn.c */
extern void polini ( int maxdeg );
extern void polprt ( double a[], int na, int d );
extern void polclr ( double *a, int n );
extern void polmov ( double *a, int na, double *b );
extern void polmul ( double a[], int na, double b[], int nb, double c[] );
extern void poladd ( double a[], int na, double b[], int nb, double c[] );
extern void polsub ( double a[], int na, double b[], int nb, double c[] );
extern int poldiv ( double a[], int na, double b[], int nb, double c[] );
extern void polsbt ( double a[], int na, double b[], int nb, double c[] );
extern double poleva ( double a[], int na, double x );
#endif
#endif /* _CEPHES_H_ */

81
ao-tools/lib/chbevl.c Normal file
View File

@@ -0,0 +1,81 @@
/* chbevl.c
*
* Evaluate Chebyshev series
*
*
*
* SYNOPSIS:
*
* int N;
* double x, y, coef[N], chebevl();
*
* y = chbevl( x, coef, N );
*
*
*
* DESCRIPTION:
*
* Evaluates the series
*
* N-1
* - '
* y = > coef[i] T (x/2)
* - i
* i=0
*
* of Chebyshev polynomials Ti at argument x/2.
*
* Coefficients are stored in reverse order, i.e. the zero
* order term is last in the array. Note N is the number of
* coefficients, not the order.
*
* If coefficients are for the interval a to b, x must
* have been transformed to x -> 2(2x - b - a)/(b-a) before
* entering the routine. This maps x from (a, b) to (-1, 1),
* over which the Chebyshev polynomials are defined.
*
* If the coefficients are for the inverted interval, in
* which (a, b) is mapped to (1/b, 1/a), the transformation
* required is x -> 2(2ab/x - b - a)/(b-a). If b is infinity,
* this becomes x -> 4a/x - 1.
*
*
*
* SPEED:
*
* Taking advantage of the recurrence properties of the
* Chebyshev polynomials, the routine requires one more
* addition per loop than evaluating a nested polynomial of
* the same degree.
*
*/
/* chbevl.c */
/*
Cephes Math Library Release 2.0: April, 1987
Copyright 1985, 1987 by Stephen L. Moshier
Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*/
#include "cephes.h"
double chbevl(double x,void* array,int n )
{
double b0, b1, b2, *p;
int i;
p = (double *) array;
b0 = *p++;
b1 = 0.0;
i = n - 1;
do
{
b2 = b1;
b1 = b0;
b0 = x * b1 - b2 + *p++;
}
while( --i );
return( 0.5*(b0-b2) );
}

179
ao-tools/lib/cmath.h Normal file
View File

@@ -0,0 +1,179 @@
/*
* Grace - GRaphing, Advanced Computation and Exploration of data
*
* Home page: http://plasma-gate.weizmann.ac.il/Grace/
*
* Copyright (c) 1991-1995 Paul J Turner, Portland, OR
* Copyright (c) 1996-2000 Grace Development Team
*
* Maintained by Evgeny Stambulchik <fnevgeny@plasma-gate.weizmann.ac.il>
*
*
* All Rights Reserved
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* cmath.h - replacement for math.h or missing in libm functions */
#if defined(HAVE_MATH_H)
# include <math.h>
#endif
#if defined(HAVE_FLOAT_H)
# include <float.h>
#endif
#if defined(HAVE_IEEEFP_H)
# include <ieeefp.h>
#endif
#ifndef __GRACE_SOURCE_
#ifndef MACHEP
extern double MACHEP;
#endif
#ifndef UFLOWTHRESH
extern double UFLOWTHRESH;
#endif
#ifndef MAXNUM
extern double MAXNUM;
#endif
#endif /* __GRACE_SOURCE_ */
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#ifndef M_SQRT2
# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
#endif
#ifndef M_SQRT1_2
# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
#endif
#ifndef M_SQRT1_3
# define M_SQRT1_3 0.57735026918962576451 /* 1/sqrt(3) */
#endif
#ifndef HAVE_HYPOT
# define hypot(x, y) sqrt((x)*(x) + (y)*(y))
#endif
extern double round ( double x );
#ifndef HAVE_RINT
# define rint round
#else
# ifndef HAVE_RINT_DECL
extern double rint ( double x );
# endif
#endif
#ifndef HAVE_CBRT_DECL
extern double cbrt ( double x );
#endif
/* Cygnus gnuwin32 has the log2 macro */
#ifdef log2
# undef log2
#endif
#ifndef HAVE_LOG2_DECL
extern double log2 ( double x );
#endif
#ifndef HAVE_LGAMMA
extern int sgngam;
# define lgamma lgam
# define signgam sgngam
extern double lgam ( double x );
#else
# ifndef HAVE_LGAMMA_DECL
extern double lgamma ( double x );
# endif
# ifndef HAVE_SIGNGAM_DECL
extern int signgam;
# endif
# define lgam lgamma
# define sgngam signgam
#endif
#ifndef HAVE_ACOSH_DECL
extern double acosh ( double x );
#endif
#ifndef HAVE_ASINH_DECL
extern double asinh ( double x );
#endif
#ifndef HAVE_ATANH_DECL
extern double atanh ( double x );
#endif
#ifndef HAVE_ERF_DECL
extern double erf ( double x );
#endif
#ifndef HAVE_ERFC_DECL
extern double erfc ( double x );
#endif
#ifndef HAVE_Y0_DECL
extern double y0 ( double x );
#endif
#ifndef HAVE_Y1_DECL
extern double y1 ( double x );
#endif
#ifndef HAVE_YN_DECL
extern double yn ( int n, double x );
#endif
#ifndef HAVE_J0_DECL
extern double j0 ( double x );
#endif
#ifndef HAVE_J1_DECL
extern double j1 ( double x );
#endif
#ifndef HAVE_JN_DECL
extern double jn ( int n, double x );
#endif
/* isfinite is a macro */
#ifdef isfinite
# define HAVE_ISFINITE_MACRO
#endif
#ifndef HAVE_FINITE
# define finite isfinite
# if !defined(HAVE_ISFINITE_DECL) && !defined(HAVE_ISFINITE_MACRO)
extern int isfinite ( double x );
# endif
#else
# ifndef HAVE_FINITE_DECL
extern int finite ( double x );
# endif
#endif
#ifndef HAVE_ISNAN_DECL
#ifdef __FreeBSD__
# include <sys/param.h>
# if __FreeBSD_version < 500100
extern int isnan ( double x );
# endif
#endif
#else
extern int isnan ( double x );
#endif

189
ao-tools/lib/cp-usb-async.c Normal file
View File

@@ -0,0 +1,189 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "cp-usb-async.h"
#include "ccdbg-debug.h"
#define MAX_OUTSTANDING 256
#define CP_TIMEOUT 1000 /* ms */
struct cp_usb_packet {
struct libusb_transfer *transfer;
enum { packet_read, packet_write } direction;
unsigned char data[9];
uint8_t *valuep;
};
struct cp_usb_async {
libusb_context *ctx;
libusb_device_handle *handle;
struct cp_usb_packet packet[MAX_OUTSTANDING];
int p, ack;
uint8_t value;
uint8_t set;
};
struct cp_usb_async *
cp_usb_async_open(void)
{
struct cp_usb_async *cp;
int ret;
cp = calloc(sizeof (struct cp_usb_async), 1);
if (!cp)
return NULL;
ret = libusb_init(&cp->ctx);
if (ret) {
free(cp);
return NULL;
}
cp->handle = libusb_open_device_with_vid_pid(cp->ctx,
0x10c4, 0xea60);
cp->ack = -1;
if (!cp->handle) {
fprintf(stderr, "Cannot find USB device 10c4:ea60\n");
libusb_exit(cp->ctx);
free(cp);
return NULL;
}
cp->value = 0;
cp->set = 0;
return cp;
}
void
cp_usb_async_close(struct cp_usb_async *cp)
{
libusb_close(cp->handle);
libusb_exit(cp->ctx);
free(cp);
}
static void
cp_usb_async_transfer_callback(struct libusb_transfer *transfer)
{
struct cp_usb_async *cp = transfer->user_data;
int p;
for (p = 0; p < cp->p; p++)
if (cp->packet[p].transfer == transfer)
break;
if (p == cp->p) {
fprintf(stderr, "unknown transfer\n");
return;
}
switch (cp->packet[p].direction) {
case packet_read:
ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack read %d 0x%02x\n",
p, cp->packet[p].data[8]);
*cp->packet[p].valuep = cp->packet[p].data[8];
break;
case packet_write:
ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack write %d\n", p);
break;
}
if (p > cp->ack)
cp->ack = p;
}
void
cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value)
{
int p;
uint16_t gpio_set;
int ret;
if (cp->set) {
value = (cp->value & ~mask) | (value & mask);
mask = value ^ cp->value;
}
cp->set = 1;
cp->value = value;
gpio_set = ((uint16_t) value << 8) | mask;
if (cp->p == MAX_OUTSTANDING)
cp_usb_async_sync(cp);
p = cp->p;
if (!cp->packet[p].transfer)
cp->packet[p].transfer = libusb_alloc_transfer(0);
cp->packet[p].direction = packet_write;
libusb_fill_control_setup(cp->packet[p].data,
0x40, /* request */
0xff, /* request type */
0x37e1, /* value */
gpio_set, /* index */
0); /* length */
libusb_fill_control_transfer(cp->packet[p].transfer,
cp->handle,
cp->packet[p].data,
cp_usb_async_transfer_callback,
cp,
CP_TIMEOUT);
ccdbg_debug(CC_DEBUG_USB_ASYNC, "Write packet %d 0x%x 0x%x\n", p, mask, value);
ret = libusb_submit_transfer(cp->packet[p].transfer);
if (ret)
fprintf(stderr, "libusb_submit_transfer failed %d\n", ret);
cp->p++;
}
void
cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep)
{
int p;
int ret;
if (cp->p == MAX_OUTSTANDING)
cp_usb_async_sync(cp);
p = cp->p;
if (!cp->packet[p].transfer)
cp->packet[p].transfer = libusb_alloc_transfer(0);
cp->packet[p].valuep = valuep;
cp->packet[p].direction = packet_read;
libusb_fill_control_setup(cp->packet[p].data,
0xc0, /* request */
0xff, /* request type */
0x00c2, /* value */
0, /* index */
1); /* length */
libusb_fill_control_transfer(cp->packet[p].transfer,
cp->handle,
cp->packet[p].data,
cp_usb_async_transfer_callback,
cp,
CP_TIMEOUT);
ccdbg_debug(CC_DEBUG_USB_ASYNC, "Read packet %d\n", p);
ret = libusb_submit_transfer(cp->packet[p].transfer);
if (ret)
fprintf(stderr, "libusb_submit_transfer failed %d\n", ret);
cp->p++;
}
void
cp_usb_async_sync(struct cp_usb_async *cp)
{
while (cp->ack < cp->p - 1) {
libusb_handle_events(cp->ctx);
}
cp->p = 0;
cp->ack = -1;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2008 Keith Packard <keithp@keithp.com>
*
* 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 _CP_USB_ASYNC_H_
#define _CP_USB_ASYNC_H_
#include <libusb.h>
struct cp_usb_async *
cp_usb_async_open(void);
void
cp_usb_async_close(struct cp_usb_async *cp);
void
cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value);
void
cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep);
void
cp_usb_async_sync(struct cp_usb_async *cp);
#endif

415
ao-tools/lib/i0.c Normal file
View File

@@ -0,0 +1,415 @@
/*
* This file comes from the cephes math library, which was
* released under the GPLV2+ license as a part of the Debian labplot
* package (I've included the GPLV2 license reference here to make
* this clear) - Keith Packard <keithp@keithp.com>
*
* Cephes Math Library Release 2.0: April, 1987
* Copyright 1984, 1987 by Stephen L. Moshier
* Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*
* 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.
*/
/* i0.c
*
* Modified Bessel function of order zero
*
*
*
* SYNOPSIS:
*
* double x, y, i0();
*
* y = i0( x );
*
*
*
* DESCRIPTION:
*
* Returns modified Bessel function of order zero of the
* argument.
*
* The function is defined as i0(x) = j0( ix ).
*
* The range is partitioned into the two intervals [0,8] and
* (8, infinity). Chebyshev polynomial expansions are employed
* in each interval.
*
*
*
* ACCURACY:
*
* Relative error:
* arithmetic domain # trials peak rms
* DEC 0,30 6000 8.2e-17 1.9e-17
* IEEE 0,30 30000 5.8e-16 1.4e-16
*
*/
/* i0e.c
*
* Modified Bessel function of order zero,
* exponentially scaled
*
*
*
* SYNOPSIS:
*
* double x, y, i0e();
*
* y = i0e( x );
*
*
*
* DESCRIPTION:
*
* Returns exponentially scaled modified Bessel function
* of order zero of the argument.
*
* The function is defined as i0e(x) = exp(-|x|) j0( ix ).
*
*
*
* ACCURACY:
*
* Relative error:
* arithmetic domain # trials peak rms
* IEEE 0,30 30000 5.4e-16 1.2e-16
* See i0().
*
*/
/* i0.c */
/*
Cephes Math Library Release 2.0: April, 1987
Copyright 1984, 1987 by Stephen L. Moshier
Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*/
#include <math.h>
#include "mconf.h"
#include "cephes.h"
/* Chebyshev coefficients for exp(-x) I0(x)
* in the interval [0,8].
*
* lim(x->0){ exp(-x) I0(x) } = 1.
*/
#ifdef UNK
static double A[] =
{
-4.41534164647933937950E-18,
3.33079451882223809783E-17,
-2.43127984654795469359E-16,
1.71539128555513303061E-15,
-1.16853328779934516808E-14,
7.67618549860493561688E-14,
-4.85644678311192946090E-13,
2.95505266312963983461E-12,
-1.72682629144155570723E-11,
9.67580903537323691224E-11,
-5.18979560163526290666E-10,
2.65982372468238665035E-9,
-1.30002500998624804212E-8,
6.04699502254191894932E-8,
-2.67079385394061173391E-7,
1.11738753912010371815E-6,
-4.41673835845875056359E-6,
1.64484480707288970893E-5,
-5.75419501008210370398E-5,
1.88502885095841655729E-4,
-5.76375574538582365885E-4,
1.63947561694133579842E-3,
-4.32430999505057594430E-3,
1.05464603945949983183E-2,
-2.37374148058994688156E-2,
4.93052842396707084878E-2,
-9.49010970480476444210E-2,
1.71620901522208775349E-1,
-3.04682672343198398683E-1,
6.76795274409476084995E-1
};
#endif
#ifdef DEC
static unsigned short A[] = {
0121642,0162671,0004646,0103567,
0022431,0115424,0135755,0026104,
0123214,0023533,0110365,0156635,
0023767,0033304,0117662,0172716,
0124522,0100426,0012277,0157531,
0025254,0155062,0054461,0030465,
0126010,0131143,0013560,0153604,
0026517,0170577,0006336,0114437,
0127227,0162253,0152243,0052734,
0027724,0142766,0061641,0160200,
0130416,0123760,0116564,0125262,
0031066,0144035,0021246,0054641,
0131537,0053664,0060131,0102530,
0032201,0155664,0165153,0020652,
0132617,0061434,0074423,0176145,
0033225,0174444,0136147,0122542,
0133624,0031576,0056453,0020470,
0034211,0175305,0172321,0041314,
0134561,0054462,0147040,0165315,
0035105,0124333,0120203,0162532,
0135427,0013750,0174257,0055221,
0035726,0161654,0050220,0100162,
0136215,0131361,0000325,0041110,
0036454,0145417,0117357,0017352,
0136702,0072367,0104415,0133574,
0037111,0172126,0072505,0014544,
0137302,0055601,0120550,0033523,
0037457,0136543,0136544,0043002,
0137633,0177536,0001276,0066150,
0040055,0041164,0100655,0010521
};
#endif
#ifdef IBMPC
static unsigned short A[] = {
0xd0ef,0x2134,0x5cb7,0xbc54,
0xa589,0x977d,0x3362,0x3c83,
0xbbb4,0x721e,0x84eb,0xbcb1,
0x5eba,0x93f6,0xe6d8,0x3cde,
0xfbeb,0xc297,0x5022,0xbd0a,
0x2627,0x4b26,0x9b46,0x3d35,
0x1af0,0x62ee,0x164c,0xbd61,
0xd324,0xe19b,0xfe2f,0x3d89,
0x6abc,0x7a94,0xfc95,0xbdb2,
0x3c10,0xcc74,0x98be,0x3dda,
0x9556,0x13ae,0xd4fe,0xbe01,
0xcb34,0xa454,0xd903,0x3e26,
0x30ab,0x8c0b,0xeaf6,0xbe4b,
0x6435,0x9d4d,0x3b76,0x3e70,
0x7f8d,0x8f22,0xec63,0xbe91,
0xf4ac,0x978c,0xbf24,0x3eb2,
0x6427,0xcba5,0x866f,0xbed2,
0x2859,0xbe9a,0x3f58,0x3ef1,
0x1d5a,0x59c4,0x2b26,0xbf0e,
0x7cab,0x7410,0xb51b,0x3f28,
0xeb52,0x1f15,0xe2fd,0xbf42,
0x100e,0x8a12,0xdc75,0x3f5a,
0xa849,0x201a,0xb65e,0xbf71,
0xe3dd,0xf3dd,0x9961,0x3f85,
0xb6f0,0xf121,0x4e9e,0xbf98,
0xa32d,0xcea8,0x3e8a,0x3fa9,
0x06ea,0x342d,0x4b70,0xbfb8,
0x88c0,0x77ac,0xf7ac,0x3fc5,
0xcd8d,0xc057,0x7feb,0xbfd3,
0xa22a,0x9035,0xa84e,0x3fe5,
};
#endif
#ifdef MIEEE
static unsigned short A[] = {
0xbc54,0x5cb7,0x2134,0xd0ef,
0x3c83,0x3362,0x977d,0xa589,
0xbcb1,0x84eb,0x721e,0xbbb4,
0x3cde,0xe6d8,0x93f6,0x5eba,
0xbd0a,0x5022,0xc297,0xfbeb,
0x3d35,0x9b46,0x4b26,0x2627,
0xbd61,0x164c,0x62ee,0x1af0,
0x3d89,0xfe2f,0xe19b,0xd324,
0xbdb2,0xfc95,0x7a94,0x6abc,
0x3dda,0x98be,0xcc74,0x3c10,
0xbe01,0xd4fe,0x13ae,0x9556,
0x3e26,0xd903,0xa454,0xcb34,
0xbe4b,0xeaf6,0x8c0b,0x30ab,
0x3e70,0x3b76,0x9d4d,0x6435,
0xbe91,0xec63,0x8f22,0x7f8d,
0x3eb2,0xbf24,0x978c,0xf4ac,
0xbed2,0x866f,0xcba5,0x6427,
0x3ef1,0x3f58,0xbe9a,0x2859,
0xbf0e,0x2b26,0x59c4,0x1d5a,
0x3f28,0xb51b,0x7410,0x7cab,
0xbf42,0xe2fd,0x1f15,0xeb52,
0x3f5a,0xdc75,0x8a12,0x100e,
0xbf71,0xb65e,0x201a,0xa849,
0x3f85,0x9961,0xf3dd,0xe3dd,
0xbf98,0x4e9e,0xf121,0xb6f0,
0x3fa9,0x3e8a,0xcea8,0xa32d,
0xbfb8,0x4b70,0x342d,0x06ea,
0x3fc5,0xf7ac,0x77ac,0x88c0,
0xbfd3,0x7feb,0xc057,0xcd8d,
0x3fe5,0xa84e,0x9035,0xa22a
};
#endif
/* Chebyshev coefficients for exp(-x) sqrt(x) I0(x)
* in the inverted interval [8,infinity].
*
* lim(x->inf){ exp(-x) sqrt(x) I0(x) } = 1/sqrt(2pi).
*/
#ifdef UNK
static double B[] =
{
-7.23318048787475395456E-18,
-4.83050448594418207126E-18,
4.46562142029675999901E-17,
3.46122286769746109310E-17,
-2.82762398051658348494E-16,
-3.42548561967721913462E-16,
1.77256013305652638360E-15,
3.81168066935262242075E-15,
-9.55484669882830764870E-15,
-4.15056934728722208663E-14,
1.54008621752140982691E-14,
3.85277838274214270114E-13,
7.18012445138366623367E-13,
-1.79417853150680611778E-12,
-1.32158118404477131188E-11,
-3.14991652796324136454E-11,
1.18891471078464383424E-11,
4.94060238822496958910E-10,
3.39623202570838634515E-9,
2.26666899049817806459E-8,
2.04891858946906374183E-7,
2.89137052083475648297E-6,
6.88975834691682398426E-5,
3.36911647825569408990E-3,
8.04490411014108831608E-1
};
#endif
#ifdef DEC
static unsigned short B[] = {
0122005,0066672,0123124,0054311,
0121662,0033323,0030214,0104602,
0022515,0170300,0113314,0020413,
0022437,0117350,0035402,0007146,
0123243,0000135,0057220,0177435,
0123305,0073476,0144106,0170702,
0023777,0071755,0017527,0154373,
0024211,0052214,0102247,0033270,
0124454,0017763,0171453,0012322,
0125072,0166316,0075505,0154616,
0024612,0133770,0065376,0025045,
0025730,0162143,0056036,0001632,
0026112,0015077,0150464,0063542,
0126374,0101030,0014274,0065457,
0127150,0077271,0125763,0157617,
0127412,0104350,0040713,0120445,
0027121,0023765,0057500,0001165,
0030407,0147146,0003643,0075644,
0031151,0061445,0044422,0156065,
0031702,0132224,0003266,0125551,
0032534,0000076,0147153,0005555,
0033502,0004536,0004016,0026055,
0034620,0076433,0142314,0171215,
0036134,0146145,0013454,0101104,
0040115,0171425,0062500,0047133
};
#endif
#ifdef IBMPC
static unsigned short B[] = {
0x8b19,0x54ca,0xadb7,0xbc60,
0x9130,0x6611,0x46da,0xbc56,
0x8421,0x12d9,0xbe18,0x3c89,
0x41cd,0x0760,0xf3dd,0x3c83,
0x1fe4,0xabd2,0x600b,0xbcb4,
0xde38,0xd908,0xaee7,0xbcb8,
0xfb1f,0xa3ea,0xee7d,0x3cdf,
0xe6d7,0x9094,0x2a91,0x3cf1,
0x629a,0x7e65,0x83fe,0xbd05,
0xbb32,0xcf68,0x5d99,0xbd27,
0xc545,0x0d5f,0x56ff,0x3d11,
0xc073,0x6b83,0x1c8c,0x3d5b,
0x8cec,0xfa26,0x4347,0x3d69,
0x8d66,0x0317,0x9043,0xbd7f,
0x7bf2,0x357e,0x0fd7,0xbdad,
0x7425,0x0839,0x511d,0xbdc1,
0x004f,0xabe8,0x24fe,0x3daa,
0x6f75,0xc0f4,0xf9cc,0x3e00,
0x5b87,0xa922,0x2c64,0x3e2d,
0xd56d,0x80d6,0x5692,0x3e58,
0x616e,0xd9cd,0x8007,0x3e8b,
0xc586,0xc101,0x412b,0x3ec8,
0x9e52,0x7899,0x0fa3,0x3f12,
0x9049,0xa2e5,0x998c,0x3f6b,
0x09cb,0xaca8,0xbe62,0x3fe9
};
#endif
#ifdef MIEEE
static unsigned short B[] = {
0xbc60,0xadb7,0x54ca,0x8b19,
0xbc56,0x46da,0x6611,0x9130,
0x3c89,0xbe18,0x12d9,0x8421,
0x3c83,0xf3dd,0x0760,0x41cd,
0xbcb4,0x600b,0xabd2,0x1fe4,
0xbcb8,0xaee7,0xd908,0xde38,
0x3cdf,0xee7d,0xa3ea,0xfb1f,
0x3cf1,0x2a91,0x9094,0xe6d7,
0xbd05,0x83fe,0x7e65,0x629a,
0xbd27,0x5d99,0xcf68,0xbb32,
0x3d11,0x56ff,0x0d5f,0xc545,
0x3d5b,0x1c8c,0x6b83,0xc073,
0x3d69,0x4347,0xfa26,0x8cec,
0xbd7f,0x9043,0x0317,0x8d66,
0xbdad,0x0fd7,0x357e,0x7bf2,
0xbdc1,0x511d,0x0839,0x7425,
0x3daa,0x24fe,0xabe8,0x004f,
0x3e00,0xf9cc,0xc0f4,0x6f75,
0x3e2d,0x2c64,0xa922,0x5b87,
0x3e58,0x5692,0x80d6,0xd56d,
0x3e8b,0x8007,0xd9cd,0x616e,
0x3ec8,0x412b,0xc101,0xc586,
0x3f12,0x0fa3,0x7899,0x9e52,
0x3f6b,0x998c,0xa2e5,0x9049,
0x3fe9,0xbe62,0xaca8,0x09cb
};
#endif
double i0(double x)
{
double y;
if( x < 0 )
x = -x;
if( x <= 8.0 )
{
y = (x/2.0) - 2.0;
return( exp(x) * chbevl( y, A, 30 ) );
}
return( exp(x) * chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) );
}
double i0e(double x )
{
double y;
if( x < 0 )
x = -x;
if( x <= 8.0 )
{
y = (x/2.0) - 2.0;
return( chbevl( y, A, 30 ) );
}
return( chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) );
}

212
ao-tools/lib/mconf.h Normal file
View File

@@ -0,0 +1,212 @@
/*
* This file comes from the cephes math library, which was
* released under the GPLV2+ license as a part of the Debian labplot
* package (I've included the GPLV2 license reference here to make
* this clear) - Keith Packard <keithp@keithp.com>
*
* Cephes Math Library Release 2.0: April, 1987
* Copyright 1984, 1987 by Stephen L. Moshier
* Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*
* 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.
*/
/* mconf.h
*
* Common include file for math routines
*
*
*
* SYNOPSIS:
*
* #include "mconf.h"
*
*
*
* DESCRIPTION:
*
* This file contains definitions for error codes that are
* passed to the common error handling routine mtherr()
* (which see).
*
* The file also includes a conditional assembly definition
* for the type of computer arithmetic (IEEE, DEC, Motorola
* IEEE, or UNKnown).
*
* For Digital Equipment PDP-11 and VAX computers, certain
* IBM systems, and others that use numbers with a 56-bit
* significand, the symbol DEC should be defined. In this
* mode, most floating point constants are given as arrays
* of octal integers to eliminate decimal to binary conversion
* errors that might be introduced by the compiler.
*
* For little-endian computers, such as IBM PC, that follow the
* IEEE Standard for Binary Floating Point Arithmetic (ANSI/IEEE
* Std 754-1985), the symbol IBMPC should be defined. These
* numbers have 53-bit significands. In this mode, constants
* are provided as arrays of hexadecimal 16 bit integers.
*
* Big-endian IEEE format is denoted MIEEE. On some RISC
* systems such as Sun SPARC, double precision constants
* must be stored on 8-byte address boundaries. Since integer
* arrays may be aligned differently, the MIEEE configuration
* may fail on such machines.
*
* To accommodate other types of computer arithmetic, all
* constants are also provided in a normal decimal radix
* which one can hope are correctly converted to a suitable
* format by the available C language compiler. To invoke
* this mode, define the symbol UNK.
*
* An important difference among these modes is a predefined
* set of machine arithmetic constants for each. The numbers
* MACHEP (the machine roundoff error), MAXNUM (largest number
* represented), and several other parameters are preset by
* the configuration symbol. Check the file const.c to
* ensure that these values are correct for your computer.
*
* Configurations NANS, INFINITIES, MINUSZERO, and DENORMAL
* may fail on many systems. Verify that they are supposed
* to work on your computer.
*/
/*
Cephes Math Library Release 2.3: June, 1995
Copyright 1984, 1987, 1989, 1995 by Stephen L. Moshier
Adjusted for use with ACE/gr by Evgeny Stambulchik, October 1997
*/
#define __GRACE_SOURCE_
#include "cmath.h"
/* Type of computer arithmetic */
/* In ACE/gr, defined as a compiler directive - no need to define here */
/* PDP-11, Pro350, VAX:
*/
#if defined(HAVE_DEC_FPU)
# define DEC 1
#endif
/* Intel IEEE, low order words come first:
*/
#if defined(HAVE_LIEEE_FPU)
# define IBMPC 1
#endif
/* Motorola IEEE, high order words come first
* (Sun 680x0 workstation):
*/
#if defined(HAVE_BIEEE_FPU)
# define MIEEE 1
#endif
/* UNKnown arithmetic, invokes coefficients given in
* normal decimal format. Beware of range boundary
* problems (MACHEP, MAXLOG, etc. in const.c) and
* roundoff problems in pow.c:
* (Sun SPARCstation)
*/
#if (!defined (DEC) && !defined (IBMPC) && !defined (MIEEE))
# define UNK 1
#endif
/* Define this `volatile' if your compiler thinks
* that floating point arithmetic obeys the associative
* and distributive laws. It will defeat some optimizations
* (but probably not enough of them).
*
* #define VOLATILE volatile
*/
#ifndef VOLATILE
# define VOLATILE
#endif
#ifdef PI
# undef PI
#endif
#ifdef NAN
# undef NAN
#endif
#ifdef INFINITY
# undef INFINITY
#endif
/* Constant definitions for math error conditions
*/
#if defined(DOMAIN)
# undef DOMAIN
#endif
#define DOMAIN 1 /* argument domain error */
#if defined(SING)
# undef SING
#endif
#define SING 2 /* argument singularity */
#if defined(OVERFLOW)
# undef OVERFLOW
#endif
#define OVERFLOW 3 /* overflow range error */
#if defined(UNDERFLOW)
# undef UNDERFLOW
#endif
#define UNDERFLOW 4 /* underflow range error */
#if defined(TLOSS)
# undef TLOSS
#endif
#define TLOSS 5 /* total loss of precision */
#if defined(PLOSS)
# undef PLOSS
#endif
#define PLOSS 6 /* partial loss of precision */
#if defined(EDOM)
# undef EDOM
#endif
#define EDOM 33
#if defined(ERANGE)
# undef ERANGE
#endif
#define ERANGE 34
#if !defined (UNK)
/* Define to support tiny denormal numbers, else undefine. */
# define DENORMAL 1
/* Define to ask for infinity support, else undefine. */
# define INFINITIES 1
/* Define to ask for support of numbers that are Not-a-Number,
else undefine. This may automatically define INFINITIES in some files. */
# define NANS 1
/* Define to distinguish between -0.0 and +0.0. */
# define MINUSZERO 1
#endif
/* Define 1 for ANSI C atan2() function
See atan.c and clog.c. */
#define ANSIC 1