Création

This commit is contained in:
Charles 2015-07-20 00:10:47 +02:00
parent 2034494df9
commit d854f8c155
9 changed files with 2138 additions and 2 deletions

657
LibTeleinfo.cpp Normal file
View File

@ -0,0 +1,657 @@
// **********************************************************************************
// Driver definition for French Teleinfo
// **********************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this library but please abide with the CC-BY-SA license:
// http://creativecommons.org/licenses/by-sa/4.0/
//
// For any explanation about teleinfo ou use , see my blog
// http://hallard.me/category/tinfo
//
// Code based on following datasheet
// http://www.erdf.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf
//
// Written by Charles-Henri Hallard (http://hallard.me)
//
// History : V1.00 2015-06-14 - First release
//
// All text above must be included in any redistribution.
//
// **********************************************************************************
#include "LibTeleinfo.h"
/* ======================================================================
Class : TInfo
Purpose : Constructor
Input : -
Output : -
Comments: -
====================================================================== */
TInfo::TInfo()
{
// Init of our linked list
_valueslist.name = NULL;
_valueslist.value = NULL;
_valueslist.checksum = '\0';
_valueslist.flags = TINFO_FLAGS_NONE;
// callback
_fn_ADPS = NULL;
_fn_data = NULL;
_fn_new_frame = NULL;
_fn_updated_frame = NULL;
}
/* ======================================================================
Function: init
Purpose : configure ULPNode I/O ports
Input : -
Output : -
Comments: -
====================================================================== */
void TInfo::init()
{
// free up linked list (in case on recall init())
listDelete();
// clear our receive buffer
clearBuffer();
// We're in INIT in term of receive data
_state = TINFO_INIT;
}
/* ======================================================================
Function: attachADPS
Purpose : attach a callback when we detected a ADPS on any phase
Input : callback function
Output : -
Comments: -
====================================================================== */
void TInfo::attachADPS(void (*fn_ADPS)(uint8_t phase))
{
// indicate the user callback
_fn_ADPS = fn_ADPS;
}
/* ======================================================================
Function: attachNewData
Purpose : attach a callback when we detected a new/changed value
Input : callback function
Output : -
Comments: -
====================================================================== */
void TInfo::attachData(void (*fn_data)(ValueList * valueslist, uint8_t state))
{
// indicate the user callback
_fn_data = fn_data;
}
/* ======================================================================
Function: attachNewFrame
Purpose : attach a callback when we received a full frame
Input : callback function
Output : -
Comments: -
====================================================================== */
void TInfo::attachNewFrame(void (*fn_new_frame)(ValueList * valueslist))
{
// indicate the user callback
_fn_new_frame = fn_new_frame;
}
/* ======================================================================
Function: attachChangedFrame
Purpose : attach a callback when we received a full frame where data
has changed since the last frame (cool to update data)
Input : callback function
Output : -
Comments: -
====================================================================== */
void TInfo::attachUpdatedFrame(void (*fn_updated_frame)(ValueList * valueslist))
{
// indicate the user callback
_fn_updated_frame = fn_updated_frame;
}
/* ======================================================================
Function: clearBuffer
Purpose : clear and init the buffer
Input : -
Output : -
Comments: -
====================================================================== */
uint8_t TInfo::clearBuffer()
{
// Clear our buffer, set index to 0
memset(_recv_buff, 0, TINFO_BUFSIZE);
_recv_idx = 0;
}
/* ======================================================================
Function : valueAdd
Purpose : Add element to the Linked List of values
Input : Pointer to the label name
pointer to the value
checksum value
state of the label (filled by function)
Output : pointer to the new node (or founded one)
state of the label changed by the function
====================================================================== */
ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t * valuestate)
{
// Get our linked list
ValueList * me = &_valueslist;
uint8_t lgname = strlen(name);
uint8_t lgvalue = strlen(value);
// clear flags
*valuestate = TINFO_FLAGS_NONE ;
// Got one and all seems good ?
if (me && lgname && lgvalue && checksum) {
// Create pointer on the new node
ValueList *newNode = NULL;
ValueList *parNode = NULL ;
// By default we done nothing
*valuestate = TINFO_FLAGS_NOTHING;
// Loop thru the node
while (me->next) {
// save parent node
parNode = me ;
// go to next node
me = me->next;
// Check if we already have this LABEL
if (strncmp(me->name, name, lgname) == 0) {
// Already got also this value, return US
if (strncmp(me->value, value, lgvalue) == 0) {
me->flags = TINFO_FLAGS_EXIST;
*valuestate = me->flags;
return ( me );
}
else {
// We changed the value
me->flags = TINFO_FLAGS_UPDATED;
*valuestate = me->flags;
// Do we have enought space to hold new value ?
if (strlen(me->value) >= lgvalue ) {
// Copy it
strncpy(me->value, value , lgvalue );
me->checksum = checksum ;
// That's all
return (me);
}
else {
// indicate parent node next following node instead of me
parNode->next = me->next;
// Return to parent (that will now point on next node and not us)
me = parNode;
// free up this node
free (me);
}
}
}
}
// Our linked list structure sizeof(ValueList)
// + Name + '\0'
// + Value + '\0'
size_t size = sizeof(ValueList) + lgname + 1 + lgvalue + 1 ;
// Create new node with size to store strings
if ((newNode = (ValueList *) malloc(size) ) == NULL) {
return ( (ValueList *) NULL );
}
else {
// get our buffer Safe
memset(newNode, 0, size);
// We not changed this node ?
if (me->flags != TINFO_FLAGS_UPDATED)
// so we added this node !
me->flags = TINFO_FLAGS_ADDED;
*valuestate = me->flags ;
}
// Put the new node on the list
me->next = newNode;
// First String located after last struct element
// Second String located after the First + \0
newNode->checksum = checksum;
newNode->name = (char *) newNode + sizeof(ValueList);
newNode->value = (char *) newNode->name + lgname + 1;
// Copy the string data
memcpy(newNode->name , name , lgname );
memcpy(newNode->value, value , lgvalue );
// return pointer on the new node
return (newNode);
}
// Error or Already Exists
return ( (ValueList *) NULL);
}
/* ======================================================================
Function : valueGet
Purpose : get value of one element
Input : Pointer to the label name
pointer to the value where we fill data
Output : pointer to the value where we filled data NULL is not found
====================================================================== */
char * TInfo::valueGet(char * name, char * value)
{
// Get our linked list
ValueList * me = &_valueslist;
uint8_t lgname = strlen(name);
// Got one and all seems good ?
if (me && lgname) {
// Loop thru the node
while (me->next) {
// go to next node
me = me->next;
// Check if we match this LABEL
if (strncmp(me->name, name, lgname) == 0) {
// this one has a value ?
if (me->value) {
// copy to dest buffer
uint8_t lgvalue = strlen(me->value);
strncpy(value, me->value , lgvalue );
return ( value );
}
}
}
}
// not found
return ( NULL);
}
/* ======================================================================
Function : getTopList
Purpose : return a pointer on the top of the linked list
Input : -
Output : Pointer
====================================================================== */
ValueList * TInfo::getList(void)
{
// Get our linked list
return &_valueslist;
}
/* ======================================================================
Function : valuesDump
Purpose : dump linked list content
Input : -
Output : total number of values
====================================================================== */
uint8_t TInfo::valuesDump(void)
{
// Get our linked list
ValueList * me = &_valueslist;
uint8_t index = 0;
// Got one ?
if (me) {
// Loop thru the node
while (me->next) {
// go to next node
me = me->next;
index++;
TI_Debug(index) ;
TI_Debug(F(") ")) ;
if (me->name)
TI_Debug(me->name) ;
else
TI_Debug(F("NULL")) ;
TI_Debug(F("=")) ;
if (me->value)
TI_Debug(me->value) ;
else
TI_Debug(F("NULL")) ;
TI_Debug(F(" '")) ;
TI_Debug(me->checksum) ;
TI_Debug(F("' "));
// Flags management
if ( me->flags) {
TI_Debug(F("Flags : "));
if ( me->flags & TINFO_FLAGS_EXIST)
TI_Debug(F("Exist ")) ;
if ( me->flags & TINFO_FLAGS_UPDATED)
TI_Debug(F("Updated ")) ;
if ( me->flags & TINFO_FLAGS_ADDED)
TI_Debug(F("New ")) ;
}
TI_Debugln() ;
}
}
return index;
}
/* ======================================================================
Function: labelCount
Purpose : Count the number of label in the list
Input : -
Output : element numbers
====================================================================== */
int TInfo::labelCount()
{
int count = 0;
// Get our linked list
ValueList * me = &_valueslist;
if (me)
while ((me = me->next))
count++;
return (count);
}
/* ======================================================================
Function: listDelete
Purpose : Delete the ENTIRE Linked List, not a value
Input : -
Output : True if Ok False Otherwise
====================================================================== */
boolean TInfo::listDelete()
{
// Get our linked list
ValueList * me = &_valueslist;
// Got a pointer
if (me) {
ValueList *current;
// For each linked list
while ((current = me->next)) {
// Get the next
me->next = current->next;
// Free the current
free(current);
}
// Free the top element
me->next = NULL ;
// Ok
return (true);
}
return (false);
}
/* ======================================================================
Function: checksum
Purpose : calculate the checksum based on data/value fields
Input : label name
label value
Output : checksum
Comments: return '\0' in case of error
====================================================================== */
unsigned char TInfo::calcChecksum(char *etiquette, char *valeur)
{
uint8_t i ;
uint8_t sum = ' '; // Somme des codes ASCII du message + un espace
// avoid dead loop, always check all is fine
if (etiquette && valeur) {
// this will not hurt and may save our life ;-)
if (strlen(etiquette) && strlen(valeur)) {
while (*etiquette)
sum += *etiquette++ ;
while(*valeur)
sum += *valeur++ ;
return ( (sum & 63) + ' ' ) ;
}
}
return 0;
}
/* ======================================================================
Function: customLabel
Purpose : do action when received a correct label / value + checksum line
Input : plabel : pointer to string containing the label
: pvalue : pointer to string containing the associated value
Output :
Comments:
====================================================================== */
void TInfo::customLabel( char * plabel, char * pvalue)
{
// Traitement de l'ADPS demandé
if (_fn_ADPS) {
// Monophasé
if (strcmp(plabel, "ADPS")==0 )
_fn_ADPS(0);
// triphasé c'est ADIR + Num Phase
if (plabel[0]=='A' && plabel[1]=='D' && plabel[2]=='I' && plabel[3]=='R' )
if (plabel[4]>='1' && plabel[4]<='3')
_fn_ADPS(plabel[4]-'0');
}
}
/* ======================================================================
Function: checkLine
Purpose : check one line of teleinfo received
Input : -
Output : pointer to the data object in the linked list if OK else NULL
Comments:
====================================================================== */
ValueList * TInfo::checkLine(char * pline)
{
char * p;
char * ptok;
char * pend;
char * pvalue;
char checksum;
char buff[TINFO_BUFSIZE];
uint8_t value_state;
boolean err = true ; // Assume error
int len ; // Group len
if (pline==NULL)
return NULL;
len = strlen(pline);
// a line should be at least 7 Char
// 2 Label + Space + 1 etiquette + space + checksum + \r
if ( len < 7 )
return NULL;
// Get our own working copy
strncpy( buff, _recv_buff, len+1);
p = &buff[0];
ptok = p; // for sure we start with token name
pend = p + len; // max size
// Init values
pvalue = NULL;
checksum = 0;
//TI_Debug("Got [");
//TI_Debug(len);
//TI_Debug("] ");
// Loop in buffer
while ( p < pend ) {
// start of token value
if ( *p==' ' && ptok) {
// Isolate token name
*p++ = '\0';
// 1st space, it's the label value
if (!pvalue)
pvalue = p;
else
// 2nd space, so it's the checksum
checksum = *p;
}
// new line ? ok we got all we need ?
if ( *p=='\r' ) {
*p='\0';
// Good format ?
if ( ptok && pvalue && checksum ) {
// Always check to avoid bad behavior
if(strlen(ptok) && strlen(pvalue)) {
// Is checksum is OK
if ( calcChecksum(ptok,pvalue) == checksum) {
// In case we need to do things on specific labels
customLabel(ptok, pvalue);
// Add value to linked lists of values
ValueList * me = valueAdd(ptok, pvalue, checksum, &value_state);
// value correctly added/changed
if ( me ) {
// something to do with new datas
if (value_state & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED) ) {
// this frame will for sure be updated
_frame_updated = true;
// Do we need to advertise user callback
if (_fn_data)
_fn_data(me, value_state);
}
}
}
}
}
}
// Next char
p++;
} // While
return NULL;
}
/* ======================================================================
Function: process
Purpose : teleinfo serial char received processing, should be called
my main loop, this will take care of managing all the other
Input : pointer to the serial used
Output : teleinfo global state
====================================================================== */
_State_e TInfo::process(char c)
{
// be sure 7 bits only
c &= 0x7F;
// What we received ?
switch (c) {
// start of transmission ???
case TINFO_STX:
// Clear buffer, begin to store in it
clearBuffer();
// by default frame is not "updated"
// if data change we'll set this flag
_frame_updated = false;
// We were waiting fo this one ?
if (_state == TINFO_INIT || _state == TINFO_WAIT_STX ) {
TI_Debugln(F("TINFO_WAIT_ETX"));
_state = TINFO_WAIT_ETX;
}
break;
// End of transmission ?
case TINFO_ETX:
// Normal working mode ?
if (_state == TINFO_READY) {
// Get on top of our linked list
ValueList * me = &_valueslist;
// Call user callback if any
if (_frame_updated && _fn_updated_frame)
_fn_updated_frame(me);
else if (_fn_new_frame)
_fn_new_frame(me);
}
// We were waiting fo this one ?
if (_state == TINFO_WAIT_ETX) {
TI_Debugln(F("TINFO_READY"));
_state = TINFO_READY;
}
else if ( _state == TINFO_INIT) {
TI_Debugln(F("TINFO_WAIT_STX"));
_state = TINFO_WAIT_STX ;
}
break;
// Start of group \n ?
case TINFO_SGR:
// Do nothing we'll work at end of group
// we can safely ignore this char
break;
// End of group \r ?
case TINFO_EGR:
// Are we ready to process ?
if (_state == TINFO_READY) {
// Store data recceived (we'll need it)
if ( _recv_idx < TINFO_BUFSIZE)
_recv_buff[_recv_idx++]=c;
// clear the end of buffer (paranoia inside)
memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx);
// check the group we've just received
checkLine(_recv_buff) ;
// Whatever error or not, we done
clearBuffer();
}
break;
// other char ?
default:
{
// Only in a ready state of course
if (_state == TINFO_READY) {
// If buffer is not full, Store data
if ( _recv_idx < TINFO_BUFSIZE)
_recv_buff[_recv_idx++]=c;
else
clearBuffer();
}
}
break;
}
}

