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