00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "hdhomerun.h"
00034
00035 struct hdhomerun_pkt_t *hdhomerun_pkt_create(void)
00036 {
00037 struct hdhomerun_pkt_t *pkt = (struct hdhomerun_pkt_t *)calloc(1, sizeof(struct hdhomerun_pkt_t));
00038 if (!pkt) {
00039 return NULL;
00040 }
00041
00042 hdhomerun_pkt_reset(pkt);
00043
00044 return pkt;
00045 }
00046
00047 void hdhomerun_pkt_destroy(struct hdhomerun_pkt_t *pkt)
00048 {
00049 free(pkt);
00050 }
00051
00052 void hdhomerun_pkt_reset(struct hdhomerun_pkt_t *pkt)
00053 {
00054 pkt->limit = pkt->buffer + sizeof(pkt->buffer) - 4;
00055 pkt->start = pkt->buffer + 1024;
00056 pkt->end = pkt->start;
00057 pkt->pos = pkt->start;
00058 }
00059
00060 static uint32_t hdhomerun_pkt_calc_crc(uint8_t *start, uint8_t *end)
00061 {
00062 uint8_t *pos = start;
00063 uint32_t crc = 0xFFFFFFFF;
00064 while (pos < end) {
00065 uint8_t x = (uint8_t)(crc) ^ *pos++;
00066 crc >>= 8;
00067 if (x & 0x01) crc ^= 0x77073096;
00068 if (x & 0x02) crc ^= 0xEE0E612C;
00069 if (x & 0x04) crc ^= 0x076DC419;
00070 if (x & 0x08) crc ^= 0x0EDB8832;
00071 if (x & 0x10) crc ^= 0x1DB71064;
00072 if (x & 0x20) crc ^= 0x3B6E20C8;
00073 if (x & 0x40) crc ^= 0x76DC4190;
00074 if (x & 0x80) crc ^= 0xEDB88320;
00075 }
00076 return crc ^ 0xFFFFFFFF;
00077 }
00078
00079 uint8_t hdhomerun_pkt_read_u8(struct hdhomerun_pkt_t *pkt)
00080 {
00081 uint8_t v = *pkt->pos++;
00082 return v;
00083 }
00084
00085 uint16_t hdhomerun_pkt_read_u16(struct hdhomerun_pkt_t *pkt)
00086 {
00087 uint16_t v;
00088 v = (uint16_t)*pkt->pos++ << 8;
00089 v |= (uint16_t)*pkt->pos++ << 0;
00090 return v;
00091 }
00092
00093 uint32_t hdhomerun_pkt_read_u32(struct hdhomerun_pkt_t *pkt)
00094 {
00095 uint32_t v;
00096 v = (uint32_t)*pkt->pos++ << 24;
00097 v |= (uint32_t)*pkt->pos++ << 16;
00098 v |= (uint32_t)*pkt->pos++ << 8;
00099 v |= (uint32_t)*pkt->pos++ << 0;
00100 return v;
00101 }
00102
00103 size_t hdhomerun_pkt_read_var_length(struct hdhomerun_pkt_t *pkt)
00104 {
00105 size_t length;
00106
00107 if (pkt->pos + 1 > pkt->end) {
00108 return (size_t)-1;
00109 }
00110
00111 length = (size_t)*pkt->pos++;
00112 if (length & 0x0080) {
00113 if (pkt->pos + 1 > pkt->end) {
00114 return (size_t)-1;
00115 }
00116
00117 length &= 0x007F;
00118 length |= (size_t)*pkt->pos++ << 7;
00119 }
00120
00121 return length;
00122 }
00123
00124 uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size_t *plength)
00125 {
00126 if (pkt->pos + 2 > pkt->end) {
00127 return NULL;
00128 }
00129
00130 *ptag = hdhomerun_pkt_read_u8(pkt);
00131 *plength = hdhomerun_pkt_read_var_length(pkt);
00132
00133 if (pkt->pos + *plength > pkt->end) {
00134 return NULL;
00135 }
00136
00137 return pkt->pos + *plength;
00138 }
00139
00140 void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v)
00141 {
00142 *pkt->pos++ = v;
00143
00144 if (pkt->pos > pkt->end) {
00145 pkt->end = pkt->pos;
00146 }
00147 }
00148
00149 void hdhomerun_pkt_write_u16(struct hdhomerun_pkt_t *pkt, uint16_t v)
00150 {
00151 *pkt->pos++ = (uint8_t)(v >> 8);
00152 *pkt->pos++ = (uint8_t)(v >> 0);
00153
00154 if (pkt->pos > pkt->end) {
00155 pkt->end = pkt->pos;
00156 }
00157 }
00158
00159 void hdhomerun_pkt_write_u32(struct hdhomerun_pkt_t *pkt, uint32_t v)
00160 {
00161 *pkt->pos++ = (uint8_t)(v >> 24);
00162 *pkt->pos++ = (uint8_t)(v >> 16);
00163 *pkt->pos++ = (uint8_t)(v >> 8);
00164 *pkt->pos++ = (uint8_t)(v >> 0);
00165
00166 if (pkt->pos > pkt->end) {
00167 pkt->end = pkt->pos;
00168 }
00169 }
00170
00171 void hdhomerun_pkt_write_var_length(struct hdhomerun_pkt_t *pkt, size_t v)
00172 {
00173 if (v <= 127) {
00174 *pkt->pos++ = (uint8_t)v;
00175 } else {
00176 *pkt->pos++ = (uint8_t)(v | 0x80);
00177 *pkt->pos++ = (uint8_t)(v >> 7);
00178 }
00179
00180 if (pkt->pos > pkt->end) {
00181 pkt->end = pkt->pos;
00182 }
00183 }
00184
00185 void hdhomerun_pkt_write_mem(struct hdhomerun_pkt_t *pkt, const void *mem, size_t length)
00186 {
00187 memcpy(pkt->pos, mem, length);
00188 pkt->pos += length;
00189
00190 if (pkt->pos > pkt->end) {
00191 pkt->end = pkt->pos;
00192 }
00193 }
00194
00195 int hdhomerun_pkt_open_frame(struct hdhomerun_pkt_t *pkt, uint16_t *ptype)
00196 {
00197 pkt->pos = pkt->start;
00198
00199 if (pkt->pos + 4 > pkt->end) {
00200 return 0;
00201 }
00202
00203 *ptype = hdhomerun_pkt_read_u16(pkt);
00204 size_t length = hdhomerun_pkt_read_u16(pkt);
00205 pkt->pos += length;
00206
00207 if (pkt->pos + 4 > pkt->end) {
00208 pkt->pos = pkt->start;
00209 return 0;
00210 }
00211
00212 uint32_t calc_crc = hdhomerun_pkt_calc_crc(pkt->start, pkt->pos);
00213
00214 uint32_t packet_crc;
00215 packet_crc = (uint32_t)*pkt->pos++ << 0;
00216 packet_crc |= (uint32_t)*pkt->pos++ << 8;
00217 packet_crc |= (uint32_t)*pkt->pos++ << 16;
00218 packet_crc |= (uint32_t)*pkt->pos++ << 24;
00219 if (calc_crc != packet_crc) {
00220 return -1;
00221 }
00222
00223 pkt->start += 4;
00224 pkt->end = pkt->start + length;
00225 pkt->pos = pkt->start;
00226 return 1;
00227 }
00228
00229 void hdhomerun_pkt_seal_frame(struct hdhomerun_pkt_t *pkt, uint16_t frame_type)
00230 {
00231 size_t length = pkt->end - pkt->start;
00232
00233 pkt->start -= 4;
00234 pkt->pos = pkt->start;
00235 hdhomerun_pkt_write_u16(pkt, frame_type);
00236 hdhomerun_pkt_write_u16(pkt, (uint16_t)length);
00237
00238 uint32_t crc = hdhomerun_pkt_calc_crc(pkt->start, pkt->end);
00239 *pkt->end++ = (uint8_t)(crc >> 0);
00240 *pkt->end++ = (uint8_t)(crc >> 8);
00241 *pkt->end++ = (uint8_t)(crc >> 16);
00242 *pkt->end++ = (uint8_t)(crc >> 24);
00243
00244 pkt->pos = pkt->start;
00245 }