140
LibTeleinfo.h Normal file
View File

@ -0,0 +1,140 @@
// **********************************************************************************
// Driver definition for French Teleinfo
// **********************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this library but please abide with the CC-BY-SA license:
// http://creativecommons.org/licenses/by-sa/4.0/
//
// For any explanation about teleinfo ou use , see my blog
// http://hallard.me/category/tinfo
//
// Code based on following datasheet
// http://www.erdf.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf
//
// Written by Charles-Henri Hallard (http://hallard.me)
//
// History : V1.00 2015-06-14 - First release
//
// All text above must be included in any redistribution.
//
// **********************************************************************************
#ifndef LibTeleinfo_h
#define LibTeleinfo_h
#ifdef __arm__
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define boolean bool
#endif
#ifdef ARDUINO
#include <Arduino.h>
#endif
// Using ESP8266 ?
#ifdef ESP8266
//#include "stdlib_noniso.h"
#include <ESP8266WiFi.h>
#endif
// Define this if you want library to be verbose
//#define TI_DEBUG
// I prefix debug macro to be sure to use specific for THIS library
// debugging, this should not interfere with main sketch or other
// libraries
#ifdef TI_DEBUG
#ifdef ESP8266
#define TI_Debug(x) Serial1.print(x)
#define TI_Debugln(x) Serial1.println(x)
#define TI_Debugf(...) Serial1.printf(__VA_ARGS__)
#define TI_Debugflush Serial1.flush
#else
#define TI_Debug(x) Serial.print(x)
#define TI_Debugln(x) Serial.println(x)
#define TI_Debugf(...) Serial.printf(__VA_ARGS__)
#define TI_Debugflush Serial.flush
#endif
#else
#define TI_Debug(x)
#define TI_Debugln(x)
#define TI_Debugf(...)
#define TI_Debugflush
#endif
// Linked list structure containing all values received
typedef struct _ValueList ValueList;
struct _ValueList
{
ValueList *next; // next element
uint8_t checksum;// checksum
uint8_t flags; // specific flags
char * name; // LABEL of value name
char * value; // value
};
// Library state machine
enum _State_e {
TINFO_INIT, // We're in init
TINFO_WAIT_STX, // We're waiting for STX
TINFO_WAIT_ETX, // We had STX, We're waiting for ETX
TINFO_READY // We had STX AND ETX, So we're OK
};
// what we done with received value (also for callback flags)
#define TINFO_FLAGS_NONE 0x00
#define TINFO_FLAGS_NOTHING 0x01
#define TINFO_FLAGS_ADDED 0x02
#define TINFO_FLAGS_EXIST 0x04
#define TINFO_FLAGS_UPDATED 0x08
// Local buffer for one line of teleinfo
#define TINFO_BUFSIZE 64
// Teleinfo start and end of frame characters
#define TINFO_STX 0x02
#define TINFO_ETX 0x03
#define TINFO_SGR '\n' // start of group
#define TINFO_EGR '\r' // End of group
class TInfo
{
public:
TInfo();
void init();
_State_e process (char c);
void attachADPS(void (*_fn_ADPS)(uint8_t phase));
void attachData(void (*_fn_data)(ValueList * valueslist, uint8_t state));
void attachNewFrame(void (*_fn_new_frame)(ValueList * valueslist));
void attachUpdatedFrame(void (*_fn_updated_frame)(ValueList * valueslist));
ValueList * getList(void);
uint8_t valuesDump(void);
char * valueGet(char * name, char * value);
boolean listDelete();
private:
uint8_t clearBuffer();
ValueList * valueAdd (char * name, char * value, uint8_t checksum, uint8_t * valuestate);
int labelCount();
unsigned char calcChecksum(char *etiquette, char *valeur) ;
void customLabel( char * plabel, char * pvalue) ;
ValueList * checkLine(char * pline) ;
_State_e _state; // Teleinfo machine state
ValueList _valueslist; // Linked list of teleinfo values
char _recv_buff[TINFO_BUFSIZE]; // line receive buffer
uint8_t _recv_idx; // index in receive buffer
boolean _frame_updated; // Data on the frame has been updated
void (*_fn_ADPS)(uint8_t phase);
void (*_fn_data)(ValueList * valueslist, uint8_t state);
void (*_fn_new_frame)(ValueList * valueslist);
void (*_fn_updated_frame)(ValueList * valueslist);
//volatile uint8_t *dcport;
//uint8_t dcpinmask;
};
#endif

