Advertisement
Guest User

Untitled

a guest
Nov 27th, 2010
293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.41 KB | None | 0 0
  1. <?php
  2. define ("SERIAL_DEVICE_NOTSET", 0);
  3. define ("SERIAL_DEVICE_SET", 1);
  4. define ("SERIAL_DEVICE_OPENED", 2);
  5.  
  6. /**
  7. * Serial port control class
  8. *
  9. * THIS PROGRAM COMES WITH ABSOLUTELY NO WARANTIES !
  10. * USE IT AT YOUR OWN RISKS !
  11. *
  12. * Changes added by Rizwan Kassim <rizwank@uwink.com> for OSX functionality
  13. * default serial device for osx devices is /dev/tty.serial for machines with a built in serial device
  14. *
  15. * @author RÈmy Sanchez <thenux@gmail.com>
  16. * @thanks AurÈlien Derouineau for finding how to open serial ports with windows
  17. * @thanks Alec Avedisyan for help and testing with reading
  18. * @copyright under GPL 2 licence
  19. *
  20. * do not change this code unless you know what you are getting into. Leaving it as you have received it should work fine!
  21. */
  22. class phpSerial
  23. {
  24. var $_device = null;
  25. var $_windevice = null;
  26. var $_dHandle = null;
  27. var $_dState = SERIAL_DEVICE_NOTSET;
  28. var $_buffer = "";
  29. var $_os = "";
  30.  
  31. /**
  32. * This var says if buffer should be flushed by sendMessage (true) or manualy (false)
  33. *
  34. * @var bool
  35. */
  36. var $autoflush = true;
  37.  
  38. /**
  39. * Constructor. Perform some checks about the OS and setserial
  40. *
  41. * @return phpSerial
  42. */
  43. function phpSerial ()
  44. {
  45. setlocale(LC_ALL, "en_US");
  46.  
  47. $sysname = php_uname();
  48.  
  49. if (substr($sysname, 0, 5) === "Linux")
  50. {
  51. $this->_os = "linux";
  52.  
  53. if($this->_exec("stty --version") === 0)
  54. {
  55. register_shutdown_function(array($this, "deviceClose"));
  56. }
  57. else
  58. {
  59. trigger_error("No stty availible, unable to run.", E_USER_ERROR);
  60. }
  61. }
  62. elseif (substr($sysname, 0, 6) === "Darwin")
  63. {
  64. $this->_os = "osx";
  65. // We know stty is available in Darwin.
  66. // stty returns 1 when run from php, because "stty: stdin isn't a
  67. // terminal"
  68. // skip this check
  69. // if($this->_exec("stty") === 0)
  70. // {
  71. register_shutdown_function(array($this, "deviceClose"));
  72. // }
  73. // else
  74. // {
  75. // trigger_error("No stty availible, unable to run.", E_USER_ERROR);
  76. // }
  77. }
  78. elseif(substr($sysname, 0, 7) === "Windows")
  79. {
  80. $this->_os = "windows";
  81. register_shutdown_function(array($this, "deviceClose"));
  82. }
  83. else
  84. {
  85. trigger_error("Host OS is neither osx, linux nor windows, unable tu run.", E_USER_ERROR);
  86. exit();
  87. }
  88. }
  89.  
  90. //
  91. // OPEN/CLOSE DEVICE SECTION -- {START}
  92. //
  93.  
  94. /**
  95. * Device set function : used to set the device name/address.
  96. * -> linux : use the device address, like /dev/ttyS0
  97. * -> osx : use the device address, like /dev/tty.serial
  98. * -> windows : use the COMxx device name, like COM1 (can also be used
  99. * with linux)
  100. *
  101. * @param string $device the name of the device to be used
  102. * @return bool
  103. */
  104. function deviceSet ($device)
  105. {
  106. if ($this->_dState !== SERIAL_DEVICE_OPENED)
  107. {
  108. if ($this->_os === "linux")
  109. {
  110. if (preg_match("@^COM(\d+):?$@i", $device, $matches))
  111. {
  112. $device = "/dev/ttyS" . ($matches[1] - 1);
  113. }
  114.  
  115. if ($this->_exec("stty -F " . $device) === 0)
  116. {
  117. $this->_device = $device;
  118. $this->_dState = SERIAL_DEVICE_SET;
  119. return true;
  120. }
  121. }
  122. elseif ($this->_os === "osx")
  123. {
  124. if ($this->_exec("stty -f " . $device) === 0)
  125. {
  126. $this->_device = $device;
  127. $this->_dState = SERIAL_DEVICE_SET;
  128. return true;
  129. }
  130. }
  131. elseif ($this->_os === "windows")
  132. {
  133. if (preg_match("@^COM(\d+):?$@i", $device, $matches) and $this->_exec(exec("mode " . $device)) === 0)
  134. {
  135. $this->_windevice = "COM" . $matches[1];
  136. $this->_device = "\\.\com" . $matches[1];
  137. $this->_dState = SERIAL_DEVICE_SET;
  138. return true;
  139. }
  140. }
  141.  
  142. trigger_error("Specified serial port is not valid", E_USER_WARNING);
  143. return false;
  144. }
  145. else
  146. {
  147. trigger_error("You must close your device before to set an other one", E_USER_WARNING);
  148. return false;
  149. }
  150. }
  151.  
  152. /**
  153. * Opens the device for reading and/or writing.
  154. *
  155. * @param string $mode Opening mode : same parameter as fopen()
  156. * @return bool
  157. */
  158. function deviceOpen ($mode = "r+b")
  159. {
  160. if ($this->_dState === SERIAL_DEVICE_OPENED)
  161. {
  162. trigger_error("The device is already opened", E_USER_NOTICE);
  163. return true;
  164. }
  165.  
  166. if ($this->_dState === SERIAL_DEVICE_NOTSET)
  167. {
  168. trigger_error("The device must be set before to be open", E_USER_WARNING);
  169. return false;
  170. }
  171.  
  172. if (!preg_match("@^[raw]\+?b?$@", $mode))
  173. {
  174. trigger_error("Invalid opening mode : ".$mode.". Use fopen() modes.", E_USER_WARNING);
  175. return false;
  176. }
  177.  
  178. $this->_dHandle = @fopen($this->_device, $mode);
  179.  
  180. if ($this->_dHandle !== false)
  181. {
  182. stream_set_blocking($this->_dHandle, 0);
  183. $this->_dState = SERIAL_DEVICE_OPENED;
  184. return true;
  185. }
  186.  
  187. $this->_dHandle = null;
  188. trigger_error("Unable to open the device", E_USER_WARNING);
  189. return false;
  190. }
  191.  
  192. /**
  193. * Closes the device
  194. *
  195. * @return bool
  196. */
  197. function deviceClose ()
  198. {
  199. if ($this->_dState !== SERIAL_DEVICE_OPENED)
  200. {
  201. return true;
  202. }
  203.  
  204. if (fclose($this->_dHandle))
  205. {
  206. $this->_dHandle = null;
  207. $this->_dState = SERIAL_DEVICE_SET;
  208. return true;
  209. }
  210.  
  211. trigger_error("Unable to close the device", E_USER_ERROR);
  212. return false;
  213. }
  214.  
  215. //
  216. // OPEN/CLOSE DEVICE SECTION -- {STOP}
  217. //
  218.  
  219. //
  220. // CONFIGURE SECTION -- {START}
  221. //
  222.  
  223. /**
  224. * Configure the Baud Rate
  225. * Possible rates : 110, 150, 300, 600, 1200, 2400, 4800, 9600, 38400,
  226. * 57600 and 115200.
  227. *
  228. * @param int $rate the rate to set the port in
  229. * @return bool
  230. */
  231. function confBaudRate ($rate)
  232. {
  233. if ($this->_dState !== SERIAL_DEVICE_SET)
  234. {
  235. trigger_error("Unable to set the baud rate : the device is either not set or opened", E_USER_WARNING);
  236. return false;
  237. }
  238.  
  239. $validBauds = array (
  240. 110 => 11,
  241. 150 => 15,
  242. 300 => 30,
  243. 600 => 60,
  244. 1200 => 12,
  245. 2400 => 24,
  246. 4800 => 48,
  247. 9600 => 96,
  248. 19200 => 19,
  249. 38400 => 38400,
  250. 57600 => 57600,
  251. 115200 => 115200
  252. );
  253.  
  254. if (isset($validBauds[$rate]))
  255. {
  256. if ($this->_os === "linux")
  257. {
  258. $ret = $this->_exec("stty -F " . $this->_device . " " . (int) $rate, $out);
  259. }
  260. if ($this->_os === "darwin")
  261. {
  262. $ret = $this->_exec("stty -f " . $this->_device . " " . (int) $rate, $out);
  263. }
  264. elseif ($this->_os === "windows")
  265. {
  266. $ret = $this->_exec("mode " . $this->_windevice . " BAUD=" . $validBauds[$rate], $out);
  267. }
  268. else return false;
  269.  
  270. if ($ret !== 0)
  271. {
  272. trigger_error ("Unable to set baud rate: " . $out[1], E_USER_WARNING);
  273. return false;
  274. }
  275. }
  276. }
  277.  
  278. /**
  279. * Configure parity.
  280. * Modes : odd, even, none
  281. *
  282. * @param string $parity one of the modes
  283. * @return bool
  284. */
  285. function confParity ($parity)
  286. {
  287. if ($this->_dState !== SERIAL_DEVICE_SET)
  288. {
  289. trigger_error("Unable to set parity : the device is either not set or opened", E_USER_WARNING);
  290. return false;
  291. }
  292.  
  293. $args = array(
  294. "none" => "-parenb",
  295. "odd" => "parenb parodd",
  296. "even" => "parenb -parodd",
  297. );
  298.  
  299. if (!isset($args[$parity]))
  300. {
  301. trigger_error("Parity mode not supported", E_USER_WARNING);
  302. return false;
  303. }
  304.  
  305. if ($this->_os === "linux")
  306. {
  307. $ret = $this->_exec("stty -F " . $this->_device . " " . $args[$parity], $out);
  308. }
  309. else
  310. {
  311. $ret = $this->_exec("mode " . $this->_windevice . " PARITY=" . $parity{0}, $out);
  312. }
  313.  
  314. if ($ret === 0)
  315. {
  316. return true;
  317. }
  318.  
  319. trigger_error("Unable to set parity : " . $out[1], E_USER_WARNING);
  320. return false;
  321. }
  322.  
  323. /**
  324. * Sets the length of a character.
  325. *
  326. * @param int $int length of a character (5 <= length <= 8)
  327. * @return bool
  328. */
  329. function confCharacterLength ($int)
  330. {
  331. if ($this->_dState !== SERIAL_DEVICE_SET)
  332. {
  333. trigger_error("Unable to set length of a character : the device is either not set or opened", E_USER_WARNING);
  334. return false;
  335. }
  336.  
  337. $int = (int) $int;
  338. if ($int < 5) $int = 5;
  339. elseif ($int > 8) $int = 8;
  340.  
  341. if ($this->_os === "linux")
  342. {
  343. $ret = $this->_exec("stty -F " . $this->_device . " cs" . $int, $out);
  344. }
  345. else
  346. {
  347. $ret = $this->_exec("mode " . $this->_windevice . " DATA=" . $int, $out);
  348. }
  349.  
  350. if ($ret === 0)
  351. {
  352. return true;
  353. }
  354.  
  355. trigger_error("Unable to set character length : " .$out[1], E_USER_WARNING);
  356. return false;
  357. }
  358.  
  359. /**
  360. * Sets the length of stop bits.
  361. *
  362. * @param float $length the length of a stop bit. It must be either 1,
  363. * 1.5 or 2. 1.5 is not supported under linux and on some computers.
  364. * @return bool
  365. */
  366. function confStopBits ($length)
  367. {
  368. if ($this->_dState !== SERIAL_DEVICE_SET)
  369. {
  370. trigger_error("Unable to set the length of a stop bit : the device is either not set or opened", E_USER_WARNING);
  371. return false;
  372. }
  373.  
  374. if ($length != 1 and $length != 2 and $length != 1.5 and !($length == 1.5 and $this->_os === "linux"))
  375. {
  376. trigger_error("Specified stop bit length is invalid", E_USER_WARNING);
  377. return false;
  378. }
  379.  
  380. if ($this->_os === "linux")
  381. {
  382. $ret = $this->_exec("stty -F " . $this->_device . " " . (($length == 1) ? "-" : "") . "cstopb", $out);
  383. }
  384. else
  385. {
  386. $ret = $this->_exec("mode " . $this->_windevice . " STOP=" . $length, $out);
  387. }
  388.  
  389. if ($ret === 0)
  390. {
  391. return true;
  392. }
  393.  
  394. trigger_error("Unable to set stop bit length : " . $out[1], E_USER_WARNING);
  395. return false;
  396. }
  397.  
  398. /**
  399. * Configures the flow control
  400. *
  401. * @param string $mode Set the flow control mode. Availible modes :
  402. * -> "none" : no flow control
  403. * -> "rts/cts" : use RTS/CTS handshaking
  404. * -> "xon/xoff" : use XON/XOFF protocol
  405. * @return bool
  406. */
  407. function confFlowControl ($mode)
  408. {
  409. if ($this->_dState !== SERIAL_DEVICE_SET)
  410. {
  411. trigger_error("Unable to set flow control mode : the device is either not set or opened", E_USER_WARNING);
  412. return false;
  413. }
  414.  
  415. $linuxModes = array(
  416. "none" => "clocal -crtscts -ixon -ixoff",
  417. "rts/cts" => "-clocal crtscts -ixon -ixoff",
  418. "xon/xoff" => "-clocal -crtscts ixon ixoff"
  419. );
  420. $windowsModes = array(
  421. "none" => "xon=off octs=off rts=on",
  422. "rts/cts" => "xon=off octs=on rts=hs",
  423. "xon/xoff" => "xon=on octs=off rts=on",
  424. );
  425.  
  426. if ($mode !== "none" and $mode !== "rts/cts" and $mode !== "xon/xoff") {
  427. trigger_error("Invalid flow control mode specified", E_USER_ERROR);
  428. return false;
  429. }
  430.  
  431. if ($this->_os === "linux")
  432. $ret = $this->_exec("stty -F " . $this->_device . " " . $linuxModes[$mode], $out);
  433. else
  434. $ret = $this->_exec("mode " . $this->_windevice . " " . $windowsModes[$mode], $out);
  435.  
  436. if ($ret === 0) return true;
  437. else {
  438. trigger_error("Unable to set flow control : " . $out[1], E_USER_ERROR);
  439. return false;
  440. }
  441. }
  442.  
  443. /**
  444. * Sets a setserial parameter (cf man setserial)
  445. * NO MORE USEFUL !
  446. * -> No longer supported
  447. * -> Only use it if you need it
  448. *
  449. * @param string $param parameter name
  450. * @param string $arg parameter value
  451. * @return bool
  452. */
  453. function setSetserialFlag ($param, $arg = "")
  454. {
  455. if (!$this->_ckOpened()) return false;
  456.  
  457. $return = exec ("setserial " . $this->_device . " " . $param . " " . $arg . " 2>&1");
  458.  
  459. if ($return{0} === "I")
  460. {
  461. trigger_error("setserial: Invalid flag", E_USER_WARNING);
  462. return false;
  463. }
  464. elseif ($return{0} === "/")
  465. {
  466. trigger_error("setserial: Error with device file", E_USER_WARNING);
  467. return false;
  468. }
  469. else
  470. {
  471. return true;
  472. }
  473. }
  474.  
  475. //
  476. // CONFIGURE SECTION -- {STOP}
  477. //
  478.  
  479. //
  480. // I/O SECTION -- {START}
  481. //
  482.  
  483. /**
  484. * Sends a string to the device
  485. *
  486. * @param string $str string to be sent to the device
  487. * @param float $waitForReply time to wait for the reply (in seconds)
  488. */
  489. function sendMessage ($str, $waitForReply = 0.1)
  490. {
  491. $this->_buffer .= $str;
  492.  
  493. if ($this->autoflush === true) $this->serialflush();
  494.  
  495. usleep((int) ($waitForReply * 1000000));
  496. }
  497.  
  498. /**
  499. * Reads the port until no new datas are availible, then return the content.
  500. *
  501. * @pararm int $count number of characters to be read (will stop before
  502. * if less characters are in the buffer)
  503. * @return string
  504. */
  505. function readPort ($count = 0)
  506. {
  507. if ($this->_dState !== SERIAL_DEVICE_OPENED)
  508. {
  509. trigger_error("Device must be opened to read it", E_USER_WARNING);
  510. return false;
  511. }
  512.  
  513. if ($this->_os === "linux" || $this->_os === "osx")
  514. {
  515. // Behavior in OSX isn't to wait for new data to recover, but just grabs what's there!
  516. // Doesn't always work perfectly for me in OSX
  517. $content = ""; $i = 0;
  518.  
  519. if ($count !== 0)
  520. {
  521. do {
  522. if ($i > $count) $content .= fread($this->_dHandle, ($count - $i));
  523. else $content .= fread($this->_dHandle, 128);
  524. } while (($i += 128) === strlen($content));
  525. }
  526. else
  527. {
  528. do {
  529. $content .= fread($this->_dHandle, 128);
  530. } while (($i += 128) === strlen($content));
  531. }
  532.  
  533. return $content;
  534. }
  535. elseif ($this->_os === "windows")
  536. {
  537. /* Do nothing : not implented yet */
  538. }
  539.  
  540. trigger_error("Reading serial port is not implemented for Windows", E_USER_WARNING);
  541. return false;
  542. }
  543.  
  544. /**
  545. * Flushes the output buffer
  546. * Renamed from flush for osx compat. issues
  547. *
  548. * @return bool
  549. */
  550. function serialflush ()
  551. {
  552. if (!$this->_ckOpened()) return false;
  553.  
  554. if (fwrite($this->_dHandle, $this->_buffer) !== false)
  555. {
  556. $this->_buffer = "";
  557. return true;
  558. }
  559. else
  560. {
  561. $this->_buffer = "";
  562. trigger_error("Error while sending message", E_USER_WARNING);
  563. return false;
  564. }
  565. }
  566.  
  567. //
  568. // I/O SECTION -- {STOP}
  569. //
  570.  
  571. //
  572. // INTERNAL TOOLKIT -- {START}
  573. //
  574.  
  575. function _ckOpened()
  576. {
  577. if ($this->_dState !== SERIAL_DEVICE_OPENED)
  578. {
  579. trigger_error("Device must be opened", E_USER_WARNING);
  580. return false;
  581. }
  582.  
  583. return true;
  584. }
  585.  
  586. function _ckClosed()
  587. {
  588. if ($this->_dState !== SERIAL_DEVICE_CLOSED)
  589. {
  590. trigger_error("Device must be closed", E_USER_WARNING);
  591. return false;
  592. }
  593.  
  594. return true;
  595. }
  596.  
  597. function _exec($cmd, &$out = null)
  598. {
  599. $desc = array(
  600. 1 => array("pipe", "w"),
  601. 2 => array("pipe", "w")
  602. );
  603.  
  604. $proc = proc_open($cmd, $desc, $pipes);
  605.  
  606. $ret = stream_get_contents($pipes[1]);
  607. $err = stream_get_contents($pipes[2]);
  608.  
  609. fclose($pipes[1]);
  610. fclose($pipes[2]);
  611.  
  612. $retVal = proc_close($proc);
  613.  
  614. if (func_num_args() == 2) $out = array($ret, $err);
  615. return $retVal;
  616. }
  617.  
  618. //
  619. // INTERNAL TOOLKIT -- {STOP}
  620. //
  621. }
  622. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement