diff options
-rw-r--r-- | include/osm/protocol.h | 84 | ||||
-rw-r--r-- | include/osm/types.h | 6 | ||||
-rw-r--r-- | src/types.c | 154 |
3 files changed, 194 insertions, 50 deletions
diff --git a/include/osm/protocol.h b/include/osm/protocol.h index 29eb6cc..5eec65f 100644 --- a/include/osm/protocol.h +++ b/include/osm/protocol.h @@ -19,7 +19,7 @@ extern const char OSM_MAGIC_INIT[4]; extern const char OSM_MAGIC_FRAME[4]; /** - * The init frame from the controller + * The init frame header from the controller * includes the uuid of the sender and the public * key the sender will use to sign messages (up to 4096 bytes) * @@ -28,10 +28,20 @@ extern const char OSM_MAGIC_FRAME[4]; */ typedef struct { uint8_t magic[4]; + uint8_t version; uint8_t uuid[8]; uint8_t keytype; uint16_t keylen; - uint8_t pubkey[4096]; +} OSMInitFrameHeader; + +/** + * The max possible length of an init frame. + * The actual frame length will vary based on the size of the + * pubkey. + */ +typedef struct { + OSMInitFrameHeader header; + uint8_t key[4096]; } OSMInitFrame; /** @@ -41,22 +51,27 @@ typedef struct { typedef struct { uint8_t magic[4]; uint8_t uuid[8]; +} OSMPairHeader; -} OSMInitPairfmt; +/** + * Represents a frame which describes + */ +typedef struct { + OSMPairHeader header; + uint8_t data[1024]; // message data +} OSMPairFrame; /** - * All OSM messages are at most 2048 bytes long and include a gpg signature at - * the start of the data to validate the sender. The signature length is determined based on - * the signing key of the sender. + * Main OSM Frame header: All frames contain this plus a secondary header + * with more information based on the frame's type */ typedef struct { uint8_t magic[4]; // magic number uint8_t uuid[8]; // device that this message is from uint8_t sub_uuid[8]; // sub device that this message is from uint8_t frame_type; // type of frame - uint8_t data[2048]; // message data -} OSMFrame; +} OSMFrameHeader; /* * Once the data has been validated, it is one of the following frame types @@ -81,20 +96,59 @@ typedef struct { * Result of a sent frame */ typedef struct { - uint8_t res_type; // the type of frame sent - uint8_t a; -} OSMResFrame; + uint8_t res_type; // the type of frame we are replying to +} OSMResHeader; +/** + * Header for frames where we are attempting to set + * data on the other device + */ typedef struct { uint8_t num_set; - uint8_t pairs[2047]; -} OSMSetFrame; +} OSMSetHeader; + +/** + * Header for frames where we are attempting to get + * data from the other device + */ +typedef struct { + uint8_t num_get; +} OSMGetHeader; + +/** + * Header for frames where we are sending + * an arbitrary data payload to the other device + */ +typedef struct { + uint8_t number; // Which "set" this data frame belongs to (if multiple data streams are being sent at once) + uint16_t len; // How many significant bytes are in this frame +} OSMDataHeader; + +/** + * Header for streams where we are going to send a + * continuous stream of data to the other device + */ +typedef struct { +} OSMStreamOutHeader; + +/** + * Header for streams where we are asking for + * a continuous data stream from the other device + */ +typedef struct { +} OSMStreamInHeader; + +/** + * Header for a control frame where we are closing + * a previously opened stream. + */ +typedef struct { +} OSMStreamCloseHeader; typedef struct { uint8_t control_id[8]; // The ID of the control we are setting the value on - uint8_t val_type; // The data type of the value (or 0 for future data frames) uint8_t value[8]; // The new value for the control, or the data frame number we will next use -} OSMSetControl; +} OSMControl; diff --git a/include/osm/types.h b/include/osm/types.h index 08a0d03..81a072e 100644 --- a/include/osm/types.h +++ b/include/osm/types.h @@ -33,6 +33,12 @@ typedef int64_t OSMInteger; /// Represents a floating point (IEEE 754 64 bit) typedef uint64_t OSMFloat; +#define OSM_FLOAT_EXPO_LEN 11 +#define OSM_FLOAT_EXPO_MASK 0x7ff +#define OSM_FLOAT_EXPO_BIAS 0x3ff +#define OSM_FLOAT_FRAC_LEN 52 +#define OSM_FLOAT_FRAC_MASK 0xffffffffffffff + /// Represents the broken down floating point number typedef struct { uint8_t sign; diff --git a/src/types.c b/src/types.c index ff0459e..8fda424 100644 --- a/src/types.c +++ b/src/types.c @@ -16,9 +16,9 @@ OSMFloatBreakdown osm_float_to_break(OSMFloat f) { OSMFloatBreakdown out; - out.sign = f >> 63; - out.mantissa = (f >> 52) & 0x7ff; - out.fraction = f & 0xfffffffffffff; + out.sign = f >> (OSM_FLOAT_EXPO_LEN + OSM_FLOAT_FRAC_LEN); + out.mantissa = (f >> OSM_FLOAT_FRAC_LEN) & OSM_FLOAT_EXPO_MASK; + out.fraction = f & OSM_FLOAT_FRAC_MASK; return out; } @@ -39,32 +39,37 @@ OSMFloatBreakdown _osm_ieee754_enlarge(uint64_t d, uint16_t m_len, uint16_t f_le mask = (1 << f_len) - 1; out.fraction = d & mask; + // Create corrected mantissa and fraction (if not denormal) if (out.mantissa >= bias) { // non-negative exponent out.mantissa -= bias; - out.mantissa += 0x3ff; + out.mantissa += OSM_FLOAT_EXPO_BIAS; } else if (out.mantissa < bias && out.mantissa > 0) { - out.mantissa = bias - out.mantissa; // true exponent (abs value) - out.mantissa = 0x3ff - out.mantissa; // corrected for double precision numbers (won't overflow since we use this function with smaller mantissa) - out.fraction = out.fraction << (52 - f_len); // corrected fraction based on difference in bit lengths + // true exponent (abs value) + out.mantissa = bias - out.mantissa; + // corrected for double precision numbers (won't overflow since we use this function with smaller mantissa) + out.mantissa = OSM_FLOAT_EXPO_BIAS - out.mantissa; + // corrected fraction based on difference in bit lengths + out.fraction = out.fraction << (OSM_FLOAT_FRAC_LEN - f_len); } - + + // Handle zero and denormal if (out.mantissa == 0) { if (out.fraction == 0) return out; // Denormal numbers (TODO) - out.mantissa = 0x3ff - bias; // corrected mantissa - out.fraction = out.fraction << (52 - f_len); // corrected fraction based on difference in bit lengths + out.mantissa = OSM_FLOAT_EXPO_BIAS - bias; + if (OSM_FLOAT_FRAC_LEN) + out.fraction = out.fraction << (OSM_FLOAT_FRAC_LEN - f_len); // corrected fraction based on difference in bit lengths bias = (uint16_t) ceil(log2(out.fraction)); } - return out; } @@ -112,20 +117,110 @@ OSMFloat osm_break_to_float(OSMFloatBreakdown b) if (b.sign) out = 1; - out = out << 63; + out = out << (OSM_FLOAT_FRAC_LEN + OSM_FLOAT_EXPO_LEN); - out |= (OSMFloat)(b.mantissa & 0x7ff) << 52; + out |= (OSMFloat)(b.mantissa & OSM_FLOAT_EXPO_MASK) << OSM_FLOAT_FRAC_LEN; - out |= b.fraction & 0xfffffffffffff; + out |= b.fraction & OSM_FLOAT_FRAC_MASK; return out; } +bool _osm_is_nan(const OSMFloatBreakdown b) +{ + return b.mantissa == OSM_FLOAT_EXPO_MASK && b.fraction != 0; +} + +int8_t _osm_is_infinity(const OSMFloatBreakdown b) +{ + if (b.mantissa == OSM_FLOAT_EXPO_MASK && b.fraction == 0) + { + if (b.sign) + return -1; + return 1; + } + return 0; +} + +/// Handle NaN +double _osm_ieee754_nan(OSMFloatBreakdown b, uint16_t m_len, uint16_t f_len) +{ +} + +/// Handle subnormal numbers +double _osm_ieee754_subnormal(OSMFloatBreakdown b, uint16_t m_len, uint16_t f_len) +{ + // TODO + return 0; +} + +/** + * Converts a breakdown to a floating point number with given mantissa and + * fraction length (so long as the format is less than or equal to 64 bits) + */ double _osm_ieee754_assemble(OSMFloatBreakdown b, uint16_t m_len, uint16_t f_len) { - double out = 0; - // Check - return out; + uint64_t out = 0; + + // Sign (assumed to be at end) + out |= b.sign << (m_len + f_len); + + if (b.mantissa == 0 || ) + { + // denormal numbers (TODO) + return *(double *)&out; + } + + // Mantissa mask + uint64_t mask = (1 << m_len) - 1; + + if (_osm_is_nan(b)) + { + // Handle NaN + out |= mask << f_len; + if (f_len >= OSM_FLOAT_FRAC_LEN) + out |= b.fraction << (f_len - OSM_FLOAT_FRAC_LEN); + else + out |= b.fraction >> (OSM_FLOAT_FRAC_LEN - f_len); + + // Make sure it's still nan just in case all the + // fraction bits got cleared + mask = (1 << f_len) - 1; + if ((out & mask) == 0) + out |= 1; + + return *(double *)&out; + } + + // Handle mantissa + uint64_t bias = mask >> 1; + if (b.mantissa > OSM_FLOAT_EXPO_BIAS) + { + b.mantissa -= OSM_FLOAT_EXPO_BIAS; + b.mantissa += bias; + } + else + { + b.mantissa = OSM_FLOAT_EXPO_BIAS - b.mantissa; + b.mantissa = bias - b.mantissa; + } + + // Fraction (assumed to be low bits) + mask = (1 << f_len) - 1; + + if (f_len >= OSM_FLOAT_FRAC_LEN) + out |= b.fraction << (f_len - OSM_FLOAT_FRAC_LEN); + else + out |= b.fraction >> (OSM_FLOAT_FRAC_LEN - f_len); + + if ( && (out & mask) != 0) + out &= ~mask; + +#ifdef _OSM_FLOAT_USE_HIGH_BITS + out = out << (64 - (m_len + f_len + 1)); +#endif + + return *(double *)&out; } /* @@ -136,26 +231,26 @@ double _osm_ieee754_assemble(OSMFloatBreakdown b, uint16_t m_len, uint16_t f_len * * WARNING: This code flushes out of bounds values to infinity * - * INFO: This code keeps NaN values + * INFO: The fraction part of NaN values are set to 1 * * Should probably be updated with more formats if I was * feeling frisky. */ double osm_break_to_native_float(OSMFloatBreakdown b) { - double out = 0; - switch(sizeof(double)) { case 2: { + return _osm_ieee754_assemble(b, 5, 10); } break; case 4: { + return _osm_ieee754_assemble(b, 8, 23); } break; case 8: { OSMFloat f = osm_break_to_float(b); - out = * (double *) &f; + return * (double *) &f; } break; default: @@ -163,10 +258,7 @@ double osm_break_to_native_float(OSMFloatBreakdown b) break; } - if (b.sign) - out = -out; - - return out; + return 0; } double osm_float_to_native(OSMFloat f) @@ -187,20 +279,12 @@ OSMFloat osm_native_to_float(double d) bool osm_is_nan(OSMFloat f) { - OSMFloatBreakdown b = osm_float_to_break(f); - return b.mantissa == 0x3ff && b.fraction != 0; + return _osm_is_nan(osm_float_to_break(f)); } int8_t osm_is_infinity(OSMFloat f) { - OSMFloatBreakdown b = osm_float_to_break(f); - if (b.mantissa == 0x3ff && b.fraction == 0) - { - if (b.sign) - return -1; - return 1; - } - return 0; + return _osm_is_infinity(osm_float_to_break(f)); } OSMColor osm_rgb_to_color(uint8_t r, uint8_t g, uint8_t b) |