View File

@ -5,10 +5,10 @@ This is a generic Teleinfo French Meter Measure Library, it can be used on Ardui
You can see Teleinformation official french datasheet [there][1]
Since this is really dedicted to French energy measuring system, I will continue in French
Since this is really dedicated to French energy measuring system, I will continue in French
###Installation
Copier le contenu de ce dossier (fichier zip) dans le dossier libraries de votre environnement Arduino Vous devriez avoir maintenant quelque chose comme "your_sketchbook_folder/libraries/LibTeleinfo" et ce dossier doit contentir les fichiers .cpp et .h ainsi que le sous dossier examples.
Copier le contenu de ce dossier (download zip) dans le dossier libraries de votre environnement Arduino Vous devriez avoir maintenant quelque chose comme `your_sketchbook_folder/libraries/LibTeleinfo` et ce dossier doit contentir les fichiers .cpp et .h ainsi que le sous dossier `examples`.
<br/>
Pour trouver votre dossier de sketchbook, dans l'environnement IDE, allez dans File>Preferences.
<br/>

View File

@ -0,0 +1,219 @@
// **********************************************************************************
// Arduino Teleinfo sample, display information on teleinfo values received + blink
// **********************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this library but please abide with the CC-BY-SA license:
// http://creativecommons.org/licenses/by-sa/4.0/
//
// for detailled explanation of this library see dedicated article
// https://hallard.me/libteleinfo/
//
// For any explanation about teleinfo or use, see my blog
// https://hallard.me/category/tinfo
//
// connect Teleinfo RXD pin To Arduin D3
// see schematic here https://hallard.me/demystifier-la-teleinfo/
// and dedicated article here
//
// Written by Charles-Henri Hallard (https://hallard.me)
//
// History : V1.00 2015-06-14 - First release
//
// All text above must be included in any redistribution.
//
// **********************************************************************************
#include <SoftwareSerial.h>
#include <LibTeleinfo.h>
// Arduino on board LED
// I use moteino, so it's D9
// classic Arduino is D13
#define LEDPIN 9
//#define LEDPIN 13
SoftwareSerial Serial1(3,4); // Teleinfo Serial
TInfo tinfo; // Teleinfo object
// Pour clignotement LED asynchrone
unsigned long blinkLed = 0;
uint8_t blinkDelay= 0;
/* ======================================================================
Function: printUptime
Purpose : print pseudo uptime value
Input : -
Output : -
Comments: compteur de secondes basique sans controle de dépassement
En plus SoftwareSerial rend le compteur de millis() totalement
A la rue, donc la precision de ce compteur de seconde n'est
pas fiable du tout, dont acte !!!
====================================================================== */
void printUptime(void)
{
Serial.print(millis()/1000);
Serial.print(F("s\t"));
}
/* ======================================================================
Function: ADPSCallback
Purpose : called by library when we detected a ADPS on any phased
Input : phase number
0 for ADPS (monophase)
1 for ADIR1 triphase
2 for ADIR2 triphase
3 for ADIR3 triphase
Output : -
Comments: should have been initialised in the main sketch with a
tinfo.attachADPSCallback(ADPSCallback())
====================================================================== */
void ADPSCallback(uint8_t phase)
{
printUptime();
// Monophasé
if (phase == 0 ) {
Serial.println(F("ADPS"));
}
else {
Serial.print(F("ADPS PHASE #"));
Serial.println('0' + phase);
}
}
/* ======================================================================
Function: DataCallback
Purpose : callback when we detected new or modified data received
Input : linked list pointer on the concerned data
current flags value
Output : -
Comments: -
====================================================================== */
void DataCallback(ValueList * me, uint8_t flags)
{
// Show our not accurate second counter
printUptime();
if (flags & TINFO_FLAGS_ADDED)
Serial.print(F("NEW -> "));
if (flags & TINFO_FLAGS_UPDATED)
Serial.print(F("MAJ -> "));
// Display values
Serial.print(me->name);
Serial.print("=");
Serial.println(me->value);
}
/* ======================================================================
Function: NewFrame
Purpose : callback when we received a complete teleinfo frame
Input : linked list pointer on the concerned data
Output : -
Comments: -
====================================================================== */
void NewFrame(ValueList * me)
{
// Start short led blink
digitalWrite(LEDPIN, HIGH);
blinkLed = millis();
blinkDelay = 50; // 50ms
// Show our not accurate second counter
printUptime();
Serial.println(F("FRAME -> SAME AS PREVIOUS"));
}
/* ======================================================================
Function: NewFrame
Purpose : callback when we received a complete teleinfo frame
Input : linked list pointer on the concerned data
Output : -
Comments: it's called only if one data in the frame is different than
the previous frame
====================================================================== */
void UpdatedFrame(ValueList * me)
{
// Start long led blink
digitalWrite(LEDPIN, HIGH);
blinkLed = millis();
blinkDelay = 100; // 100ms
// Show our not accurate second counter
printUptime();
Serial.println(F("FRAME -> UPDATED"));
}
/* ======================================================================
Function: setup
Purpose : Setup I/O and other one time startup stuff
Input : -
Output : -
Comments: -
====================================================================== */
void setup()
{
// Arduino LED
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, LOW);
// Serial, pour le debug
Serial.begin(115200);
Serial.println(F("========================================"));
Serial.println(F(__FILE__));
Serial.println(F(__DATE__ " " __TIME__));
Serial.println();
// Configure Teleinfo Soft serial
// La téléinfo est connectee sur D3
// ceci permet d'eviter les conflits avec la
// vraie serial lors des uploads
Serial1.begin(1200);
// Init teleinfo
tinfo.init();
// Attacher les callback dont nous avons besoin
// pour cette demo, toutes
tinfo.attachADPS(ADPSCallback);
tinfo.attachData(DataCallback);
tinfo.attachNewFrame(NewFrame);
tinfo.attachUpdatedFrame(UpdatedFrame);
// Show our not accurate second counter
printUptime();
Serial.println(F("Teleinfo started"));
}
/* ======================================================================
Function: loop
Purpose : infinite loop main code
Input : -
Output : -
Comments: -
====================================================================== */
void loop()
{
static char c;
// On a reçu un caractère ?
if ( Serial1.available() )
{
c = Serial1.read() ;
//Serial.print(c & 0x7F);
// Gerer
tinfo.process(c);
}
// Verifier si le clignotement LED doit s'arreter
if (blinkLed && ((millis()-blinkLed) >= blinkDelay))
{
digitalWrite(LEDPIN, LOW);
blinkLed = 0;
}
}

