Initial Commit - Copy from Altus Metrum AltOS
This commit is contained in:
60
ao-tools/lib/Makefile.am
Normal file
60
ao-tools/lib/Makefile.am
Normal 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
|
175
ao-tools/lib/ao-atmosphere.c
Normal file
175
ao-tools/lib/ao-atmosphere.c
Normal 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;
|
||||
}
|
24
ao-tools/lib/ao-atmosphere.h
Normal file
24
ao-tools/lib/ao-atmosphere.h
Normal 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
203
ao-tools/lib/ao-dfu.c
Normal 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
36
ao-tools/lib/ao-dfu.h
Normal 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
237
ao-tools/lib/ao-editaltos.c
Normal 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;
|
||||
}
|
69
ao-tools/lib/ao-editaltos.h
Normal file
69
ao-tools/lib/ao-editaltos.h
Normal 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_ */
|
258
ao-tools/lib/ao-eeprom-read.c
Normal file
258
ao-tools/lib/ao-eeprom-read.c
Normal 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;
|
||||
}
|
567
ao-tools/lib/ao-eeprom-read.h
Normal file
567
ao-tools/lib/ao-eeprom-read.h
Normal 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
325
ao-tools/lib/ao-elf.c
Normal 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
29
ao-tools/lib/ao-elf.h
Normal 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
651
ao-tools/lib/ao-hex.c
Normal 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
85
ao-tools/lib/ao-hex.h
Normal 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_ */
|
63
ao-tools/lib/ao-ms5607-convert.c
Normal file
63
ao-tools/lib/ao-ms5607-convert.c
Normal 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
50
ao-tools/lib/ao-ms5607.h
Normal 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
197
ao-tools/lib/ao-selfload.c
Normal 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;
|
||||
}
|
||||
|
48
ao-tools/lib/ao-selfload.h
Normal file
48
ao-tools/lib/ao-selfload.h
Normal 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
37
ao-tools/lib/ao-verbose.c
Normal 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
33
ao-tools/lib/ao-verbose.h
Normal 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
268
ao-tools/lib/cc-analyse.c
Normal 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
237
ao-tools/lib/cc-bitbang.c
Normal 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
94
ao-tools/lib/cc-bitbang.h
Normal 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
305
ao-tools/lib/cc-convert.c
Normal 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
146
ao-tools/lib/cc-dsp.c
Normal 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;
|
||||
}
|
82
ao-tools/lib/cc-integrate.c
Normal file
82
ao-tools/lib/cc-integrate.c
Normal 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
122
ao-tools/lib/cc-log.c
Normal 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
337
ao-tools/lib/cc-logfile.c
Normal 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
161
ao-tools/lib/cc-mega.c
Normal 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
57
ao-tools/lib/cc-period.c
Normal 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
167
ao-tools/lib/cc-process.c
Normal 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
213
ao-tools/lib/cc-telem.c
Normal 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", °, &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;
|
||||
}
|
92
ao-tools/lib/cc-telemetry.c
Normal file
92
ao-tools/lib/cc-telemetry.c
Normal 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
338
ao-tools/lib/cc-telemetry.h
Normal 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
502
ao-tools/lib/cc-usb.c
Normal 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
79
ao-tools/lib/cc-usb.h
Normal 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
338
ao-tools/lib/cc-usbdev.c
Normal 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
81
ao-tools/lib/cc-util.c
Normal 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
652
ao-tools/lib/cc.h
Normal 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_ */
|
176
ao-tools/lib/ccdbg-command.c
Normal file
176
ao-tools/lib/ccdbg-command.c
Normal 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;
|
||||
}
|
63
ao-tools/lib/ccdbg-debug.c
Normal file
63
ao-tools/lib/ccdbg-debug.c
Normal 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);
|
||||
}
|
44
ao-tools/lib/ccdbg-debug.h
Normal file
44
ao-tools/lib/ccdbg-debug.h
Normal 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
351
ao-tools/lib/ccdbg-flash.c
Normal 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
144
ao-tools/lib/ccdbg-io.c
Normal 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);
|
||||
}
|
77
ao-tools/lib/ccdbg-manual.c
Normal file
77
ao-tools/lib/ccdbg-manual.c
Normal 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
179
ao-tools/lib/ccdbg-memory.c
Normal 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
63
ao-tools/lib/ccdbg-rom.c
Normal 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
128
ao-tools/lib/ccdbg-state.c
Normal 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
302
ao-tools/lib/ccdbg.h
Normal 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
123
ao-tools/lib/cephes.h
Normal 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
81
ao-tools/lib/chbevl.c
Normal 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
179
ao-tools/lib/cmath.h
Normal 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
189
ao-tools/lib/cp-usb-async.c
Normal 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;
|
||||
}
|
38
ao-tools/lib/cp-usb-async.h
Normal file
38
ao-tools/lib/cp-usb-async.h
Normal 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
415
ao-tools/lib/i0.c
Normal 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
212
ao-tools/lib/mconf.h
Normal 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
|
Reference in New Issue
Block a user