Archives par mot-clé : Bibliothèque

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;
		}
	}
	
}
?>

Librairie VirtualWire 1.12 pour le MSP430 [MAJ2]

[GTranslate]

Pour une fois, je ne cache pas ma fierté. En environ 2 heures de travail, j’ai réussi mon premier vrai portage d’une libairie conçue pour l’Arduino, la librairie VirtualWire (http://www NULL.open NULL.com NULL.au/mikem/arduino/), vers le MSP430 avec Energia. Sans être un exploit, c’est un succès personnel car cela demande de se plonger dans le travail des autres, ce qui n’est jamais facile.

La difficulté technique était, je l’avoue, faible, car la seule spécificité matérielle était liée aux Timer de l’AVR qui sont différents du MSP430. Par contre, une certaine dose de réécriture de code a été nécessaire pour que cela se compile convenablement car il y a toute de même quelques différences entre les deux environnements Arduino et Energia dès qu’on commence à écrire en C.

Pour mémoire, le but de cette librairie et de pouvoir utiliser des petits modules de communication sans-fil sur 433 MHz ou 2,4 GHz pour relier deux micro-contrôleurs. Ces modules étant souvent très sommaires au niveau matériel avec une transmission du signal bande de base en On-Off Keying (tout ou rien), il faut que le logiciel apporte quelques subtilités supplémentaires pour rendre la transmission fiable. On peut ensuite obtenir des débits de 9000 bps ou plus souvent environ 2000 bps si on s’éloigne de 150 mètres. C’est suffisant pour faire un capteur de station météo (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=31) par exemple…

Le code n’est pas complètement testé mais compile correctement et les premiers essais que j’ai pu faire s’avèrent très concluants. J’ai entre autres fait communiquer un Arduino et un MSP430 par liaison sans-fil ce qui prouve que les timings sont stables!

Je mets à disposition le code source tel qu’il est aujourd’hui avec peut-être encore des bugs. N’hésitez pas à me faire parvenir vos commentaires pour l’améliorer! La documentation d’origine (http://www NULL.open NULL.com NULL.au/mikem/arduino/VirtualWire NULL.pdf) reste valable pour cette version du code.

MAJ :   (http://xv4y NULL.radioclub NULL.asia/ftp/VirtualWire_110_EnergiaMSP430_20120109 NULL.zip)L’auteur a intégré mes modifications et publié une nouvelle version de la librairie, la 1.12, qui devrait fonctionner à la fois sur Arduino et Energia. Elle est téléchargeable ici (http://www NULL.open NULL.com NULL.au/mikem/arduino/VirtualWire/).

MAJ2 :   (http://xv4y NULL.radioclub NULL.asia/ftp/VirtualWire_110_EnergiaMSP430_20120109 NULL.zip)Il semblerait que l’auteur de la librairie originale a bien intégré mes apports mais n’a pas testé la librairie et celle-ci ne fonctionne pas. Voici mon portage de VirtualWire 1.10 pour Energia/MSP430 tel que je l’utilise (http://xv4y NULL.radioclub NULL.asia/ftp/VirtualWire110_Energia_XV4Y NULL.zip).

Bibliothèque RTC pour Energia version 1.04

Suite à une suggestion sur le forum dédié à Energia et au MSP430 en général (http://forum NULL.43oh NULL.com/forum/28-energia/), j’ai procédé à une petite réécriture de ma librairie horloge temps-réel (http://xv4y NULL.radioclub NULL.asia/2012/05/22/bibliotheque-rtc-pour-le-msp430/) (Real Time Clock ou RTC) pour le MSP430. Le changement sont principalement cosmétiques mais quelques petits bogues ont été corrigés.

Les fichiers peuvent être téléchargés sur la page téléchargements (http://xv4y NULL.radioclub NULL.asia/boutique/docs/).

Ici le fichier de déclarations sRTC.h :

/*
 sRTC.h - Library for adding simple RTC capabilities using MSP430 hardware
 By Yannick DEVOS (XV4Y) - 2012-2013
 Any commercial use or inclusion in a kit is subject to author approval

 ====
 Revision history :
 v1.00    2012-05-22
 First release
 v1.01    2012-12-17
 Minor cosmetic changes
 v1.02    2012-12-18
 Strucutral changes to improve code cleaness
 Currently does not work with Energia009
 v1.03    2012-12-21
 Settings in constructor to override default Energia settings, work with Energia 009
 v1.04    2013-01-08
 Moved settings to begin(), corrected bug related to Energia 009 => Thanks Grahamf72 from 43oh forums

 ====
 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 can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>

///////////////////////////////// How to use the lib

 * Create an instance of the object

 RealTimeClock myClock;

 * Do low-level Timer and Clock setup yourself or call begin();

 myClock.begin();

 * In order to have this RTC library working you should add this code to the end of your main program :

 interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
	myClock++;		      // Update chunks
 };

 * Enjoy the clock reading the RTC_sec, RTC_min, RTC_hr variables

 */

// ensure this library description is only included once
#ifndef RTC_h
#define RTC_h

// library interface description
class RealTimeClock
{
	// user-accessible "public" interface
public:
	RealTimeClock(void);
	void begin(void);
	void Set_Time(char hr, char mins, char secs);
    int RTC_chunk; // This how you read the time, by reading the vars
    char RTC_sec; // This how you read the time, by reading the vars
    char RTC_min;
    char RTC_hr;
	void Inc_chunk(void); // This methode should be invoked by an Interrupt call (see top of the file comment)
	RealTimeClock& operator++();	// Overload ++ operator for writing convenience (Prefix Variant)
	RealTimeClock& operator++(int);	// PostFix variant

	// A few private methods
private:
	void Inc_sec(void);
	void Inc_min(void);
	void Inc_hr(void);	
};

#endif

Et le code par lui même sRTC.cpp :

/*
 sRTC.h - Library for adding simple RTC capabilities using MSP430 hardware
 By Yannick DEVOS (XV4Y) - 2012
 Any commercial use or inclusion in a kit is subject to author approval

 ====
 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 can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/>

 */

// include this library's description file
#include 
#include 

// Constructor /////////////////////////////////////////////////////////////////

RealTimeClock::RealTimeClock(void)
{

};

// Methods /////////////////////////////////////////////////////////////////

void RealTimeClock::begin(void) {

	BCSCTL1 &= ~DIVA_3;		// ACLK without divider, set it to DIVA_0
	BCSCTL3 |= XCAP_3;		// Internal 12.5pF cap for 32KHz crystal

	TA1CCTL0 = CCIE;             //  CCR0 interupt activated
	TA1CCR0 = 128-1;             // 4096 ticks of 32KHz XTal = 1 second, so 4 slices are 1 second => CCR0 counts N+1
	TA1CTL = TASSEL_1 | ID_0 | MC_1;  // Clock for TIMER 1 = ACLK, No division, up mode

	P2SEL |= (BIT6 | BIT7); // This is to override default Energia settings that set P2_6 and P2_7 to GPIO instead of ACLK
	BCSCTL3 = LFXT1S_0;		// Override default Energia setting sourcing ACLK from VLO, now source from XTal

	RTC_chunk = 0;
	RTC_sec = 0;
	RTC_min = 0;
	RTC_hr = 0;	

};

RealTimeClock& RealTimeClock::operator++() {	// Overload ++ operator for writing convenience (Prefix Variant)
	Inc_chunk();	// This just call Inc_chunk
	return *this;
};

RealTimeClock& RealTimeClock::operator++(int) {	// PostFix variant
	RealTimeClock tmp(*this);
	++(*this);
	return tmp;
};

void RealTimeClock::Inc_chunk(void) {
	RTC_chunk = RTC_chunk + 1;		      // Update chuncks
	if (RTC_chunk == 256) {
		RTC_chunk=0;
		Inc_sec();
	};
};

void RealTimeClock::Inc_sec(void) {
	RTC_sec = RTC_sec + 1;		      // Update seconds
	if (RTC_sec == 60) {
		RTC_sec=0;
		Inc_min();
	};
};

void RealTimeClock::Inc_min(void) {
	RTC_min = RTC_min + 1;		      // Update minutes
	if (RTC_min == 60) {
		RTC_min=0;
		Inc_hr();
	};
};

void RealTimeClock::Inc_hr(void) {
	RTC_hr = RTC_hr + 1;		      // Update hours
	if (RTC_hr == 24) {
		RTC_hr=0;
	};
};

void RealTimeClock::Set_Time(char hrs=0, char mins=0, char secs=0) {
	if ((hrs>=0 && hrs <24) && (mins>=0 && mins<60) && (secs>=0 && secs<60)) {
		RTC_hr = hrs;	// Set time to values given in parameters
		RTC_min = mins;
		RTC_sec = secs;
		RTC_chunk = 0;
	};
};

Bibliothèque RTC pour le MSP430

[GTranslate]

Le micro-contrôleur MSP430G2553 de Texas Instruments livrés avec le LaunchPad dispose de tout le nécessaire pour en faire une horloge temps-réel (RTC). Il suffit de lui connecter un quartz 32KHz et de le programmer convenablement.

TI donne les librairies en assembleur utilisable avec leur environnement de développement. Pour Energia, une nouvelle librairie était nécessaire, je me suis donc attelé à sa conception.

Rien de révolutionnaire, mais ça peut servir à d’autres. C’est sur cette librairie qu’est basée ma balise autonome WSPR que je compte proposer en semi-kit d’ici peu (certainement à mon retour de vacances début juillet). D’origine la dérive en fréquence est de l’ordre du Hertz pour 24 heures (20ppm) ce qui suffit pour une nuit de transmission WSPR, mais peut-être ajustée avec un condensateur variable pour corriger la fréquence du quartz.

Le fichier d’en-têtes (sRTCsec.h) :

/*
 sRTC.h - Library for adding simple RTC capabilities using MSP430 hardware
 By Yannick DEVOS (XV4Y) - 2012

///////////////////////////////// How to use the lib

 * Create an instance of the object

 RealTimeClock myClock;

 * In order to have this RTC library working you should add this code to the end of your main program :

 interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
	myClock.Inc_sec();		      // Update secondes
 };

 * Enjoy the clock reading the RTC_sec, RTC_min, RTC_hr variables

 */

// ensure this library description is only included once
#ifndef RTCsec_h
#define RTCsec_h

// library interface description
class RealTimeClockSec
{
	// user-accessible "public" interface
public:
	RealTimeClockSec(void);
	void Set_Time(char hr, char mins, char secs);
    char RTC_sec; // This how you read the time, by reading the vars
    char RTC_min;
    char RTC_hr;
	void Inc_sec(void); // This methode should be invoked by an Interrupt call (see top of the file comment)
	// A few private methods
private:
	void Inc_min(void);
	void Inc_hr(void);
};

#endif

Le code par lui-même (sRTCsec.cpp) :

/*
 sRTC.h - Library for adding simple RTC capabilities using MSP430 hardware
 By Yannick DEVOS (XV4Y) - 2012
 */

// include this library's description file
#include <sRTCsec.h>
#include <legacymsp430.h>

// Constructor /////////////////////////////////////////////////////////////////

RealTimeClockSec::RealTimeClockSec(void)
{
	RTC_sec = 0;
	RTC_min = 0;
	RTC_hr = 0;

	WDTCTL = WDTPW | WDTHOLD; // Kill watch-dog

	BCSCTL1 = DIVA_3;        // Clock = ACLK / 8
	BCSCTL3 |= (LFXT1S_0 | XCAP_3);        // Internal 12.5pF cap for 32KHz crystal

	TA1CCTL0 = CCIE;             //  CCR0 interupt activated
	TA1CCR0 = 4096-1;               // 4096 ticks of 32KHz XTal = 1 second => CCR0 counts N+1
	TA1CTL = TASSEL_1 | ID_3 | MC_1;  // Clock for TIMER 1 = ACLK, By 8 division, up front

};

// Methods /////////////////////////////////////////////////////////////////

void RealTimeClockSec::Inc_sec(void) {
	RTC_sec = RTC_sec + 1;		      // Update seconds
	if (RTC_sec == 60) {
		RTC_sec=0;
		Inc_min();
	};
};

void RealTimeClockSec::Inc_min(void) {
	RTC_min = RTC_min + 1;		      // Update minutes
	if (RTC_min == 60) {
		RTC_min=0;
		Inc_hr();
	};
};

void RealTimeClockSec::Inc_hr(void) {
	RTC_hr = RTC_hr + 1;		      // Update hours
	if (RTC_hr == 24) {
		RTC_hr=0;
	};
};

void RealTimeClockSec::Set_Time(char hrs=0, char mins=0, char secs=0) {
	if ((hrs>=0 && hrs <24) && (mins>=0 && mins<60) && (secs>=0 && secs<60)) {
		RTC_hr = hrs;	// Set time to values given in parameters
		RTC_min = mins;
		RTC_sec = secs;
	};
};

Avec un exemple (testé sous Energia 005a) c’est plus facile à comprendre :

#include &lt;sRTCsec.h&gt;
#include &lt;legacymsp430.h&gt;
#include &lt;TimerSerial.h&gt;

TimerSerial mySerial;
RealTimeClockSec myRTC;

  int ledState = LOW;

void setup() {
  pinMode(2, OUTPUT);

  // This is to close the serial output so you are able to upload a new sketch to the LaunchPad
  pinMode(5, INPUT_PULLUP),
  attachInterrupt(5,fin,LOW);

  mySerial.begin();

};

// The LED1 will blink each exact second and the time will be printed to the serial port
void loop() {
  if ((myRTC.RTC_sec % 2)==0 && ledState== HIGH) {
  ledState = LOW;
  mySerial.print(myRTC.RTC_min, DEC);
  mySerial.print(":");
  mySerial.println(myRTC.RTC_sec, DEC);
  digitalWrite(2, ledState);
  };

  if ((myRTC.RTC_sec % 2)==1 && ledState== LOW) {
  ledState = HIGH;
  mySerial.print(myRTC.RTC_min, DEC);
  mySerial.print(":");
  mySerial.println(myRTC.RTC_sec, DEC);
  digitalWrite(2, ledState);
  };
};

void fin() {
  mySerial.end();
};

interrupt(TIMER1_A0_VECTOR) Tic_Tac(void) {
	myRTC.Inc_sec();		      // Update secondes
};