4 * Copyright © 2005-2006 Silicondust Engineering Ltd. <www.silicondust.com>.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 * As a special exception to the GNU Lesser General Public License,
20 * you may link, statically or dynamically, an application with a
21 * publicly distributed version of the Library to produce an
22 * executable file containing portions of the Library, and
23 * distribute that executable file under terms of your choice,
24 * without any of the additional requirements listed in clause 4 of
25 * the GNU Lesser General Public License.
27 * By "a publicly distributed version of the Library", we mean
28 * either the unmodified Library as distributed by Silicondust, or a
29 * modified version of the Library that is distributed under the
30 * conditions defined in the GNU Lesser General Public License.
33 #include "hdhomerun.h"
35 struct hdhomerun_pkt_t *hdhomerun_pkt_create(void)
37 struct hdhomerun_pkt_t *pkt = (struct hdhomerun_pkt_t *)calloc(1, sizeof(struct hdhomerun_pkt_t));
42 hdhomerun_pkt_reset(pkt);
47 void hdhomerun_pkt_destroy(struct hdhomerun_pkt_t *pkt)
52 void hdhomerun_pkt_reset(struct hdhomerun_pkt_t *pkt)
54 pkt->limit = pkt->buffer + sizeof(pkt->buffer) - 4;
55 pkt->start = pkt->buffer + 1024;
56 pkt->end = pkt->start;
57 pkt->pos = pkt->start;
60 static uint32_t hdhomerun_pkt_calc_crc(uint8_t *start, uint8_t *end)
63 uint32_t crc = 0xFFFFFFFF;
65 uint8_t x = (uint8_t)(crc) ^ *pos++;
67 if (x & 0x01) crc ^= 0x77073096;
68 if (x & 0x02) crc ^= 0xEE0E612C;
69 if (x & 0x04) crc ^= 0x076DC419;
70 if (x & 0x08) crc ^= 0x0EDB8832;
71 if (x & 0x10) crc ^= 0x1DB71064;
72 if (x & 0x20) crc ^= 0x3B6E20C8;
73 if (x & 0x40) crc ^= 0x76DC4190;
74 if (x & 0x80) crc ^= 0xEDB88320;
76 return crc ^ 0xFFFFFFFF;
79 uint8_t hdhomerun_pkt_read_u8(struct hdhomerun_pkt_t *pkt)
81 uint8_t v = *pkt->pos++;
85 uint16_t hdhomerun_pkt_read_u16(struct hdhomerun_pkt_t *pkt)
88 v = (uint16_t)*pkt->pos++ << 8;
89 v |= (uint16_t)*pkt->pos++ << 0;
93 uint32_t hdhomerun_pkt_read_u32(struct hdhomerun_pkt_t *pkt)
96 v = (uint32_t)*pkt->pos++ << 24;
97 v |= (uint32_t)*pkt->pos++ << 16;
98 v |= (uint32_t)*pkt->pos++ << 8;
99 v |= (uint32_t)*pkt->pos++ << 0;
103 size_t hdhomerun_pkt_read_var_length(struct hdhomerun_pkt_t *pkt)
107 if (pkt->pos + 1 > pkt->end) {
111 length = (size_t)*pkt->pos++;
112 if (length & 0x0080) {
113 if (pkt->pos + 1 > pkt->end) {
118 length |= (size_t)*pkt->pos++ << 7;
124 uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size_t *plength)
126 if (pkt->pos + 2 > pkt->end) {
130 *ptag = hdhomerun_pkt_read_u8(pkt);
131 *plength = hdhomerun_pkt_read_var_length(pkt);
133 if (pkt->pos + *plength > pkt->end) {
137 return pkt->pos + *plength;
140 void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v)
144 if (pkt->pos > pkt->end) {
149 void hdhomerun_pkt_write_u16(struct hdhomerun_pkt_t *pkt, uint16_t v)
151 *pkt->pos++ = (uint8_t)(v >> 8);
152 *pkt->pos++ = (uint8_t)(v >> 0);
154 if (pkt->pos > pkt->end) {
159 void hdhomerun_pkt_write_u32(struct hdhomerun_pkt_t *pkt, uint32_t v)
161 *pkt->pos++ = (uint8_t)(v >> 24);
162 *pkt->pos++ = (uint8_t)(v >> 16);
163 *pkt->pos++ = (uint8_t)(v >> 8);
164 *pkt->pos++ = (uint8_t)(v >> 0);
166 if (pkt->pos > pkt->end) {
171 void hdhomerun_pkt_write_var_length(struct hdhomerun_pkt_t *pkt, size_t v)
174 *pkt->pos++ = (uint8_t)v;
176 *pkt->pos++ = (uint8_t)(v | 0x80);
177 *pkt->pos++ = (uint8_t)(v >> 7);
180 if (pkt->pos > pkt->end) {
185 void hdhomerun_pkt_write_mem(struct hdhomerun_pkt_t *pkt, const void *mem, size_t length)
187 memcpy(pkt->pos, mem, length);
190 if (pkt->pos > pkt->end) {
195 int hdhomerun_pkt_open_frame(struct hdhomerun_pkt_t *pkt, uint16_t *ptype)
197 pkt->pos = pkt->start;
199 if (pkt->pos + 4 > pkt->end) {
203 *ptype = hdhomerun_pkt_read_u16(pkt);
204 size_t length = hdhomerun_pkt_read_u16(pkt);
207 if (pkt->pos + 4 > pkt->end) {
208 pkt->pos = pkt->start;
212 uint32_t calc_crc = hdhomerun_pkt_calc_crc(pkt->start, pkt->pos);
215 packet_crc = (uint32_t)*pkt->pos++ << 0;
216 packet_crc |= (uint32_t)*pkt->pos++ << 8;
217 packet_crc |= (uint32_t)*pkt->pos++ << 16;
218 packet_crc |= (uint32_t)*pkt->pos++ << 24;
219 if (calc_crc != packet_crc) {
224 pkt->end = pkt->start + length;
225 pkt->pos = pkt->start;
229 void hdhomerun_pkt_seal_frame(struct hdhomerun_pkt_t *pkt, uint16_t frame_type)
231 size_t length = pkt->end - pkt->start;
234 pkt->pos = pkt->start;
235 hdhomerun_pkt_write_u16(pkt, frame_type);
236 hdhomerun_pkt_write_u16(pkt, (uint16_t)length);
238 uint32_t crc = hdhomerun_pkt_calc_crc(pkt->start, pkt->end);
239 *pkt->end++ = (uint8_t)(crc >> 0);
240 *pkt->end++ = (uint8_t)(crc >> 8);
241 *pkt->end++ = (uint8_t)(crc >> 16);
242 *pkt->end++ = (uint8_t)(crc >> 24);
244 pkt->pos = pkt->start;