BayEOS-PHP
 All Data Structures Namespaces Files Functions Variables Pages
BayEOSSerialPHP.php
Go to the documentation of this file.
1 <?php
2 /*
3  * +--------------------------------------------------------------------------+
4 * | Copyright (c) 2012 Chris Barnes | (c) 2014 S. Holzheu
5 * +--------------------------------------------------------------------------+
6 * | This program is free software; you can redistribute it and/or modify |
7 * | it under the terms of the GNU General Public License as published by |
8 * | the Free Software Foundation; either version 2 of the License, or |
9 * | (at your option) any later version. |
10 * | |
11 * | This program is distributed in the hope that it will be useful, |
12 * | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 * | GNU General Public License for more details. |
15 * | |
16 * | You should have received a copy of the GNU General Public License |
17 * | along with this program; if not, write to the Free Software |
18 * | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 * +--------------------------------------------------------------------------+
20 */
21 
22 define ("SERIAL_DEVICE_NOTSET", 0);
23 define ("SERIAL_DEVICE_SET", 1);
24 define ("SERIAL_DEVICE_OPENED", 2);
25 
41 class phpSerial
42 {
43  var $_device = null;
44  var $_windevice = null;
45  var $_dHandle = null;
47  var $_buffer = "";
48  var $_os = "";
49 
55  var $autoflush = true;
56 
62  function phpSerial ()
63  {
64  setlocale(LC_ALL, "en_US");
65 
66  $sysname = php_uname();
67 
68  if (substr($sysname, 0, 5) === "Linux")
69  {
70  $this->_os = "linux";
71 
72  if($this->_exec("stty --version") === 0)
73  {
74  register_shutdown_function(array($this, "deviceClose"));
75  }
76  else
77  {
78  trigger_error("No stty availible, unable to run.", E_USER_ERROR);
79  }
80  }
81  elseif (substr($sysname, 0, 6) === "Darwin")
82  {
83  $this->_os = "osx";
84  // We know stty is available in Darwin.
85  // stty returns 1 when run from php, because "stty: stdin isn't a
86  // terminal"
87  // skip this check
88  // if($this->_exec("stty") === 0)
89  // {
90  register_shutdown_function(array($this, "deviceClose"));
91  // }
92  // else
93  // {
94  // trigger_error("No stty availible, unable to run.", E_USER_ERROR);
95  // }
96  }
97  elseif(substr($sysname, 0, 7) === "Windows")
98  {
99  $this->_os = "windows";
100  register_shutdown_function(array($this, "deviceClose"));
101  }
102  else
103  {
104  trigger_error("Host OS is neither osx, linux nor windows, unable to run.", E_USER_ERROR);
105  exit();
106  }
107  }
108 
109  //
110  // OPEN/CLOSE DEVICE SECTION -- {START}
111  //
112 
123  function deviceSet ($device)
124  {
125  if ($this->_dState !== SERIAL_DEVICE_OPENED)
126  {
127  if ($this->_os === "linux")
128  {
129  if (preg_match("@^COM(\d+):?$@i", $device, $matches))
130  {
131  $device = "/dev/ttyS" . ($matches[1] - 1);
132  }
133 
134  if ($this->_exec("stty -F " . $device) === 0)
135  {
136  $this->_device = $device;
137  $this->_dState = SERIAL_DEVICE_SET;
138  return true;
139  }
140  }
141  elseif ($this->_os === "osx")
142  {
143  if ($this->_exec("stty -f " . $device) === 0)
144  {
145  $this->_device = $device;
146  $this->_dState = SERIAL_DEVICE_SET;
147  return true;
148  }
149  }
150  elseif ($this->_os === "windows")
151  {
152  if (preg_match("@^COM(\d+):?$@i", $device, $matches) and $this->_exec(exec("mode " . $device . " xon=on BAUD=9600")) === 0)
153  {
154  $this->_windevice = "COM" . $matches[1];
155  $this->_device = "\\.\com" . $matches[1];
156  $this->_dState = SERIAL_DEVICE_SET;
157  return true;
158  }
159  }
160 
161  trigger_error("Specified serial port is not valid", E_USER_WARNING);
162  return false;
163  }
164  else
165  {
166  trigger_error("You must close your device before to set an other one", E_USER_WARNING);
167  return false;
168  }
169  }
170 
177  function deviceOpen ($mode = "r+b")
178  {
179  if ($this->_dState === SERIAL_DEVICE_OPENED)
180  {
181  trigger_error("The device is already opened", E_USER_NOTICE);
182  return true;
183  }
184 
185  if ($this->_dState === SERIAL_DEVICE_NOTSET)
186  {
187  trigger_error("The device must be set before to be open", E_USER_WARNING);
188  return false;
189  }
190 
191  if (!preg_match("@^[raw]\+?b?$@", $mode))
192  {
193  trigger_error("Invalid opening mode : ".$mode.". Use fopen() modes.", E_USER_WARNING);
194  return false;
195  }
196 
197  $this->_dHandle = @fopen($this->_device, $mode);
198 
199  if ($this->_dHandle !== false)
200  {
201  stream_set_blocking($this->_dHandle, 0);
202  $this->_dState = SERIAL_DEVICE_OPENED;
203  return true;
204  }
205 
206  $this->_dHandle = null;
207  trigger_error("Unable to open the device", E_USER_WARNING);
208  return false;
209  }
210 
216  function deviceClose ()
217  {
218  if ($this->_dState !== SERIAL_DEVICE_OPENED)
219  {
220  return true;
221  }
222 
223  if (fclose($this->_dHandle))
224  {
225  $this->_dHandle = null;
226  $this->_dState = SERIAL_DEVICE_SET;
227  return true;
228  }
229 
230  trigger_error("Unable to close the device", E_USER_ERROR);
231  return false;
232  }
233 
234  //
235  // OPEN/CLOSE DEVICE SECTION -- {STOP}
236  //
237 
238  //
239  // CONFIGURE SECTION -- {START}
240  //
241 
250  function confBaudRate ($rate)
251  {
252  if ($this->_dState !== SERIAL_DEVICE_SET)
253  {
254  trigger_error("Unable to set the baud rate : the device is either not set or opened", E_USER_WARNING);
255  return false;
256  }
257 
258  $validBauds = array (
259  110 => 11,
260  150 => 15,
261  300 => 30,
262  600 => 60,
263  1200 => 12,
264  2400 => 24,
265  4800 => 48,
266  9600 => 96,
267  19200 => 19,
268  38400 => 38400,
269  57600 => 57600,
270  115200 => 115200
271  );
272 
273  if (isset($validBauds[$rate]))
274  {
275  if ($this->_os === "linux")
276  {
277  //note this is the only place modified from the original, I submitted a patch on Google Code for this change
278  //See switches here: http://www.daemon-systems.org/man/stty.1.html
279  $ret = $this->_exec("stty -F " . $this->_device . " raw speed -echo " . (int) $rate, $out);
280  }
281  if ($this->_os === "osx")
282  {
283  $ret = $this->_exec("stty -f " . $this->_device . " " . (int) $rate, $out);
284  }
285  elseif ($this->_os === "windows")
286  {
287  $ret = $this->_exec("mode " . $this->_windevice . " BAUD=" . $validBauds[$rate], $out);
288  }
289  else return false;
290 
291  if ($ret !== 0)
292  {
293  trigger_error ("Unable to set baud rate: " . $out[1], E_USER_WARNING);
294  return false;
295  }
296  }
297  }
298 
306  function confParity ($parity)
307  {
308  if ($this->_dState !== SERIAL_DEVICE_SET)
309  {
310  trigger_error("Unable to set parity : the device is either not set or opened", E_USER_WARNING);
311  return false;
312  }
313 
314  $args = array(
315  "none" => "-parenb",
316  "odd" => "parenb parodd",
317  "even" => "parenb -parodd",
318  );
319 
320  if (!isset($args[$parity]))
321  {
322  trigger_error("Parity mode not supported", E_USER_WARNING);
323  return false;
324  }
325 
326  if ($this->_os === "linux")
327  {
328  $ret = $this->_exec("stty -F " . $this->_device . " " . $args[$parity], $out);
329  }
330  elseif ($this->_os === "osx")
331  {
332  $ret = $this->_exec("stty -f " . $this->_device . " " . $args[$parity], $out);
333  }
334  else
335  {
336  $ret = $this->_exec("mode " . $this->_windevice . " PARITY=" . $parity{0}, $out);
337  }
338 
339  if ($ret === 0)
340  {
341  return true;
342  }
343 
344  trigger_error("Unable to set parity : " . $out[1], E_USER_WARNING);
345  return false;
346  }
347 
354  function confCharacterLength ($int)
355  {
356  if ($this->_dState !== SERIAL_DEVICE_SET)
357  {
358  trigger_error("Unable to set length of a character : the device is either not set or opened", E_USER_WARNING);
359  return false;
360  }
361 
362  $int = (int) $int;
363  if ($int < 5) $int = 5;
364  elseif ($int > 8) $int = 8;
365 
366  if ($this->_os === "linux")
367  {
368  $ret = $this->_exec("stty -F " . $this->_device . " cs" . $int, $out);
369  }
370  elseif ($this->_os === "osx")
371  {
372  $ret = $this->_exec("stty -f " . $this->_device . " cs" . $int, $out);
373  }
374  else
375  {
376  $ret = $this->_exec("mode " . $this->_windevice . " DATA=" . $int, $out);
377  }
378 
379  if ($ret === 0)
380  {
381  return true;
382  }
383 
384  trigger_error("Unable to set character length : " .$out[1], E_USER_WARNING);
385  return false;
386  }
387 
395  function confStopBits ($length)
396  {
397  if ($this->_dState !== SERIAL_DEVICE_SET)
398  {
399  trigger_error("Unable to set the length of a stop bit : the device is either not set or opened", E_USER_WARNING);
400  return false;
401  }
402 
403  if ($length != 1 and $length != 2 and $length != 1.5 and !($length == 1.5 and $this->_os === "linux"))
404  {
405  trigger_error("Specified stop bit length is invalid", E_USER_WARNING);
406  return false;
407  }
408 
409  if ($this->_os === "linux")
410  {
411  $ret = $this->_exec("stty -F " . $this->_device . " " . (($length == 1) ? "-" : "") . "cstopb", $out);
412  }
413  elseif ($this->_os === "osx")
414  {
415  $ret = $this->_exec("stty -f " . $this->_device . " " . (($length == 1) ? "-" : "") . "cstopb", $out);
416  }
417  else
418  {
419  $ret = $this->_exec("mode " . $this->_windevice . " STOP=" . $length, $out);
420  }
421 
422  if ($ret === 0)
423  {
424  return true;
425  }
426 
427  trigger_error("Unable to set stop bit length : " . $out[1], E_USER_WARNING);
428  return false;
429  }
430 
440  function confFlowControl ($mode)
441  {
442  if ($this->_dState !== SERIAL_DEVICE_SET)
443  {
444  trigger_error("Unable to set flow control mode : the device is either not set or opened", E_USER_WARNING);
445  return false;
446  }
447 
448  $linuxModes = array(
449  "none" => "clocal -crtscts -ixon -ixoff",
450  "rts/cts" => "-clocal crtscts -ixon -ixoff",
451  "xon/xoff" => "-clocal -crtscts ixon ixoff"
452  );
453  $windowsModes = array(
454  "none" => "xon=off octs=off rts=on",
455  "rts/cts" => "xon=off octs=on rts=hs",
456  "xon/xoff" => "xon=on octs=off rts=on",
457  );
458 
459  if ($mode !== "none" and $mode !== "rts/cts" and $mode !== "xon/xoff") {
460  trigger_error("Invalid flow control mode specified", E_USER_ERROR);
461  return false;
462  }
463 
464  if ($this->_os === "linux")
465  $ret = $this->_exec("stty -F " . $this->_device . " " . $linuxModes[$mode], $out);
466  elseif ($this->_os === "osx")
467  $ret = $this->_exec("stty -f " . $this->_device . " " . $linuxModes[$mode], $out);
468  else
469  $ret = $this->_exec("mode " . $this->_windevice . " " . $windowsModes[$mode], $out);
470 
471  if ($ret === 0) return true;
472  else {
473  trigger_error("Unable to set flow control : " . $out[1], E_USER_ERROR);
474  return false;
475  }
476  }
477 
488  function setSetserialFlag ($param, $arg = "")
489  {
490  if (!$this->_ckOpened()) return false;
491 
492  $return = exec ("setserial " . $this->_device . " " . $param . " " . $arg . " 2>&1");
493 
494  if ($return{0} === "I")
495  {
496  trigger_error("setserial: Invalid flag", E_USER_WARNING);
497  return false;
498  }
499  elseif ($return{0} === "/")
500  {
501  trigger_error("setserial: Error with device file", E_USER_WARNING);
502  return false;
503  }
504  else
505  {
506  return true;
507  }
508  }
509 
510  //
511  // CONFIGURE SECTION -- {STOP}
512  //
513 
514  //
515  // I/O SECTION -- {START}
516  //
517 
524  function sendMessage ($str, $waitForReply = 0.1)
525  {
526  $this->_buffer .= $str;
527 
528  if ($this->autoflush === true) $this->serialflush();
529 
530  usleep((int) ($waitForReply * 1000000));
531  }
532 
540  function readPort ($count = 0)
541  {
542  if ($this->_dState !== SERIAL_DEVICE_OPENED)
543  {
544  trigger_error("Device must be opened to read it", E_USER_WARNING);
545  return false;
546  }
547 
548  if ($this->_os === "linux" || $this->_os === "osx")
549  {
550  // Behavior in OSX isn't to wait for new data to recover, but just grabs what's there!
551  // Doesn't always work perfectly for me in OSX
552  $content = ""; $i = 0;
553 
554  if ($count !== 0)
555  {
556  do {
557  if ($i > $count) $content .= fread($this->_dHandle, ($count - $i));
558  else $content .= fread($this->_dHandle, 128);
559  } while (($i += 128) === strlen($content));
560  }
561  else
562  {
563  do {
564  $content .= fread($this->_dHandle, 128);
565  } while (($i += 128) === strlen($content));
566  }
567  return $content;
568  }
569  elseif ($this->_os === "windows")
570  {
571  // Windows port reading procedures still buggy
572  $content = ""; $i = 0;
573 
574  if ($count !== 0)
575  {
576  do {
577  if ($i > $count) $content .= fread($this->_dHandle, ($count - $i));
578  else $content .= fread($this->_dHandle, 128);
579  } while (($i += 128) === strlen($content));
580  }
581  else
582  {
583  do {
584  $content .= fread($this->_dHandle, 128);
585  } while (($i += 128) === strlen($content));
586  }
587 
588  return $content;
589  }
590 
591  return false;
592  }
593 
600  function serialflush ()
601  {
602  if (!$this->_ckOpened()) return false;
603 
604  if (fwrite($this->_dHandle, $this->_buffer) !== false)
605  {
606  $this->_buffer = "";
607  return true;
608  }
609  else
610  {
611  $this->_buffer = "";
612  trigger_error("Error while sending message", E_USER_WARNING);
613  return false;
614  }
615  }
616 
617  //
618  // I/O SECTION -- {STOP}
619  //
620 
621  //
622  // INTERNAL TOOLKIT -- {START}
623  //
624 
625  function _ckOpened()
626  {
627  if ($this->_dState !== SERIAL_DEVICE_OPENED)
628  {
629  trigger_error("Device must be opened", E_USER_WARNING);
630  return false;
631  }
632 
633  return true;
634  }
635 
636  function _ckClosed()
637  {
638  if ($this->_dState !== SERIAL_DEVICE_CLOSED)
639  {
640  trigger_error("Device must be closed", E_USER_WARNING);
641  return false;
642  }
643 
644  return true;
645  }
646 
647  function _exec($cmd, &$out = null)
648  {
649  $desc = array(
650  1 => array("pipe", "w"),
651  2 => array("pipe", "w")
652  );
653 
654  $proc = proc_open($cmd, $desc, $pipes);
655 
656  $ret = stream_get_contents($pipes[1]);
657  $err = stream_get_contents($pipes[2]);
658 
659  fclose($pipes[1]);
660  fclose($pipes[2]);
661 
662  $retVal = proc_close($proc);
663 
664  if (func_num_args() == 2) $out = array($ret, $err);
665  return $retVal;
666  }
667 
668  //
669  // INTERNAL TOOLKIT -- {STOP}
670  //
671 }
672 
673 
674 
675 ?>
deviceOpen($mode="r+b")
confFlowControl($mode)
confStopBits($length)
$count
Definition: BayEOSWriter.php:8
readPort($count=0)
confBaudRate($rate)
sendMessage($str, $waitForReply=0.1)
const SERIAL_DEVICE_NOTSET
const SERIAL_DEVICE_OPENED
_exec($cmd, &$out=null)
deviceSet($device)
setSetserialFlag($param, $arg="")
confCharacterLength($int)
confParity($parity)
const SERIAL_DEVICE_SET