Advertisement
Guest User

Untitled

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