View File

@ -0,0 +1,121 @@
// **********************************************************************************
// Arduino Teleinfo sample, display information on teleinfo values received
// **********************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this library but please abide with the CC-BY-SA license:
// http://creativecommons.org/licenses/by-sa/4.0/
//
// for detailled explanation of this library see dedicated article
// https://hallard.me/libteleinfo/
//
// For any explanation about teleinfo or use, see my blog
// https://hallard.me/category/tinfo
//
// connect Teleinfo RXD pin To Arduin D3
// see schematic here https://hallard.me/demystifier-la-teleinfo/
// and dedicated article here
//
// Written by Charles-Henri Hallard (https://hallard.me)
//
// History : V1.00 2015-06-14 - First release
//
// All text above must be included in any redistribution.
//
// **********************************************************************************
#include <SoftwareSerial.h>
#include <LibTeleinfo.h>
SoftwareSerial Serial1(3,4); // Teleinfo Serial
TInfo tinfo; // Teleinfo object
/* ======================================================================
Function: printUptime
Purpose : print pseudo uptime value
Input : -
Output : -
Comments: compteur de secondes basique sans controle de dépassement
En plus SoftwareSerial rend le compteur de millis() totalement
A la rue, donc la precision de ce compteur de seconde n'est
pas fiable du tout, dont acte !!!
====================================================================== */
void printUptime(void)
{
Serial.print(millis()/1000);
Serial.print(F("s\t"));
}
/* ======================================================================
Function: DataCallback
Purpose : callback when we detected new or modified data received
Input : linked list pointer on the concerned data
current flags value
Output : -
Comments: -
====================================================================== */
void DataCallback(ValueList * me, uint8_t flags)
{
// Show our not accurate second counter
printUptime();
if (flags & TINFO_FLAGS_ADDED)
Serial.print(F("NEW -> "));
if (flags & TINFO_FLAGS_UPDATED)
Serial.print(F("MAJ -> "));
// Display values
Serial.print(me->name);
Serial.print("=");
Serial.println(me->value);
}
/* ======================================================================
Function: setup
Purpose : Setup I/O and other one time startup stuff
Input : -
Output : -
Comments: -
====================================================================== */
void setup()
{
// Serial, pour le debug
Serial.begin(115200);
Serial.println(F("========================================"));
Serial.println(F(__FILE__));
Serial.println(F(__DATE__ " " __TIME__));
Serial.println();
// Configure Teleinfo Soft serial
// La téléinfo est connectee sur D3
// ceci permet d'eviter les conflits avec la
// vraie serial lors des uploads
Serial1.begin(1200);
// Init teleinfo
tinfo.init();
// Attacher les callback dont nous avons besoin
// pour cette demo, ici attach data
tinfo.attachData(DataCallback);
printUptime();
Serial.println(F("Teleinfo started"));
}
/* ======================================================================
Function: loop
Purpose : infinite loop main code
Input : -
Output : -
Comments: -
====================================================================== */
void loop()
{
// Teleinformation processing
if ( Serial1.available() ) {
tinfo.process(Serial1.read());
}
}

View File

@ -0,0 +1,291 @@
// **********************************************************************************
// Arduino Teleinfo sample, return JSON data of modified teleinfo values received
// **********************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this library but please abide with the CC-BY-SA license:
// http://creativecommons.org/licenses/by-sa/4.0/
//
// for detailled explanation of this library see dedicated article
// https://hallard.me/libteleinfo/
//
// For any explanation about teleinfo or use, see my blog
// https://hallard.me/category/tinfo
//
// connect Teleinfo RXD pin To Arduin D3
// see schematic here https://hallard.me/demystifier-la-teleinfo/
// and dedicated article here
//
// Written by Charles-Henri Hallard (https://hallard.me)
//
// History : V1.00 2015-06-14 - First release
//
// All text above must be included in any redistribution.
//
// **********************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Arduino.h"
#include <SoftwareSerial.h>
#include <LibTeleinfo.h>
// Arduino on board LED
// I use moteino, so it's D9
// classic Arduino is D13
#define LEDPIN 9
//#define LEDPIN 13
// Teleinfo Serial (on D3)
SoftwareSerial Serial1(3,4);
TInfo tinfo; // Teleinfo object
// Pour clignotement LED asynchrone
unsigned long blinkLed = 0;
uint8_t blinkDelay= 0;
// Uptime timer
volatile boolean tick1sec=0;// one for interrupt, don't mess with
unsigned long uptime=0; // save value we can use in sketch even if we're interrupted
// Used to indicate if we need to send all date or just modified ones
boolean fulldata = true;
/* ======================================================================
Function: ADPSCallback
Purpose : called by library when we detected a ADPS on any phased
Input : phase number
0 for ADPS (monophase)
1 for ADIR1 triphase
2 for ADIR2 triphase
3 for ADIR3 triphase
Output : -
Comments: should have been initialised in the main sketch with a
tinfo.attachADPSCallback(ADPSCallback())
====================================================================== */
void ADPSCallback(uint8_t phase)
{
// Envoyer JSON { "ADPS"; n}
// n = numero de la phase 1 à 3
if (phase == 0)
phase = 1;
Serial.print(F("{\"ADPS\":"));
Serial.print('0' + phase);
Serial.println(F("}"));
}
/* ======================================================================
Function: NewFrame
Purpose : callback when we received a complete teleinfo frame
Input : linked list pointer on the concerned data
Output : -
Comments: -
====================================================================== */
void NewFrame(ValueList * me)
{
// Start short led blink
digitalWrite(LEDPIN, HIGH);
blinkLed = millis();
blinkDelay = 50; // 50ms
// Envoyer les valeurs uniquement si demandé
if (fulldata)
sendJSON(me, true);
fulldata = false;
}
/* ======================================================================
Function: UpdatedFrame
Purpose : callback when we received a complete teleinfo frame
Input : linked list pointer on the concerned data
Output : -
Comments: it's called only if one data in the frame is different than
the previous frame
====================================================================== */
void UpdatedFrame(ValueList * me)
{
// Start long led blink
digitalWrite(LEDPIN, HIGH);
blinkLed = millis();
blinkDelay = 50; // 50ms
// Envoyer les valeurs
sendJSON(me, fulldata);
fulldata = false;
}
/* ======================================================================
Function: sendJSON
Purpose : dump teleinfo values on serial
Input : linked list pointer on the concerned data
true to dump all values, false for only modified ones
Output : -
Comments: -
====================================================================== */
void sendJSON(ValueList * me, boolean all)
{
bool firstdata = true;
// Got at least one ?
if (me) {
// Json start
Serial.print(F("{"));
if (all) {
Serial.print(F("\"_UPTIME\":"));
Serial.print(uptime, DEC);
firstdata = false;
}
// Loop thru the node
while (me->next) {
// go to next node
me = me->next;
// uniquement sur les nouvelles valeurs ou celles modifiées
// sauf si explicitement demandé toutes
if ( all || ( me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED) ) )
{
// First elemement, no comma
if (firstdata)
firstdata = false;
else
Serial.print(F(", ")) ;
Serial.print(F("\"")) ;
Serial.print(me->name) ;
Serial.print(F("\":")) ;
// we have at least something ?
if (me->value && strlen(me->value))
{
boolean isNumber = true;
uint8_t c;
char * p = me->value;
// check if value is number
while (*p && isNumber) {
if ( *p < '0' || *p > '9' )
isNumber = false;
p++;
}
// this will add "" on not number values
if (!isNumber) {
Serial.print(F("\"")) ;
Serial.print(me->value) ;
Serial.print(F("\"")) ;
}
// this will remove leading zero on numbers
else
Serial.print(atol(me->value));
}
}
}
// Json end
Serial.println(F("}")) ;
}
}
/* ======================================================================
Function: TIMER VECTOR
Purpose : Interrupt that gets called once a second
Input : -
Output : -
Comments: -
====================================================================== */
ISR(TIMER1_COMPA_vect)
{
// got our second ticker
tick1sec = true;
}
/* ======================================================================
Function: setup
Purpose : Setup I/O and other one time startup stuff
Input : -
Output : -
Comments: -
====================================================================== */
void setup()
{
// disable global interrupts
cli();
// set timer1 to fire event every second
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
OCR1A = 15624; // set compare match register to desired timer count. 16 MHz with 1024 prescaler = 15624 counts/s
TCCR1B |= (1 << WGM12); // turn on CTC mode. clear timer on compare match
TCCR1B |= (1 << CS10); // Set CS10 and CS12 bits for 1024 prescaler
TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
// enable global interrupts
sei();
// Arduino LED
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, LOW);
// Serial, pour le debug
Serial.begin(115200);
// Configure Teleinfo Soft serial
// La téléinfo est connectee sur D3
// ceci permet d'eviter les conflits avec la
// vraie serial lors des uploads
Serial1.begin(1200);
// Init teleinfo
tinfo.init();
// Attacher les callback dont nous avons besoin
// pour cette demo, ADPS et TRAME modifiée
tinfo.attachADPS(ADPSCallback);
tinfo.attachUpdatedFrame(UpdatedFrame);
tinfo.attachNewFrame(NewFrame);
}
/* ======================================================================
Function: loop
Purpose : infinite loop main code
Input : -
Output : -
Comments: -
====================================================================== */
void loop()
{
static char c;
// Avons nous recu un ticker de seconde?
if (tick1sec)
{
tick1sec = false;
uptime++;
// Forcer un envoi de trame complète toutes les minutes
// fulldata sera remis à 0 après l'envoi
if (uptime % 60 == 0)
fulldata = true;
}
// On a reçu un caractère ?
if ( Serial1.available() ) {
// Le lire
c = Serial1.read();
// Gerer
tinfo.process(c);
}
// Verifier si le clignotement LED doit s'arreter
if (blinkLed && ((millis()-blinkLed) >= blinkDelay))
{
digitalWrite(LEDPIN, LOW);
blinkLed = 0;
}
}

