Interim but working support for crunched data streams when reading from the

device; writes haven't been converted yet. Reduces the bandiwidth from about
800kB/s to about 500kB/s, which is about what I thought.
This commit is contained in:
David Given
2019-03-26 23:03:19 +01:00
parent 0453837c03
commit bcc5a5f2cd
13 changed files with 290 additions and 27 deletions

View File

@@ -39,6 +39,20 @@
<build_action v="HEADER;;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="crunch.c" persistent="..\lib\common\crunch.c">
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="crunch.h" persistent="..\lib\common\crunch.h">
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
</dependencies>
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
@@ -2164,20 +2178,20 @@
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep4" persistent="">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
<dependencies>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep4_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep4_dma.c">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;CortexM3;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep4_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep4_dma.h">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
@@ -2190,20 +2204,20 @@
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep3" persistent="">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
<dependencies>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep3_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep3_dma.c">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;CortexM3;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep3_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep3_dma.h">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
@@ -2216,20 +2230,20 @@
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep2" persistent="">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
<dependencies>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep2_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep2_dma.c">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;CortexM3;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep2_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep2_dma.h">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
@@ -2242,20 +2256,20 @@
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep1" persistent="">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
<dependencies>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep1_dma.c" persistent="Generated_Source\PSoC5\USBFS_ep1_dma.c">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;CortexM3;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="USBFS_ep1_dma.h" persistent="Generated_Source\PSoC5\USBFS_ep1_dma.h">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />

View File

Binary file not shown.

View File

@@ -4,6 +4,7 @@
#include <setjmp.h>
#include "project.h"
#include "../protocol.h"
#include "../lib/common/crunch.h"
#define MOTOR_ON_TIME 5000 /* milliseconds */
#define STEP_INTERVAL_TIME 6 /* ms */
@@ -28,6 +29,7 @@ static uint8_t current_drive_flags = 0;
#define BUFFER_SIZE 64
static uint8_t td[BUFFER_COUNT];
static uint8_t dma_buffer[BUFFER_COUNT][BUFFER_SIZE] __attribute__((aligned()));
static uint8_t usb_buffer[BUFFER_SIZE] __attribute__((aligned()));
static uint8_t dma_channel;
#define NEXT_BUFFER(b) (((b)+1) % BUFFER_COUNT)
@@ -281,6 +283,11 @@ static void cmd_read(struct read_frame* f)
;
index_irq = false;
crunch_state_t cs;
cs.fifolen = 0;
cs.outputptr = usb_buffer;
cs.outputlen = BUFFER_SIZE;
dma_writing_to_td = 0;
dma_reading_from_td = -1;
dma_underrun = false;
@@ -302,6 +309,8 @@ static void cmd_read(struct read_frame* f)
int revolutions = f->revolutions;
while (!dma_underrun)
{
CyWdtClear();
/* Have we reached the index pulse? */
if (index_irq)
{
@@ -325,17 +334,35 @@ static void cmd_read(struct read_frame* f)
goto abort;
}
USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, dma_buffer[dma_reading_from_td], BUFFER_SIZE);
uint8_t dma_buffer_usage = 0;
while (dma_buffer_usage < BUFFER_SIZE)
{
cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage;
cs.inputlen = BUFFER_SIZE - dma_buffer_usage;
crunch(&cs);
dma_buffer_usage += BUFFER_SIZE - cs.inputlen;
count++;
if (cs.outputlen == 0)
{
USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE);
cs.outputptr = usb_buffer;
cs.outputlen = BUFFER_SIZE;
}
}
dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td);
count++;
}
abort:
CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN);
while (CyDmaChGetRequest(dma_channel))
;
donecrunch(&cs);
wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM);
if (cs.outputlen != BUFFER_SIZE)
USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE-cs.outputlen);
else
USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0);
wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM);
USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0);
deinit_dma();
if (dma_underrun)

View File

