Archives par mot-clé : cahier de traffic

KLog version 9.2.2

KLog EA4TV screenshot (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2015/12/Screen-Shot-2016-01-05-at-10 NULL.09 NULL.09 NULL.png)Jaime EA4TV m’a récemment informé d’une nouvelle version de KLog, son logiciel de cahier de traffic gratuit qui fonctionne sous OS X, Linux et Windows.

La version 9.2.2 comprend pas mal de corrections de bogues et quelques nouvelles fonctionnalités (http://jaime NULL.robles NULL.es). Elle est disponible en Anglais, Espagnol (Castillan) et Catalan. Jaime est ouvert à d’autres traductions avec votre aide si vous la souhaitez en français.

Bibliothèque PHP de traitement de fichiers logs ADIF v2

Une nouvelle version de la bibliothèque, compatible ADIF v3, est disponible (http://xv4y NULL.radioclub NULL.asia/2015/03/10/bibliotheque-php-de-traitement-de-fichiers-logs-adif-v3/).

Comme promis, je mets à disposition de la communauté ma version de la librairie de traitement (parser) de fichiers logs ADIF v2 (http://adif NULL.org/). Elle accepte les fichiers issus des logiciels les plus courants actuellement (N1MM, DXKeeper, HAM Radio Deluxe, WinLog…) et en extrait les différents champs.

Aucune vérification n’est faite sur la cohérence des informations et celle-ci dépend donc du logiciel de cahier de trafic qui a généré ces fichiers. Contrairement au parser ADIF de KJ4IWX depuis lequel j’étais parti au début, cette librairie n’a aucune limite de taille et elle peut tout à fait traiter des logs de plusieurs centaines de milliers de lignes. Tout dépend du traitement que vous faites ensuite, mais sur une machine aux performances actuelles, on peut facilement espérer insérer 2000 QSOs par minute dans une base de données. Sur QScope (http://www NULL.qscope NULL.org/) où la qualité d’origine des logs importés est très aléatoire de nombreuses vérifications sont nécessaires et la vitesse chute à environ 500 QSOs par minute.

<?php

/*

=== ADIF v2 Parser library v1.00 (2013-10-11) ===

   This Library his based on work by Jason Harris KJ4IWX but has been simplified and improvedfor better ADIF compatiblity by Yannick DEVOS XV4Y
   Copyright 2011-2013 Jason Harris KJ4IWX (Apache v2.00 License)
   Copyright 2013 Yannick DEVOS XV4Y (GNU GPL v3.00 License)
   Any commercial use is subject to authorization from the respective authors
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

---

	This PHP library is designed to work with the Jelix 1.5 PHP Framework and PHP 5.4.
	However, it can simply be called by any PHP program.
	
	Usage (with Jelix):
		$ADIFParser = jClasses::createInstance('yourmodule~ADIFParser');
		$file_handler = fopen($complete_path_to_the_file,'r');
		$ADIFParser->initialize($file_handler);

		while(($record = $ADIFParser->get_record($file_handler))!=-1) {	// Check for end of file
			if ($record!=false) {	// If line is empty we skip
				if(count($record) == 0) {
					break;
				};
				echo ($record['call']);
				echo ($record['qso_date']);
				echo ($record['mode']);
				// Do whatever you like with the ADIF fields...
			};
		};
		fclose($file_handler);

	Fore more infos find contacts at:
	http://xv4y.radioclub.asia/
	http://www.qscope.org/

*/

class ADIFParser
{

	var $data; //the adif data
	var $i; //the iterator
	var $headers = array();
	
	public function initialize($fhandler) //this function locates the <EOH>
	{
		$eoh=$eof=false;
		$this->data='';
		while (!$eoh && !$eof) {
			$newdata = fgets($fhandler);
			if (!$newdata) {
				$eof = true;
			} else {
				if (stripos($newdata, "<eoh>")===false) {
					$this->data .= $newdata;
				} else {
				$eoh = true;
				}
			};
		}
		if($eoh == false) //did we find the end of headers?
		{
			return 0;
		};
		
		
		//get headers
		
		$this->i = 0;
		$in_tag = false;
		$tag = "";
		$value_length = "";
		$value = "";
		$pos = strlen($this->data)-1;
				
		while($this->i < $pos)
		{
			//skip comments
			if($this->data[$this->i] == "#")
			{
				while($this->i < $pos)
				{
					if($this->data[$this->i] == "\n")
					{
						break;
					}
				
					$this->i++;
				}
			}else{
				//find the beginning of a tag
				if($this->data[$this->i] == "<")
				{
					$this->i++;
					//record the key
					while($this->data[$this->i] < $pos && $this->data[$this->i] != ':')
					{
						$tag = $tag.$this->data[$this->i];
						$this->i++;
					}
					
					$this->i++; //iterate past the :
					
					//find out how long the value is
					
					while($this->data[$this->i] < $pos && $this->data[$this->i] != '>')
					{
						$value_length = $value_length.$this->data[$this->i];
						$this->i++;
					}
					
					$this->i++; //iterate past the >
					
					$len = (int)$value_length;
					//copy the value into the buffer
					while($len > 0 && $this->i < $pos)
					{
						$value = $value.$this->data[$this->i];
						$len--;
						$this->i++;
					};

					$this->headers[strtolower(trim($tag))] = $value; //convert it to lowercase and trim it in case of \r
					//clear all of our variables
					$tag = "";
					$value_length = "";
					$value = "";
					
				}
			}
			
			$this->i++;
			
		};
		return 1;
	}
	
	//the following function does the processing of the array into its key and value pairs
	public function record_to_array(&$record)
	{
		$return = array();
		for($a = 0; $a < strlen($record); $a++)
		{
			if($record[$a] == '<') //find the start of the tag
			{
				$tag_name = "";
				$value = "";
				$len_str = "";
				$len = 0;
				$a++; //go past the <
				while($record[$a] != ':') //get the tag
				{
					$tag_name = $tag_name.$record[$a]; //append this char to the tag name
					$a++;
				};
				$a++; //iterate past the colon
				while($record[$a] != '>' && $record[$a] != ':')
				{
					$len_str = $len_str.$record[$a];
					$a++;
				};
				if($record[$a] == ':')
				{
					while($record[$a] != '>')
					{
						$a++;
					};
				};
				$len = (int)$len_str;
				while($len > 0)
				{
					$a++;
					$value = $value.$record[$a];
					$len--;
				};
				$return[strtolower($tag_name)] = $value;
			};
			//skip comments
			if($record[$a] == "#")
			{
				while($a < strlen($record))
				{
					if($record[$a] == "\n")
					{
						break;
					}
					$a++;
				}
			}
		};
		return $return;
	}
	
	
	//finds the next record in the file
	public function get_record($fhandle)
	{
		$record ='';
		$out_condition = false;
		while (!$out_condition) {
			$newdata = fgets($fhandle);
			if ($newdata===false) {
				$out_condition = true;
				return -1;	// This is the end of file
			} else {
				$end = stripos($newdata , "<eor>");
				if($end !== false) { //we got a full line
					$record .= substr($newdata, 0, $end);
					$out_condition = true;
					return $this->record_to_array($record); //process and return output
				} else {
				$record .= $newdata;	// The line is not complete and we need to fetch a new string
				}
			}
		}
 	}
	
	public function get_header($key)
	{
		if(array_key_exists(strtolower($key), $this->headers))
		{
			return $this->headers[strtolower($key)];
		}else{
			return NULL;
		}
	}
	
}
?>

Application de statistiques pour les concours radio

COSTA XV4Y TimeChart (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/08/TimeChart NULL.png)Vous avez remarqué que les actualités sur mon blog se font rares en ce moment. Cela tient à deux choses, la première c’est que l’été il y a toujours moins de nouveautés et d’activités à propos desquelles parler. La deuxième c’est que récemment j’ai travaillé sur un nouveau projet de site web dont vous connaissez peut-être l’existence par Freddy F5IRO (http://j28ro NULL.blogspot NULL.com/2013/08/costa-par-xv4y NULL.html) qui fait partie de l’équipe de testeurs.

Ce projet d’application de statistiques pour les concours radio s’appelle pour l’instant COSTA (COntests STAtistics) mais le nom définitif n’est pas encore fixé car tous les noms de domaines avec “costa” sont pris et j’hésite encore pour un nom court et facile à retenir mais qui reste significatif. L’application peut actuellement être considérée comme une version béta et est ouverte à tous gratuitement (http://costa NULL.radioclub NULL.asia). J’ai en effet besoin que le plus de testeurs volontaires téléchargent leurs logs et essaient de générer des statistiques pour à la fois trouver les bogues et surtout voir comment le site web tient la charge.

COSTA XV4Y OpTimeBandPieChart

Une fois que tout fonctionnera normalement et que les fonctionnalités donneront satisfaction aux utilisateurs, je choisirai une architecture serveur dimensionnée en fonction des performances mesurées pendant la béta. Pour l’instant je continue à recevoir des idées et des commentaires et j’essaye d’implémenter les nouvelles fonctionnalités peu à peu. A noter que la difficulté ne tient pas réellement aux nombres de lignes de logs à traiter (sauf pour l’importation dans la base de données bien entendu) mais à la complexité du logs : nombre d’opérateurs, bandes et modes activés simultanément…

Bien que volontairement orienté vers les amateurs de contests, COSTA (http://costa NULL.radioclub NULL.asia) est capable de traiter n’importe quel log ADIF ou Cabrillo même si toutes les statistique ne sont pas pertinentes. Pour le DXer souhaitant suivre son évolution au DXCC, l’outil de choix reste tout de même Club Log (http://clublog NULL.org) dont la maturité est maintenant tout à fait acquise.

 

COSTA XV4Y QSORateChart (http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/08/QSORateChart NULL.png)