Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Convert over to using doubles

  • Loading branch information...
commit 4e675bcd651bee87cbeba345d353d8268efd63c9 1 parent 4be40f6
@scheibo authored
Showing with 140 additions and 218 deletions.
  1. +34 −30 activity.c
  2. +44 −78 activity.h
  3. +32 −50 csv.c
  4. +29 −57 gpx.c
  5. +1 −3 util.c
View
64 activity.c
@@ -3,6 +3,26 @@
#include "activity.h"
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/*
+ * Realloc the buffer pointed at by variable 'x' so that it can hold
+ * at least 'nr' entries; the number of entries currently allocated
+ * is 'alloc', using the standard growing factor alloc_nr() macro.
+ *
+ * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+ do { \
+ if ((nr) > alloc) { \
+ if (alloc_nr(alloc) < (nr)) \
+ alloc = (nr); \
+ else \
+ alloc = alloc_nr(alloc); \
+ x = realloc((x), alloc * sizeof(*(x))); \
+ } \
+ } while (0)
+
Activity *activity_new(void) {
Activity *a;
if (!(a = malloc(sizeof(*a)))) {
@@ -10,7 +30,8 @@ Activity *activity_new(void) {
}
a->sport = UnknownSport;
a->laps = NULL; /* TODO */
- a->data_points = a->last_point = NULL;
+ a->data_points = NULL;
+ a->num_points = 0;
memset(a->has_data, false, sizeof(a->has_data));
memset(a->errors, 0, sizeof(a->errors));
@@ -18,14 +39,12 @@ Activity *activity_new(void) {
}
void activity_destroy(Activity *a) {
- DataPoint *d, *next;
-
/* delete all data points */
- for (d = a->data_points; d; d = next) {
- next = d->next;
- free(d);
+ if (a->data_points) {
+ free(a->data_points);
+ a->data_points = NULL;
+ a->num_points = 0;
}
- a->data_points = NULL;
/* delete all laps */
if (a->laps) {
@@ -38,34 +57,19 @@ void activity_destroy(Activity *a) {
}
/* TODO make sure we infer missing values and do corrections */
-int activity_add_point(Activity *a, DataPoint *point) {
+int activity_add_point(Activity *a, DataPoint *dp) {
+ unsigned i;
- /* TODO (don't malloc one point at a time...), also check return */
- DataPoint *d;
- if (!(d = malloc(sizeof(*d)))) {
+ ALLOC_GROW(a->data_points, a->num_points + 1, a->points_alloc);
+ if (!(a->data_points)) {
return 1;
}
- /* TODO fill in inferred missing values a la gpx/tcx */
- d->timestamp = point->timestamp;
- d->latitude = point->latitude;
- d->longitude = point->longitude;
- d->altitude = point->altitude;
- d->distance = point->distance;
- d->speed = point->speed;
- d->power = point->power;
- d->grade = point->grade;
- d->heart_rate = point->heart_rate;
- d->cadence = point->cadence;
- d->lr_balance = point->lr_balance;
- d->temperature = point->temperature;
- d->next = NULL;
- if (!a->data_points) {
- a->last_point = a->data_points = d;
- } else {
- a->last_point->next = d;
- a->last_point = d;
+ /* TODO fill in inferred missing values a la gpx/tcx */
+ for (i = 0; i < DataFieldCount; i++) {
+ a->data_points[a->num_points].data[i] = dp->data[i];;
}
+ a->num_points++;
return 0;
}
View
122 activity.h
@@ -28,87 +28,52 @@ typedef enum {
DataFieldCount
} DataField;
-typedef struct DataPoint {
- uint32_t timestamp; /* s since Unix Epoch UTC */
- double latitude; /* degrees */
- double longitude; /* degrees */
- int32_t altitude; /* 1000 * m */
- uint32_t distance; /* 100 * m */
- uint32_t speed; /* 1000 * m/s */
- uint16_t power; /* watts */
- int16_t grade; /* 100 * % */
- uint8_t heart_rate; /* bpm */
- uint8_t cadence; /* rpm */
- uint8_t lr_balance; /* ? */
- int8_t temperature; /* C */
- struct DataPoint *next;
-} DataPoint;
-
+typedef struct { double data[DataFieldCount]; } DataPoint;
static const char *DATA_FIELDS[DataFieldCount] = { "timestamp", "latitude", "longitude", "altitude", "distance", "speed", "power", "grade", "heart_rate", "cadence", "lr_balance", "temperature" };
-typedef struct Summary {
- unsigned lap; /* lap number 0 vs 1? */
-
- uint8_t cadence_avg;
- uint8_t heart_rate_avg;
- int8_t temperature_avg;
- uint8_t lr_balance_avg;
-
- uint16_t calories;
- uint32_t distance; /* 100 * m */
- uint32_t elevation; /* 100 * m */
- uint32_t time; /* s */
- uint32_t time_elapsed; /* s */
- uint32_t ascent; /* 100 * m */
- uint32_t descent; /* 100 * m */
- /* function to calc pace from speed */
- uint32_t speed_avg; /* 1000 * m/s */
- uint32_t speed_max; /* 1000 * m/s */
-
- uint16_t power_avg; /* TODO 3s, 10s, 30s - for speed as well? */
- uint16_t power_max;
- uint16_t power_kj; /* TODO correct? */
-
- /* TODO coggans powers - IF, NP, TSS, W/kg */
-} Summary;
-
-#define UNSET_TIMESTAMP UINT32_MAX
-#define UNSET_LATITUDE DBL_MAX
-#define UNSET_LONGITUDE DBL_MAX
-#define UNSET_ALTITUDE INT32_MAX
-#define UNSET_DISTANCE UINT32_MAX
-#define UNSET_SPEED UINT32_MAX
-#define UNSET_POWER UINT16_MAX
-#define UNSET_GRADE INT16_MAX
-#define UNSET_HEART_RATE UINT8_MAX
-#define UNSET_CADENCE UINT8_MAX
-#define UNSET_LR_BALANCE UINT8_MAX
-#define UNSET_TEMPERATURE INT8_MAX
-
-#define UNSET_DATA_POINT(d) \
- do { \
- (d).timestamp = UNSET_TIMESTAMP; \
- (d).latitude = UNSET_LATITUDE; \
- (d).longitude = UNSET_LONGITUDE; \
- (d).altitude = UNSET_ALTITUDE; \
- (d).distance = UNSET_DISTANCE; \
- (d).speed = UNSET_SPEED; \
- (d).power = UNSET_POWER; \
- (d).grade = UNSET_GRADE; \
- (d).heart_rate = UNSET_HEART_RATE; \
- (d).lr_balance = UNSET_LR_BALANCE; \
- (d).temperature = UNSET_TEMPERATURE; \
- (d).next = NULL; \
- } while (0)
+/* TODO convert to array...
+//typedef struct Summary {
+ //unsigned lap; [> lap number 0 vs 1? <]
+
+ //uint8_t cadence_avg;
+ //uint8_t heart_rate_avg;
+ //int8_t temperature_avg;
+ //uint8_t lr_balance_avg;
+
+ //uint16_t calories;
+ //uint32_t distance; [> 100 * m <]
+ //uint32_t elevation; [> 100 * m <]
+ //uint32_t time; [> s <]
+ //uint32_t time_elapsed; [> s <]
+ //uint32_t ascent; [> 100 * m <]
+ //uint32_t descent; [> 100 * m <]
+ //[> function to calc pace from speed <]
+ //uint32_t speed_avg; [> 1000 * m/s <]
+ //uint32_t speed_max; [> 1000 * m/s <]
+
+ //uint16_t power_avg; [> TODO 3s, 10s, 30s - for speed as well? <]
+ //uint16_t power_max;
+ //uint16_t power_kj; [> TODO correct? <]
+
+ //[> TODO coggans powers - IF, NP, TSS, W/kg <]
+//} Summary;
+*/
+
+#define UNSET_FIELD DBL_MAX
+
+static inline void unset_data_point(DataPoint *dp) {
+ unsigned char i;
+ for (i = 0; i < DataFieldCount; i++) dp->data[i] = UNSET_FIELD;
+}
/* TODO debug */
-static inline void print_data_point(DataPoint *d) {
+static inline void print_data_point(DataPoint *dp) {
+ double *d = dp->data;
fprintf(stderr,
- "time: %u, lat: %f, lon: %f, alt: %d, dist: %u, speed: %u, pow: %u, "
- "grd: %d, hr: %u, cad: %u, bal: %u, temp: %d, next: %p\n",
- d->timestamp, d->latitude, d->longitude, d->altitude, d->distance,
- d->speed, d->power, d->grade, d->heart_rate, d->cadence,
- d->lr_balance, d->temperature, (void *)d->next);
+ "time: %.0f, lat: %.15f, lon: %.15f, alt: %.2f, dist: %.2f, speed: %.2f, pow: %.0f, "
+ "grd: %.2f, hr: %.0f, cad: %.0f, bal: %.0f, temp: %.0f\n",
+ d[Timestamp], d[Latitude], d[Longitude], d[Altitude], d[Distance], d[Speed], d[Power],
+ d[Grade], d[HeartRate], d[Cadence], d[LRBalance], d[Temperature]);
}
typedef enum {
@@ -136,7 +101,8 @@ typedef struct {
Sport sport;
uint32_t *laps; /* TODO array of timestamps, always at least one */
DataPoint *data_points;
- DataPoint *last_point;
+ size_t num_points;
+ size_t points_alloc;
bool has_data[DataFieldCount];
unsigned errors[DataErrorCount];
/*
@@ -146,7 +112,7 @@ typedef struct {
Activity *activity_new(void);
void activity_destroy(Activity *a);
-int activity_add_point(Activity *a, DataPoint *point);
+int activity_add_point(Activity *a, DataPoint *dp);
int activity_add_lap(Activity *a, uint32_t lap);
#endif /* _ACTIVITY_H_ */
View
82 csv.c
@@ -1,35 +1,5 @@
#include "csv.h"
-#define CSV(f, s, d, u, p, t, v, o) \
- do { \
- if (!(o).remove_unset || ((t)[(p)])) { \
- if ((d) == (u)) { \
- fprintf((f), "%s", (o).unset_value); \
- } else { \
- fprintf((f), (s), (d)); \
- } \
- if (!(v)) { \
- fprintf((f), ","); \
- } \
- (v) = false; \
- } \
- } while (0)
-
-#define DATA_ARRAY_TO_POINT(a,p) \
- do { \
- (d).timestamp = (a)[Timestamp]; \
- (d).latitude = (a)[Latitude]; \
- (d).longitude = (a)[Longitude]; \
- (d).altitude = (a)[Altitude]; \
- (d).distance = (a)[Distance]; \
- (d).speed = (a)[Speed]; \
- (d).power = (a)[Power]; \
- (d).grade = (a)[Grade]; \
- (d).heart_rate = (a)[HeartRate]; \
- (d).lr_balance = (a)[LRBalance]; \
- (d).temperature = (a)[Temperature]; \
- } while(0)
-
static DataField name_to_field(char *name) {
// TODO convert name to lower case....
if (!strcmp(name, "timestamp") || !strcmp(name, "time")) {
@@ -59,7 +29,6 @@ static DataField name_to_field(char *name) {
} else if (!strcmp(name, "balance") || !strcmp(name, "bal") ||
!strcmp(name, "lr_balance")) {
return LRBalance;
-
} else if (!strcmp(name, "temperature") || !strcmp(name, "atemp") ||
!strcmp(name, "temp")) {
return Cadence;
@@ -73,11 +42,10 @@ static DataField name_to_field(char *name) {
int csv_read(char *filename, Activity *a) {
FILE *f = NULL;
DataField data_fields[DataFieldCount]; // TODO worry all set to zero which is Timestamp
- double data[DataFieldCount];
DataPoint point;
char buf[CSV_BUFSIZ];
- UNSET_DATA_POINT(point);
+ unset_data_point(&point);
if (!(f = fopen(filename, "r"))) {
return 1;
@@ -94,21 +62,35 @@ int csv_read(char *filename, Activity *a) {
// read in array of doubles - IN ORDER
- DATA_ARRAY_TO_POINT(point);
activity_add_point(a, &point);
- UNSET_DATA_POINT(point);
+ unset_data_point(&point);
}
fclose(f);
return 0;
}
+static int write_csv(FILE *f, const char *format, size_t i, DataField f, Activity *a, CSVOptions o, bool *first) {
+ double d = a->data_points[i].data[field];
+ if (!o.remove_unset || a->has_data[field]) {
+ if (d == UNSET_FIELD) {
+ fprintf(f, "%s", o.unset_value);
+ } else {
+ fprintf(f, format, d);
+ }
+ if (!*first) {
+ fprintf(f, ",");
+ }
+ *first = false;
+ }
+}
+
+
int csv_write(char *filename, Activity *a, CSVOptions o) {
FILE *f = NULL;
unsigned i;
bool first = true;
DataPoint *d;
- bool *t = a->has_data;
if (!(f = fopen(filename, "w"))) {
return 1;
@@ -116,7 +98,7 @@ int csv_write(char *filename, Activity *a, CSVOptions o) {
/* print header */
for (i = 0; i < DataFieldCount; i++) {
- if (!o.remove_unset || t[i]) {
+ if (!o.remove_unset || a->has_data[i]) {
if (first) {
fprintf(f, "%s" DATA_FIELDS[i]);
first = false;
@@ -127,19 +109,19 @@ int csv_write(char *filename, Activity *a, CSVOptions o) {
}
fprintf(f, "\n");
- for (d = a->data_points; d; d = d->next, first = true) {
- CSV(f, "%d", d->timestamp, UNSET_TIMESTAMP, Timestamp, t, first, o);
- CSV(f, "%15.f", d->latitude, UNSET_LATITUDE, Latitude, t, first, o);
- CSV(f, "%15.f", d->longitude, UNSET_LONGITUDE, Longitude, t, first, o);
- CSV(f, "%3.f", d->altitude / 1000.0, UNSET_ALTITUDE, Altitude, t, first, o);
- CSV(f, "%2.f", d->distance / 100.0, UNSET_DISTANCE, Distance, t, first, o);
- CSV(f, "%2.f", d->speed / 1000.0, UNSET_SPEED, Speed, t, first, o);
- CSV(f, "%d", d->power, UNSET_POWER, Power, t, first, o);
- CSV(f, "%2.f", d->grade / 100.0, UNSET_GRADE, Grade, t, first, o);
- CSV(f, "%d", d->heart_rate, UNSET_HEART_RATE, HeartRate, t, first, o);
- CSV(f, "%d", d->cadence, UNSET_CADENCE, Cadence, t, first, o);
- CSV(f, "%d", d->lr_balance, UNSET_LR_BALANCE, LRBalance, t, first, o);
- CSV(f, "%d", d->temperature, UNSET_TEMPERATURE, Temperature, t, first, o);
+ for (i = 0; i < a->num_points; i++, first = true) {
+ CSV(f, "%.0f", i, Timestamp, a, &o, &first);
+ CSV(f, "%.15f", i, Latitude, a, &o, &first);
+ CSV(f, "%.15f", i, Longitude, a, &o, &first);
+ CSV(f, "%.3f", i, Altitude, a, &o, &first);
+ CSV(f, "%.2f", i, Distance, a, &o, &first);
+ CSV(f, "%.2f", i, Speed, a, &o, &first);
+ CSV(f, "%.0f", i, Power, a, &o, &first);
+ CSV(f, "%.2f", i, Grade, a, &o, &first);
+ CSV(f, "%.0f", i, HeartRate, a, &o, &first);
+ CSV(f, "%.0f", i, Cadence, a, &o, &first);
+ CSV(f, "%.0f", i, LRBalance, a, &o, &first);
+ CSV(f, "%.0f", i, Temperature, a, &o, &first);
fprintf(f, "\n");
}
View
86 gpx.c
@@ -10,7 +10,7 @@ typedef struct {
bool metadata;
bool first_element;
bool first_time;
- DataPoint *data;
+ DataPoint dp;
} State;
int allspace(const char *str) {
@@ -20,9 +20,14 @@ int allspace(const char *str) {
return !*str;
}
+static inline void parse_field(DataField field, State* state, const char *str) {
+ char *end;
+ state->dp.data[field] = strtod(str, &end);
+ if (*end) state->dp.data[field] = UNSET_FIELD;
+}
+
static int sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *sax_data) {
const char *name, *attr, *data;
- char *end;
State *state = (State *)sax_data;
if (event == MXML_SAX_ELEMENT_OPEN) {
@@ -41,13 +46,11 @@ static int sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *sax_data) {
} else if (!strcmp(name, "trkpt")) {
attr = mxmlElementGetAttr(node, "lat");
if (attr) {
- state->data->latitude = strtod(attr, &end);
- if (*end) state->data->latitude = UNSET_LATITUDE;
+ parse_field(Latitude, state, attr);
}
attr = mxmlElementGetAttr(node, "lon");
if (attr) {
- state->data->longitude = strtod(attr, &end);
- if (*end) state->data->longitude = UNSET_LONGITUDE;
+ parse_field(Longitude, state, attr);
}
}
state->first_element = false;
@@ -60,26 +63,21 @@ static int sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *sax_data) {
} else if (state->metadata) {
return 0;
} else if (!strcmp(name, "time")) {
- state->data->timestamp = parse_timestamp(data);
+ state->dp.data[Timestamp] = parse_timestamp(data);
} else if (!strcmp(name, "ele")) {
- state->data->altitude = (int32_t)(strtod(data, &end) * 1000);
- if (*end) state->data->altitude = UNSET_ALTITUDE;
+ parse_field(Altitude, state, data);
} else if (!strcmp(name, "gpxdata:hr") || !strcmp(name, "gpxtpx:hr")) {
- state->data->heart_rate = (uint8_t) strtod(data, &end);
- if (*end) state->data->heart_rate = UNSET_HEART_RATE;
+ parse_field(HeartRate, state, data);
} else if (!strcmp(name, "gpxdata:temp") || !strcmp(name, "gpxtpx:atemp")) {
- state->data->temperature = (int8_t) strtod(data, &end);
- if (*end) state->data->temperature = UNSET_TEMPERATURE;
+ parse_field(Temperature, state, data);
} else if (!strcmp(name, "gpxdata:cadence") || !strcmp(name, "gpxtpx:cad")) {
- state->data->cadence = (uint8_t) strtod(data, &end);
- if (*end) state->data->cadence = UNSET_CADENCE;
+ parse_field(Cadence, state, data);
} else if (!strcmp(name, "gpxdata:bikepower")) {
- state->data->power = (uint16_t) strtod(data, &end);
- if (*end) state->data->power = UNSET_POWER;
+ parse_field(Power, state, data);
} else if (!strcmp(name, "trkpt")) {
/* TODO */
- print_data_point(state->data);
- UNSET_DATA_POINT(*(state->data));
+ print_data_point(&(state->dp));
+ unset_data_point(&(state->dp));
}
} else if (event == MXML_SAX_DATA) {
mxmlRetain(node);
@@ -88,71 +86,45 @@ static int sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *sax_data) {
return 0;
}
-static State *create_state(void) {
- State *state;
- if (!(state = malloc(sizeof(*state)))) {
- return NULL;
- }
- state->metadata = false;
- state->first_element = true;
- state->first_time = true;
- if (!(state->data = malloc(sizeof(*(state->data))))) {
- return NULL;
- }
- UNSET_DATA_POINT(*(state->data));
-
- return state;
-}
-
-static void destroy_state(State *state) {
- free(state->data);
- free(state);
-}
-
int gpx_read(char *filename, Activity *activity) {
FILE *f = NULL;
- State *state;
- if (!(state = create_state())) {
- return 1;
- }
+ State state = { false, true, true, {{0}} };
+ unset_data_point(&(state.dp));
if (!(f = fopen(filename, "r"))) {
- destroy_state(state);
return 1;
}
- if (!mxmlSAXLoadFile(NULL, f, MXML_OPAQUE_CALLBACK, sax_cb, (void *)state)) {
+ if (!mxmlSAXLoadFile(NULL, f, MXML_OPAQUE_CALLBACK, sax_cb, (void *)&state)) {
fprintf(stderr, "failed\n"); /* TODO */
- destroy_state(state);
fclose(f);
return 1;
}
fprintf(stderr, "Made it\n"); /* TODO */
- destroy_state(state);
fclose(f);
return 0;
}
-static mxml_node_t *to_gpx_xml(Activity *activity) {
+static mxml_node_t *to_gpx_xml(Activity *a) {
+ unsigned i;
mxml_node_t *xml; /*, *gpx, *trk, *trkseg, *trkpt, *ele, *time, *hr, *temp,
*cadence, *bikepower; */
- DataPoint *data;
xml = mxmlNewXML("1.0");
- for (data = activity->data_points; data; data = data->next) {
+ for (i = 0; i < a->num_points; i++) {
/* TODO */
}
return xml;
}
-int gpx_write(char *filename, Activity *activity) {
+int gpx_write(char *filename, Activity *a) {
FILE *f;
mxml_node_t *tree;
f = fopen(filename, "w");
- if (!(f = fopen(filename, "w")) || !(tree = to_gpx_xml(activity))) {
+ if (!(f = fopen(filename, "w")) || !(tree = to_gpx_xml(a))) {
return 1;
}
@@ -169,11 +141,11 @@ int gpx_write(char *filename, Activity *activity) {
/* TODO */
int main(int argc, char *argv[]) {
- Activity *activity = activity_new();
- int err = gpx_read(argv[1], activity);
+ Activity *a = activity_new();
+ int err = gpx_read(argv[1], a);
if (!err && argc > 2) {
- err = gpx_write(argv[2], activity);
+ err = gpx_write(argv[2], a);
}
- activity_destroy(activity);
+ activity_destroy(a);
return err;
}
View
4 util.c
@@ -9,9 +9,7 @@
uint32_t parse_timestamp(const char *date) {
unsigned long timestamp;
int offset;
- return (parse_date_basic(date, &timestamp, &offset) < 0)
- ? UNSET_TIMESTAMP
- : (uint32_t) timestamp;
+ return (parse_date_basic(date, &timestamp, &offset) < 0) ? UNSET_FIELD : (uint32_t) timestamp;
}
int format_timestamp(char *buf, uint32_t timestamp) {
Please sign in to comment.
Something went wrong with that request. Please try again.