File modules/modbusy/request/MultibyteRequest.class.php

Last commit: Thu Dec 26 19:50:18 2024 +0100	Jan Dankert	New: ModbusTCP for later use in the scriptbox.
1 <?php 2 namespace modbusy\request; 3 4 5 abstract class MultibyteRequest extends Request 6 { 7 const ERRORS = [ 8 1 => 'Illegal Function Function code received in the query is not recognized or allowed by server', 9 2 => 'Illegal Data Address Data address of some or all the required entities are not allowed or do not exist in server', 10 3 => 'Illegal Data Value Value is not accepted by server', 11 4 => 'Server Device Failure Unrecoverable error occurred while server was attempting to perform requested action', 12 5 => 'Acknowledge Server has accepted request and is processing it, but a long duration of time is required. This response is returned to prevent a timeout error from occurring in the client. client can next issue a Poll Program Complete message to determine whether processing is completed', 13 6 => 'Server Device Busy Server is engaged in processing a long-duration command; client should retry later', 14 7 => 'Negative Acknowledge Server cannot perform the programming functions; client should request diagnostic or error information from server', 15 8 => 'Memory Parity Error Server detected a parity error in memory; client can retry the request', 16 10=> 'Gateway Path Unavailable Specialized for Modbus gateways: indicates a misconfigured gateway', 17 11=> 'Gateway Target Device Failed to Respond', 18 ]; 19 20 protected function request($command ) 21 { 22 $this->log("Sending"); 23 $this->transactionId = rand(0,65535); 24 $transaction = pack("n",$this->transactionId); 25 26 $this->logHex("Sending transaction",$transaction); 27 // When sending a Modbus TCP frame, the frame is split into 6 different sections: 28 //1) Transaction Identifier ( 2 bytes ) 29 //2) Protocol Identifier (2 bytes) 30 //3) Length Field (2 bytes) 31 //4) Unit Identifier (1 byte) 32 //5) Function Code (1 byte) 33 //6) Data bytes (n bytes) 34 $bytes = fwrite($this->socket,$transaction); 35 if ( $bytes !== 2 ) 36 throw new \InvalidArgumentException("could not write transaction id to socket"); 37 38 $bytes = fwrite($this->socket,self::PROTOCOL_IDENTIFIER); 39 $this->logHex("Sending protocol",self::PROTOCOL_IDENTIFIER); 40 if ( $bytes !== 2 ) 41 throw new \InvalidArgumentException("could not write 00 to socket"); 42 43 // length 44 $length = strlen($command)+2; 45 $this->logHex("sending length",pack("n",$length)); 46 fwrite($this->socket,pack("n",$length) ); // 2 bytes 47 48 $this->logHex("sending unit",pack("C",$this->unitId)); 49 fwrite($this->socket,pack("C",$this->unitId) ); // unit identifier 1 byte 50 51 $this->logHex("sending function code",pack("C",$this->functionCode)); 52 fwrite($this->socket,pack("C",$this->functionCode) ); 53 54 $this->logHexDump( "sending command",$command); 55 fwrite($this->socket,$command ); 56 57 $this->log("now getting data..."); 58 $transactionResponse = fgets($this->socket,2+1); 59 $this->logHex("Transaction",$transactionResponse); 60 if ( $transaction != $transactionResponse ) 61 throw new \InvalidArgumentException("transaction from modbus slave '".bin2hex($transactionResponse)."' does not match ours '".bin2hex($transaction)."'"); 62 $protocol = fgets($this->socket,2+1); 63 if ( $protocol != self::PROTOCOL_IDENTIFIER ) 64 throw new \InvalidArgumentException("protocol does not match"); 65 $this->logHex("Protocol",$protocol); 66 $length = unpack("n",fgets($this->socket,2+1))[1]; 67 $this->log("Response-Length ".$length.' bytes'); 68 $response = fgets($this->socket,$length+1); 69 70 $unitResponse = unpack("C",substr($response,0,1))[1]; 71 $this->log("Unit ".$unitResponse); 72 73 $functionResponse = unpack("C",substr($response,1,1))[1]; 74 $this->log("Function code ".$functionResponse); 75 76 $data = substr($response,2); // truncate unitId and functionCode (1+1=2 bytes) 77 $this->logHexDump("Result",$data); 78 79 if ( $functionResponse == $this->functionCode ) { 80 // success 81 82 return $data; 83 } 84 elseif ( $functionResponse == $this->functionCode + 128 ) { 85 86 if ( strlen($data) == 1 ) { 87 $errorCode = unpack("C",$data)[1]; 88 if ( isset(self::ERRORS[$errorCode]) ) 89 throw new \InvalidArgumentException("server error: ".self::ERRORS[$errorCode]); 90 91 else 92 throw new \InvalidArgumentException("server error with unknown error code ".$errorCode); 93 } 94 else 95 throw new \InvalidArgumentException("server error with unknown error data: '".bin2hex($data)); 96 } 97 else { 98 throw new \InvalidArgumentException("server error: function in response is ".$functionResponse." and not the called function ".$function.". Data is '".bin2hex($data)."'"); 99 } 100 } 101 }
Download modules/modbusy/request/MultibyteRequest.class.php
History Thu, 26 Dec 2024 19:50:18 +0100 Jan Dankert New: ModbusTCP for later use in the scriptbox.