<?
/*****
* ---------- SOUS LICENCE GPL --------
*
*--------------- VERSION 2.0 du 29/02/2004 ---------
* Amelioration importante du temps de lecture.
* Envoie des requetes Modbus multiples sur le socket avant lecture et recuperation
* des données.
* + Rectification des exemples ci-dessous
*
* -------------- VERSION 1.3 du 05/11/2003 ---------
* Correction des exemples ci-dessous.....
*
* -------------- VERSION 1.2 du 17/11/2002 ---------
* Rajout d'un mode Simulation ( retourne des valeurs aleatoires sans connexions )
*
* -------------- VERSION 1.1 du 01/07/2002 ---------
* Rajout du routage dynamique avec passerelle 174 CEV 200 30 MB+ / ModBusTcp
*
* -------------- VERSION 1.0 du 30/10/2001 ---------
* Creation de la classe
*
*------------------------------------------------------------------
* EXEMPLES
*------------------------------------------------------------------
*
*------ Lecture d'un tableau de registres ou bits contigus --------
*
* ...
* include "class_ModbusTcp.inc";
*
* $Plc = new ModbusTcp;
* $Plc->SetAdIpPLC ("195.6.140.177");
*
* $Plc->Unit = 5; // Sans routage dynamique
* $Plc->BridgeRoute = array( 52, 11, 0, 0, 0 ); // Avec routage MB+ dynamique si passerelle 174CEV20030
*
* $valeurs = $Plc->ReadModbus( "400001", 50 ); // Lecture de 50 mots ?artir de 400001
* $Plc->print_r_log ($valeurs); echo "<br>";
*
* $valeurs = $Plc->ReadModbus( "300001", 15 ); // Lecture de 15 mots d'entr??artir de 300001
* $Plc->print_r_log ($valeurs); echo "<br>";
*
* $valeurs = $Plc->ReadModbus( "000001", 200 ); // Lecture de 200 bits de ?artir de 000001
* $Plc->print_r_log ($valeurs); echo "<br>";
*
* $valeurs = $Plc->ReadModbus( "100001", 125 ); // Lecture de 125 bits d'entr??artir de 100001
* $Plc->print_r_log ($valeurs); echo "<br>";
* ...
*
* $Plc->ModClose();
*
*
*------- Lecture d'un tableau de registres aleatoires -------------
*
* //...
* include "class_ModbusTcp.inc";
*
* $Plc = new ModbusArray; // **** /!\ =Class extend de ModbusTcp
* $Plc->SetAdIpPLC ("195.6.140.177");
*
* $Plc->Unit = 5; // Sans routage dynamique
* //$Plc->BridgeRoute = array( 52, 11, 0, 0, 0 ); // Avec routage MB+ dynamique si passerelle 174CEV20030 de =S=
*
* $Registre = array (400001, 400250, 400625, 400002, 400050, 300001, 000005, 100010, 100035 );
* $arrValeurs = $Plc->ReadArrRegs( $Registre );
* $Plc->print_r_log ($arrValeurs); echo "<br>";
* //...
*
* $Plc->ModClose();
*
* A noter que dans ce cas, les trames envoyees sont optimisees au niveau du reseau de
* facon a lire des tableaux de mots contigus.
* A voir avec $Plc->SetDebug();
*
*
*------ Utilisation du mode Simulation -----------------------------
*
* ...
* include "class_ModbusTcp.inc";
*
* $Plc = new ModbusTcp;
* $Plc->SetSimulation();
*
* $valeurs = $Plc->ReadModbus( "400001", 50 );
* $Plc->print_r_log($valeurs); echo "<br>";
*
* $valeurs = $Plc->ReadModbus( "300001", 63 );
* $Plc->print_r_log($valeurs); echo "<br>";
*
* $valeurs = $Plc->ReadModbus( "000001", 2000 );
* $Plc->print_r_log ($valeurs); echo "<br>";
* ...
*
* $Plc->ModClose();
**/
class ModbusTcp {
var $AdIpPLC;
var $PortIpPLC;
var $Unit;
var $DebutAdresse;
var $Nbre;
var $WriteValues;
var $NrTransact;
var $SockOutBuffer;
var $Erreur;
var $Fp;
var $BridgeRoute;
var $TmpBridgeRoute;
var $Debug;
var $Simulation;
function ModbusTcp () { // Constructeur
$this->Fp = false;
$this->AdIpPLC = "";
$this->PortIpPLC = 502;
$this->Unit = 255;
$this->DebutAdresse = 0;
$this->Nbre = 1;
$this->WriteValues = array(0);
$this->SockOutBuffer = array();
$this->NrTransact = 0;
$this->Erreur = "";
$this->BridgeRoute = array();
$this->TmpBridgeRoute = array();
$this->Debug = false;
$this->Simulation = false;
srand( (float) microtime()*1000000 );
}
function SetAdIpPLC( $Ip ) {
$this->AdIpPLC = $Ip;
$this->ModClose(); // Fermeture de la connection en cours dans le cas de changement d'adresse IP
$this->SockOutBuffer = array(); // Initialisation du buffer de sortie après changement de Device
}
function ModConn() {
if ( !$this->Simulation ) {
$this->Fp = @fsockopen( "$this->AdIpPLC", $this->PortIpPLC, $errno, $errstr, 5 ) or die("$errstr ($errno)<br>\nPas de connexion a l'Adresse $this->AdIpPLC");
}
}
function ModClose() {
@fclose($this->Fp);
}
function MbReadQuery ( $Unit=255, $MbFunction, $Debut=0, $Nbre=1 ) {
$Query = chr(0).chr(0).chr(0).chr(0).chr(0).chr(6).chr($Unit).chr($MbFunction) ;
list( $Query[1], $Query[0] ) = $this->WordToBytes( $this->NrTransact );
list( $Query[9], $Query[8] ) = $this->WordToBytes( $Debut );
list( $Query[11], $Query[10] ) = $this->WordToBytes( $Nbre );
$this->NrTransact++;
return $Query;
}
function MbWriteQuery ( $Unit=255, $MbFunction=3, $Debut=0, $valeurs = array(0) ) {
if ( ($NbreMots = Sizeof( $valeurs )) > 100 ) $NbreMots = 100;
$Query = chr(0).chr(0).chr(0).chr(0).chr(0).chr(6).chr($Unit).chr($MbFunction) ;
list( $Query[1], $Query[0] ) = $this->WordToBytes( $this->NrTransact );
list( $Query[5], $obuf[4] ) = $this->WordToBytes( $NbreMots * 2 + 7 ); //Nbre de mots
list( $Query[9], $Query[8] ) = $this->WordToBytes($Debut-1); //Adresse de debut
list( $Query[11], $Query[10] ) = $this->WordToBytes( $NbreMots ); //Nbre de mots
$Query[12] = chr( $NbreMots * 2 ); //Nbre d'octets
for ( $i=0; $i < $NbreMots*2; $i += 2 ) {
list( $Query[13+$i], $Query[13+$i+1] ) = $this->WordToBytes( $valeurs[$i/2] ); //Valeurs
}
$this->NrTransact++;
return $Query;
}
function WriteSocket( &$sOutBuf ) {
if (!$this->Fp) $this->ModConn();
fwrite( $this->Fp, $sOutBuf );
if ( $this->Debug ) { //Affichage des octets emis si en mode Debug
echo "<b>Bytes sent</b><br>";
for ($i=0;$i<strlen($sOutBuf);$i++ ) {
echo "OctEmis[$i] =".ord($sOutBuf[$i])."<br>";
}
}
return true;
}
function ReadSocket () {
$InBuf = fgetc($this->Fp); //Lire le 1er octet du socket pour utiliser après stream_get_meta_data()
$status = stream_get_meta_data($this->Fp);
$InBuf .= fread($this->Fp, $status["unread_bytes"]); //Lire les octets restants
return $InBuf;
}
function SetSimulation() {
$this->Simulation = True; //
srand( (float) microtime()*1000000 ); //Pour Simulation
echo "<br><font color='#FF9900' size=3><b>Attention: valeurs en Mode SIMULATION ! ! ! ! </b></font><br>";
}
function SetDebug() {
$this->Debug = True; //
}
function WordToBytes( $word ) {
if ( $word > 65535 ) $word = 65535;
return array( chr( $word % 256 ), chr( ( $word - $word % 256 ) / 256 ) ) ;
}
function BytesToWord( $byte1, $byte2 ) {
return ord($byte1) * 256 + ord($byte2);
}
function ByteToBits( $byte1 = 0) { // converti un octet en string format binaire inverse
return strrev( sprintf( "%08d", decbin( ord( $byte1 ) ) ) );
}
function print_r_log($var) {
echo "<pre><font color='#000000' size='1' face='Verdana'>";
print_r($var);
echo "</pre><br>";
}
// --------------------------------------------------------------------------------------------
// FONCTION PRINCIPALE LECTURE D'UN TABLEAU DE 0/1/3/4xxxxx
// ( retourne un tableau [0/1/3/4xxxxx] = valeur )
// --------------------------------------------------------------------------------------------
function ReadModbus( $AdrDebut, $NbreReg ) {
($NbreReg > 0) ? $this->Nbre = (int)$NbreReg : $this->Nbre = 1;
switch ( substr( sprintf("%06d", $AdrDebut), 0, 1) ) {
case "4":
$this->DebutAdresse = $AdrDebut - 400001;
return $this->ReadHoldRegisters();
break;
case "3":
$this->DebutAdresse = $AdrDebut - 300001;
return $this->ReadInputRegisters();
break;
case "1":
$this->DebutAdresse = $AdrDebut - 100001;
return $this->ReadDiscretInputs();
break;
case "0":
$this->DebutAdresse = $AdrDebut - 1;
return $this->ReadCoils();
break;
default:
return array();
}
}
// -------------------------------------------------------
// LECTURE DES 4xxxxx
// ( retourne un tableau [4xxxxx] = valeur )
// -------------------------------------------------------
function ReadHoldRegisters() {
if ( $this->Nbre > 125 ) $this->Nbre = 125;
//Retourne des valeurs aléatoires entre 0 et 4095 sans ouvrir les sockets
if ( $this->Simulation ) {
for ( $i=0; $i<=$this->Nbre; $i++ ) {
$buffer[400000 + $this->DebutAdresse + $i] = rand(0, 65535); //Simulation ANA
}
return $buffer;
} // FIN Simulation
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
$obuf = &$this->MbReadQuery($this->Unit, 3, $this->DebutAdresse, $this->Nbre);
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf );
//--------- LECTURE DU SOCKET ---------------
$OctetRecu = $this->ReadSocket();
if ( $OctetRecu[7] != $obuf[7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR DE LECTURE des REGISTRES de SORTIE de ".sprintf("4%05d", $this->DebutAdresse)." a ".sprintf("4%05d", ($this->DebutAdresse + $this->Nbre))."<br>";
for ( $i=0; $i<count($OctetRecu); $i++ ) {
echo "OctRecu[$i] =". ord($OctetRecu[$i])."<br>";
}
echo "</b></FONT>\n";
return $buffer = array();
}
//Recuperation des DATAs
$i = 0;
$buffer = array();
for ($j=0; $j < ord($OctetRecu[8]); $j=$j+2) {
$i++;
$buffer[400000 + $this->DebutAdresse + $i] = $this->BytesToWord( $OctetRecu[$j+9], $OctetRecu[$j+10] );
}
return $buffer ;
}
// --------------------------------------------------------------
// LECTURE DES 3xxxxx
// ( retourne un tableau [3xxxxx] = valeur )
// --------------------------------------------------------------
function ReadInputRegisters() {
if ( $this->Nbre > 125 ) $this->Nbre = 125;
//Retourne des valeurs aleatoires entre 0 et 4095 sans ouvrir les sockets
if ( $this->Simulation ) {
for ( $i=0; $i<=$this->Nbre; $i++ ) {
$buffer[300000 + $this->DebutAdresse + $i] = rand(0, 4095);
}
return $buffer;
} // FIN Simulation
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
$obuf = &$this->MbReadQuery( $this->Unit, 4, $this->DebutAdresse, $this->Nbre);
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf );
//--------- LECTURE DU SOCKET ---------------
$OctetRecu = $this->ReadSocket();
if ( $OctetRecu[7] != $obuf[7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR DE LECTURE des REGISTRES d'ENTREE de ".sprintf("3%05d", $this->DebutAdresse)." ".sprintf("3%05d", ($this->DebutAdresse + $this->Nbre))."<br>";
for ( $i=0; $i<count($OctetRecu); $i++ ) {
echo "OctRecu[$i] =". ord($OctetRecu[$i])."<br>";
}
echo "</b></FONT>\n";
return $buffer = array();
}
//Recuperation des DATAs
$i = 0;
$buffer = array();
for ($j=0; $j < ord($OctetRecu[8]); $j=$j+2) {
$i++;
$buffer[300000 + $this->DebutAdresse + $i] = $this->BytesToWord( $OctetRecu[$j+9], $OctetRecu[$j+10] );
}
return $buffer ;
}
// -------------------------------------------------------------
// LECTURE DES 1xxxxx
// ( retourne un tableau [1xxxxx] = valeur )
// -------------------------------------------------------------
function ReadDiscretInputs() {
if ( $this->Nbre > 2000 ) $this->Nbre = 2000;
//Retourne des valeurs aleatoires entre 0 et 1 sans ouvrir les sockets
if ( $this->Simulation ) {
for ( $i=0; $i<=$this->Nbre; $i++ ) {
$buffer[100000 + $this->DebutAdresse + $i] = rand(0, 1);
}
return $buffer;
} // FIN Simulation
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
$obuf = &$this->MbReadQuery( $this->Unit, 2, $this->DebutAdresse, $this->Nbre);
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf );
//--------- LECTURE DU SOCKET --------------
$OctetRecu = $this->ReadSocket();
if ( $OctetRecu[7] != $obuf[7] ) { // Lecture du 8eme octet = Code function renvoy?ar destinataire
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR DE LECTURE des Bits d'ENTREES de ".sprintf("1%05d", $this->DebutAdresse)." ".sprintf("1%05d", ($this->DebutAdresse + $this->Nbre))."<br>";
echo "</b></FONT>\n";
return $buffer = array();
}
//$OctetRecu[8] 9eme octet = nbre d'octets (mots) de donn?
$i = 0;
$buffer = array();
$debut = 100000 + $this->DebutAdresse + 1;
while( $i < ord($OctetRecu[8]) ) {
$tmp = $this->ByteToBits( $OctetRecu[$i+9] );
for ( $j=0; $j<8; $j++ ) { //extraction des bits de mots
$bit = $i*8 + $j;
if ( $bit >= $this->Nbre ) break;
$buffer[$debut + $j + $i*8] = $tmp[$j];
}
$i++;
}
return $buffer;
}
// -------------------------------------------------------------
// LECTURE DES 0xxxxx
// ( retourne un tableau ['0xxxxx'] = valeur )
// -------------------------------------------------------------
function ReadCoils() {
if ( $this->Nbre > 2000 ) $this->Nbre = 2000;
//Retourne des valeurs aleatoires entre 0 et 1 sans ouvrir les sockets
if ( $this->Simulation ) {
for ( $i=0; $i<=$this->Nbre; $i++ ) {
$buffer[sprintf( "%06d", $this->DebutAdresse + $i)] = rand(0, 1);
}
return $buffer;
} // FIN Simulation
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
$obuf = &$this->MbReadQuery( $this->Unit, 1, $this->DebutAdresse, $this->Nbre);
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf );
//--------- LECTURE DU SOCKET --------------
$OctetRecu = $this->ReadSocket();
if ( $OctetRecu[7] != $obuf[7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR DE LECTURE des Bits de SORTIES de ".sprintf("%06d", $this->DebutAdresse)." ".sprintf("%06d", ($this->DebutAdresse + $this->Nbre))."<br>\n";
echo "</b></FONT>\n";
return $buffer = array();
}
//$OctetRecu[8] 9eme octet = nbre mots(2octets) de donn?
$i = 0;
$buffer = array();
$debut = $this->DebutAdresse + 1;
while( $i < ord($OctetRecu[8]) ) {
$tmp = $this->ByteToBits( $OctetRecu[$i+9] );
for ( $j=0; $j<8; $j++ ) {
$bit = $i*8 + $j;
if ( $bit >= $this->Nbre ) break;
$buffer[ sprintf( "%06d", $debut + $j + $i*8 )] = $tmp[$j];
}
$i++;
}
return $buffer;
}
// -----------------------------------------------
// ECRITURE DES 400000
// -----------------------------------------------
function WriteHoldRegisters( $DebutAdresse = 0, $valeurs = array(0) ) {
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
$CodeFunction = 16; // 16 = Ecriture d'un tableau de registres 400001
$obuf = $this->MbWriteQuery( $this->Unit, $CodeFunction, $this->DebutAdresse, $valeurs);
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf );
//--------- LECTURE DU SOCKET ---------------
$OctetRecu = $this->ReadSocket();
if ( $OctetRecu[7] != $obuf[7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR D'ECRITURE<br>";
echo "</b></FONT>\n";
return False;
}
//$OctetRecu[8] //Confirmation Debut tableau d'adresse ecrite (octet Haut)
//$OctetRecu[9] //Confirmation Debut tableau d'adresse ecrite (octet Bas) adresse = Oct.Haut*256 + Oct.Bas
//$OctetRecu[10] //Nbre d'octets suivent
return True ;
}
// -----------------------------------------------
// ECRITURE D'UNE BOBINE
// -----------------------------------------------
function WriteCoil( $Adresse = 0, $valeur = false ) {
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
$CodeFunction = 5; // 5 = Ecriture d'une Bobine
$obuf = chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr($this->Unit).chr($CodeFunction);
list( $obuf[5], $obuf[4] ) = $this->WordToBytes(6); //Nbre de mots qui suivent
list( $obuf[9], $obuf[8] ) = $this->WordToBytes($Adresse -1); //Adresse de la bobine
$valeur ? $obuf[10] = chr(255) : $obuf[10] = chr(0);
$obuf[11] = chr(0);
if ( $this->Debug ) {
echo "<b>WriteCoil</b><br>";
for ($i=0;$i<count($obuf);$i++ ) {
echo "OctEmis[$i] =". ord($obuf[$i])."<br>";
}
}
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf );
//--------- LECTURE DU SOCKET ---------------
$OctetRecu = $this->ReadSocket();
if ( $OctetRecu[7] != $obuf[7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR D'ECRITURE BIT<br>";
echo "</b></FONT>\n";
return False;
}
return True ;
}
// --------------------------------------------------------
// SETUP BRIDGE FOR DYNAMIC ROUTING
// --------------------------------------------------------
function SetBridgeRoute() {
//--------------------------------------------------------------------------------------------------------
//Consiste a ecrire a l'adresse 255 du device 255 de la passerelle, le routage MB+ avec la fonction 16
//Une fois la route etablie, on peut lire ou ecrire dans le device 254 pour atteindre l'automate concerne
//---------------------------------------------------------------------------------------------------------
//Test si la nouvelle route est la meme que l'ancienne.
//Si pas de changement de routage MB+, on n'envoie pas de nouvelle route a la passerelle MB+/Ethernet
$result = array_diff($this->BridgeRoute, $this->TmpBridgeRoute);
if ( count($result) == 0 ) return True;
$this->TmpBridgeRoute = $this->BridgeRoute;
$obuf1 = chr(0).chr(0).chr(0).chr(0).chr(0).chr(13)
.chr(255) // 1=Host-based routing 255=Socket-based routing
.chr(16) //Code fonction Modbus 16 = Ecriture d'un tableau de registres 4xxxxx
.chr(0) //Octet 8 = Adresse de debut octet 1
.chr(255-1) //Octet 9 = Adresse de debut octet 2
.chr(0) //Octet 10 = Nbre de mots octet 1
.chr(3) //Octet 11 = Nbre de mots octet 2
.chr(6) //Octet 12 = Nbre d'octets qui suivent
.chr(5) //Octet 13 = Nbre d'octets qui suivent = Cte => Attention: fait parti des champs data's
.chr($this->BridgeRoute[0]) //Octet 14 = Routage 1
.chr($this->BridgeRoute[1]) //Octet 15 = Routage 2
.chr($this->BridgeRoute[2]) //Octet 16 = Routage 3
.chr($this->BridgeRoute[3]) //Octet 17 = Routage 4
.chr($this->BridgeRoute[4]); //Octet 18 = Routage 5
if ( $this->Debug == true ) {
echo "<b>SetBridgeRoute<br></b>";
}
//--------- ECRITURE DU SOCKET --------------
$this->WriteSocket ( $obuf1 );
//--------- LECTURE DU SOCKET --------------
$OctetRecu = &$this->ReadSocket();
if ( $this->Debug == true ) echo "Reception - Adresse Unite = ".ord($OctetRecu[6])." <br>"; // 7eme octet = adresse du device
if ( $OctetRecu[7] != $obuf1[7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR D'ECRITURE dans la fonction de routage dynamique de la passerelle ETH/MB+ (SetBridgeRoute) adr. IP ".$this->AdIpPLC."<br>\n";
echo "</b></FONT>\n";
fclose($this->Fp);
exit;
}
if ( $this->Debug == true ) echo "Reception - Code function = ".ord($obuf1[7])."<br>";
$adresse = $this->BytesToWord( ord($obuf1[8]), ord($obuf1[9]) );
if ( $this->Debug == true ) echo "Reception - Adresse debut = $adresse <br>";
$nbMots = $this->BytesToWord( ord($obuf1[10]), ord($obuf1[11]) );
if ( $this->Debug == true ) echo "Reception - Nbre de mots = $nbMots <br>";
//Ne pas fermer la connection !! car la fonction Modbus suivante suivra !
//fclose($this->Fp);
$this->Unit = 254; //Preparation pour la fonction Modbus suivante.
return True ;
}
} //Fin de la class 'ModbusTcp'
class ModbusArray extends ModbusTcp {
// --------------------------------------------------------------------------------------------
// CONSTRUCTION DES TRAMES POUR ENVOIE MULTIPLES
// --------------------------------------------------------------------------------------------
function BuildSockOutBuffer( $AdrDebut, $NbreReg ) {
($NbreReg > 0) ? $this->Nbre = (int)$NbreReg : $this->Nbre = 1;
switch ( substr( sprintf("%06d", $AdrDebut), 0, 1) ) {
case "4":
$this->DebutAdresse = $AdrDebut - 400001;
$this->SockOutBuffer[$this->NrTransact] = &$this->MbReadQuery($this->Unit, 3, $this->DebutAdresse, $this->Nbre);
return;
break;
case "3":
$this->DebutAdresse = $AdrDebut - 300001;
$this->SockOutBuffer[$this->NrTransact] = &$this->MbReadQuery( $this->Unit, 4, $this->DebutAdresse, $this->Nbre);
return;
break;
case "1":
$this->DebutAdresse = $AdrDebut - 100001;
$this->SockOutBuffer[$this->NrTransact] = &$this->MbReadQuery( $this->Unit, 2, $this->DebutAdresse, $this->Nbre);
return;
break;
case "0":
$this->DebutAdresse = $AdrDebut - 1;
$this->SockOutBuffer[$this->NrTransact] = &$this->MbReadQuery( $this->Unit, 1, $this->DebutAdresse, $this->Nbre);
return;
break;
default:
return;
}
}
function SendOutBuffer() {
if ( $this->BridgeRoute ) $this->SetBridgeRoute();
for ($i=0; $i<count($this->SockOutBuffer); $i++) {
$this->WriteSocket( $this->SockOutBuffer[$i] );
}
}
function ReadSockResult() {
$buffer = array();
//---- MODE SIMULATION
if ( $this->Simulation ) {
//---- Boucle de lecture par requete Modbus envoyee
for ($k=0; $k < sizeof($this->SockOutBuffer); $k++) {
//---- Init variables par les trames émisent
$DebutAdresse = $this->BytesToWord( $this->SockOutBuffer[$k][8], $this->SockOutBuffer[$k][9] );
$Nbre = $this->BytesToWord( $this->SockOutBuffer[$k][10], $this->SockOutBuffer[$k][11] );
switch ( ord($this->SockOutBuffer[$k][7]) ) {
case 3: //---- HoldRegisters
for ( $i=0; $i<=$Nbre; $i++ ) {
$buffer[400000 + $DebutAdresse + $i] = rand(0, 65535); //Simulation ANA
}
break;
case 4: //---- InputRegisters
for ( $i=0; $i<=$Nbre; $i++ ) {
$buffer[300000 + $DebutAdresse + $i] = rand(0, 4095);
}
break;
case 2: //---- DiscretInputs
for ( $i=0; $i<=$Nbre; $i++ ) {
$buffer[100000 + $DebutAdresse + $i] = rand(0, 1);
}
break;
case 1: //---- Coils
for ( $i=0; $i<=$Nbre; $i++ ) {
$buffer[sprintf( "%06d", $DebutAdresse + $i)] = rand(0, 1);
}
break;
}
}
return $buffer;
} // FIN Simulation
//---- Boucle de lecture par requete Modbus envoyee
for ($w=0; $w < sizeof($this->SockOutBuffer); $w++) {
$arrOctetRecu[$w] = $this->ReadSocket();
}
for ($w=0; $w < sizeof($arrOctetRecu); $w++) {
$OctetRecu = &$arrOctetRecu[$w];
//---- Affichage des octets recu si en mode Debug
if ( $this->Debug ) {
echo "<b>Bytes received</b><br>";
for ( $i=0; $i<strlen($OctetRecu); $i++ ) {
echo "OctRecu[$i] =". ord($OctetRecu[$i])."<br>";
}
}
//---- Recherche Nr Trame recue
$k = $this->BytesToWord( $OctetRecu[0], $OctetRecu[1] );
//---- Init variables par les trames émisent
$DebutAdresse = $this->BytesToWord( $this->SockOutBuffer[$k][8], $this->SockOutBuffer[$k][9] );
$Nbre = $this->BytesToWord( $this->SockOutBuffer[$k][10], $this->SockOutBuffer[$k][11] );
//---- Test code fonction MB retourné = code fonction envoyé
if ( $OctetRecu[7] != $this->SockOutBuffer[$k][7] ) {
echo "<FONT SIZE='3' COLOR='#FFFF00'><b>";
echo "ERREUR CODE FONCTION MODBUS RECU <br>";
for ( $i=0; $i<count($OctetRecu); $i++ ) {
echo "OctRecu[$i] =". ord($OctetRecu[$i])."<br>";
}
echo "</b></FONT>\n";
}
//---- Test du code fonction Modbus retourné pour extraction des données
switch ( ord($OctetRecu[7]) ) {
case 3: //---- Read HoldRegisters
$i = 0;
for ($j=0; $j < ord($OctetRecu[8]); $j=$j+2) {
$i++;
$buffer[400000 + $DebutAdresse + $i] = $this->BytesToWord( $OctetRecu[$j+9], $OctetRecu[$j+10] );
}
break;
case 4: //---- Read InputRegisters
$i = 0;
for ($j=0; $j < ord($OctetRecu[8]); $j=$j+2) {
$i++;
$buffer[300000 + $DebutAdresse + $i] = $this->BytesToWord( $OctetRecu[$j+9], $OctetRecu[$j+10] );
}
break;
case 2: //---- Read DiscretInputs
$i = 0;
$debut = 100000 + $DebutAdresse + 1;
while( $i < ord($OctetRecu[8]) ) {
$tmp = $this->ByteToBits( $OctetRecu[$i+9] );
for ( $j=0; $j<8; $j++ ) { //extraction des bits de mots
$bit = $i*8 + $j;
if ( $bit >= $Nbre ) break 2;
$buffer[$debut + $j + $i*8] = $tmp[$j];
}
$i++;
}
break;
case 1: //---- Read Coils
$i = 0;
$debut = $DebutAdresse + 1;
while( $i < ord($OctetRecu[8]) ) {
$tmp = $this->ByteToBits( $OctetRecu[$i+9] );
for ( $j=0; $j<8; $j++ ) {
$bit = $i*8 + $j;
if ( $bit >= $Nbre ) break 2;
$buffer[ sprintf( "%06d", $debut + $j + $i*8 )] = $tmp[$j];
}
$i++;
}
break;
Default:
}
}
$this->SockOutBuffer = array(); // Initialisation du tableau des requetes Modbus. Utile en cas de changement de device sur passerelle 174CEV20030
return $buffer ;
}
// -------------------------------------------------------------------------
// DECOUPAGE D'UN TABLEAU de 0/1/3/4xxxxx
// ( retourne un tableau [debut_adres] = Nbre de mots/bits )
// -------------------------------------------------------------------------
function DecoupeTrame( $arr ) {
asort($arr);
// print_r($arr); echo "<br>";
$tmp = $arr[key($arr)]; //init ?a premi? valeur du tableau
foreach ( $arr as $i => $value) {
ereg( "^3|^4", $arr[$i]) ? $max = 125 : $max = 500 ;
if ( $arr[$i] - $tmp >= $max ) {
$resultat[$tmp] = $arr[$i_1] - $tmp + 1;
$tmp = $arr[$i];
}
$i_1 = $i;
}
$resultat[$tmp] = $arr[$i] - $tmp + 1; //traitement de la derni? adresse
// print_r($resultat); echo "<br>";
return $resultat;
}
// ------------------------------------------------------------------------------------------
// LECTURE D'UN TABLEAU HETEROGENE TRIE ou NON TRIE 0/1/3/4xxxxx POUR UN DEVICE
// ( retourne un tableau [0/1/3/4xxxxx] = valeur )
// ------------------------------------------------------------------------------------------
function ReadArrRegs( $arrAdr = array ("400001") ) {
$buf = &$this->DecoupeTrame( $arrAdr );
// Fait apparaitre les tableau de bits ou de Mots utilisé pour les trames
if ( $this->Debug ) {
echo "TRAMES: DEVICE => ".$this->Unit." :";
$this->print_r_log ($buf);
echo "<br>\n";
}
foreach ( $buf as $debut => $nbre ) {
$this->BuildSockOutBuffer( $debut, $nbre );
}
if (!$this->Simulation) $this->SendOutBuffer();
return $this->ReadSockResult();
}
}
?>