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