1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/**
* Lit une trame de téléinformation
* @param integer $handle : handle du device en entrée
* @param integer $readMode : mode de lecture des données (READ_MODE_HISTORIC | READ_MODE_STANDARD)
* @return array : Le tableau de données pour une trame, null si lecture incorrecte.
*/
function readTrame($handle, $readMode) {
// On attend la fin d'une trame pour commencer avec la trame suivante
$foundTrame = false;
$char = '';
Tools::writeLog("Positionnement en début de trame.");
do {
if (($char = fread($handle, 1)) === false) {
// On sort si on rencontre une erreur de lecture
handleReadError($handle);
return null;
}
} while ($char != chr(2) && $char != chr(0));
// On peut bloquer sur la lecture de caractères null. On force la sortie dans ce cas
if ($char === chr(0)) {
Tools::writeLog("Lecture impossible - caractère null reçu.");
return null;
}
// On est en début de trame
Tools::writeLog("Début de trame");
// On vérifie en lisant la 1ère étiquette, soit les 6c suivants
if (($trame = fread($handle, 6)) === false) {
// On sort si on rencontre une erreur de lecture
handleReadError($handle);
return null;
}
$firstTag = substr($trame, 1, 4);
Tools::writeLog(sprintf("Vérification avec le 1er tag : %s", $firstTag));
$foundTrame = (($readMode === READ_MODE_HISTORIC && $firstTag == "ADCO") ||
($readMode === READ_MODE_STANDARD && $firstTag == "ADSC"));
// Si le 1er tag n'est pas celui souhaité, on sort
if (!$foundTrame) {
Tools::writeLog("Le TAG trouvé n'est pas celui attendu.");
return null;
}
// On a lu le 1er tag d'une nouvelle trame et c'est bien celui attendu. On lit toute la trame
Tools::writeLog("Lecture d'une nouvelle trame.");
// On lit tous les caractères jusqu'a la fin de la trame ou jusqu'à ce qu'on détecte une interruption d'émission
do {
if (($char = fread($handle, 1)) === false) {
// On sort si on rencontre une erreur de lecture
handleReadError($handle);
return null;
}
// Le flux peut -être stoppé. Un EOT est envoyé pour prévenir.
if ($char == chr(4)) {
Tools::writeLog("L'émission est interrompue. On stoppe la lecture.");
return null;
}
if ($char != chr(3)) $trame .= $char;
} while ($char != chr(3));
Tools::writeLog("Analyse de la trame");
// on supprime le 1er caractère de début de trame, soit le chr(10) de la 1ère étiquette
$trame = substr($trame, 1);
// on sépare les messages de la trame
$informations = explode(chr(10), $trame);
// Le caractère séparateur entre étiquette et donnée dépend du mode de lecture
// Le nombre de caractères à exclure de la checksum aussi
if ($readMode === READ_MODE_HISTORIC) {
$sep = chr(0x20);
$extraCars = 2;
} else {
$sep = chr(0x09);
$extraCars = 1;
}
// On analyse et on récupère chaque information de la trame
foreach ($informations as $key => $information) {
// Une info se termine par 0x0d. On supprime ce caractère de contrôle.
if ($information[strlen($information)-1] == chr(0x0d))
$information = substr($information, 0, -1);
else
{
Tools::writeLog(sprintf("Structure de donnée incomplète : %s", $information));
return null;
}
// Somme de contrôle du groupe d'info = dernier caractère
$ctrlCar = ord(substr($information, -1));
// Vérification
$ctrlCheck = 0;
$checkZoneLength = strlen($information) - $extraCars;
for ($c = 0; $c < $checkZoneLength ; $c++) {
$ctrlCheck += ord($information[$c]);
}
$ctrlCheck = ($ctrlCheck & 0x3f) + 0x20;
if ($ctrlCheck != $ctrlCar) {
Tools::writeLog(sprintf("Echec du controle de checksum pour l'information %s", $information));
return null;
}
// Suppression du dernier caractère séparateur et du caractère de contrôle
$information = substr($information, 0, -2);
// On construit un tableau comportant l'étiquette, et la ou les valeurs
$information = explode($sep, $information);
if (! empty($information[0]) && ! empty($information[1])) {
$etiquette = $information[0];
$valeur = "";
// Il peut y avoir un horodatage. Dans ce cas, il y a 2 valeurs : horodatage + valeur de la données
switch (count($information)) {
case 2:
$valeur = $information[1];
break;
case 3:
$valeur = (strlen($information[2]) > 0) ? $information[2] : $information[1];
break;
default:
Tools::writeLog(sprintf("La valeur de %s ne possède pas le nombre de champs attendu.", $etiquette));
Tools::writeLog(print_r($information));
}
if (!empty($valeur))
$datas[$etiquette] = $valeur; // on stocke les étiquettes et les valeurs de l'array datas
else {
Tools::WriteLog(sprintf("L'étiquette %s possède une valeur mais n'a pas le format attendu.", $etiquette));
Tools::WriteLog(print_r($information));
}
}
}
print_r($datas);
return $datas;
}
/**
* Log un message en cas d'erreur de lecture
* @param int $handle : handle du fichier
*/
function handleReadError($handle) {
$info = stream_get_meta_data($handle);
if ($info['timed_out'])
Tools::writeLog("Timeout. Lecture abandonnée.");
else
Tools::writeLog("Erreur de lecture.");
} |
Partager