@@ -1,6 +1,7 @@
#include "globals.h"
#include "bytes.h"
#include "fmt/format.h"
#include "crunch.h"
#include <zlib.h>
static std::shared_ptr<std::vector<uint8_t>> createVector(unsigned size)
@@ -208,6 +209,34 @@ Bytes Bytes::decompress() const
return output;
}
Bytes Bytes::uncrunch() const
{
Bytes output;
ByteWriter bw(output);
Bytes outputBuffer(1024*1024);
crunch_state_t cs = {};
cs.inputptr = begin();
cs.inputlen = size();
do
{
cs.outputptr = outputBuffer.begin();
cs.outputlen = outputBuffer.size();
::uncrunch(&cs);
bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen);
}
while (cs.inputlen != 0);
cs.outputptr = outputBuffer.begin();
cs.outputlen = outputBuffer.size();
doneuncrunch(&cs);
bw += outputBuffer.slice(0, outputBuffer.size() - cs.outputlen);
return output;
}
ByteReader Bytes::reader() const
{
return ByteReader(*this);

View File

@@ -46,6 +46,8 @@ public:
Bytes slice(unsigned start, unsigned len) const;
Bytes compress() const;
Bytes decompress() const;
Bytes crunch() const;
Bytes uncrunch() const;
ByteReader reader() const;
ByteWriter writer();

87
lib/common/crunch.c Normal file
View File

@@ -0,0 +1,87 @@
#include <stdint.h>
#include <stdbool.h>
#include "crunch.h"
void crunch(crunch_state_t* state)
{
while (state->inputlen && state->outputlen)
{
uint8_t data = *state->inputptr++;
state->inputlen--;
if (data & 0x80)
{
state->fifo = (state->fifo << 2) | 2 | (data & 1);
state->fifolen += 2;
}
else
{
state->fifo = (state->fifo << 8) | data;
state->fifolen += 8;
}
if (state->fifolen >= 8)
{
data = state->fifo >> (state->fifolen - 8);
*state->outputptr++ = data;
state->outputlen--;
state->fifolen -= 8;
}
}
}
void donecrunch(crunch_state_t* state)
{
if (state->fifolen > 0)
{
uint8_t b = 0;
state->inputptr = &b;
state->inputlen = 1;
crunch(state);
}
}
void uncrunch(crunch_state_t* state)
{
do
{
if (state->fifolen < 8)
{
if (state->inputlen)
{
state->fifo = (state->fifo << 8) | *state->inputptr++;
state->inputlen--;
state->fifolen += 8;
}
else
state->fifo <<= 8;
}
uint8_t data = state->fifo >> (state->fifolen - 8);
if (data & 0x80)
{
data = ((data >> 6) & 0x01) | 0x80;
state->fifolen -= 2;
}
else
state->fifolen -= 8;
if (data)
{
*state->outputptr++ = data;
state->outputlen--;
}
}
while (state->inputlen && state->outputlen);
}
void doneuncrunch(crunch_state_t* state)
{
if (state->fifolen > 0)
{
uint8_t b = 0;
state->inputptr = &b;
state->inputlen = 1;
uncrunch(state);
}
}

45
lib/common/crunch.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef CRUNCH_H
#define CRUNCH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* To save bandwidth, we compress the byte stream from the sampler when
* sending it over USB. The encoding used is:
*
* 0nnn.nnnn: value 0x00..0x7f
* 1n : value 0x80|n
*
* The end of the buffer is terminated with zeroes, which are ignored
* (not written to the output).
*
* This saves ~40%, which gets us in under the bandwidth cap.
*/
typedef struct crunch_state_t
{
const uint8_t* inputptr;
uint32_t inputlen;
uint8_t* outputptr;
uint32_t outputlen;
uint16_t fifo;
uint8_t fifolen;
}
crunch_state_t;
/* Crunches as much as possible and then stops. */
extern void crunch(crunch_state_t* state);
extern void donecrunch(crunch_state_t* state);
/* Uncrunches as much as possible and then stops. */
extern void uncrunch(crunch_state_t* state);
extern void doneuncrunch(crunch_state_t* state);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -3,6 +3,7 @@
#include "fluxmap.h"
#include "usb.h"
#include "fluxreader.h"
#include <fmt/format.h>
static IntFlag revolutions(
{ "--revolutions" },
@@ -10,7 +11,7 @@ static IntFlag revolutions(
1);
static SettableFlag highDensity(
{ "--high-density", "-H" },
{ "--high-density", "--hd" },
"sets the drive to high density mode");
class HardwareFluxReader : public FluxReader
@@ -30,7 +31,13 @@ public:
{
usbSetDrive(_drive, highDensity);
usbSeek(track);
return usbRead(side, revolutions);
Bytes crunched = usbRead(side, _revolutions);
std::cout << fmt::format("({} bytes crunched) ", crunched.size());
Bytes uncrunched = crunched.uncrunch();
auto fluxmap = std::make_unique<Fluxmap>();
fluxmap->appendBytes(uncrunched);
return fluxmap;
}
void recalibrate()

View File

@@ -55,10 +55,9 @@ std::unique_ptr<Fluxmap> Track::read()
std::cout << fmt::format("{0:>3}.{1}: ", track, side) << std::flush;
std::unique_ptr<Fluxmap> fluxmap = _fluxReader->readFlux(track, side);
std::cout << fmt::format(
"{0} ms in {1} bytes ({2} kB/s)\n",
"{0} ms in {1} bytes\n",
int(fluxmap->duration()/1e6),
fluxmap->bytes(),
(int)(1e6 * fluxmap->bytes() / fluxmap->duration()));
fluxmap->bytes());
if (outdb)
sqlWriteFlux(outdb, track, side, *fluxmap);
return fluxmap;

View File

@@ -3,6 +3,7 @@
#include "protocol.h"
#include "fluxmap.h"
#include "bytes.h"
#include "crunch.h"
#include <libusb.h>
#define TIMEOUT 5000
@@ -188,7 +189,7 @@ void usbTestBulkTransport()
await_reply<struct any_frame>(F_FRAME_BULK_TEST_REPLY);
}
std::unique_ptr<Fluxmap> usbRead(int side, int revolutions)
Bytes usbRead(int side, int revolutions)
{
struct read_frame f = {
.f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) },
@@ -203,10 +204,8 @@ std::unique_ptr<Fluxmap> usbRead(int side, int revolutions)
int len = large_bulk_transfer(FLUXENGINE_DATA_IN_EP, buffer);
buffer.resize(len);
fluxmap->appendBytes(buffer);
await_reply<struct any_frame>(F_FRAME_READ_REPLY);
return fluxmap;
return buffer;
}
void usbWrite(int side, const Fluxmap& fluxmap)

