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