mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-28 04:23:37 +01:00
fxlink: add interactive mode to exchange data with gint
This commit is contained in:
parent
30befdd2cf
commit
d2b6da5122
8 changed files with 521 additions and 68 deletions
|
@ -34,9 +34,10 @@ add_custom_target(fxsdk ALL DEPENDS "${BIN}/fxsdk.sh")
|
|||
|
||||
# fxlink
|
||||
configure_file(fxlink/config.h.in "${BIN}/include/fxlink/config.h")
|
||||
add_executable(fxlink fxlink/usb.c fxlink/filter.c fxlink/main.c
|
||||
fxlink/properties.c fxlink/ud2.c fxlink/util.c)
|
||||
target_link_libraries(fxlink PkgConfig::libusb) # PkgConfig::libudev
|
||||
add_executable(fxlink fxlink/usb.c fxlink/filter.c fxlink/interactive.c
|
||||
fxlink/main.c fxlink/png.c fxlink/properties.c fxlink/ud2.c fxlink/util.c
|
||||
fxlink/protocol.c)
|
||||
target_link_libraries(fxlink PkgConfig::libpng PkgConfig::libusb) # PkgConfig::libudev
|
||||
target_include_directories(fxlink PRIVATE "${BIN}/include/fxlink")
|
||||
if(NOT FXLINK_DISABLE_UDISKS2)
|
||||
target_link_libraries(fxlink PkgConfig::udisks2)
|
||||
|
|
|
@ -18,4 +18,7 @@ int main_blocks(filter_t *filter, delay_t *delay);
|
|||
/* Main function for -s */
|
||||
int main_send(filter_t *filter, delay_t *delay, char **files);
|
||||
|
||||
/* Main function for -i */
|
||||
int main_interactive(filter_t *filter,delay_t *delay,libusb_context *context);
|
||||
|
||||
#endif /* FXLINK_FXLINK_H */
|
||||
|
|
232
fxlink/interactive.c
Normal file
232
fxlink/interactive.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
#include "config.h"
|
||||
#include "fxlink.h"
|
||||
#include "util.h"
|
||||
#include "properties.h"
|
||||
#include "filter.h"
|
||||
#include "protocol.h"
|
||||
#include "usb.h"
|
||||
#include "png.h"
|
||||
|
||||
#include <libusb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <png.h>
|
||||
|
||||
static char *output_file(char const *path,char const *type,char const *suffix)
|
||||
{
|
||||
char *filename = NULL;
|
||||
int counter = 1;
|
||||
|
||||
time_t time_raw;
|
||||
struct tm time_bd;
|
||||
time(&time_raw);
|
||||
localtime_r(&time_raw, &time_bd);
|
||||
|
||||
while(1) {
|
||||
asprintf(&filename, "%s/fxlink-%.16s-%04d.%02d.%02d-%02dh%02d-%d.%s",
|
||||
path, type, time_bd.tm_year + 1900, time_bd.tm_mon,
|
||||
time_bd.tm_mday, time_bd.tm_hour, time_bd.tm_min, counter, suffix);
|
||||
if(!filename) continue;
|
||||
|
||||
/* Try to find a name for a file that doesn't exist */
|
||||
if(access(filename, F_OK) == -1) break;
|
||||
|
||||
free(filename);
|
||||
counter++;
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
static bool message_new(message_t *msg, usb_fxlink_header_t const *h)
|
||||
{
|
||||
int version_major = (h->version >> 8) & 0xff;
|
||||
int version_minor = (h->version) & 0xff;
|
||||
|
||||
fprintf(stderr, "New message (v%d.%d): application '%.16s', type '%.16s', "
|
||||
"size %d bytes\n", version_major, version_minor, h->application,
|
||||
h->type, h->size);
|
||||
|
||||
msg->output = malloc(h->size);
|
||||
if(!msg->output) {
|
||||
err("cannot allocate memory for message of %d bytes", h->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
msg->header = *h;
|
||||
msg->size_read = 0;
|
||||
msg->valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void message_finish(message_t *msg)
|
||||
{
|
||||
char const *path = ".";
|
||||
|
||||
if(!strncmp(msg->header.application, "fxlink", 16)) {
|
||||
if(!strncmp(msg->header.type, "image", 16)) {
|
||||
usb_fxlink_image_t *img = (void *)msg->output;
|
||||
char *filename = output_file(path, msg->header.type, "png");
|
||||
|
||||
uint8_t **row_pointers = fxlink_protocol_decode_image(msg);
|
||||
fxlink_png_save(row_pointers, img->width, img->height, filename);
|
||||
|
||||
printf("Saved image (%dx%d, format=%d) to '%s'\n",
|
||||
img->width, img->height, img->pixel_format, filename);
|
||||
free(row_pointers);
|
||||
free(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strncmp(msg->header.type, "text", 16)) {
|
||||
printf("------------------\n");
|
||||
fwrite(msg->output, 1, msg->header.size, stdout);
|
||||
if(msg->output[msg->header.size - 1] != '\n') printf("\n");
|
||||
printf("------------------\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default to saving to a blob */
|
||||
char *filename = output_file(path, "blob", "bin");
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if(!fp) {
|
||||
err("could not save to '%s': %m", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(msg->output, 1, msg->header.size, fp);
|
||||
fclose(fp);
|
||||
fprintf(stderr, "Saved as blob to '%s'\n", filename);
|
||||
free(filename);
|
||||
}
|
||||
|
||||
static void message_output(message_t *msg, void *buffer, int size)
|
||||
{
|
||||
int data_left = msg->header.size - msg->size_read;
|
||||
|
||||
printf("Got %d bytes of message data!\n", size);
|
||||
|
||||
if(size > data_left) {
|
||||
err("Too much data in message, dropping %d bytes", size - data_left);
|
||||
size = data_left;
|
||||
}
|
||||
|
||||
memcpy(msg->output + msg->size_read, buffer, size);
|
||||
|
||||
msg->size_read += size;
|
||||
if(msg->size_read >= msg->header.size) {
|
||||
fprintf(stderr, "Successfully read %d bytes\n", msg->size_read);
|
||||
message_finish(msg);
|
||||
msg->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
int main_interactive(filter_t *filter, delay_t *delay, libusb_context *context)
|
||||
{
|
||||
libusb_device *dev = NULL;
|
||||
libusb_device_handle *dh = NULL;
|
||||
|
||||
/* Wait for a device to be connected */
|
||||
filter_clean_libusb(filter);
|
||||
int rc = usb_unique_wait(filter, delay, context, &dev);
|
||||
|
||||
if(rc == FILTER_NONE) {
|
||||
printf("No device found.\n");
|
||||
return 1;
|
||||
}
|
||||
else if(rc == FILTER_MULTIPLE) {
|
||||
printf("Multiple devices found, ambiguous!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((rc = libusb_open(dev, &dh))) {
|
||||
rc = libusb_err(rc, "cannot open device %s", usb_id(dev));
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Don't detach kernel drivers to avoid breaking the Mass Storage
|
||||
communications if fxlink is ever started while the native LINK
|
||||
application is running! */
|
||||
libusb_set_auto_detach_kernel_driver(dh, false);
|
||||
|
||||
if((rc = libusb_claim_interface(dh, 0))) {
|
||||
rc = libusb_err(rc, "cannot claim interface on %s", usb_id(dev));
|
||||
goto end;
|
||||
}
|
||||
|
||||
printf("Connected to %s, starting test.\n", usb_id(dev));
|
||||
|
||||
/* This buffer is used to receive messages; if the header is not complete
|
||||
it is left in the buffer, hence the extra room */
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t buffer[2048 + sizeof(usb_fxlink_header_t)] = { 0 };
|
||||
/* Amount of data in the buffer */
|
||||
int buffer_size = 0;
|
||||
|
||||
/* Current message */
|
||||
message_t msg = { 0 };
|
||||
|
||||
while(1)
|
||||
{
|
||||
int transferred = -1;
|
||||
rc = libusb_bulk_transfer(dh, 0x81, buffer + buffer_size, 2048,
|
||||
&transferred, 2000);
|
||||
|
||||
if(rc == LIBUSB_ERROR_NO_DEVICE) {
|
||||
printf("Disconnected, leaving.\n");
|
||||
break;
|
||||
}
|
||||
else if(rc && rc != LIBUSB_ERROR_TIMEOUT) {
|
||||
rc = libusb_err(rc, "bulk transfer failed on %s", usb_id(dev));
|
||||
continue;
|
||||
}
|
||||
if(transferred <= 0) continue;
|
||||
|
||||
buffer_size += transferred;
|
||||
|
||||
/* If there is an unfinished message, continue working on it */
|
||||
if(msg.valid) {
|
||||
message_output(&msg, buffer, buffer_size);
|
||||
buffer_size = 0;
|
||||
}
|
||||
|
||||
/* If the header is not yet fully transmitted, wait */
|
||||
usb_fxlink_header_t *h = (void *)buffer;
|
||||
if(buffer_size < (int)sizeof *h) continue;
|
||||
|
||||
/* Handle a new message */
|
||||
if(h->version == 0x00000100) {
|
||||
int data_size = buffer_size - sizeof *h;
|
||||
|
||||
if(!message_new(&msg, h))
|
||||
printf("dropping %d bytes\n", data_size);
|
||||
else
|
||||
message_output(&msg, buffer + sizeof *h, data_size);
|
||||
|
||||
buffer_size = 0;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
err("invalid header, dropping %d bytes", transferred);
|
||||
buffer_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save last unfinished message */
|
||||
if(buffer_size > 0) {
|
||||
printf("%d bytes not collected dropped\n", buffer_size);
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
end:
|
||||
if(dh) {
|
||||
libusb_release_interface(dh, 0);
|
||||
libusb_close(dh);
|
||||
}
|
||||
if(dev) libusb_unref_device(dev);
|
||||
return rc;
|
||||
}
|
|
@ -12,8 +12,6 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Main functions for each mdoe */
|
||||
int main_list(filter_t *filter, delay_t *delay, libusb_context *context);
|
||||
int main_test(libusb_device *device, libusb_context *context);
|
||||
|
||||
static const char *help_string =
|
||||
|
@ -31,7 +29,7 @@ static const char *help_string =
|
|||
" -l, --list List detected calculators on the USB ports (libusb)\n"
|
||||
" -b, --blocks List detected Mass Storage filesystems (udisks2)\n"
|
||||
" -s, --send Send a file to a Mass Storage calculator (udisks2)\n"
|
||||
" --test Communication tests by Lephe (libusb) [WIP!]\n"
|
||||
" -i, --interactive Interactive messaging with a gint add-in (libusb)\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
" -w DELAY Wait up to this many seconds for a calculator to\n"
|
||||
|
@ -67,18 +65,18 @@ int main(int argc, char **argv)
|
|||
// Command-line argument parsing
|
||||
//---
|
||||
|
||||
enum { TEST=1, LIBUSB_LOG };
|
||||
enum { LIBUSB_LOG=1 };
|
||||
const struct option longs[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "list", no_argument, NULL, 'l' },
|
||||
{ "blocks", no_argument, NULL, 'b' },
|
||||
{ "send", no_argument, NULL, 's' },
|
||||
{ "test", no_argument, NULL, TEST },
|
||||
{ "libusb-log", required_argument, NULL, LIBUSB_LOG },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "list", no_argument, NULL, 'l' },
|
||||
{ "blocks", no_argument, NULL, 'b' },
|
||||
{ "send", no_argument, NULL, 's' },
|
||||
{ "interactive", no_argument, NULL, 'i' },
|
||||
{ "libusb-log", required_argument, NULL, LIBUSB_LOG },
|
||||
};
|
||||
|
||||
while(option >= 0 && option != '?')
|
||||
switch((option = getopt_long(argc, argv, "hlbsf:w::", longs, NULL)))
|
||||
switch((option = getopt_long(argc, argv, "hlbsif:w::", longs, NULL)))
|
||||
{
|
||||
case 'h':
|
||||
fprintf(stderr, help_string, argv[0]);
|
||||
|
@ -86,7 +84,7 @@ int main(int argc, char **argv)
|
|||
case 'l':
|
||||
case 'b':
|
||||
case 's':
|
||||
case TEST:
|
||||
case 'i':
|
||||
mode = option;
|
||||
break;
|
||||
case LIBUSB_LOG:
|
||||
|
@ -141,7 +139,7 @@ int main(int argc, char **argv)
|
|||
libusb_context *context = NULL;
|
||||
|
||||
/* Initialize libusb for corresponding modes */
|
||||
if(mode == 'l' || mode == TEST) {
|
||||
if(mode == 'l' || mode == 'i') {
|
||||
if((rc = libusb_init(&context)))
|
||||
return libusb_err(rc, "error initializing libusb");
|
||||
libusb_set_option(context, LIBUSB_OPTION_LOG_LEVEL, loglevel);
|
||||
|
@ -168,18 +166,8 @@ int main(int argc, char **argv)
|
|||
rc = err("this fxlink was built without UDisks2; -s is disabled");
|
||||
#endif
|
||||
}
|
||||
else if(mode == TEST) {
|
||||
libusb_device *dev = NULL;
|
||||
int rc = usb_unique_wait(filter, &delay, context, &dev);
|
||||
|
||||
if(rc == FILTER_NONE)
|
||||
printf("No device found.\n");
|
||||
else if(rc == FILTER_MULTIPLE)
|
||||
printf("Multiple devices found, ambiguous!\n");
|
||||
else if(rc == FILTER_UNIQUE) {
|
||||
rc = main_test(dev, context);
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
else if(mode == 'i') {
|
||||
rc = main_interactive(filter, &delay, context);
|
||||
}
|
||||
|
||||
if(context) libusb_exit(context);
|
||||
|
@ -240,48 +228,9 @@ int main_list(filter_t *filter, delay_t *delay, libusb_context *context)
|
|||
}
|
||||
|
||||
//---
|
||||
// WIP tests
|
||||
// libudev tests; work but not useful yet
|
||||
//---
|
||||
|
||||
int main_test(libusb_device *dev, libusb_context *context)
|
||||
{
|
||||
libusb_device_handle *dh;
|
||||
int rc;
|
||||
(void)context;
|
||||
|
||||
if((rc = libusb_open(dev, &dh)))
|
||||
return libusb_err(rc, "cannot open device %s", usb_id(dev));
|
||||
|
||||
/* When possible detach any existing driver */
|
||||
libusb_set_auto_detach_kernel_driver(dh, true);
|
||||
|
||||
if((rc = libusb_claim_interface(dh, 0))) {
|
||||
libusb_close(dh);
|
||||
return libusb_err(rc, "cannot claim interface on %s", usb_id(dev));
|
||||
}
|
||||
|
||||
uint8_t buffer[2048];
|
||||
int transferred = -1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
rc = libusb_bulk_transfer(dh, 0x81, buffer, 2048, &transferred, 500);
|
||||
|
||||
if((rc == 0 || rc == LIBUSB_ERROR_TIMEOUT) && transferred > 0)
|
||||
fwrite(buffer, 1, transferred, stdout);
|
||||
if(rc)
|
||||
rc=libusb_err(rc,"cannot perform bulk transfer on %s",usb_id(dev));
|
||||
|
||||
fprintf(stderr, "Transferred: %d\n", transferred);
|
||||
if(rc || transferred == 0) break;
|
||||
}
|
||||
|
||||
libusb_release_interface(dh, 0);
|
||||
libusb_close(dh);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* libudev tests, work but not useful yet */
|
||||
#if 0
|
||||
#include <libudev.h>
|
||||
int main_udev_test(libusb_device *dev)
|
||||
|
|
42
fxlink/png.c
Normal file
42
fxlink/png.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "png.h"
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* fxlink_png_save(): Save a bitmap into a PNG file */
|
||||
int fxlink_png_save(png_byte **row_pointers, int width, int height,
|
||||
char const *path)
|
||||
{
|
||||
png_struct *png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL, NULL, NULL);
|
||||
if(!png)
|
||||
return err("failed to write PNG: png_create_write_struct");
|
||||
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if(!info)
|
||||
return err("failed to write PNG: png_create_info_struct");
|
||||
|
||||
FILE *fp = fopen(path, "wb");
|
||||
if(!fp) {
|
||||
png_destroy_write_struct(&png, &info);
|
||||
return err("failed to open '%s' to write PNG: %m", path);
|
||||
}
|
||||
|
||||
if(setjmp(png_jmpbuf(png))) {
|
||||
fclose(fp);
|
||||
png_destroy_write_struct(&png, &info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
png_init_io(png, fp);
|
||||
png_set_IHDR(png, info,
|
||||
width, height, 8,
|
||||
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_write_info(png, info);
|
||||
png_write_image(png, row_pointers);
|
||||
png_write_end(png, NULL);
|
||||
png_destroy_write_struct(&png, &info);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
14
fxlink/png.h
Normal file
14
fxlink/png.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
//---
|
||||
// fxlink:png - Tools to output PNG images with libpng
|
||||
//---
|
||||
|
||||
#ifndef FXLINK_PNG_H
|
||||
#define FXLINK_PNG_H
|
||||
|
||||
#include <png.h>
|
||||
|
||||
/* fxlink_png_save(): Save a bitmap into a PNG file */
|
||||
int fxlink_png_save(png_byte **row_pointers, int width, int height,
|
||||
char const *path);
|
||||
|
||||
#endif /* FXLINK_PNG_H */
|
141
fxlink/protocol.c
Normal file
141
fxlink/protocol.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
#include "protocol.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <endian.h>
|
||||
|
||||
//---
|
||||
// Image format
|
||||
//---
|
||||
|
||||
static int img_bytes_per_row(int format, int width)
|
||||
{
|
||||
if(format == USB_FXLINK_IMAGE_RGB565)
|
||||
return 2 * width;
|
||||
if(format == USB_FXLINK_IMAGE_MONO)
|
||||
return (width + 7) >> 3;
|
||||
if(format == USB_FXLINK_IMAGE_GRAY)
|
||||
return 2 * ((width + 7) >> 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void decode_rgb565(void *pixels, int width, int height, int size,
|
||||
uint8_t **row_pointers)
|
||||
{
|
||||
int bpr = img_bytes_per_row(USB_FXLINK_IMAGE_RGB565, width);
|
||||
|
||||
for(int y = 0; y < height; y++) {
|
||||
void *row = pixels + y * bpr;
|
||||
|
||||
for(int x = 0; x < width; x++) {
|
||||
/* Don't read past the read buffer if the image is incomplete */
|
||||
void *input = row + 2 * x;
|
||||
uint16_t color = 0;
|
||||
if(input - pixels + 2 <= size) color = *(uint16_t *)input;
|
||||
|
||||
color = be16toh(color);
|
||||
|
||||
row_pointers[y][3*x+0] = (color >> 11) << 3;
|
||||
row_pointers[y][3*x+1] = ((color >> 5) & 0x3f) << 2;
|
||||
row_pointers[y][3*x+2] = (color & 0x1f) << 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_mono(void *pixels, int width, int height, int size,
|
||||
uint8_t **row_pointers)
|
||||
{
|
||||
int bpr = img_bytes_per_row(USB_FXLINK_IMAGE_MONO, width);
|
||||
|
||||
for(int y = 0; y < height; y++) {
|
||||
void *row = pixels + y * bpr;
|
||||
|
||||
for(int x = 0; x < width; x++) {
|
||||
/* Don't read past the read buffer if the image is incomplete */
|
||||
void *input = row + (x >> 3);
|
||||
int byte = 0;
|
||||
if(input - pixels + 1 <= size) byte = *(uint8_t *)input;
|
||||
int color = (byte & (0x80 >> (x & 7))) ? 0 : 255;
|
||||
|
||||
row_pointers[y][3*x+0] = color;
|
||||
row_pointers[y][3*x+1] = color;
|
||||
row_pointers[y][3*x+2] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_gray(void *pixels, int width, int height, int size,
|
||||
uint8_t **row_pointers)
|
||||
{
|
||||
int bpr = img_bytes_per_row(USB_FXLINK_IMAGE_MONO, width);
|
||||
|
||||
for(int k = 0; k < 2 * height; k++) {
|
||||
void *row = pixels + k * bpr;
|
||||
int y = k % height;
|
||||
|
||||
for(int x = 0; x < width; x++) {
|
||||
/* Don't read past the read buffer if the image is incomplete */
|
||||
void *input = row + (x >> 3);
|
||||
int byte = 0;
|
||||
if(input - pixels + 1 <= size) byte = *(uint8_t *)input;
|
||||
|
||||
int color = (byte & (0x80 >> (x & 7)));
|
||||
/* Everything is inverted */
|
||||
if(!color) color = (k >= height) ? 0xaa : 0x55;
|
||||
else color = 0x00;
|
||||
|
||||
row_pointers[y][3*x+0] += color;
|
||||
row_pointers[y][3*x+1] += color;
|
||||
row_pointers[y][3*x+2] += color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t **fxlink_protocol_decode_image(message_t *msg)
|
||||
{
|
||||
usb_fxlink_image_t *img = (void *)msg->output;
|
||||
void *pixels = msg->output + sizeof *img;
|
||||
|
||||
/* Compute the amount of data for the specified image format and size */
|
||||
int bytes_per_row = img_bytes_per_row(img->pixel_format, img->width);
|
||||
int expected_size = img->height * bytes_per_row;
|
||||
|
||||
/* Check that the correct amount of data was sent */
|
||||
int size = msg->size_read - sizeof *img;
|
||||
if(size < expected_size)
|
||||
printf("warning: got %d bytes but needed %d, image will be "
|
||||
"incomplete\n", size, expected_size);
|
||||
if(size > expected_size)
|
||||
printf("warning: got %d bytes but needed %d for image, dropping extra"
|
||||
"\n", size, expected_size);
|
||||
|
||||
/* Allocate row pointers */
|
||||
uint8_t **row_pointers = malloc(img->height*sizeof *row_pointers);
|
||||
if(!row_pointers) {
|
||||
err("failed to write allocate memory to decode image");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(size_t y = 0; y < img->height; y++) {
|
||||
row_pointers[y] = calloc(img->width, 3);
|
||||
if(!row_pointers[y]) {
|
||||
err("failed to write allocate memory to decode image");
|
||||
for(size_t i = 0 ; i < y; i++) free(row_pointers[i]);
|
||||
free(row_pointers);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode image */
|
||||
if(img->pixel_format == USB_FXLINK_IMAGE_RGB565)
|
||||
decode_rgb565(pixels, img->width, img->height, size, row_pointers);
|
||||
if(img->pixel_format == USB_FXLINK_IMAGE_MONO)
|
||||
decode_mono(pixels, img->width, img->height, size, row_pointers);
|
||||
if(img->pixel_format == USB_FXLINK_IMAGE_GRAY)
|
||||
decode_gray(pixels, img->width, img->height, size, row_pointers);
|
||||
|
||||
return row_pointers;
|
||||
}
|
71
fxlink/protocol.h
Normal file
71
fxlink/protocol.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
//---
|
||||
// fxlink:protocol - Custom fxlink protocol
|
||||
//---
|
||||
|
||||
#ifndef FXLINK_PROTOCOL_H
|
||||
#define FXLINK_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* See the gint source for details on the protocol */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t version;
|
||||
uint32_t size;
|
||||
uint32_t transfer_size;
|
||||
|
||||
char application[16];
|
||||
char type[16];
|
||||
|
||||
} usb_fxlink_header_t;
|
||||
|
||||
/* Subheader for the fxlink built-in "image" type */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
int pixel_format;
|
||||
|
||||
} usb_fxlink_image_t;
|
||||
|
||||
/* Pixel formats */
|
||||
typedef enum
|
||||
{
|
||||
/* Image is an array of *big-endian* uint16_t with RGB565 format */
|
||||
USB_FXLINK_IMAGE_RGB565 = 0,
|
||||
/* Image is an array of bits in mono format */
|
||||
USB_FXLINK_IMAGE_MONO,
|
||||
/* Image is two consecutive mono arrays, one for light, one for dark */
|
||||
USB_FXLINK_IMAGE_GRAY,
|
||||
|
||||
} usb_fxlink_image_format_t;
|
||||
|
||||
//---
|
||||
// Utilities in this implementation
|
||||
//---
|
||||
|
||||
/* Message currently being transferred */
|
||||
typedef struct
|
||||
{
|
||||
usb_fxlink_header_t header;
|
||||
/* Valid when we are reading a message */
|
||||
bool valid;
|
||||
/* Data already read in this message */
|
||||
uint32_t size_read;
|
||||
/* Data buffer */
|
||||
char *output;
|
||||
|
||||
} message_t;
|
||||
|
||||
/* fxlink_protocol_decode_image(): Decode an image into RGB888 format
|
||||
|
||||
This function decodes the message into an RGB888 image and returns an array
|
||||
of row pointers with the image data (free the array and each element of the
|
||||
array after use).
|
||||
|
||||
If there are not enough bytes in the input, it pads with zeros, and if there
|
||||
are extra bytes, they are dropped; in both cases a warning is printed. */
|
||||
uint8_t **fxlink_protocol_decode_image(message_t *msg);
|
||||
|
||||
#endif /* FXLINK_PROTOCOL_H */
|
Loading…
Reference in a new issue