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