#include "lib/core/globals.h" #include "protocol.h" #include "lib/core/bytes.h" #include "lib/external/greaseweazle.h" Bytes fluxEngineToGreaseweazle(const Bytes& fldata, nanoseconds_t clock) { Bytes gwdata; ByteWriter bw(gwdata); ByteReader br(fldata); uint32_t ticks_fl = 0; uint32_t ticks_gw = 0; auto write_28 = [&](uint32_t val) { bw.write_8(1 | (val << 1) & 0xff); bw.write_8(1 | (val >> 6) & 0xff); bw.write_8(1 | (val >> 13) & 0xff); bw.write_8(1 | (val >> 20) & 0xff); }; while (!br.eof()) { uint8_t b = br.read_8(); ticks_fl += b & 0x3f; if (b & F_BIT_PULSE) { uint32_t newticks_gw = ticks_fl * NS_PER_TICK / clock; uint32_t delta = newticks_gw - ticks_gw; if (delta < 250) bw.write_8(delta); else { int high = (delta - 250) / 255; if (high < 5) { bw.write_8(250 + high); bw.write_8(1 + (delta - 250) % 255); } else { bw.write_8(255); bw.write_8(FLUXOP_SPACE); write_28(delta - 249); bw.write_8(249); } } ticks_gw = newticks_gw; } } bw.write_8(0); /* end of stream */ return gwdata; } Bytes greaseweazleToFluxEngine(const Bytes& gwdata, nanoseconds_t clock) { Bytes fldata; ByteReader br(gwdata); ByteWriter bw(fldata); auto read_28 = [&]() { return ((br.read_8() & 0xfe) >> 1) | ((br.read_8() & 0xfe) << 6) | ((br.read_8() & 0xfe) << 13) | ((br.read_8() & 0xfe) << 20); }; uint32_t ticks_gw = 0; uint32_t lastevent_fl = 0; uint32_t index_gw = ~0; while (!br.eof()) { uint8_t b = br.read_8(); if (!b) break; uint8_t event = 0; if (b == 255) { switch (br.read_8()) { case FLUXOP_INDEX: index_gw = ticks_gw + read_28(); break; case FLUXOP_SPACE: ticks_gw += read_28(); break; default: error("bad opcode in Greaseweazle stream"); } } else { if (b < 250) ticks_gw += b; else { int delta = 250 + (b - 250) * 255 + br.read_8() - 1; ticks_gw += delta; } event = F_BIT_PULSE; } if (event) { uint32_t index_fl = round((index_gw * clock) / NS_PER_TICK); uint32_t ticks_fl = round((ticks_gw * clock) / NS_PER_TICK); if (index_gw != ~0) { if (index_fl < ticks_fl) { uint32_t delta_fl = index_fl - lastevent_fl; while (delta_fl > 0x3f) { bw.write_8(0x3f); delta_fl -= 0x3f; } bw.write_8(delta_fl | F_BIT_INDEX); lastevent_fl = index_fl; index_gw = ~0; } else if (index_fl == ticks_fl) event |= F_BIT_INDEX; } uint32_t delta_fl = ticks_fl - lastevent_fl; while (delta_fl > 0x3f) { bw.write_8(0x3f); delta_fl -= 0x3f; } bw.write_8(delta_fl | event); lastevent_fl = ticks_fl; } } return fldata; } /* Left-truncates at the first index mark, so the resulting data as aligned at * the index. */ Bytes stripPartialRotation(const Bytes& fldata) { for (unsigned i = 0; i < fldata.size(); i++) { uint8_t b = fldata[i]; if (b & F_BIT_INDEX) return fldata.slice(i); } return fldata; }