View File

@ -0,0 +1,73 @@
Teleinfo Universal Library
==========================
Programme d'exemple de la librairie universelle pour la téléinformation pour Raspberry Pi
##Documentation
J'ai écrit un article [dédié][10] sur cette librairie, vous pouvez aussi voir les [catégories][6] associées à la téléinfo sur mon [blog][7].
Pour les commentaires et le support vous pouvez allez sur le [forum][8] dédié ou dans la [communauté][9]
###Installation
Se connecter en ssh sur votre Pi, il doit y avoir les environnements de développement, sinon faites un
`apt-get install build-essential git-core`
Ensuite :
```
git clone https://github.com/hallard/LibTeleinfo
cd LibTeleinfo/examples/Raspberry_JSON/
make
./raspjson
```
Et voilà ce que ça donne avec un dongle MicroTeleinfo
```
root@pi01(rw):~/LibTeleinfo/examples/Raspberry_JSON# ./raspjson -d /dev/ttyUSB0
{"_UPTIME":30788, "ADCO":2147483647, "OPTARIF":"HC..", "ISOUSC":15, "HCHC":247295, "HCHP":0, "PTEC":"HC..", "IINST":1, "IMAX":1, "PAPP":140, "HHPHC":"A", "MOTDETAT":0}
{"HCHC":247296}
{"PAPP":170}
{"HCHC":247297}
q{"PAPP":160}
{"PAPP":140}
{"_UPTIME":30848, "ADCO":2147483647, "OPTARIF":"HC..", "ISOUSC":15, "HCHC":247297, "HCHP":0, "PTEC":"HC..", "IINST":1, "IMAX":1, "PAPP":140, "HHPHC":"A", "MOTDETAT":0}
{"PAPP":150}
{"PAPP":140}
{"PAPP":150}
{"PAPP":140}
{"PAPP":160}
{"PAPP":170}
{"PAPP":160}
{"HCHC":247298, "PAPP":140}
{"PAPP":150}
{"PAPP":140}
{"PAPP":150}
{"PAPP":140}
{"PAPP":150}
{"PAPP":140}
{"PAPP":150}
{"PAPP":160}
{"PAPP":150}
{"PAPP":170}
{"PAPP":160}
{"PAPP":170}
{"PAPP":150}
{"HCHC":247299, "PAPP":160}
{"PAPP":150}
{"_UPTIME":30908, "ADCO":2147483647, "OPTARIF":"HC..", "ISOUSC":15, "HCHC":247299, "HCHP":0, "PTEC":"HC..", "IINST":1, "IMAX":1, "PAPP":160, "HHPHC":"A", "MOTDETAT":0}
{"PAPP":140}
{"PAPP":150}
{"PAPP":140}
{"PAPP":150}
````
##Divers
Vous pouvez aller voir les nouveautés et autres projets sur [blog][7]
[6]: https://hallard.me/category/tinfo/
[7]: https://hallard.me
[8]: https://community.hallard.me/category/7
[9]: https://community.hallard.me
[10]: https://hallard.me/libteleinfo

View File

@ -0,0 +1,21 @@
SHELL=/bin/sh
CFLAGS=-DRASPBERRY_PI
# raspjson
all: raspjson
# ===== Compile
LibTeleinfo.o: ../../LibTeleinfo.cpp
$(CC) $(CFLAGS) -c ../../LibTeleinfo.cpp
raspjson.o: raspjson.cpp
$(CC) $(CFLAGS) -c raspjson.cpp
# ===== Link
raspjson: raspjson.o LibTeleinfo.o
$(CC) $(CFLAGS) $(LDFLAGS) -o raspjson raspjson.o LibTeleinfo.o
clean:
rm -f *.o raspjson

View File

@ -0,0 +1,614 @@
// **********************************************************************************
// Raspberry PI LibTeleinfo sample, display JSON data of modified teleinfo values received
// **********************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this library but please abide with the CC-BY-SA license:
// http://creativecommons.org/licenses/by-sa/4.0/
//
// for detailled explanation of this library see dedicated article
// https://hallard.me/libteleinfo/
//
// For any explanation about teleinfo or use, see my blog
// https://hallard.me/category/tinfo
//
// Written by Charles-Henri Hallard (https://hallard.me)
//
// History : V1.00 2015-07-14 - First release
//
// All text above must be included in any redistribution.
//
// **********************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <termios.h>
#include <getopt.h>
#include <sys/sysinfo.h>
#include "../../LibTeleinfo.h"
// ----------------
// Constants
// ----------------
#define true 1
#define false 0
#define PRG_NAME "raspjson"
#define TELEINFO_DEVICE ""
#define TELEINFO_BUFSIZE 512
// Some enum for serial
enum parity_e { P_NONE, P_EVEN, P_ODD };
enum flowcntrl_e { FC_NONE, FC_RTSCTS, FC_XONXOFF };
enum mode_e { MODE_NONE, MODE_SEND, MODE_RECEIVE, MODE_TEST };
enum value_e { VALUE_NOTHING, VALUE_ADDED, VALUE_EXIST, VALUE_CHANGED};
// Configuration structure
static struct
{
char port[128];
int baud;
enum flowcntrl_e flow;
char flow_str[32];
enum parity_e parity;
char parity_str[32];
int databits;
int verbose;
// Configuration structure defaults values
} opts ;
void sendJSON(ValueList * me, boolean all);
// ======================================================================
// Global vars
// ======================================================================
int g_fd_teleinfo; // teleinfo serial handle
struct termios g_oldtermios ; // old serial config
int g_exit_pgm; // indicate en of the program
struct sysinfo g_info;
TInfo tinfo; // Teleinfo object
// Used to indicate if we need to send all date or just modified ones
boolean fulldata = true;
/* ======================================================================
Function: ADPSCallback
Purpose : called by library when we detected a ADPS on any phased
Input : phase number
0 for ADPS (monophase)
1 for ADIR1 triphase
2 for ADIR2 triphase
3 for ADIR3 triphase
Output : -
Comments: should have been initialised in the main sketch with a
tinfo.attachADPSCallback(ADPSCallback())
====================================================================== */
void ADPSCallback(uint8_t phase)
{
// Envoyer JSON { "ADPS"; n}
// n = numero de la phase 1 à 3
if (phase == 0)
phase = 1;
printf( "{\"ADPS\":%c}\r\n",'0' + phase);
fflush(stdout);
}
/* ======================================================================
Function: NewFrame
Purpose : callback when we received a complete teleinfo frame
Input : linked list pointer on the concerned data
Output : -
Comments: -
====================================================================== */
void NewFrame(ValueList * me)
{
// Envoyer les valeurs uniquement si demandé
if (fulldata)
sendJSON(me, true);
fulldata = false;
}
/* ======================================================================
Function: UpdatedFrame
Purpose : callback when we received a complete teleinfo frame
Input : linked list pointer on the concerned data
Output : -
Comments: it's called only if one data in the frame is different than
the previous frame
====================================================================== */
void UpdatedFrame(ValueList * me)
{
// Envoyer les valeurs
sendJSON(me, fulldata);
fulldata = false;
}
/* ======================================================================
Function: sendJSON
Purpose : dump teleinfo values on serial
Input : linked list pointer on the concerned data
true to dump all values, false for only modified ones
Output : -
Comments: -
====================================================================== */
void sendJSON(ValueList * me, boolean all)
{
bool firstdata = true;
// Got at least one ?
if (me) {
// Json start
printf("{");
if (all) {
printf("\"_UPTIME\":%ld", g_info.uptime);
firstdata = false;
}
// Loop thru the node
while (me->next) {
// go to next node
me = me->next;
// uniquement sur les nouvelles valeurs ou celles modifiées
// sauf si explicitement demandé toutes
if ( all || ( me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED) ) )
{
// First elemement, no comma
if (firstdata)
firstdata = false;
else
printf(", ") ;
printf("\"%s\":", me->name) ;
// we have at least something ?
if (me->value && strlen(me->value))
{
boolean isNumber = true;
uint8_t c;
char * p = me->value;
// check if value is number
while (*p && isNumber) {
if ( *p < '0' || *p > '9' )
isNumber = false;
p++;
}
// this will add "" on not number values
if (!isNumber) {
printf("\"%s\"", me->value) ;
}
// this will remove leading zero on numbers
else
printf("%ld",atol(me->value));
}
}
}
// Json end
printf("}\r\n") ;
fflush(stdout);
}
}
// ======================================================================
// some func declaration
// ======================================================================
void tlf_close_serial(int);
/* ======================================================================
Function: log_syslog
Purpose : write event to syslog
Input : stream to write if needed
string to write in printf format
printf other arguments
Output : -
Comments:
====================================================================== */
void log_syslog( FILE * stream, const char *format, ...)
{
static char tmpbuff[512]="";
va_list args;
int len;
// do a style printf style in ou buffer
va_start (args, format);
len = vsnprintf (tmpbuff, sizeof(tmpbuff), format, args);
tmpbuff[sizeof(tmpbuff) - 1] = '\0';
va_end (args);
// Write to logfile
openlog( PRG_NAME, LOG_PID|LOG_CONS, LOG_USER);
syslog(LOG_INFO, "%s", tmpbuff);
closelog();
// stream passed ? write also to it
if (stream && opts.verbose )
{
fprintf(stream, "%s", tmpbuff);
//fprintf(stream, "\n");
fflush(stream);
}
}
/* ======================================================================
Function: clean_exit
Purpose : exit program
Input : exit code
Output : -
Comments:
====================================================================== */
void clean_exit (int exit_code)
{
int r;
// free up linked list
tinfo.listDelete();
// close serials
if (g_fd_teleinfo)
{
// Restore Old parameters.
if ( (r = tcsetattr(g_fd_teleinfo, TCSAFLUSH, &g_oldtermios)) < 0 )
log_syslog(stderr, "cannot restore old parameters %s: %s", opts.port, strerror(errno));
// then close
tlf_close_serial(g_fd_teleinfo);
}
exit(exit_code);
}
/* ======================================================================
Function: fatal
Purpose : exit program due to a fatal error
Input : string to write in printf format
printf other arguments
Output : -
Comments:
====================================================================== */
void fatal (const char *format, ...)
{
char tmpbuff[512] = "";
va_list args;
int len;
va_start(args, format);
len = vsnprintf(tmpbuff, sizeof(tmpbuff), format, args);
tmpbuff[sizeof(tmpbuff) - 1] = '\0';
va_end(args);
// Write to logfile
openlog( PRG_NAME, LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_INFO, "%s", tmpbuff);
closelog();
fprintf(stderr,"\r\nFATAL: %s \r\n", tmpbuff );
fflush(stderr);
clean_exit(EXIT_FAILURE);
}
/* ======================================================================
Function: signal_handler
Purpose : Interrupt routine Code for signal
Input : signal received
Output : -
Comments:
====================================================================== */
void signal_handler (int signum)
{
// Does we received CTRL-C ?
if ( signum==SIGINT )
{
// Indicate we want to quit
g_exit_pgm = true;
log_syslog(stdout, "\nReceived SIGINT\n");
}
else if ( signum==SIGTERM )
{
// Indicate we want to quit
g_exit_pgm = true;
log_syslog(stdout, "\nReceived SIGTERM\n");
}
}
/* ======================================================================
Function: tlf_init_serial
Purpose : initialize serial port for receiving teleinfo
Input : -
Output : Serial Port Handle
Comments: -
====================================================================== */
int tlf_init_serial(void)
{
int tty_fd, r ;
struct termios termios ;
// Open serial device
if ( (tty_fd = open(opts.port, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) < 0 )
fatal( "tlf_init_serial %s: %s", opts.port, strerror(errno));
else
log_syslog( stdout, "'%s' opened.\n",opts.port);
// Set descriptor status flags
fcntl (tty_fd, F_SETFL, O_RDWR ) ;
// Get current parameters for saving
if ( (r = tcgetattr(tty_fd, &g_oldtermios)) < 0 )
log_syslog(stderr, "cannot get current parameters %s: %s", opts.port, strerror(errno));
// copy current parameters and change for our own
memcpy( &termios, &g_oldtermios, sizeof(termios));
// raw mode
cfmakeraw(&termios);
// Set serial speed to 1200 bps
if (cfsetospeed(&termios, B1200) < 0 || cfsetispeed(&termios, B1200) < 0 )
log_syslog(stderr, "cannot set serial speed to 1200 bps: %s", strerror(errno));
// Parity Even
termios.c_cflag &= ~PARODD;
termios.c_cflag |= PARENB;
// 7 databits
termios.c_cflag = (termios.c_cflag & ~CSIZE) | CS7;
// No Flow Control
termios.c_cflag &= ~(CRTSCTS);
termios.c_iflag &= ~(IXON | IXOFF | IXANY);
// Local
termios.c_cflag |= CLOCAL;
// No minimal char but 5 sec timeout
termios.c_cc [VMIN] = 0 ;
termios.c_cc [VTIME] = 50 ;
// now setup the whole parameters
if ( tcsetattr (tty_fd, TCSANOW | TCSAFLUSH, &termios) <0)
log_syslog(stderr, "cannot set current parameters %s: %s", opts.port, strerror(errno));
// Sleep 50ms
// trust me don't forget this one, it will remove you some
// headache to find why serial is not working
usleep(50000);
return tty_fd ;
}
/* ======================================================================
Function: tlf_close_serial
Purpose : close serial port for receiving teleinfo
Input : Serial Port Handle
Output : -
Comments:
====================================================================== */
void tlf_close_serial(int device)
{
if (device)
{
// flush and restore old settings
tcsetattr(device, TCSANOW | TCSAFLUSH, &g_oldtermios);
close(device) ;
}
}
/* ======================================================================
Function: usage
Purpose : display usage
Input : program name
Output : -
Comments:
====================================================================== */
int usage( char * name)
{
printf("%s\n", PRG_NAME);
printf("Usage is: %s [options] -d device\n", PRG_NAME);
printf("Options are:\n");
printf(" --<d>evice dev : open serial device name\n");
printf(" --<v>erbose : speak more to user\n");
printf(" --<h>elp\n");
printf("<?> indicates the equivalent short option.\n");
printf("Short options are prefixed by \"-\" instead of by \"--\".\n");
printf("Example :\n");
printf( "%s -d /dev/ttyAMA0\n\tstart listeming on hardware serial port /dev/ttyAMA0\n\n", PRG_NAME);
printf( "%s -d /dev/ttyUSB0\n\tstart listeming on USB microteleinfo dongle\n\n", PRG_NAME);
}
/* ======================================================================
Function: read_config
Purpose : read configuration from config file and/or command line
Input : -
Output : -
Comments: Config is read from config file then from command line params
this means that command line parameters always override config
file parameters
====================================================================== */
void read_config(int argc, char *argv[])
{
static struct option longOptions[] =
{
{"port", required_argument,0, 'p'},
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int optionIndex = 0;
int c;
char str_opt[64];
char buffer[512];
char* bufp = NULL;
char* opt = NULL;
char* optdata = NULL;
// default values
*opts.port = '\0';
opts.baud = 1200;
opts.flow = FC_NONE;
strcpy(opts.flow_str, "none");
opts.parity = P_EVEN;
strcpy(opts.parity_str, "even");
opts.databits = 7;
opts.verbose = false;
// default options
strcpy( str_opt, "hvd:");
// We will scan all options given on command line.
while (1)
{
// no default error messages printed.
opterr = 0;
// Get option
c = getopt_long(argc, argv, str_opt, longOptions, &optionIndex);
// Last one ?
if (c < 0)
break;
switch (c)
{
case 'v':
opts.verbose = true;
break;
case 'd':
strncpy(opts.port, optarg, sizeof(opts.port) - 1);
opts.port[sizeof(opts.port) - 1] = '\0';
break;
// These ones exit direct
case 'h':
case '?':
usage(argv[0]);
exit(EXIT_SUCCESS);
break;
default:
fprintf(stderr, "Unrecognized option.\n");
fprintf(stderr, "Run %s with '--help'.\n", PRG_NAME);
exit(EXIT_FAILURE);
break;
}
}
if ( !*opts.port)
{
fprintf(stderr, "No tty device given\n");
fprintf(stderr, "please select at least tty device such as /dev/ttyS0\n");
fprintf(stderr, "Run %s with '--help'.\n", PRG_NAME);
exit(EXIT_FAILURE);
}
if (opts.verbose)
{
printf("%s\n", PRG_NAME);
printf("-- Serial Stuff -- \n");
printf("tty device : %s\n", opts.port);
printf("flowcontrol : %s\n", opts.flow_str);
printf("baudrate is : %d\n", opts.baud);
printf("parity is : %s\n", opts.parity_str);
printf("databits are : %d\n", opts.databits);
printf("-- Other Stuff -- \n");
printf("verbose is : %s\n", opts.verbose? "yes" : "no");
printf("\n");
}
}
/* ======================================================================
Function: main
Purpose : Main entry Point
Input : -
Output : -
Comments:
====================================================================== */
int main(int argc, char **argv)
{
struct sigaction sa;
fd_set rdset, wrset;
unsigned char c;
char rcv_buff[TELEINFO_BUFSIZE];
int rcv_idx;
char time_str[200];
time_t t;
struct tm *tmp;
int n;
struct sysinfo info;
g_fd_teleinfo = 0;
g_exit_pgm = false;
// get configuration
read_config(argc, argv);
// Set up the structure to specify the exit action.
sa.sa_handler = signal_handler;
sa.sa_flags = SA_RESTART;
sigfillset(&sa.sa_mask);
sigaction (SIGTERM, &sa, NULL);
sigaction (SIGINT, &sa, NULL);
// Open serial port
g_fd_teleinfo = tlf_init_serial();
// Init teleinfo
tinfo.init();
// Attacher les callback dont nous avons besoin
// pour cette demo, ADPS et TRAME modifiée
tinfo.attachADPS(ADPSCallback);
tinfo.attachUpdatedFrame(UpdatedFrame);
tinfo.attachNewFrame(NewFrame);
log_syslog(stdout, "Inits succeded, entering Main loop\n");
// Do while not end
while ( ! g_exit_pgm ) {
// Read from serial port
n = read(g_fd_teleinfo, &c, 1);
if (n >= 0)
tinfo.process(c);
// Check full frame every 60 sec
sysinfo(&info);
if (info.uptime >= g_info.uptime + 60) {
g_info.uptime = info.uptime;
fulldata = true;
}
// Sleep 10ms; let time to others process
usleep(10000);
}
log_syslog(stderr, "Program terminated\n");
clean_exit(EXIT_SUCCESS);
// avoid compiler warning
return (0);
}