test.cpp
author sl
Wed, 21 May 2014 10:19:22 +0200
changeset 8 631f53604811
parent 7 e8c05ae7f418
child 9 e6c42e1e2a96
permissions -rw-r--r--
Font selection now generates and saves a TGA sample.
     1 /*******************************************************
     2  Demo Program for HIDAPI
     3 
     4  Alan Ott
     5  Signal 11 Software
     6 
     7  2010-07-20
     8 
     9  Copyright 2010, All Rights Reserved
    10 
    11  This contents of this file may be used by anyone
    12  for any reason without any conditions and may be
    13  used as a starting point for your own applications
    14  which use HIDAPI.
    15 ********************************************************/
    16 
    17 #include "MainWindow.h"
    18 
    19 
    20 // FOX 1.7 changes the timeouts to all be nanoseconds.
    21 // Fox 1.6 had all timeouts as milliseconds.
    22 #if (FOX_MINOR >= 7)
    23 	const int timeout_scalar = 1000*1000;
    24 #else
    25 	const int timeout_scalar = 1;
    26 #endif
    27 
    28 
    29 FXDEFMAP(MainWindow) MainWindowMap [] = {
    30 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CONNECT, MainWindow::onConnect ),
    31 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_DISCONNECT, MainWindow::onDisconnect ),
    32 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_RESCAN, MainWindow::onRescan ),
    33 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_OUTPUT_REPORT, MainWindow::onSendOutputReport ),
    34 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_FEATURE_REPORT, MainWindow::onSendFeatureReport ),
    35 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_GET_FEATURE_REPORT, MainWindow::onGetFeatureReport ),
    36 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CLEAR, MainWindow::onClear ),
    37 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_CLEAR_DISPLAY, MainWindow::onFutabaClearDisplay ),
    38 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_DIMMING, MainWindow::onFutabaDimming ),
    39 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_DISPLAY_DATA_INPUT, MainWindow::onFutabaDisplayDataInput ),
    40 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_READ_ID, MainWindow::onFutabaReadId ),
    41 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_READ_FIRMWARE_REVISION, MainWindow::onFutabaReadFirmwareRevision ),
    42 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_POWER_SUPPLY_MONITOR, MainWindow::onFutabaPowerSupplyMonitor ),
    43     FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_SET_PIXEL, MainWindow::onFutabaSetPixel ),
    44 	FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_RESET_PIXEL, MainWindow::onFutabaResetPixel ),
    45     FXMAPFUNC(SEL_COMMAND, MainWindow::ID_FUTABA_SET_ALL_PIXELS, MainWindow::onFutabaSetAllPixels ),
    46     FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SELECT_FONT, MainWindow::onSelectFont ),
    47 	FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_TIMER, MainWindow::onTimeout ),
    48 	FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_MAC_TIMER, MainWindow::onMacTimeout ),
    49 };
    50 
    51 FXIMPLEMENT(MainWindow, FXMainWindow, MainWindowMap, ARRAYNUMBER(MainWindowMap));
    52 
    53 MainWindow::MainWindow(FXApp *app)
    54 	: FXMainWindow(app, "HIDAPI Test Application", NULL, NULL, DECOR_ALL, 200,100, 600,900),
    55     iCurrentFont(NULL),
    56     iFontImage(NULL)
    57 {
    58 	iDimming=0x35;
    59 	devices = NULL;
    60 	connected_device = NULL;
    61 
    62 	FXVerticalFrame *vf = new FXVerticalFrame(this, LAYOUT_FILL_Y|LAYOUT_FILL_X);
    63 
    64 	FXLabel *label = new FXLabel(vf, "HIDAPI Test Tool");
    65 	title_font = new FXFont(getApp(), "Arial", 14, FXFont::Bold);
    66 	label->setFont(title_font);
    67 
    68 	new FXLabel(vf,
    69 		"Select a device and press Connect.", NULL, JUSTIFY_LEFT);
    70 	new FXLabel(vf,
    71 		"Output data bytes can be entered in the Output section, \n"
    72 		"separated by space, comma or brackets. Data starting with 0x\n"
    73 		"is treated as hex. Data beginning with a 0 is treated as \n"
    74 		"octal. All other data is treated as decimal.", NULL, JUSTIFY_LEFT);
    75 	new FXLabel(vf,
    76 		"Data received from the device appears in the Input section.",
    77 		NULL, JUSTIFY_LEFT);
    78 	new FXLabel(vf,
    79 		"Optionally, a report length may be specified. Extra bytes are\n"
    80 		"padded with zeros. If no length is specified, the length is \n"
    81 		"inferred from the data.",
    82 		NULL, JUSTIFY_LEFT);
    83 	new FXLabel(vf, "");
    84 
    85 	// Device List and Connect/Disconnect buttons
    86 	FXHorizontalFrame *hf = new FXHorizontalFrame(vf, LAYOUT_FILL_X);
    87 	//device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0,0,300,200);
    88 	device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,300,200);
    89 	FXVerticalFrame *buttonVF = new FXVerticalFrame(hf);
    90 	connect_button = new FXButton(buttonVF, "Connect", NULL, this, ID_CONNECT, BUTTON_NORMAL|LAYOUT_FILL_X);
    91 	disconnect_button = new FXButton(buttonVF, "Disconnect", NULL, this, ID_DISCONNECT, BUTTON_NORMAL|LAYOUT_FILL_X);
    92 	disconnect_button->disable();
    93 	rescan_button = new FXButton(buttonVF, "Re-Scan devices", NULL, this, ID_RESCAN, BUTTON_NORMAL|LAYOUT_FILL_X);
    94 	new FXHorizontalFrame(buttonVF, 0, 0,0,0,0, 0,0,50,0);
    95 
    96 	connected_label = new FXLabel(vf, "Disconnected");
    97 
    98     //Font group
    99     new FXHorizontalFrame(vf);
   100     FXGroupBox *gb = new FXGroupBox(vf, "Fonts", FRAME_GROOVE|LAYOUT_FILL_X);
   101     FXMatrix *matrix = new FXMatrix(gb, 3, MATRIX_BY_COLUMNS|LAYOUT_FILL_X);
   102     iButtonSelectFont = new FXButton(matrix, "Select Font", NULL, this, ID_SELECT_FONT, BUTTON_NORMAL|LAYOUT_FILL_X);
   103 
   104 	//Futaba VFD commands
   105 	new FXHorizontalFrame(vf);
   106 	gb = new FXGroupBox(vf, "Futaba GP1212A01A", FRAME_GROOVE|LAYOUT_FILL_X);
   107 	matrix = new FXMatrix(gb, 3, MATRIX_BY_COLUMNS|LAYOUT_FILL_X);
   108 	iButtonClearDisplay = new FXButton(matrix, "Clear Display", NULL, this, ID_FUTABA_CLEAR_DISPLAY, BUTTON_NORMAL|LAYOUT_FILL_X);
   109 	iButtonDimming = new FXButton(matrix, "Dimming", NULL, this, ID_FUTABA_DIMMING, BUTTON_NORMAL|LAYOUT_FILL_X);
   110 	iButtonDisplayDataInput = new FXButton(matrix, "Display Data Input", NULL, this, ID_FUTABA_DISPLAY_DATA_INPUT, BUTTON_NORMAL|LAYOUT_FILL_X);
   111 	iButtonReadId = new FXButton(matrix, "Read Id", NULL, this, ID_FUTABA_READ_ID, BUTTON_NORMAL|LAYOUT_FILL_X);
   112 	iButtonReadFirmwareRevision =  new FXButton(matrix, "Read Firmware Revision", NULL, this, ID_FUTABA_READ_FIRMWARE_REVISION, BUTTON_NORMAL|LAYOUT_FILL_X);
   113 	iButtonPowerSupplyMonitor = new FXButton(matrix, "Power Supply Monitor", NULL, this, ID_FUTABA_POWER_SUPPLY_MONITOR, BUTTON_NORMAL|LAYOUT_FILL_X);
   114     new FXLabel(matrix, "X",NULL,LABEL_NORMAL|LAYOUT_FILL_X);
   115     new FXLabel(matrix, "Y",NULL,LABEL_NORMAL|LAYOUT_FILL_X);
   116     new FXLabel(matrix, "",NULL,LABEL_NORMAL|LAYOUT_FILL_X);
   117     iTextFieldX = new FXTextField(matrix, 3, NULL, 0, TEXTFIELD_NORMAL|TEXTFIELD_INTEGER|LAYOUT_FILL_X);
   118     iTextFieldY = new FXTextField(matrix, 3, NULL, 0, TEXTFIELD_NORMAL|TEXTFIELD_INTEGER|LAYOUT_FILL_X);
   119     iButtonSetPixel = new FXButton(matrix, "Set Pixel", NULL, this, ID_FUTABA_SET_PIXEL, BUTTON_NORMAL|LAYOUT_FILL_X);
   120 	iButtonResetPixel = new FXButton(matrix, "Reset Pixel", NULL, this, ID_FUTABA_RESET_PIXEL, BUTTON_NORMAL|LAYOUT_FILL_X);
   121     //
   122     iButtonSetAllPixels = new FXButton(matrix, "Set All Pixels", NULL, this, ID_FUTABA_SET_ALL_PIXELS, BUTTON_NORMAL|LAYOUT_FILL_X);
   123     //
   124 
   125 	//
   126 	iButtonClearDisplay->disable();
   127 	iButtonDimming->disable();
   128 	iButtonDisplayDataInput->disable();
   129 	iButtonReadId->disable();
   130 	iButtonReadFirmwareRevision->disable();
   131 	iButtonPowerSupplyMonitor->disable();
   132     iTextFieldX->disable();
   133     iTextFieldY->disable();
   134     iButtonSetPixel->disable();
   135 	iButtonResetPixel->disable();
   136     iButtonSetAllPixels->disable();
   137 	//
   138 
   139 	// Output Group Box
   140 	new FXHorizontalFrame(vf);
   141 	gb = new FXGroupBox(vf, "Output", FRAME_GROOVE|LAYOUT_FILL_X);
   142 	matrix = new FXMatrix(gb, 3, MATRIX_BY_COLUMNS|LAYOUT_FILL_X);
   143 	new FXLabel(matrix, "Data");
   144 	new FXLabel(matrix, "Length");
   145 	new FXLabel(matrix, "");
   146 
   147 	//hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X);
   148 	output_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
   149 	output_text->setText("1 0x81 0");
   150 	output_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
   151 	output_button = new FXButton(matrix, "Send Output Report", NULL, this, ID_SEND_OUTPUT_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
   152 	output_button->disable();
   153 	//new FXHorizontalFrame(matrix, LAYOUT_FILL_X);
   154 
   155 	//hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X);
   156 	feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
   157 	feature_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
   158 	feature_button = new FXButton(matrix, "Send Feature Report", NULL, this, ID_SEND_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
   159 	feature_button->disable();
   160 
   161 	get_feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
   162 	new FXWindow(matrix);
   163 	get_feature_button = new FXButton(matrix, "Get Feature Report", NULL, this, ID_GET_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
   164 	get_feature_button->disable();
   165 
   166 
   167 	// Input Group Box
   168 	gb = new FXGroupBox(vf, "Input", FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
   169 	FXVerticalFrame *innerVF = new FXVerticalFrame(gb, LAYOUT_FILL_X|LAYOUT_FILL_Y);
   170 	input_text = new FXText(new FXHorizontalFrame(innerVF,LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y);
   171 	input_text->setEditable(false);
   172 	new FXButton(innerVF, "Clear", NULL, this, ID_CLEAR, BUTTON_NORMAL|LAYOUT_RIGHT);
   173 
   174 
   175 }
   176 
   177 MainWindow::~MainWindow()
   178 {
   179     delete iCurrentFont;
   180     iCurrentFont = NULL;
   181 
   182     delete iFontImage;
   183     iFontImage = NULL;
   184 
   185 	if (connected_device)
   186 		hid_close(connected_device);
   187 	hid_exit();
   188 	delete title_font;
   189 }
   190 
   191 void
   192 MainWindow::create()
   193 {
   194 	FXMainWindow::create();
   195 	show();
   196 
   197 	onRescan(NULL, 0, NULL);
   198 
   199 
   200 #ifdef __APPLE__
   201 	init_apple_message_system();
   202 #endif
   203 
   204 	getApp()->addTimeout(this, ID_MAC_TIMER,
   205 		50 * timeout_scalar /*50ms*/);
   206 }
   207 
   208 long
   209 MainWindow::onConnect(FXObject *sender, FXSelector sel, void *ptr)
   210 {
   211 	if (connected_device != NULL)
   212 		return 1;
   213 
   214 	FXint cur_item = device_list->getCurrentItem();
   215 	if (cur_item < 0)
   216 		return -1;
   217 	FXListItem *item = device_list->getItem(cur_item);
   218 	if (!item)
   219 		return -1;
   220 	struct hid_device_info *device_info = (struct hid_device_info*) item->getData();
   221 	if (!device_info)
   222 		return -1;
   223 
   224 	connected_device =  hid_open_path(device_info->path);
   225 
   226 	if (!connected_device) {
   227 		FXMessageBox::error(this, MBOX_OK, "Device Error", "Unable To Connect to Device");
   228 		return -1;
   229 	}
   230 
   231 	hid_set_nonblocking(connected_device, 1);
   232 
   233 	getApp()->addTimeout(this, ID_TIMER,
   234 		5 * timeout_scalar /*5ms*/);
   235 
   236 	FXString s;
   237 	s.format("Connected to: %04hx:%04hx -", device_info->vendor_id, device_info->product_id);
   238 	s += FXString(" ") + device_info->manufacturer_string;
   239 	s += FXString(" ") + device_info->product_string;
   240 	connected_label->setText(s);
   241 	output_button->enable();
   242 	feature_button->enable();
   243 	get_feature_button->enable();
   244 	connect_button->disable();
   245 	disconnect_button->enable();
   246 	input_text->setText("");
   247 	//
   248 	iButtonClearDisplay->enable();
   249 	iButtonDimming->enable();
   250 	iButtonDisplayDataInput->enable();
   251 	iButtonReadId->enable();
   252 	iButtonReadFirmwareRevision->enable();
   253 	iButtonPowerSupplyMonitor->enable();
   254     iTextFieldX->enable();
   255     iTextFieldY->enable();
   256     iButtonSetPixel->enable();
   257 	iButtonResetPixel->enable();
   258     iButtonSetAllPixels->enable();
   259 
   260 	//
   261 	iOutputReportBuffer=new unsigned char[KFutabaOutputReportLength]; //TODO: use connected_device->output_report_length
   262 
   263 	return 1;
   264 }
   265 
   266 long
   267 MainWindow::onDisconnect(FXObject *sender, FXSelector sel, void *ptr)
   268 {
   269 	hid_close(connected_device);
   270 	connected_device = NULL;
   271 	connected_label->setText("Disconnected");
   272 	output_button->disable();
   273 	feature_button->disable();
   274 	get_feature_button->disable();
   275 	connect_button->enable();
   276 	disconnect_button->disable();
   277 
   278 	getApp()->removeTimeout(this, ID_TIMER);
   279 
   280 	//
   281 	iButtonClearDisplay->disable();
   282 	iButtonDimming->disable();
   283 	iButtonDisplayDataInput->disable();
   284 	iButtonReadId->disable();
   285 	iButtonReadFirmwareRevision->disable();
   286 	iButtonPowerSupplyMonitor->disable();
   287     iTextFieldX->disable();
   288     iTextFieldY->disable();
   289     iButtonSetPixel->disable();
   290 	iButtonResetPixel->disable();
   291     iButtonSetAllPixels->disable();
   292 	//
   293 
   294 
   295 	delete iOutputReportBuffer;
   296 	iOutputReportBuffer=NULL;
   297 
   298 	return 1;
   299 }
   300 
   301 long
   302 MainWindow::onRescan(FXObject *sender, FXSelector sel, void *ptr)
   303 {
   304 	struct hid_device_info *cur_dev;
   305 
   306 	device_list->clearItems();
   307 
   308 	//Define Futaba vendor ID to filter our list of device
   309 	const unsigned short KFutabaVendorId = 0x1008;
   310 
   311 	// List the Devices
   312 	hid_free_enumeration(devices);
   313 	devices = hid_enumerate(0x0, 0x0);
   314 	cur_dev = devices;
   315 	while (cur_dev) {
   316 		// Add it to the List Box only if it is a Futaba device
   317 		if (cur_dev->vendor_id == KFutabaVendorId)
   318 			{
   319 			FXString s;
   320 			FXString usage_str;
   321 			s.format("%04hx:%04hx -", cur_dev->vendor_id, cur_dev->product_id);
   322 			s += FXString(" ") + cur_dev->manufacturer_string;
   323 			s += FXString(" ") + cur_dev->product_string;
   324 			usage_str.format(" (usage: %04hx:%04hx) ", cur_dev->usage_page, cur_dev->usage);
   325 			s += usage_str;
   326 			FXListItem *li = new FXListItem(s, NULL, cur_dev);
   327 			device_list->appendItem(li);
   328 			}
   329 
   330 		cur_dev = cur_dev->next;
   331 	}
   332 
   333 	if (device_list->getNumItems() == 0)
   334 		device_list->appendItem("*** No Devices Connected ***");
   335 	else {
   336 		device_list->selectItem(0);
   337 	}
   338 
   339 	return 1;
   340 }
   341 
   342 size_t
   343 MainWindow::getDataFromTextField(FXTextField *tf, char *buf, size_t len)
   344 {
   345 	const char *delim = " ,{}\t\r\n";
   346 	FXString data = tf->getText();
   347 	const FXchar *d = data.text();
   348 	size_t i = 0;
   349 
   350 	// Copy the string from the GUI.
   351 	size_t sz = strlen(d);
   352 	char *str = (char*) malloc(sz+1);
   353 	strcpy(str, d);
   354 
   355 	// For each token in the string, parse and store in buf[].
   356 	char *token = strtok(str, delim);
   357 	while (token) {
   358 		char *endptr;
   359 		long int val = strtol(token, &endptr, 0);
   360 		buf[i++] = val;
   361 		token = strtok(NULL, delim);
   362 	}
   363 
   364 	free(str);
   365 	return i;
   366 }
   367 
   368 /* getLengthFromTextField()
   369    Returns length:
   370 	 0: empty text field
   371 	>0: valid length
   372 	-1: invalid length */
   373 int
   374 MainWindow::getLengthFromTextField(FXTextField *tf)
   375 {
   376 	long int len;
   377 	FXString str = tf->getText();
   378 	size_t sz = str.length();
   379 
   380 	if (sz > 0) {
   381 		char *endptr;
   382 		len = strtol(str.text(), &endptr, 0);
   383 		if (endptr != str.text() && *endptr == '\0') {
   384 			if (len <= 0) {
   385 				FXMessageBox::error(this, MBOX_OK, "Invalid length", "Enter a length greater than zero.");
   386 				return -1;
   387 			}
   388 			return len;
   389 		}
   390 		else
   391 			return -1;
   392 	}
   393 
   394 	return 0;
   395 }
   396 
   397 long
   398 MainWindow::onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr)
   399 {
   400 	char buf[256];
   401 	size_t data_len, len;
   402 	int textfield_len;
   403 
   404 	memset(buf, 0x0, sizeof(buf));
   405 	textfield_len = getLengthFromTextField(output_len);
   406 	data_len = getDataFromTextField(output_text, buf, sizeof(buf));
   407 
   408 	if (textfield_len < 0) {
   409 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
   410 		return 1;
   411 	}
   412 
   413 	if (textfield_len > sizeof(buf)) {
   414 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
   415 		return 1;
   416 	}
   417 
   418 	len = (textfield_len)? textfield_len: data_len;
   419 
   420 	int res = hid_write(connected_device, (const unsigned char*)buf, len);
   421 	if (res < 0) {
   422 		FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not write to device. Error reported was: %ls", hid_error(connected_device));
   423 	}
   424 
   425 	return 1;
   426 }
   427 
   428 long
   429 MainWindow::onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
   430 {
   431 	char buf[256];
   432 	size_t data_len, len;
   433 	int textfield_len;
   434 
   435 	memset(buf, 0x0, sizeof(buf));
   436 	textfield_len = getLengthFromTextField(feature_len);
   437 	data_len = getDataFromTextField(feature_text, buf, sizeof(buf));
   438 
   439 	if (textfield_len < 0) {
   440 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
   441 		return 1;
   442 	}
   443 
   444 	if (textfield_len > sizeof(buf)) {
   445 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
   446 		return 1;
   447 	}
   448 
   449 	len = (textfield_len)? textfield_len: data_len;
   450 
   451 	int res = hid_send_feature_report(connected_device, (const unsigned char*)buf, len);
   452 	if (res < 0) {
   453 		FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not send feature report to device. Error reported was: %ls", hid_error(connected_device));
   454 	}
   455 
   456 	return 1;
   457 }
   458 
   459 long
   460 MainWindow::onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
   461 {
   462 	char buf[256];
   463 	size_t len;
   464 
   465 	memset(buf, 0x0, sizeof(buf));
   466 	len = getDataFromTextField(get_feature_text, buf, sizeof(buf));
   467 
   468 	if (len != 1) {
   469 		FXMessageBox::error(this, MBOX_OK, "Too many numbers", "Enter only a single report number in the text field");
   470 	}
   471 
   472 	int res = hid_get_feature_report(connected_device, (unsigned char*)buf, sizeof(buf));
   473 	if (res < 0) {
   474 		FXMessageBox::error(this, MBOX_OK, "Error Getting Report", "Could not get feature report from device. Error reported was: %ls", hid_error(connected_device));
   475 	}
   476 
   477 	if (res > 0) {
   478 		FXString s;
   479 		s.format("Returned Feature Report. %d bytes:\n", res);
   480 		for (int i = 0; i < res; i++) {
   481 			FXString t;
   482 			t.format("%02hhx ", buf[i]);
   483 			s += t;
   484 			if ((i+1) % 4 == 0)
   485 				s += " ";
   486 			if ((i+1) % 16 == 0)
   487 				s += "\n";
   488 		}
   489 		s += "\n";
   490 		input_text->appendText(s);
   491 		input_text->setBottomLine(INT_MAX);
   492 	}
   493 
   494 	return 1;
   495 }
   496 
   497 long
   498 MainWindow::onClear(FXObject *sender, FXSelector sel, void *ptr)
   499 {
   500 	input_text->setText("");
   501 	return 1;
   502 }
   503 
   504 
   505 long
   506 MainWindow::onFutabaClearDisplay(FXObject *sender, FXSelector sel, void *ptr)
   507 {
   508 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   509 	iOutputReportBuffer[0]=0x00; //Report ID
   510 	iOutputReportBuffer[1]=0x04; //Report length
   511 	iOutputReportBuffer[2]=0x1B; //
   512 	iOutputReportBuffer[3]=0x5B; //
   513 	iOutputReportBuffer[4]=0x32; //
   514 	iOutputReportBuffer[5]=0x4A; //
   515 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   516 
   517 	return 1;
   518 }
   519 
   520 long
   521 MainWindow::onFutabaDimming(FXObject *sender, FXSelector sel, void *ptr)
   522 {
   523 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   524 	iOutputReportBuffer[0]=0x00; //Report ID
   525 	iOutputReportBuffer[1]=0x06; //Report length
   526 	iOutputReportBuffer[2]=0x1B; //
   527 	iOutputReportBuffer[3]=0x5C; //
   528 	iOutputReportBuffer[4]=0x3F; //
   529 	iOutputReportBuffer[5]=0x4C; //
   530 	iOutputReportBuffer[6]=0x44; //
   531 	iDimming = (iDimming==0x35?0x30:++iDimming);
   532 	iOutputReportBuffer[7]=iDimming;
   533 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   534 
   535 	return 1;
   536 }
   537 
   538 long
   539 MainWindow::onFutabaDisplayDataInput(FXObject *sender, FXSelector sel, void *ptr)
   540 {
   541 	//@1B 5B F0 00 00 07 00 01 FF
   542 
   543 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   544 	iOutputReportBuffer[0]=0x00; //Report ID
   545 	iOutputReportBuffer[1]=0x09; //Report length
   546 	iOutputReportBuffer[2]=0x1B; //
   547 	iOutputReportBuffer[3]=0x5B; //
   548 	iOutputReportBuffer[4]=0xF0; //
   549 	iOutputReportBuffer[5]=0x00; //X
   550 	iOutputReportBuffer[6]=0x00; //Y
   551 	iOutputReportBuffer[7]=0x07; //
   552 	iOutputReportBuffer[8]=0x00; //
   553 	iOutputReportBuffer[9]=0x01; //
   554 	iOutputReportBuffer[10]=0xFF; //
   555 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   556 
   557 
   558 	return 1;
   559 }
   560 
   561 
   562 
   563 
   564 /**
   565 Set a single pixel to the specified value.
   566 @param X coordinate of our pixel.
   567 @param Y coordinate of our pixel.
   568 @param The LSB defines our pixel value.
   569 */
   570 void MainWindow::SetPixel(int aX, int aY, unsigned char aValue)
   571 	{
   572 	//Just specify a one pixel block
   573 	SetPixelBlock(aX,aY,0x00,0x01,aValue);
   574 	}
   575 
   576 /**
   577 */
   578 void MainWindow::SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char aValue)
   579 	{
   580 	//Size must be 63 or below
   581 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   582 	iOutputReportBuffer[0]=0x00; //Report ID
   583 	iOutputReportBuffer[1]=0x08+aSize; //Report length
   584 	iOutputReportBuffer[2]=0x1B; //
   585 	iOutputReportBuffer[3]=0x5B; //
   586 	iOutputReportBuffer[4]=0xF0; //
   587 	iOutputReportBuffer[5]=aX; //X
   588 	iOutputReportBuffer[6]=aY; //Y
   589 	iOutputReportBuffer[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other.
   590 	iOutputReportBuffer[8]=0x00; //Size of pixel data in bytes (MSB)
   591 	iOutputReportBuffer[9]=aSize; //Size of pixel data in bytes (LSB)
   592 	memset(iOutputReportBuffer+10, aValue, KFutabaOutputReportLength);
   593 	//iOutputReportBuffer[10]=aValue; //Pixel data
   594 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   595 	}
   596 
   597 
   598 /**
   599 */
   600 long MainWindow::onFutabaSetPixel(FXObject *sender, FXSelector sel, void *ptr)
   601 {
   602 	int x=0;
   603 	int y=0;
   604 	iTextFieldX->getText().scan("%d",&x);
   605 	iTextFieldY->getText().scan("%d",&y);
   606     SetPixel(x,y,0x01);
   607 	return 1;
   608 }
   609 
   610 /**
   611 */
   612 long MainWindow::onFutabaResetPixel(FXObject *sender, FXSelector sel, void *ptr)
   613 {
   614 	int x=0;
   615 	int y=0;
   616 	iTextFieldX->getText().scan("%d",&x);
   617 	iTextFieldY->getText().scan("%d",&y);
   618     SetPixel(x,y,0x00);
   619     return 1;
   620 }
   621 
   622 long MainWindow::onFutabaSetAllPixels(FXObject *sender, FXSelector sel, void *ptr)
   623 	{
   624 	//One pixel at a time
   625 	/*
   626 	for (int i=0;i<256;i++)
   627 		{
   628 		for (int j=0;j<64;j++)
   629 			{
   630 			SetPixel(i,j,0x01);
   631 			}
   632 		}
   633 	*/
   634 	//16x16=256 pixels at a time goes much faster
   635 	for (int i=0;i<256;i+=16)
   636 		{
   637 		for (int j=0;j<64;j+=16)
   638 			{
   639 			SetPixelBlock(i,j,15,32,0xFF);
   640 			//FXThread::sleep(1000000000);
   641 			}
   642 		}
   643 
   644     return 1;
   645 	}
   646 
   647 long
   648 MainWindow::onFutabaReadId(FXObject *sender, FXSelector sel, void *ptr)
   649 {
   650 	//1BH,5BH,63H,49H,44H
   651 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   652 	iOutputReportBuffer[0]=0x00; //Report ID
   653 	iOutputReportBuffer[1]=0x05; //Report length
   654 	iOutputReportBuffer[2]=0x1B; //
   655 	iOutputReportBuffer[3]=0x5B; //
   656 	iOutputReportBuffer[4]=0x63; //
   657 	iOutputReportBuffer[5]=0x49; //
   658 	iOutputReportBuffer[6]=0x44; //
   659 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   660 
   661 	return 1;
   662 }
   663 
   664 long
   665 MainWindow::onFutabaReadFirmwareRevision(FXObject *sender, FXSelector sel, void *ptr)
   666 {
   667 	//1BH,5BH,63H,46H,52H
   668 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   669 	iOutputReportBuffer[0]=0x00; //Report ID
   670 	iOutputReportBuffer[1]=0x05; //Report length
   671 	iOutputReportBuffer[2]=0x1B; //
   672 	iOutputReportBuffer[3]=0x5B; //
   673 	iOutputReportBuffer[4]=0x63; //
   674 	iOutputReportBuffer[5]=0x46; //
   675 	iOutputReportBuffer[6]=0x52; //
   676 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   677 
   678 	return 1;
   679 }
   680 
   681 long
   682 MainWindow::onFutabaPowerSupplyMonitor(FXObject *sender, FXSelector sel, void *ptr)
   683 {
   684 	//1BH,5BH,63H,50H,4DH
   685 	memset(iOutputReportBuffer, 0x0, KFutabaOutputReportLength);
   686 	iOutputReportBuffer[0]=0x00; //Report ID
   687 	iOutputReportBuffer[1]=0x05; //Report length
   688 	iOutputReportBuffer[2]=0x1B; //
   689 	iOutputReportBuffer[3]=0x5B; //
   690 	iOutputReportBuffer[4]=0x63; //
   691 	iOutputReportBuffer[5]=0x50; //
   692 	iOutputReportBuffer[6]=0x4D; //
   693 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaOutputReportLength);
   694 
   695 	return 1;
   696 }
   697 
   698 
   699 
   700 long
   701 MainWindow::onTimeout(FXObject *sender, FXSelector sel, void *ptr)
   702 {
   703 	unsigned char buf[256];
   704 	int res = hid_read(connected_device, buf, sizeof(buf));
   705 
   706 	if (res > 0) {
   707 		FXString s;
   708 		s.format("Received %d bytes:\n", res);
   709 		for (int i = 0; i < res; i++) {
   710 			FXString t;
   711 			t.format("%02hhx ", buf[i]);
   712 			s += t;
   713 			if ((i+1) % 4 == 0)
   714 				s += " ";
   715 			if ((i+1) % 16 == 0)
   716 				s += "\n";
   717 		}
   718 		s += "\n";
   719 		input_text->appendText(s);
   720 		input_text->setBottomLine(INT_MAX);
   721 	}
   722 	if (res < 0) {
   723 		input_text->appendText("hid_read() returned error\n");
   724 		input_text->setBottomLine(INT_MAX);
   725 	}
   726 
   727 	getApp()->addTimeout(this, ID_TIMER,
   728 		5 * timeout_scalar /*5ms*/);
   729 	return 1;
   730 }
   731 
   732 long
   733 MainWindow::onMacTimeout(FXObject *sender, FXSelector sel, void *ptr)
   734 {
   735 #ifdef __APPLE__
   736 	check_apple_events();
   737 
   738 	getApp()->addTimeout(this, ID_MAC_TIMER,
   739 		50 * timeout_scalar /*50ms*/);
   740 #endif
   741 
   742 	return 1;
   743 }
   744 
   745 /**
   746 
   747 */
   748 long MainWindow::onSelectFont(FXObject *sender, FXSelector sel, void *ptr)
   749     {
   750     FXFontDialog* dlg=new FXFontDialog(this,"Pick a font");
   751     if (dlg->execute())
   752         {
   753         dlg->getFontSelection(iCurrentFontDesc);
   754         delete iCurrentFont;
   755         iCurrentFont = NULL;
   756         iCurrentFont = new FXFont(getApp(),iCurrentFontDesc);
   757         iCurrentFont->create();
   758         //
   759         delete iFontImage;
   760         iFontImage = NULL;
   761         //
   762         FXString text="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-[]{}();%$£&~#|_";
   763         //Create an image the proper size for our text
   764         iFontImage = new FXTGAImage(getApp(),NULL,IMAGE_SHMI|IMAGE_SHMP,iCurrentFont->getTextWidth(text),iCurrentFont->getFontHeight());
   765         iFontImage->create();
   766         //Perform our drawing
   767             {
   768             FXDCWindow dc(iFontImage);
   769             //dc.begin(iFontImage);
   770             dc.setFont(iCurrentFont);
   771             dc.setForeground(0xFFFFFFFF);
   772             //dc.setBackground(0xFF000000);
   773             //dc.setFillStyle(FILL_SOLID);
   774             dc.fillRectangle(0,0,iFontImage->getWidth(),iFontImage->getHeight());
   775             dc.setForeground(0xFF000000);
   776             dc.drawText(0,iCurrentFont->getFontAscent(),text);
   777             //dc.end();
   778             }
   779         FXFileStream file;
   780         file.open("fonttest.tga",FXStreamSave);
   781         iFontImage->restore();
   782         iFontImage->savePixels(file);
   783         file.close();
   784 
   785         //
   786 
   787         }
   788 
   789     delete dlg;
   790     return 1;
   791     }
   792 
   793 
   794