Add push mode

This commit is contained in:
Heath Mitchell 2023-01-17 23:02:29 +00:00
parent 7b2294d8c0
commit 6849c1624e
4 changed files with 147 additions and 4 deletions

View File

@ -43,7 +43,7 @@ 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/interactive.c
add_executable(fxlink fxlink/usb.c fxlink/filter.c fxlink/interactive.c fxlink/push.c
fxlink/main.c fxlink/png.c fxlink/properties.c fxlink/ud2.c fxlink/util.c
fxlink/protocol.c fxlink/sdl2.c)
target_link_libraries(fxlink PkgConfig::libpng PkgConfig::libusb)

View File

@ -28,6 +28,9 @@ int main_blocks(filter_t *filter, delay_t *delay);
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);
int main_interactive(filter_t *filter, delay_t *delay, libusb_context *context);
/* Main function for -p */
int main_push(filter_t *filter, delay_t *delay, libusb_context *context, char **files);
#endif /* FXLINK_FXLINK_H */

View File

@ -30,6 +30,7 @@ static const char *help_string =
" -b, --blocks List detected Mass Storage filesystems (udisks2)\n"
" -s, --send Send a file to a Mass Storage calculator (udisks2)\n"
" -i, --interactive Interactive messaging with a gint add-in (libusb)\n"
" -p, --push Push a .bin file to the Add-In Push app (libusb)\n"
"\n"
"General options:\n"
" -w DELAY Wait up to this many seconds for a calculator to\n"
@ -87,6 +88,7 @@ int main(int argc, char **argv)
{ "blocks", no_argument, NULL, 'b' },
{ "send", no_argument, NULL, 's' },
{ "interactive", no_argument, NULL, 'i' },
{ "push", no_argument, NULL, 'p' },
{ "libusb-log", required_argument, NULL, LIBUSB_LOG },
{ "quiet", no_argument, NULL, 'q' },
{ "fxlink-log", optional_argument, NULL, LOG_TO_FILE },
@ -95,7 +97,7 @@ int main(int argc, char **argv)
};
while(option >= 0 && option != '?')
switch((option = getopt_long(argc, argv, "hlbsiquf:w::r", longs, NULL)))
switch((option = getopt_long(argc, argv, "hlbsipquf:w::r", longs, NULL)))
{
case 'h':
fprintf(stderr, help_string, argv[0]);
@ -104,6 +106,7 @@ int main(int argc, char **argv)
case 'b':
case 's':
case 'i':
case 'p':
mode = option;
break;
case LIBUSB_LOG:
@ -163,6 +166,11 @@ int main(int argc, char **argv)
if(mode == 's' && optind == argc)
error = err("send mode requires additional arguments (file names)");
if(mode == 'p' && optind == argc)
error = err("push mode requires a file name");
if(mode == 'p' && optind < argc-1)
error = err("push mode only accepts one file name");
/* No arguments or bad arguments */
if(error)
return 1;
@ -178,7 +186,7 @@ int main(int argc, char **argv)
libusb_context *context = NULL;
/* Initialize libusb for corresponding modes */
if(mode == 'l' || mode == 'i') {
if(mode == 'l' || mode == 'i' || mode == 'p') {
if((rc = libusb_init(&context)))
return libusb_err(rc, "error initializing libusb");
libusb_set_option(context, LIBUSB_OPTION_LOG_LEVEL, loglevel);
@ -211,6 +219,9 @@ int main(int argc, char **argv)
}
while(repeat);
}
else if(mode == 'p') {
rc = main_push(filter, &delay, context, argv + optind);
}
if(context)
libusb_exit(context);

129
fxlink/push.c Normal file
View File

@ -0,0 +1,129 @@
#include "config.h"
#include "fxlink.h"
#include "util.h"
#include "properties.h"
#include "filter.h"
#include "usb.h"
#include <libusb.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main_push(filter_t *filter, delay_t *delay, libusb_context *context, char** files)
{
int rc = 1;
libusb_device *dev = NULL;
libusb_device_handle *dh = NULL;
FILE *fp = fopen(files[0], "rb");
if (!fp) {
printf("error: Unable to open file %s\n", files[0]);
goto end;
}
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
// If more than 6MB, abort
if (fsize > 6 * 1024 * 1024) {
printf("error: File is too large (max 6MB)\n");
goto end;
}
fseek(fp, 0, SEEK_SET);
uint8_t *filebuf = malloc(fsize);
fread(filebuf, fsize, 1, fp);
fclose(fp);
/* Wait for a device to be connected */
filter_clean_libusb(filter);
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\n", usb_id(dev));
// Wait to receive "USB loader ready" over USB bulk transfer
uint8_t buf[18];
while (1)
{
int actual_length;
rc = libusb_bulk_transfer(dh, 0x82, buf, sizeof(buf) - 1, &actual_length, 0);
buf[sizeof(buf) - 1] = 0;
// if (rc == LIBUSB_ERROR_TIMEOUT) continue;
if (rc) {
rc = libusb_err(rc, "cannot receive data: %s", usb_id(dev));
goto end;
}
if (actual_length == 0) continue;
if (actual_length != 17) {
printf("error: Received %d bytes, expected 17\n", actual_length);
goto end;
}
// See if it's the "USB loader ready" message with strcmp
if (strcmp((char*) buf, "USB loader ready") == 0) {
printf("Ready to send!\n");
break;
} else {
printf("error: Unknown message received: %s\n", buf);
goto end;
}
}
// Send the contents of the passed file over USB bulk transfer
// First send the size of the file
uint8_t sizebuf[4];
sizebuf[0] = (fsize >> 24) & 0xFF;
sizebuf[1] = (fsize >> 16) & 0xFF;
sizebuf[2] = (fsize >> 8) & 0xFF;
sizebuf[3] = fsize & 0xFF;
rc = libusb_bulk_transfer(dh, 0x01, sizebuf, sizeof(sizebuf), NULL, 0);
if (rc) {
rc = libusb_err(rc, "cannot send size: %s", usb_id(dev));
goto end;
}
// Then send the file contents
printf("Sending %ld bytes\n", fsize);
int sent = 0;
while (sent < fsize) {
int actual_length;
rc = libusb_bulk_transfer(dh, 0x01, filebuf + sent, fsize - sent, &actual_length, 0);
if (rc) {
rc = libusb_err(rc, "cannot send data: %s", usb_id(dev));
goto end;
}
sent += actual_length;
}
printf("Sent %d bytes\n", sent);
end:
if(dh) {
libusb_release_interface(dh, 0);
libusb_close(dh);
}
if(dev) libusb_unref_device(dev);
return rc;
}