<?php

/*******************************************************************************

 WINBINDER - The native Windows binding for PHP for PHP

 Copyright © Hypervisual - see LICENSE.TXT for details
 Author: Rubem Pechansky (http://winbinder.org/contact.php)

 Code sample: how to access a serial port

*******************************************************************************/

//------------------------------------------------------------ SYSTEM PARAMETERS

define("PATH_SCRIPT",	dirname(__FILE__) . "/");
define("PATH_DATA",		PATH_SCRIPT);
define("PATH_INC",		PATH_SCRIPT . "../include/");
define("PATH_RES",		PATH_SCRIPT . "../resources/");

//----------------------------------------------------------------- DEPENDENCIES

include PATH_INC . "winbinder.php";

//-------------------------------------------------------------- USER PARAMETERS

define("APPNAME",			"Serial port tests");	// Application name

//-------------------------------------------------------------------- CONSTANTS

// Control identifiers

define("ID_TEST",			101);

//-------------------------------------------------------------- EXECUTABLE CODE

// Initialize serial functions

init_serial();

// Create main window

$mainwin = wb_create_window(NULL, AppWindow, APPNAME, 540, 340);
wb_set_handler($mainwin, "process_main");

$term = wb_create_control($mainwin, EditBox, "", 0, 28, 532, 243, 101, WBC_MULTILINE | WBC_READONLY);

// Create menu, toolbar, statusbar

wb_create_control($mainwin, Menu, array(
    "&File",
        array(IDCLOSE,  "E&xit\\tAlt+F4",    NULL, PATH_RES . "menu_exit.bmp"),
));

wb_create_control($mainwin, ToolBar, array(
    null,
    array(ID_TEST,  NULL,   "Test serial port",      22),
    null,
    array(IDCLOSE,  NULL,   "Exit this application",    14),
), 0, 0, 16, 15, 0, 0, PATH_RES . "toolbar.bmp");

$statusbar = wb_create_control($mainwin, StatusBar, APPNAME);

// Enter application loop

wb_main_loop();

//--------------------------------------------------------------- MAIN FUNCTIONS

/* Process main window commands */

function process_main($window, $id)
{
	global $statusbar;

	switch($id) {

		case ID_TEST:

			// Open port

			wb_set_text($statusbar, "Wait...");
			for($i = 0; $i < 100; $i++) {
				$port = open_serial("COM1");
				if($port != INVALID_HANDLE_VALUE)
					break;
				wb_wait(null, 10);
			};

			if($port == INVALID_HANDLE_VALUE) {
				output("Cannot open COM port\\n");
				break;
			}

			// Configure port

			$cfg = config_serial($port, "BAUD=115200 PARITY=N DATA=8 STOP=1 XON=OFF");
			if(!$cfg) {
				output("COM port configuration error\\n");
				break;
			}

			// Write something and wait for output

			write_serial($port, "ATE0\\r\\n");		// Echo off
			write_serial($port, "AT\\r\\n");
			do {
				$str = read_serial($port);
				output($str);
			} while(substr($str, -4) != "OK\\r\\n");

			write_serial($port, "AT&V\\r\\n");		// Show configuration
			do {
				$str = read_serial($port);
				output($str);
			} while(substr($str, -4) != "OK\\r\\n");

			// Close port

			close_serial($port);

			break;

		case IDCLOSE:
			wb_destroy_window($window);
			break;
	}
}

function output($str)
{
	global $term, $statusbar;

	wb_set_text($term, wb_get_text($term) . $str);
	wb_set_text($statusbar, "Done.");
}

//-------------------------------------------------------- SERIAL PORT FUNCTIONS

function init_serial()
{
	global $CreateFile, $WriteFile, $ReadFile;
	global $GetLastError, $SetCommState, $BuildCommDCB, $CloseHandle;

	define("GENERIC_READ",				0x80000000);
	define("GENERIC_WRITE",				0x40000000);
	define("OPEN_EXISTING",				3);
	define("INVALID_HANDLE_VALUE", 		-1);
	define("ERROR_IO_PENDING", 			997);
	define("DCB", 						"Vx198");
	define("DCB_SIZE",					200);


	$KERNEL = wb_load_library("KERNEL");

	$CreateFile = wb_get_function_address("CreateFile", $KERNEL);
	$WriteFile = wb_get_function_address("WriteFile", $KERNEL);
	$ReadFile = wb_get_function_address("ReadFile", $KERNEL);
	$GetLastError = wb_get_function_address("GetLastError", $KERNEL);
	$SetCommState = wb_get_function_address("SetCommState", $KERNEL);
	$BuildCommDCB = wb_get_function_address("BuildCommDCB", $KERNEL);
	$CloseHandle = wb_get_function_address("CloseHandle", $KERNEL);
}

function open_serial($portname)
{
	global $CreateFile;

	return wb_call_function($CreateFile, array(
		$portname,
		GENERIC_READ | GENERIC_WRITE,
		0,
		null,
		OPEN_EXISTING,
		0,
		0
	));
}

function config_serial($handle, $string)
{
	global $BuildCommDCB, $SetCommState;

	$dcb = pack(DCB, DCB_SIZE);

	if(!wb_call_function($BuildCommDCB, array($string, $dcb)))
		return FALSE;
	return wb_call_function($SetCommState, array($handle, $dcb));
}

function close_serial($handle)
{
	global $CloseHandle;

	if($handle) {
		if(wb_call_function($CloseHandle, array($handle))) {
			return TRUE;
		} else
			return FALSE;
	} else
		return FALSE;
}

function write_serial($handle, $buffer, $len=0)
{
	global $WriteFile, $GetLastError;

	$written = 0;
	$lpwritten = wb_get_address($written);

	if($len <= 0)
		$len = strlen($buffer);

	if(!wb_call_function($WriteFile, array($handle, $buffer, $len, $lpwritten, NULL))) {
		if(wb_call_function($GetLastError) != ERROR_IO_PENDING)
			return FALSE;
	}
	return $written;
}

function read_serial($handle)
{
	global $ReadFile, $GetLastError;

	$read = 0;
	$lpread = wb_get_address($read);
	$buffer = str_repeat(chr(0), 8192);

	if(!wb_call_function($ReadFile, array($handle, $buffer, 8192, $lpread, NULL))) {
		if(wb_call_function($GetLastError) != ERROR_IO_PENDING)
			return FALSE;
	}
	if($read)
		return substr($buffer, 0, $read);
	else
		return FALSE;
}

//------------------------------------------------------------------ END OF FILE

?>