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