View File

@@ -2,13 +2,14 @@
#define USB_H
class Fluxmap;
class Bytes;
extern int usbGetVersion();
extern void usbRecalibrate();
extern void usbSeek(int track);
extern nanoseconds_t usbGetRotationalPeriod();
extern void usbTestBulkTransport();
extern std::unique_ptr<Fluxmap> usbRead(int side, int revolutions);
extern Bytes usbRead(int side, int revolutions);
extern void usbWrite(int side, const Fluxmap& fluxmap);
extern void usbErase(int side);
extern void usbSetDrive(int drive, bool high_density);

View File

@@ -1,4 +1,4 @@
project('fluxclient', 'cpp')
project('fluxclient', 'c', 'cpp')
add_global_arguments('--std=c++14', language: 'cpp')
libusb = dependency('libusb-1.0')
@@ -17,6 +17,15 @@ fmtlib = declare_dependency(
include_directories('dep/fmt')
)
crunchlib = declare_dependency(
link_with:
shared_library('crunch',
['lib/common/crunch.c']
),
include_directories:
include_directories('lib/common')
)
felib = declare_dependency(
link_with:
shared_library('felib',
@@ -33,7 +42,7 @@ felib = declare_dependency(
'lib/usb.cc',
'lib/bytes.cc',
],
dependencies: [fmtlib, libusb, zlib]
dependencies: [fmtlib, crunchlib, libusb, zlib]
),
include_directories:
include_directories('lib')
@@ -231,3 +240,4 @@ test('BitAccumulator', executable('bitaccumulator-test', ['tests/bitaccumulator
test('Kryoflux', executable('kryoflux-test', ['tests/kryoflux.cc'], dependencies: [felib, decoderlib, fluxreaderlib]))
test('Compression', executable('compression-test', ['tests/compression.cc'], dependencies: [felib, decoderlib]))
test('Bytes', executable('bytes-test', ['tests/bytes.cc'], dependencies: [felib]))
test('Crunch', executable('crunch-test', ['tests/crunch.cc'], dependencies: [felib, crunchlib]))

43
tests/crunch.cc Normal file
View File

@@ -0,0 +1,43 @@
#include "globals.h"
#include "bytes.h"
#include "crunch.h"
static uint8_t outputbuffer[64];
static void test_crunch()
{
crunch_state_t cs = {};
Bytes inputdata = { 0x01, 0x7f, 0x80, 0x81, 0x01 };
cs.inputptr = inputdata.begin();
cs.inputlen = inputdata.size();
cs.outputptr = outputbuffer;
cs.outputlen = 64;
crunch(&cs);
donecrunch(&cs);
Bytes outputdata(outputbuffer, cs.outputptr - outputbuffer);
assert((outputdata == Bytes{ 0x01, 0x7f, 0xb0, 0x10 }));
}
static void test_uncrunch()
{
crunch_state_t cs = {};
Bytes inputdata = { 0x01, 0x7f, 0xb0, 0x10 };
cs.inputptr = inputdata.begin();
cs.inputlen = inputdata.size();
cs.outputptr = outputbuffer;
cs.outputlen = 64;
uncrunch(&cs);
doneuncrunch(&cs);
Bytes outputdata(outputbuffer, cs.outputptr - outputbuffer);
assert((outputdata == Bytes { 0x01, 0x7f, 0x80, 0x81, 0x01 }));
}
int main(int argc, const char* argv[])
{
test_crunch();
test_uncrunch();
return 0;
}