Advertisement
Guest User

Untitled

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