153 lines
4.5 KiB
C++

#ifndef AP_MSGHANDLER_H
#define AP_MSGHANDLER_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h> // for abort()
#include <math.h>
#define radians(x) (x / 180 * M_PI)
#include "Vector3f.h"
#include "Location.h"
#include "DataFlash/LogMessage.h"
#define LOGREADER_MAX_FIELDS 30
#ifndef streq
#define streq(x, y) (!strcmp(x, y))
#endif
class MsgHandler
{
public:
// constructor - create a parser for a MavLink message format
MsgHandler(const struct log_Format &f);
// retrieve a comma-separated list of all labels
void string_for_labels(char *buffer, uint bufferlen);
// field_value - retrieve the value of a field from the supplied message
// these return false if the field was not found
template < typename R >
bool field_value(const uint8_t *msg, const char *label, R &ret);
bool field_value(uint8_t *msg, const char *label, Vector3f &ret);
bool field_value(const uint8_t *msg, const char *label, char *buffer, uint8_t bufferlen);
template < typename R >
void require_field(const uint8_t *msg, const char *label, R &ret)
{
if (!field_value(msg, label, ret)) {
field_not_found(msg, label);
}
}
void require_field(const uint8_t *msg, const char *label, char *buffer, uint8_t bufferlen);
float require_field_float(const uint8_t *msg, const char *label);
uint8_t require_field_uint8_t(const uint8_t *msg, const char *label);
int32_t require_field_int32_t(const uint8_t *msg, const char *label);
uint16_t require_field_uint16_t(const uint8_t *msg, const char *label);
int16_t require_field_int16_t(const uint8_t *msg, const char *label);
private:
void add_field(const char *_label, uint8_t _type, uint8_t _offset, uint8_t length);
template < typename R >
void field_value_for_type_at_offset(const uint8_t *msg, uint8_t type, uint8_t offset, R &ret);
struct format_field_info { // parsed field information
char *label;
uint8_t type;
uint8_t offset;
uint8_t length;
};
struct format_field_info field_info[LOGREADER_MAX_FIELDS] = {};
uint8_t next_field;
size_t size_for_type_table[52]; // maps field type (e.g. 'f') to e.g 4 bytes
void parse_format_fields();
void init_field_types();
void add_field_type(char type, size_t size);
uint8_t size_for_type(char type);
protected:
struct format_field_info *find_field_info(const char *label);
struct log_Format f; // the format we are a parser for
~MsgHandler();
void location_from_msg(uint8_t *msg, Location &loc, const char *label_lat,
const char *label_long, const char *label_alt);
void ground_vel_from_msg(uint8_t *msg, Vector3f &vel, const char *label_speed,
const char *label_course, const char *label_vz);
void attitude_from_msg(uint8_t *msg, Vector3f &att, const char *label_roll,
const char *label_pitch, const char *label_yaw);
void field_not_found(const uint8_t *msg, const char *label);
};
template < typename R >
bool MsgHandler::field_value(const uint8_t *msg, const char *label, R &ret)
{
struct format_field_info *info = find_field_info(label);
if (info == NULL) {
return false;
}
uint8_t offset = info->offset;
if (offset == 0) {
return false;
}
field_value_for_type_at_offset(msg, info->type, offset, ret);
return true;
}
template < typename R >
inline void MsgHandler::field_value_for_type_at_offset(const uint8_t *msg, uint8_t type,
uint8_t offset, R &ret)
{
/* we register the types - add_field_type - so can we do without
* this switch statement somehow? */
switch (type) {
case 'B':
ret = (R)(((uint8_t *)&msg[offset])[0]);
break;
case 'c':
case 'h':
ret = (R)(((int16_t *)&msg[offset])[0]);
break;
case 'H':
ret = (R)(((uint16_t *)&msg[offset])[0]);
break;
case 'C':
ret = (R)(((uint16_t *)&msg[offset])[0]);
break;
case 'f':
ret = (R)(((float *)&msg[offset])[0]);
break;
case 'I':
case 'E':
ret = (R)(((uint32_t *)&msg[offset])[0]);
break;
case 'L':
case 'e':
ret = (R)(((int32_t *)&msg[offset])[0]);
break;
case 'q':
ret = (R)(((int64_t *)&msg[offset])[0]);
break;
case 'Q':
ret = (R)(((uint64_t *)&msg[offset])[0]);
break;
default:
::printf("Unhandled format type (%c)\n", type);
::abort();
}
}
#endif