/* This souce code written my Michael Rolig (email: michael_rolig@alumni.macalester.edu)
 * This can be considered to be in the public domain
 */

/* Modified for Rocket FM 2000-08-01
 * This source code is written by Sergii Guriev (email: piratfm@gmail.com)
 * exchange protocol dumped by USBlyzer (http://www.usblyzer.com/)
 * This can be considered to be in the public domain.
 */

#define DEBUG false		/* Set true for copious debugging output */
#define ROCKET_VENDID 0x077d	/* Griffin's Vendor ID */
#define ROCKET_DEVID 0x0503	/* The RocketFM's Device ID */

#define READ_EP 0x5		/* libhid read command? */
#define WRITE_EP 0x5		/* libhid write command? */
#define SEND_PACKET_LENGTH 6	/* size of an instruction packet: rocketfm=6 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <hid.h>

void usage(int argc, const char** argv) {
	printf("%s -freq <freqeuncy> [-m]\n\tchange state of RocketFM\n\n", argv[0]);
	printf("commands:\n"
		" -freq <freqeuncy>  : set FM transmitting frequency, e.g. '-freq 91.5'\n"
		" -m                 : turn off stereo transmitting (by default RocketFM transmitting in stereo)\n");
}

int main(int argc, const char** argv) {

	/* Declare variables used later */
	hid_return ret;
	HIDInterface* hid;
	HIDInterfaceMatcher matcher = { ROCKET_VENDID, ROCKET_DEVID, NULL, NULL, 0 };

	/* Build the instruction packet to send to the rocket */
	unsigned char PACKET[SEND_PACKET_LENGTH] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
	unsigned char power = 0x01;
	unsigned short encodedFreq;
	float freq;
	unsigned short stereo;
	if (argc == 3 || (argc == 4 && strcmp(argv[3], "-m") == 0)) {
		if (strcmp(argv[1], "-freq") == 0) {
			/* Setup FM transmitting frequency */
			PACKET[0] = 0xC0;
			freq = atof(argv[2]);
			encodedFreq  = freq * 10;
			
			if ( (argc == 4) && strcmp(argv[3], "-m") == 0) {
			    PACKET[1] = ((encodedFreq >> 8) & 0x07) | 0x40; /* Stereo - OFF  */
			} else {
			    PACKET[1] = ((encodedFreq >> 8) & 0x07) | 0x48; /* By default, stereo turned ON */			
			}
			
			PACKET[2] = encodedFreq & 0xFF;
			PACKET[3] = ~(2 * power + 1) & 0x0F;
			PACKET[4] = 0x00;
			PACKET[5] = 0x00;
			if (DEBUG) {
				printf("fm freq = %.1f\n", freq);
				printf("encoded freq = 0x%x\n", (unsigned int)encodedFreq);
				printf("packet = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", PACKET[0], PACKET[1], PACKET[2], PACKET[3], PACKET[4], PACKET[5]);
			}
		} else {
			/* Bad command - display the program's usage instructions */
			usage(argc, argv);
			exit(1);
		}
	} else {
		usage(argc, argv);
		exit(1);
	}

	/* Turn libhid debugging on if requested.  See include/debug.h for possible values. */
	if (DEBUG) {
		hid_set_debug(HID_DEBUG_ALL);
		hid_set_debug_stream(stderr);
		hid_set_usb_debug(0);			/* passed directly to libusb */
	}

	/* Initialize the hid library */
	ret = hid_init();
	if (ret != HID_RET_SUCCESS) {
		fprintf(stderr, "hid_init failed with return code %d\n", ret);
		return 1;
	}

	/* Initialize the hid object */
	hid = hid_new_HIDInterface();
	if (hid == 0) {
		fprintf(stderr, "hid_new_HIDInterface() failed, out of memory?\n");
		return 1;
	}

	/* Open the rocket */
	ret = hid_force_open(hid, 2, &matcher, 3);
	if (ret != HID_RET_SUCCESS) {
		fprintf(stderr, "hid_force_open failed with return code %d\n", ret);
		return 1;
	}

	/* Send the instruction packet constructed above to the RocketFM */
	ret = hid_interrupt_write(hid, WRITE_EP, (char*)PACKET, SEND_PACKET_LENGTH, 10000);
	if (ret != HID_RET_SUCCESS) fprintf(stderr, "hid_interrupt_write failed with return code %d\n", ret);

	/* Close the rocket */
	ret = hid_close(hid);
	if (ret != HID_RET_SUCCESS) {
		fprintf(stderr, "hid_close failed with return code %d\n", ret);
		return 1;
	}

	/* Delete the hid object */
	hid_delete_HIDInterface(&hid);

	/* Clean up the hid library */
	ret = hid_cleanup();
	if (ret != HID_RET_SUCCESS) {
		fprintf(stderr, "hid_cleanup failed with return code %d\n", ret);
		return 1;
	}

	return 0;
}
