src/test.cpp
author sl
Thu, 22 May 2014 07:50:02 +0200
changeset 14 4a5538e0ccbf
parent 12 7268128148b8
child 15 e5b84f315be7
permissions -rw-r--r--
Moving base HID classes into separate files.
     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 	//Just testing our new VFD class
   200 	if (iVfd01.Open())
   201         {
   202 	    iVfd01.SetAllPixels(true);
   203 	    iVfd01.Close();
   204         }
   205 
   206 #ifdef __APPLE__
   207 	init_apple_message_system();
   208 #endif
   209 
   210 	getApp()->addTimeout(this, ID_MAC_TIMER,
   211 		50 * timeout_scalar /*50ms*/);
   212 }
   213 
   214 long
   215 MainWindow::onConnect(FXObject *sender, FXSelector sel, void *ptr)
   216 {
   217 	if (connected_device != NULL)
   218 		return 1;
   219 
   220 	FXint cur_item = device_list->getCurrentItem();
   221 	if (cur_item < 0)
   222 		return -1;
   223 	FXListItem *item = device_list->getItem(cur_item);
   224 	if (!item)
   225 		return -1;
   226 	struct hid_device_info *device_info = (struct hid_device_info*) item->getData();
   227 	if (!device_info)
   228 		return -1;
   229 
   230 	connected_device =  hid_open_path(device_info->path);
   231 
   232 	if (!connected_device) {
   233 		FXMessageBox::error(this, MBOX_OK, "Device Error", "Unable To Connect to Device");
   234 		return -1;
   235 	}
   236 
   237 	hid_set_nonblocking(connected_device, 1);
   238 
   239 	getApp()->addTimeout(this, ID_TIMER,
   240 		5 * timeout_scalar /*5ms*/);
   241 
   242 	FXString s;
   243 	s.format("Connected to: %04hx:%04hx -", device_info->vendor_id, device_info->product_id);
   244 	s += FXString(" ") + device_info->manufacturer_string;
   245 	s += FXString(" ") + device_info->product_string;
   246 	connected_label->setText(s);
   247 	output_button->enable();
   248 	feature_button->enable();
   249 	get_feature_button->enable();
   250 	connect_button->disable();
   251 	disconnect_button->enable();
   252 	input_text->setText("");
   253 	//
   254 	iButtonClearDisplay->enable();
   255 	iButtonDimming->enable();
   256 	iButtonDisplayDataInput->enable();
   257 	iButtonReadId->enable();
   258 	iButtonReadFirmwareRevision->enable();
   259 	iButtonPowerSupplyMonitor->enable();
   260     iTextFieldX->enable();
   261     iTextFieldY->enable();
   262     iButtonSetPixel->enable();
   263 	iButtonResetPixel->enable();
   264     iButtonSetAllPixels->enable();
   265 
   266 	//
   267 	iOutputReportBuffer=new unsigned char[KFutabaMaxHidReportSize]; //TODO: use connected_device->output_report_length
   268 
   269 	return 1;
   270 }
   271 
   272 long
   273 MainWindow::onDisconnect(FXObject *sender, FXSelector sel, void *ptr)
   274 {
   275 	hid_close(connected_device);
   276 	connected_device = NULL;
   277 	connected_label->setText("Disconnected");
   278 	output_button->disable();
   279 	feature_button->disable();
   280 	get_feature_button->disable();
   281 	connect_button->enable();
   282 	disconnect_button->disable();
   283 
   284 	getApp()->removeTimeout(this, ID_TIMER);
   285 
   286 	//
   287 	iButtonClearDisplay->disable();
   288 	iButtonDimming->disable();
   289 	iButtonDisplayDataInput->disable();
   290 	iButtonReadId->disable();
   291 	iButtonReadFirmwareRevision->disable();
   292 	iButtonPowerSupplyMonitor->disable();
   293     iTextFieldX->disable();
   294     iTextFieldY->disable();
   295     iButtonSetPixel->disable();
   296 	iButtonResetPixel->disable();
   297     iButtonSetAllPixels->disable();
   298 	//
   299 
   300 
   301 	delete iOutputReportBuffer;
   302 	iOutputReportBuffer=NULL;
   303 
   304 	return 1;
   305 }
   306 
   307 long
   308 MainWindow::onRescan(FXObject *sender, FXSelector sel, void *ptr)
   309 {
   310 	struct hid_device_info *cur_dev;
   311 
   312 	device_list->clearItems();
   313 
   314 	// List the Devices
   315 	hid_free_enumeration(devices);
   316 	devices = hid_enumerate(0x0, 0x0);
   317 	cur_dev = devices;
   318 	while (cur_dev) {
   319 		// Add it to the List Box only if it is a Futaba device
   320 		if (cur_dev->vendor_id == KFutabaVendorId)
   321 			{
   322 			FXString s;
   323 			FXString usage_str;
   324 			s.format("%04hx:%04hx -", cur_dev->vendor_id, cur_dev->product_id);
   325 			s += FXString(" ") + cur_dev->manufacturer_string;
   326 			s += FXString(" ") + cur_dev->product_string;
   327 			usage_str.format(" (usage: %04hx:%04hx) ", cur_dev->usage_page, cur_dev->usage);
   328 			s += usage_str;
   329 			FXListItem *li = new FXListItem(s, NULL, cur_dev);
   330 			device_list->appendItem(li);
   331 			}
   332 
   333 		cur_dev = cur_dev->next;
   334 	}
   335 
   336 	if (device_list->getNumItems() == 0)
   337 		device_list->appendItem("*** No Devices Connected ***");
   338 	else {
   339 		device_list->selectItem(0);
   340 	}
   341 
   342 	return 1;
   343 }
   344 
   345 size_t
   346 MainWindow::getDataFromTextField(FXTextField *tf, char *buf, size_t len)
   347 {
   348 	const char *delim = " ,{}\t\r\n";
   349 	FXString data = tf->getText();
   350 	const FXchar *d = data.text();
   351 	size_t i = 0;
   352 
   353 	// Copy the string from the GUI.
   354 	size_t sz = strlen(d);
   355 	char *str = (char*) malloc(sz+1);
   356 	strcpy(str, d);
   357 
   358 	// For each token in the string, parse and store in buf[].
   359 	char *token = strtok(str, delim);
   360 	while (token) {
   361 		char *endptr;
   362 		long int val = strtol(token, &endptr, 0);
   363 		buf[i++] = val;
   364 		token = strtok(NULL, delim);
   365 	}
   366 
   367 	free(str);
   368 	return i;
   369 }
   370 
   371 /* getLengthFromTextField()
   372    Returns length:
   373 	 0: empty text field
   374 	>0: valid length
   375 	-1: invalid length */
   376 int
   377 MainWindow::getLengthFromTextField(FXTextField *tf)
   378 {
   379 	long int len;
   380 	FXString str = tf->getText();
   381 	size_t sz = str.length();
   382 
   383 	if (sz > 0) {
   384 		char *endptr;
   385 		len = strtol(str.text(), &endptr, 0);
   386 		if (endptr != str.text() && *endptr == '\0') {
   387 			if (len <= 0) {
   388 				FXMessageBox::error(this, MBOX_OK, "Invalid length", "Enter a length greater than zero.");
   389 				return -1;
   390 			}
   391 			return len;
   392 		}
   393 		else
   394 			return -1;
   395 	}
   396 
   397 	return 0;
   398 }
   399 
   400 long
   401 MainWindow::onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr)
   402 {
   403 	char buf[256];
   404 	size_t data_len, len;
   405 	int textfield_len;
   406 
   407 	memset(buf, 0x0, sizeof(buf));
   408 	textfield_len = getLengthFromTextField(output_len);
   409 	data_len = getDataFromTextField(output_text, buf, sizeof(buf));
   410 
   411 	if (textfield_len < 0) {
   412 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
   413 		return 1;
   414 	}
   415 
   416 	if (textfield_len > sizeof(buf)) {
   417 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
   418 		return 1;
   419 	}
   420 
   421 	len = (textfield_len)? textfield_len: data_len;
   422 
   423 	int res = hid_write(connected_device, (const unsigned char*)buf, len);
   424 	if (res < 0) {
   425 		FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not write to device. Error reported was: %ls", hid_error(connected_device));
   426 	}
   427 
   428 	return 1;
   429 }
   430 
   431 long
   432 MainWindow::onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
   433 {
   434 	char buf[256];
   435 	size_t data_len, len;
   436 	int textfield_len;
   437 
   438 	memset(buf, 0x0, sizeof(buf));
   439 	textfield_len = getLengthFromTextField(feature_len);
   440 	data_len = getDataFromTextField(feature_text, buf, sizeof(buf));
   441 
   442 	if (textfield_len < 0) {
   443 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
   444 		return 1;
   445 	}
   446 
   447 	if (textfield_len > sizeof(buf)) {
   448 		FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
   449 		return 1;
   450 	}
   451 
   452 	len = (textfield_len)? textfield_len: data_len;
   453 
   454 	int res = hid_send_feature_report(connected_device, (const unsigned char*)buf, len);
   455 	if (res < 0) {
   456 		FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not send feature report to device. Error reported was: %ls", hid_error(connected_device));
   457 	}
   458 
   459 	return 1;
   460 }
   461 
   462 long
   463 MainWindow::onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
   464 {
   465 	char buf[256];
   466 	size_t len;
   467 
   468 	memset(buf, 0x0, sizeof(buf));
   469 	len = getDataFromTextField(get_feature_text, buf, sizeof(buf));
   470 
   471 	if (len != 1) {
   472 		FXMessageBox::error(this, MBOX_OK, "Too many numbers", "Enter only a single report number in the text field");
   473 	}
   474 
   475 	int res = hid_get_feature_report(connected_device, (unsigned char*)buf, sizeof(buf));
   476 	if (res < 0) {
   477 		FXMessageBox::error(this, MBOX_OK, "Error Getting Report", "Could not get feature report from device. Error reported was: %ls", hid_error(connected_device));
   478 	}
   479 
   480 	if (res > 0) {
   481 		FXString s;
   482 		s.format("Returned Feature Report. %d bytes:\n", res);
   483 		for (int i = 0; i < res; i++) {
   484 			FXString t;
   485 			t.format("%02hhx ", buf[i]);
   486 			s += t;
   487 			if ((i+1) % 4 == 0)
   488 				s += " ";
   489 			if ((i+1) % 16 == 0)
   490 				s += "\n";
   491 		}
   492 		s += "\n";
   493 		input_text->appendText(s);
   494 		input_text->setBottomLine(INT_MAX);
   495 	}
   496 
   497 	return 1;
   498 }
   499 
   500 long
   501 MainWindow::onClear(FXObject *sender, FXSelector sel, void *ptr)
   502 {
   503 	input_text->setText("");
   504 	return 1;
   505 }
   506 
   507 
   508 long
   509 MainWindow::onFutabaClearDisplay(FXObject *sender, FXSelector sel, void *ptr)
   510 {
   511 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   512 	iOutputReportBuffer[0]=0x00; //Report ID
   513 	iOutputReportBuffer[1]=0x04; //Report length
   514 	iOutputReportBuffer[2]=0x1B; //
   515 	iOutputReportBuffer[3]=0x5B; //
   516 	iOutputReportBuffer[4]=0x32; //
   517 	iOutputReportBuffer[5]=0x4A; //
   518 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   519 
   520 	return 1;
   521 }
   522 
   523 long
   524 MainWindow::onFutabaDimming(FXObject *sender, FXSelector sel, void *ptr)
   525 {
   526 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   527 	iOutputReportBuffer[0]=0x00; //Report ID
   528 	iOutputReportBuffer[1]=0x06; //Report length
   529 	iOutputReportBuffer[2]=0x1B; //
   530 	iOutputReportBuffer[3]=0x5C; //
   531 	iOutputReportBuffer[4]=0x3F; //
   532 	iOutputReportBuffer[5]=0x4C; //
   533 	iOutputReportBuffer[6]=0x44; //
   534 	iDimming = (iDimming==0x35?0x30:++iDimming);
   535 	iOutputReportBuffer[7]=iDimming;
   536 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   537 
   538 	return 1;
   539 }
   540 
   541 long
   542 MainWindow::onFutabaDisplayDataInput(FXObject *sender, FXSelector sel, void *ptr)
   543 {
   544 	//@1B 5B F0 00 00 07 00 01 FF
   545 
   546 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   547 	iOutputReportBuffer[0]=0x00; //Report ID
   548 	iOutputReportBuffer[1]=0x09; //Report length
   549 	iOutputReportBuffer[2]=0x1B; //
   550 	iOutputReportBuffer[3]=0x5B; //
   551 	iOutputReportBuffer[4]=0xF0; //
   552 	iOutputReportBuffer[5]=0x00; //X
   553 	iOutputReportBuffer[6]=0x00; //Y
   554 	iOutputReportBuffer[7]=0x07; //
   555 	iOutputReportBuffer[8]=0x00; //
   556 	iOutputReportBuffer[9]=0x01; //
   557 	iOutputReportBuffer[10]=0xFF; //
   558 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   559 
   560 
   561 	return 1;
   562 }
   563 
   564 
   565 
   566 
   567 /**
   568 Set a single pixel to the specified value.
   569 @param X coordinate of our pixel.
   570 @param Y coordinate of our pixel.
   571 @param The LSB defines our pixel value.
   572 */
   573 void MainWindow::SetPixel(int aX, int aY, unsigned char aValue)
   574 	{
   575 	//Just specify a one pixel block
   576 	SetPixelBlock(aX,aY,0x00,0x01,aValue);
   577 	}
   578 
   579 /**
   580 Set the defined pixel block to the given value.
   581 @param X coordinate of our pixel block starting point.
   582 @param Y coordinate of our pixel block starting point.
   583 @param The height of our pixel block.
   584 @param The size of our pixel data. Number of pixels divided by 8.
   585 @param The value set to 8 pixels.
   586 */
   587 void MainWindow::SetPixelBlock(int aX, int aY, int aHeight, int aSize, unsigned char aValue)
   588 	{
   589 	//Size must be 63 or below
   590 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   591 	iOutputReportBuffer[0]=0x00; //Report ID
   592 	iOutputReportBuffer[1]=0x08+aSize; //Report length
   593 	iOutputReportBuffer[2]=0x1B; //
   594 	iOutputReportBuffer[3]=0x5B; //
   595 	iOutputReportBuffer[4]=0xF0; //
   596 	iOutputReportBuffer[5]=aX; //X
   597 	iOutputReportBuffer[6]=aY; //Y
   598 	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.
   599 	iOutputReportBuffer[8]=0x00; //Size of pixel data in bytes (MSB)
   600 	iOutputReportBuffer[9]=aSize; //Size of pixel data in bytes (LSB)
   601 	memset(iOutputReportBuffer+10, aValue, KFutabaMaxHidReportSize);
   602 	//iOutputReportBuffer[10]=aValue; //Pixel data
   603 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   604 	}
   605 
   606 /**
   607 Send an output report to a Futaba VFD device.
   608 */
   609 /*
   610 void MainWindow::SendFutabaOutputReport(unsigned char* aReportData, unsigned char aSize)
   611     {
   612     //
   613     memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   614     iOutputReportBuffer[0]=0x00; //Report ID is always null
   615     iOutputReportBuffer[1]=0x08+aSize; //Report length
   616     iOutputReportBuffer[2]=0x1B; //
   617     iOutputReportBuffer[3]=0x5B; //
   618     iOutputReportBuffer[4]=0xF0; //
   619     iOutputReportBuffer[5]=aX; //X
   620     iOutputReportBuffer[6]=aY; //Y
   621     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.
   622     iOutputReportBuffer[8]=0x00; //Size of pixel data in bytes (MSB)
   623     iOutputReportBuffer[9]=aSize; //Size of pixel data in bytes (LSB)
   624     memset(iOutputReportBuffer+10, aValue, KFutabaMaxHidReportSize);
   625     //iOutputReportBuffer[10]=aValue; //Pixel data
   626     int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   627     }
   628 */
   629 
   630 
   631 /**
   632 */
   633 long MainWindow::onFutabaSetPixel(FXObject *sender, FXSelector sel, void *ptr)
   634 {
   635 	int x=0;
   636 	int y=0;
   637 	iTextFieldX->getText().scan("%d",&x);
   638 	iTextFieldY->getText().scan("%d",&y);
   639     SetPixel(x,y,0x01);
   640 	return 1;
   641 }
   642 
   643 /**
   644 */
   645 long MainWindow::onFutabaResetPixel(FXObject *sender, FXSelector sel, void *ptr)
   646 {
   647 	int x=0;
   648 	int y=0;
   649 	iTextFieldX->getText().scan("%d",&x);
   650 	iTextFieldY->getText().scan("%d",&y);
   651     SetPixel(x,y,0x00);
   652     return 1;
   653 }
   654 
   655 long MainWindow::onFutabaSetAllPixels(FXObject *sender, FXSelector sel, void *ptr)
   656 	{
   657 	//One pixel at a time
   658 	/*
   659 	for (int i=0;i<256;i++)
   660 		{
   661 		for (int j=0;j<64;j++)
   662 			{
   663 			SetPixel(i,j,0x01);
   664 			}
   665 		}
   666 	*/
   667 	//16x16=256 pixels at a time goes much faster
   668 	for (int i=0;i<256;i+=16)
   669 		{
   670 		for (int j=0;j<64;j+=16)
   671 			{
   672 			SetPixelBlock(i,j,15,32,0xFF);
   673 			//FXThread::sleep(1000000000);
   674 			}
   675 		}
   676 
   677     return 1;
   678 	}
   679 
   680 long
   681 MainWindow::onFutabaReadId(FXObject *sender, FXSelector sel, void *ptr)
   682 {
   683 	//1BH,5BH,63H,49H,44H
   684 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   685 	iOutputReportBuffer[0]=0x00; //Report ID
   686 	iOutputReportBuffer[1]=0x05; //Report length
   687 	iOutputReportBuffer[2]=0x1B; //
   688 	iOutputReportBuffer[3]=0x5B; //
   689 	iOutputReportBuffer[4]=0x63; //
   690 	iOutputReportBuffer[5]=0x49; //
   691 	iOutputReportBuffer[6]=0x44; //
   692 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   693 
   694 	return 1;
   695 }
   696 
   697 long
   698 MainWindow::onFutabaReadFirmwareRevision(FXObject *sender, FXSelector sel, void *ptr)
   699 {
   700 	//1BH,5BH,63H,46H,52H
   701 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   702 	iOutputReportBuffer[0]=0x00; //Report ID
   703 	iOutputReportBuffer[1]=0x05; //Report length
   704 	iOutputReportBuffer[2]=0x1B; //
   705 	iOutputReportBuffer[3]=0x5B; //
   706 	iOutputReportBuffer[4]=0x63; //
   707 	iOutputReportBuffer[5]=0x46; //
   708 	iOutputReportBuffer[6]=0x52; //
   709 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   710 
   711 	return 1;
   712 }
   713 
   714 long
   715 MainWindow::onFutabaPowerSupplyMonitor(FXObject *sender, FXSelector sel, void *ptr)
   716 {
   717 	//1BH,5BH,63H,50H,4DH
   718 	memset(iOutputReportBuffer, 0x0, KFutabaMaxHidReportSize);
   719 	iOutputReportBuffer[0]=0x00; //Report ID
   720 	iOutputReportBuffer[1]=0x05; //Report length
   721 	iOutputReportBuffer[2]=0x1B; //
   722 	iOutputReportBuffer[3]=0x5B; //
   723 	iOutputReportBuffer[4]=0x63; //
   724 	iOutputReportBuffer[5]=0x50; //
   725 	iOutputReportBuffer[6]=0x4D; //
   726 	int res = hid_write(connected_device, iOutputReportBuffer, KFutabaMaxHidReportSize);
   727 
   728 	return 1;
   729 }
   730 
   731 
   732 
   733 long
   734 MainWindow::onTimeout(FXObject *sender, FXSelector sel, void *ptr)
   735 {
   736 	unsigned char buf[256];
   737 	int res = hid_read(connected_device, buf, sizeof(buf));
   738 
   739 	if (res > 0) {
   740 		FXString s;
   741 		s.format("Received %d bytes:\n", res);
   742 		for (int i = 0; i < res; i++) {
   743 			FXString t;
   744 			t.format("%02hhx ", buf[i]);
   745 			s += t;
   746 			if ((i+1) % 4 == 0)
   747 				s += " ";
   748 			if ((i+1) % 16 == 0)
   749 				s += "\n";
   750 		}
   751 		s += "\n";
   752 		input_text->appendText(s);
   753 		input_text->setBottomLine(INT_MAX);
   754 	}
   755 	if (res < 0) {
   756 		input_text->appendText("hid_read() returned error\n");
   757 		input_text->setBottomLine(INT_MAX);
   758 	}
   759 
   760 	getApp()->addTimeout(this, ID_TIMER,
   761 		5 * timeout_scalar /*5ms*/);
   762 	return 1;
   763 }
   764 
   765 long
   766 MainWindow::onMacTimeout(FXObject *sender, FXSelector sel, void *ptr)
   767 {
   768 #ifdef __APPLE__
   769 	check_apple_events();
   770 
   771 	getApp()->addTimeout(this, ID_MAC_TIMER,
   772 		50 * timeout_scalar /*50ms*/);
   773 #endif
   774 
   775 	return 1;
   776 }
   777 
   778 /**
   779 
   780 */
   781 long MainWindow::onSelectFont(FXObject *sender, FXSelector sel, void *ptr)
   782     {
   783     FXFontDialog* dlg=new FXFontDialog(this,"Pick a font");
   784     if (dlg->execute())
   785         {
   786         dlg->getFontSelection(iCurrentFontDesc);
   787         delete iCurrentFont;
   788         iCurrentFont = NULL;
   789         iCurrentFont = new FXFont(getApp(),iCurrentFontDesc);
   790         iCurrentFont->create();
   791         //
   792         delete iFontImage;
   793         iFontImage = NULL;
   794         //
   795         FXString text="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-[]{}();%$£&~#|_";
   796         //Create an image the proper size for our text
   797         iFontImage = new FXTGAImage(getApp(),NULL,IMAGE_SHMI|IMAGE_SHMP,iCurrentFont->getTextWidth(text),iCurrentFont->getFontHeight());
   798         iFontImage->create();
   799         //Perform our drawing
   800             {
   801             FXDCWindow dc(iFontImage);
   802             //dc.begin(iFontImage);
   803             dc.setFont(iCurrentFont);
   804             dc.setForeground(0xFFFFFFFF);
   805             //dc.setBackground(0xFF000000);
   806             //dc.setFillStyle(FILL_SOLID);
   807             dc.fillRectangle(0,0,iFontImage->getWidth(),iFontImage->getHeight());
   808             dc.setForeground(0xFF000000);
   809             dc.drawText(0,iCurrentFont->getFontAscent(),text);
   810             //dc.end();
   811             }
   812         FXFileStream file;
   813         file.open("fonttest.tga",FXStreamSave);
   814         iFontImage->restore();
   815         iFontImage->savePixels(file);
   816         file.close();
   817 
   818         //
   819 
   820         }
   821 
   822     delete dlg;
   823     return 1;
   824     }
   825 
   826 
   827