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