MBED port of https://github.com/ys1382/filagree . The only change is adding #define MBED
serial.c@0:1a89e28dea91, 2012-05-30 (annotated)
- Committer:
- yusufx
- Date:
- Wed May 30 21:13:01 2012 +0000
- Revision:
- 0:1a89e28dea91
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
yusufx | 0:1a89e28dea91 | 1 | /* |
yusufx | 0:1a89e28dea91 | 2 | * serial.c |
yusufx | 0:1a89e28dea91 | 3 | * |
yusufx | 0:1a89e28dea91 | 4 | * stream serialization - serialies and deserializes byte_array and calls-back on each element |
yusufx | 0:1a89e28dea91 | 5 | */ |
yusufx | 0:1a89e28dea91 | 6 | |
yusufx | 0:1a89e28dea91 | 7 | #include <stdint.h> |
yusufx | 0:1a89e28dea91 | 8 | #include <stdio.h> |
yusufx | 0:1a89e28dea91 | 9 | #include <stdlib.h> |
yusufx | 0:1a89e28dea91 | 10 | #include <string.h> |
yusufx | 0:1a89e28dea91 | 11 | #include <math.h> |
yusufx | 0:1a89e28dea91 | 12 | |
yusufx | 0:1a89e28dea91 | 13 | #include "serial.h" |
yusufx | 0:1a89e28dea91 | 14 | #include "struct.h" |
yusufx | 0:1a89e28dea91 | 15 | #include "vm.h" |
yusufx | 0:1a89e28dea91 | 16 | #include "util.h" |
yusufx | 0:1a89e28dea91 | 17 | |
yusufx | 0:1a89e28dea91 | 18 | // functions /////////////////////////////////////////////////////////////// |
yusufx | 0:1a89e28dea91 | 19 | |
yusufx | 0:1a89e28dea91 | 20 | // tells how many bytes are needed to encode this value |
yusufx | 0:1a89e28dea91 | 21 | uint8_t encode_int_size(int32_t value) |
yusufx | 0:1a89e28dea91 | 22 | { |
yusufx | 0:1a89e28dea91 | 23 | uint8_t i; |
yusufx | 0:1a89e28dea91 | 24 | value = (value >= 0 ? value : -value) >> 6; |
yusufx | 0:1a89e28dea91 | 25 | for (i=1; value; i++, value >>=7); |
yusufx | 0:1a89e28dea91 | 26 | return i; |
yusufx | 0:1a89e28dea91 | 27 | } |
yusufx | 0:1a89e28dea91 | 28 | |
yusufx | 0:1a89e28dea91 | 29 | struct byte_array *encode_int(struct byte_array *buf, int32_t value) |
yusufx | 0:1a89e28dea91 | 30 | { |
yusufx | 0:1a89e28dea91 | 31 | if (!buf) |
yusufx | 0:1a89e28dea91 | 32 | buf = byte_array_new(); |
yusufx | 0:1a89e28dea91 | 33 | uint8_t growth = encode_int_size(value); |
yusufx | 0:1a89e28dea91 | 34 | byte_array_resize(buf, buf->length + growth); |
yusufx | 0:1a89e28dea91 | 35 | bool neg = value < 0; |
yusufx | 0:1a89e28dea91 | 36 | value = abs(value); |
yusufx | 0:1a89e28dea91 | 37 | uint8_t byte = (value & 0x3F) | ((value >= 0x40) ? 0x80 : 0) | (neg ? 0x40 : 0); |
yusufx | 0:1a89e28dea91 | 38 | *buf->current++ = byte; |
yusufx | 0:1a89e28dea91 | 39 | value >>= 6; |
yusufx | 0:1a89e28dea91 | 40 | while (value) { |
yusufx | 0:1a89e28dea91 | 41 | byte = (value & 0x7F) | ((value >= 0x80) ? 0x80 : 0); |
yusufx | 0:1a89e28dea91 | 42 | *buf->current++ = byte; |
yusufx | 0:1a89e28dea91 | 43 | value >>= 7; |
yusufx | 0:1a89e28dea91 | 44 | } |
yusufx | 0:1a89e28dea91 | 45 | return buf; |
yusufx | 0:1a89e28dea91 | 46 | } |
yusufx | 0:1a89e28dea91 | 47 | |
yusufx | 0:1a89e28dea91 | 48 | struct byte_array* serial_encode_int(struct byte_array* buf, int32_t key, int32_t value) { |
yusufx | 0:1a89e28dea91 | 49 | if (!buf) |
yusufx | 0:1a89e28dea91 | 50 | buf = byte_array_new(); |
yusufx | 0:1a89e28dea91 | 51 | if (key) |
yusufx | 0:1a89e28dea91 | 52 | encode_int(buf, key<<2 | SERIAL_INT); |
yusufx | 0:1a89e28dea91 | 53 | encode_int(buf, value); |
yusufx | 0:1a89e28dea91 | 54 | return buf; |
yusufx | 0:1a89e28dea91 | 55 | } |
yusufx | 0:1a89e28dea91 | 56 | |
yusufx | 0:1a89e28dea91 | 57 | int32_t serial_decode_int(struct byte_array* buf) |
yusufx | 0:1a89e28dea91 | 58 | { |
yusufx | 0:1a89e28dea91 | 59 | bool neg = *buf->current & 0x40; |
yusufx | 0:1a89e28dea91 | 60 | int32_t ret = *buf->current & 0x3F; |
yusufx | 0:1a89e28dea91 | 61 | int bitpos = 6; |
yusufx | 0:1a89e28dea91 | 62 | while ((*buf->current++ & 0x80) && (bitpos < (sizeof(int32_t)*8))) { |
yusufx | 0:1a89e28dea91 | 63 | ret |= (*buf->current & 0x7F) << bitpos; |
yusufx | 0:1a89e28dea91 | 64 | bitpos += 7; |
yusufx | 0:1a89e28dea91 | 65 | } |
yusufx | 0:1a89e28dea91 | 66 | return neg ? -ret : ret; |
yusufx | 0:1a89e28dea91 | 67 | } |
yusufx | 0:1a89e28dea91 | 68 | |
yusufx | 0:1a89e28dea91 | 69 | float serial_decode_float(struct byte_array* buf) |
yusufx | 0:1a89e28dea91 | 70 | { |
yusufx | 0:1a89e28dea91 | 71 | float f; |
yusufx | 0:1a89e28dea91 | 72 | uint8_t *uf = (uint8_t*)&f; |
yusufx | 0:1a89e28dea91 | 73 | for (int i=4; i; i--) { |
yusufx | 0:1a89e28dea91 | 74 | *uf = *buf->current; |
yusufx | 0:1a89e28dea91 | 75 | uf++; |
yusufx | 0:1a89e28dea91 | 76 | buf->current++; |
yusufx | 0:1a89e28dea91 | 77 | } |
yusufx | 0:1a89e28dea91 | 78 | //DEBUGPRINT("serial_decode_float %f\n", f); |
yusufx | 0:1a89e28dea91 | 79 | return f; |
yusufx | 0:1a89e28dea91 | 80 | } |
yusufx | 0:1a89e28dea91 | 81 | |
yusufx | 0:1a89e28dea91 | 82 | struct byte_array* serial_decode_string(struct byte_array* buf) |
yusufx | 0:1a89e28dea91 | 83 | { |
yusufx | 0:1a89e28dea91 | 84 | null_check(buf); |
yusufx | 0:1a89e28dea91 | 85 | int32_t len = serial_decode_int(buf); |
yusufx | 0:1a89e28dea91 | 86 | assert_message(len>=0, "negative malloc"); |
yusufx | 0:1a89e28dea91 | 87 | struct byte_array* ba = byte_array_new_size(len); |
yusufx | 0:1a89e28dea91 | 88 | ba->data = ba->current = (uint8_t*)malloc(len); |
yusufx | 0:1a89e28dea91 | 89 | null_check(ba->data); |
yusufx | 0:1a89e28dea91 | 90 | memcpy(ba->data, buf->current, len); |
yusufx | 0:1a89e28dea91 | 91 | buf->current += len; |
yusufx | 0:1a89e28dea91 | 92 | return ba; |
yusufx | 0:1a89e28dea91 | 93 | } |
yusufx | 0:1a89e28dea91 | 94 | |
yusufx | 0:1a89e28dea91 | 95 | void serial_decode(struct byte_array* buf, serial_element se, const void* extra) |
yusufx | 0:1a89e28dea91 | 96 | { |
yusufx | 0:1a89e28dea91 | 97 | // DEBUGPRINT("serial_decode %d %x<%x?\n", buf->size, buf->current, buf->data + buf->size); |
yusufx | 0:1a89e28dea91 | 98 | while (buf->current < buf->data + buf->length) |
yusufx | 0:1a89e28dea91 | 99 | { |
yusufx | 0:1a89e28dea91 | 100 | // get key and wire type |
yusufx | 0:1a89e28dea91 | 101 | int32_t keyWire = serial_decode_int(buf); |
yusufx | 0:1a89e28dea91 | 102 | struct key_value_pair pair = { |
yusufx | 0:1a89e28dea91 | 103 | .key = keyWire >> 2, |
yusufx | 0:1a89e28dea91 | 104 | .wire_type = (enum serial_type)(keyWire & 0x03) |
yusufx | 0:1a89e28dea91 | 105 | }; |
yusufx | 0:1a89e28dea91 | 106 | // DEBUGPRINT("serial_decode %d:%d\n", pair.key, pair.wire_type); |
yusufx | 0:1a89e28dea91 | 107 | |
yusufx | 0:1a89e28dea91 | 108 | // get data |
yusufx | 0:1a89e28dea91 | 109 | switch(pair.wire_type) { |
yusufx | 0:1a89e28dea91 | 110 | case SERIAL_INT: /* int */ |
yusufx | 0:1a89e28dea91 | 111 | pair.value.integer = serial_decode_int(buf); |
yusufx | 0:1a89e28dea91 | 112 | break; |
yusufx | 0:1a89e28dea91 | 113 | case SERIAL_FLOAT: |
yusufx | 0:1a89e28dea91 | 114 | pair.value.floater = serial_decode_float(buf); |
yusufx | 0:1a89e28dea91 | 115 | case SERIAL_STRING: /* bytes */ |
yusufx | 0:1a89e28dea91 | 116 | pair.value.bytes = serial_decode_string(buf); |
yusufx | 0:1a89e28dea91 | 117 | break; |
yusufx | 0:1a89e28dea91 | 118 | case SERIAL_ARRAY: |
yusufx | 0:1a89e28dea91 | 119 | break; |
yusufx | 0:1a89e28dea91 | 120 | default: |
yusufx | 0:1a89e28dea91 | 121 | DEBUGPRINT("serial_decode ?\n"); |
yusufx | 0:1a89e28dea91 | 122 | break; |
yusufx | 0:1a89e28dea91 | 123 | } |
yusufx | 0:1a89e28dea91 | 124 | if (se(&pair, buf, extra)) { |
yusufx | 0:1a89e28dea91 | 125 | // DEBUGPRINT("serial_decode: break\n"); |
yusufx | 0:1a89e28dea91 | 126 | break; |
yusufx | 0:1a89e28dea91 | 127 | } |
yusufx | 0:1a89e28dea91 | 128 | } |
yusufx | 0:1a89e28dea91 | 129 | // DEBUGPRINT("serial_decode done\n"); |
yusufx | 0:1a89e28dea91 | 130 | } |
yusufx | 0:1a89e28dea91 | 131 | |
yusufx | 0:1a89e28dea91 | 132 | // assume little endian |
yusufx | 0:1a89e28dea91 | 133 | struct byte_array *encode_float(struct byte_array *buf, float f) |
yusufx | 0:1a89e28dea91 | 134 | { |
yusufx | 0:1a89e28dea91 | 135 | assert_message(sizeof(float)==4, "bad float size"); |
yusufx | 0:1a89e28dea91 | 136 | uint8_t *uf = (uint8_t*)&f; |
yusufx | 0:1a89e28dea91 | 137 | for (int i=4; i; i--) { |
yusufx | 0:1a89e28dea91 | 138 | byte_array_add_byte(buf, *uf); |
yusufx | 0:1a89e28dea91 | 139 | uf++; |
yusufx | 0:1a89e28dea91 | 140 | } |
yusufx | 0:1a89e28dea91 | 141 | return buf; |
yusufx | 0:1a89e28dea91 | 142 | } |
yusufx | 0:1a89e28dea91 | 143 | |
yusufx | 0:1a89e28dea91 | 144 | struct byte_array* serial_encode_float(struct byte_array* buf, int32_t key, float value) { |
yusufx | 0:1a89e28dea91 | 145 | if (!buf) |
yusufx | 0:1a89e28dea91 | 146 | buf = byte_array_new(); |
yusufx | 0:1a89e28dea91 | 147 | if (key) |
yusufx | 0:1a89e28dea91 | 148 | encode_int(buf, key<<2 | SERIAL_FLOAT); |
yusufx | 0:1a89e28dea91 | 149 | encode_float(buf, value); |
yusufx | 0:1a89e28dea91 | 150 | return buf; |
yusufx | 0:1a89e28dea91 | 151 | } |
yusufx | 0:1a89e28dea91 | 152 | |
yusufx | 0:1a89e28dea91 | 153 | uint8_t serial_encode_string_size(int32_t key, const struct byte_array* string) { |
yusufx | 0:1a89e28dea91 | 154 | if (!string) |
yusufx | 0:1a89e28dea91 | 155 | return 0; |
yusufx | 0:1a89e28dea91 | 156 | return (key ? encode_int_size(key) : 0) + |
yusufx | 0:1a89e28dea91 | 157 | encode_int_size(string->length) + |
yusufx | 0:1a89e28dea91 | 158 | string->length; |
yusufx | 0:1a89e28dea91 | 159 | } |
yusufx | 0:1a89e28dea91 | 160 | |
yusufx | 0:1a89e28dea91 | 161 | struct byte_array* serial_encode_string(struct byte_array* buf, int32_t key, const struct byte_array* bytes) |
yusufx | 0:1a89e28dea91 | 162 | { |
yusufx | 0:1a89e28dea91 | 163 | if (!bytes) |
yusufx | 0:1a89e28dea91 | 164 | return buf; |
yusufx | 0:1a89e28dea91 | 165 | if (!buf) |
yusufx | 0:1a89e28dea91 | 166 | buf = byte_array_new(); |
yusufx | 0:1a89e28dea91 | 167 | |
yusufx | 0:1a89e28dea91 | 168 | if (key) |
yusufx | 0:1a89e28dea91 | 169 | encode_int(buf, key<<2 | SERIAL_STRING); |
yusufx | 0:1a89e28dea91 | 170 | encode_int(buf, bytes->length); |
yusufx | 0:1a89e28dea91 | 171 | byte_array_resize(buf, buf->length + bytes->length); |
yusufx | 0:1a89e28dea91 | 172 | memcpy(buf->current, bytes->data, bytes->length); |
yusufx | 0:1a89e28dea91 | 173 | |
yusufx | 0:1a89e28dea91 | 174 | buf->current = buf->data + buf->length; |
yusufx | 0:1a89e28dea91 | 175 | return buf; |
yusufx | 0:1a89e28dea91 | 176 | } |
yusufx | 0:1a89e28dea91 | 177 | |
yusufx | 0:1a89e28dea91 | 178 | struct byte_array* serial_encode_array(struct byte_array* buf, int32_t key, int32_t count) { |
yusufx | 0:1a89e28dea91 | 179 | if (!buf) buf = byte_array_new(); |
yusufx | 0:1a89e28dea91 | 180 | encode_int(buf, key<<2 | SERIAL_ARRAY); |
yusufx | 0:1a89e28dea91 | 181 | encode_int(buf, count); |
yusufx | 0:1a89e28dea91 | 182 | return buf; |
yusufx | 0:1a89e28dea91 | 183 | } |
yusufx | 0:1a89e28dea91 | 184 | |
yusufx | 0:1a89e28dea91 | 185 | #ifdef DEBUG |
yusufx | 0:1a89e28dea91 | 186 | |
yusufx | 0:1a89e28dea91 | 187 | bool display_serial(const struct key_value_pair* kvp) { |
yusufx | 0:1a89e28dea91 | 188 | DEBUGPRINT("serialElementDebug %d:\t", kvp->key); |
yusufx | 0:1a89e28dea91 | 189 | char* str; |
yusufx | 0:1a89e28dea91 | 190 | |
yusufx | 0:1a89e28dea91 | 191 | switch (kvp->wire_type) { |
yusufx | 0:1a89e28dea91 | 192 | case SERIAL_ERROR: |
yusufx | 0:1a89e28dea91 | 193 | DEBUGPRINT("error %d\n", kvp->value.serialError); |
yusufx | 0:1a89e28dea91 | 194 | break; |
yusufx | 0:1a89e28dea91 | 195 | case SERIAL_INT: |
yusufx | 0:1a89e28dea91 | 196 | DEBUGPRINT("int %d\n", kvp->value.integer); |
yusufx | 0:1a89e28dea91 | 197 | break; |
yusufx | 0:1a89e28dea91 | 198 | case SERIAL_FLOAT: |
yusufx | 0:1a89e28dea91 | 199 | DEBUGPRINT("float %f\n", kvp->value.floater) |
yusufx | 0:1a89e28dea91 | 200 | case SERIAL_STRING: |
yusufx | 0:1a89e28dea91 | 201 | str = (char*)malloc(kvp->value.bytes->length + 1); |
yusufx | 0:1a89e28dea91 | 202 | memcpy(str, kvp->value.bytes->data, kvp->value.bytes->length); |
yusufx | 0:1a89e28dea91 | 203 | str[kvp->value.bytes->length] = 0; |
yusufx | 0:1a89e28dea91 | 204 | DEBUGPRINT("bytes %s\n", str); |
yusufx | 0:1a89e28dea91 | 205 | break; |
yusufx | 0:1a89e28dea91 | 206 | case SERIAL_ARRAY: |
yusufx | 0:1a89e28dea91 | 207 | DEBUGPRINT("array\n"); |
yusufx | 0:1a89e28dea91 | 208 | break; |
yusufx | 0:1a89e28dea91 | 209 | } |
yusufx | 0:1a89e28dea91 | 210 | return true; |
yusufx | 0:1a89e28dea91 | 211 | } |
yusufx | 0:1a89e28dea91 | 212 | |
yusufx | 0:1a89e28dea91 | 213 | #endif // DEBUG |