star météo frame encoder/decoder.

This commit is contained in:
Jean-François DEL NERO
2026-07-04 19:28:24 +02:00
parent 0449bab0dd
commit 545abf31b2
2 changed files with 580 additions and 1 deletions
+7 -1
View File
@@ -24,7 +24,7 @@ endif
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
endif
EXEC=broadcast_tv broadcast_fm rf_jammer pocsag
EXEC=broadcast_tv broadcast_fm rf_jammer pocsag starmeteo
all: $(EXEC)
@@ -40,12 +40,18 @@ rf_jammer: rf_jammer.o wave.o modulator.o rand_gen.o composite.o std_crc32.o cm
pocsag: pocsag.o wave.o modulator.o serial.o std_crc32.o utils.o cmd_param.o
$(CC) -o $@ $^ $(LDFLAGS)
starmeteo: starmeteo.o utils.o cmd_param.o
$(CC) -o $@ $^ $(LDFLAGS)
broadcast_fm.o: ../src/broadcast_fm/broadcast_fm.c
$(CC) -o $@ -c $< $(CFLAGS)
pocsag.o: ../src/pocsag/pocsag.c
$(CC) -o $@ -c $< $(CFLAGS)
starmeteo.o: ../src/pocsag/starmeteo.c
$(CC) -o $@ -c $< $(CFLAGS)
rf_jammer.o: ../src/rf_jammer/rf_jammer.c
$(CC) -o $@ -c $< $(CFLAGS)
+573
View File
@@ -0,0 +1,573 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : starmeteo.c
// Contains: star meteo frame encoder / decoder
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2026 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include "cmd_param.h"
#define MAX_MSG_SIZE 512
typedef struct frame_
{
unsigned char frm[MAX_MSG_SIZE];
unsigned char dcodefrm[MAX_MSG_SIZE];
unsigned char quartetfrm[MAX_MSG_SIZE*3];
int quartets_cnt;
}frame;
void printbin(uint32_t val,int bitcnt)
{
for(int j=(bitcnt-1);j>=0;j--)
{
printf("%d", (val>>j)&1);
}
}
// Convert pocsag characters to 6 bits raw word (decoding)
unsigned char char2raw(unsigned char c)
{
if( c >= 'k' && c <= 'o')
return 59+(c-'k');
switch( c )
{
case 'p':
return 0x20;
break;
case 's':
return 0x03;
break;
}
c = c - 0x20;
return c;
}
// Convert 6 bits word to char. (encoding)
unsigned char raw2char(unsigned char r)
{
if( r >= 59 && r <= 63 )
return 'k' + (r - 59);
switch( r )
{
case 0x20:
return 'p';
break;
case 0x03:
return 's';
break;
}
r = r + 0x20;
return r;
}
// Get quartet from a decoded 6 bits words array
unsigned char get_quartet( unsigned char * buf, int idx)
{
int i,j,bitidx;
unsigned char val;
bitidx = (idx * 4);
val = 0;
j = 0;
while(j<4)
{
i = bitidx / 6;
val = val << 1;
if( (buf[i] >> (5-(bitidx%6))) & 1 )
{
val |= 1;
}
bitidx++;
j++;
}
return val;
}
// Set quartet to a decoded 6 bits words array
void set_quartet( unsigned char * buf, int idx, unsigned char q)
{
int i,j,bitidx;
bitidx = (idx * 4);
j = 0;
while(j<4)
{
i = bitidx / 6;
if( q & (0x8>>j) )
{
buf[i] = buf[i] | ( 0x01 << (5-(bitidx%6)));
}
else
{
buf[i] = buf[i] & ~( 0x01 << (5-(bitidx%6)));
}
bitidx++;
j++;
}
return;
}
// Encode temperature to BCD+40
unsigned char dectemp_to_bcd(int temp)
{
temp += 40;
return (((temp / 10)&0xF) << 4) | ((temp%10) & 0xF);
}
// Generate and encode current time frame.
int gen_current_time(unsigned char * quartets)
{
int i;
time_t t = time(NULL);
struct tm tm;
tm = *localtime(&t);
quartets[0] = 0xF;
if( tm.tm_hour < 10)
{
quartets[1] = tm.tm_hour;
quartets[2] = tm.tm_min/10;
quartets[3] = tm.tm_min%10;
}
else
{
if( tm.tm_hour >= 10 && tm.tm_hour <= 19 )
{
quartets[1] = tm.tm_hour - 10;
quartets[2] = (tm.tm_min/10) + 10;
quartets[3] = tm.tm_min%10;
}
else
{
//20 <> 23
quartets[1] = tm.tm_hour - 10;
quartets[2] = (tm.tm_min/10);
quartets[3] = tm.tm_min%10;
}
}
quartets[4] = tm.tm_mon + 1;
quartets[5] = ( ((tm.tm_mday/10)&3)<<2 ) | ( (((tm.tm_mday%10)>>2)&3) );
quartets[6] = ( ((tm.tm_mday%10)&3) )<<2;
quartets[6] |= ( ((tm.tm_year-100)>>4) & 0x3);
quartets[7] = ( ((tm.tm_year-100)) & 0xF);
int sum = 0x7;
i = 0;
while(i<8)
{
sum += quartets[i];
i++;
}
quartets[8] = sum & 0xF;
return 9;
}
// Load and decode a frame
int loadfrm(frame * frm, int idx, char *path)
{
//int size;
FILE *f;
char str[512];
char * strtmp;
int len,i;
//printf("%s\n",path);
f = fopen(path,"rb");
if(f)
{
// fseek(f,0,SEEK_END);
// size = ftell(f);
fseek(f,0,SEEK_SET);
memset((char*)str,0,sizeof(str));
fgets ((char*)&str, sizeof(str), f);
strtmp = strchr(str,'\n');
if(strtmp)
*strtmp = 0;
len = strlen((char*)str);
if( 1 )
{
strcpy((char*)&frm[idx].frm,str);
// chars to 6 bits words
i = 0;
while( frm[idx].frm[i] )
{
frm[idx].dcodefrm[i] = char2raw(frm[idx].frm[i]);
i++;
}
// 6 bits words to quartets
i = 0;
while( i < (len*6)/4 )
{
frm[idx].quartetfrm[i] = get_quartet( (unsigned char*)(&frm[idx].dcodefrm), i);
i++;
}
frm[idx].quartets_cnt = i;
idx++;
}
fclose(f);
}
return idx;
}
int main(int argc, char* argv[])
{
int i,idx,fidx;
int quiet,verbose;
int param_start_index;
frame * genfrm;
int sum;
char tmp_str[512];
verbose = 0;
if(isOption(argc, argv,"verbose",NULL, NULL) )
{
verbose = 1;
}
quiet = 0;
if(isOption(argc, argv,"quiet",NULL, NULL) )
{
quiet = 1;
}
if(!quiet)
printf("startmeteo v0.1 -help format command line syntax.\n");
if(isOption(argc, argv,"help",NULL, NULL) )
{
printf("Syntax:\n");
printf("%s -decode [files]\n",argv[0]);
printf("%s -encode:[HEX Quartets]\n",argv[0]);
printf("%s -checksum (Update checksum with \"-encode\")\n",argv[0]);
printf("%s -curtime Generate current date/hour frame\n",argv[0]);
printf("%s -quiet\n",argv[0]);
printf("%s -verbose\n",argv[0]);
printf("\n");
printf("Example: ./%s -prev_analyze ../previsions_ok/*.txt\n",argv[0]);
exit(0);
}
param_start_index = 1;
if(isOption(argc, argv,"decode",NULL, &param_start_index) )
{
genfrm = calloc(sizeof(frame)*argc,1);
if(!genfrm)
exit(-1);
fidx = 0;
i = param_start_index + 1;
while( argv[i] )
{
printf("\nFile : %s\n",argv[i]);
fidx = loadfrm(genfrm, fidx, argv[i]);
i++;
}
printf("Frames:%d\n",fidx);
for(int b=0;b<fidx;b++)
{
if(verbose)
{
i = 0;
while(i<genfrm[b].quartets_cnt)
{
//printbin( genfrm[b].quartetfrm[i],4);
//printf(" ");
printf("%X",genfrm[b].quartetfrm[i]);
i++;
}
printf("\n");
}
if( genfrm[b].quartets_cnt )
{
int hour, minutes, month, day, year;
switch( genfrm[b].quartetfrm[0] )
{
case 0xF:
// Trame horaire
printf("Date frame : ");
// Si champ heure < 10 : Codage BCD direct
if( genfrm[b].quartetfrm[1] < 10 )
{
// Si les dizaine de minutes : +10 sur les heures
if( genfrm[b].quartetfrm[2] >= 10 )
{
hour = genfrm[b].quartetfrm[1] + 10;
minutes = ((genfrm[b].quartetfrm[2]-10)*10 + genfrm[b].quartetfrm[3]) ;
}
else
{
// Sinon codage BCD direct.
hour = genfrm[b].quartetfrm[1];
minutes = (genfrm[b].quartetfrm[2]*10 + genfrm[b].quartetfrm[3]) ;
}
}
else
{
// Si heure >= 10
hour = genfrm[b].quartetfrm[1] + 10;
minutes = (genfrm[b].quartetfrm[2]*10 + genfrm[b].quartetfrm[3]) ;
}
month = genfrm[b].quartetfrm[4];
day = ((genfrm[b].quartetfrm[5]>>2)&3)*10 + ( ((genfrm[b].quartetfrm[5]&3)<<2) + (genfrm[b].quartetfrm[6]>>2));
year = 2000 + (((genfrm[b].quartetfrm[6]&3)<<4) + genfrm[b].quartetfrm[7] );
printf("%.2d:%.2d %d/%d/%d",hour, minutes,day,month,year);
sum = 0x7;
i = 0;
while(i<8)
{
sum += genfrm[b].quartetfrm[i];
i++;
}
if( (sum&0xF) == genfrm[b].quartetfrm[i] )
{
printf(" (Valid checksum)") ;
}
else
{
printf(" (Bad checksum) ");
}
printf("\n");
break;
default:
// Trame prévision
printf("Weather frame - Header : ");
for(i=0;i<6;i++)
printf("%X",genfrm[b].quartetfrm[i]);
sum = 0x7;
i = 0;
while(i<5)
{
sum += genfrm[b].quartetfrm[i];
i++;
}
printf(", ");
if( (sum&0xF) == genfrm[b].quartetfrm[5] )
{
printf("Checksum : OK");
}
else
{
printf("Checksum : KO");
}
printf("\n");
idx = ((4*6)/4);
while( ( idx + ((10*6)/4) - ( (4*6)/4) ) <= genfrm[b].quartets_cnt )
{
int lowtemp,hightemp;
printf("Frame: ");
for(i=0;i<((10*6)/4);i++)
printf("%X",genfrm[b].quartetfrm[idx+i]);
printf(", ");
// Checksum
sum = 0x7;
i = 0;
while(i<((10*6)/4)-1)
{
sum += genfrm[b].quartetfrm[idx+i];
i++;
}
if( (sum&0xF) == genfrm[b].quartetfrm[idx+i] )
{
printf("Checksum : OK, ");
}
else
{
printf("Checksum : KO, ");
}
// High temp : Quartet 0 : High BCD, Quartet 1 : Low BCD
hightemp = (((genfrm[b].quartetfrm[idx+2])*10) + genfrm[b].quartetfrm[idx+3] ) - 40;
printf("High temp: %d°C, ", hightemp);
// Loq temp : Quartet 2 : High BCD, Quartet 3 : Low BCD
lowtemp = (((genfrm[b].quartetfrm[idx+0])*10) + genfrm[b].quartetfrm[idx+1]) - 40;
printf("Low temp: %d°C, ", lowtemp);
for(int t=0;t < 5 ;t++)
{
int picto = (((genfrm[b].quartetfrm[idx+4+ (t*2)])<<4) | genfrm[b].quartetfrm[idx+4+ (t*2) + 1]) & 0x3F;
printf("Picto %d: %d (0x%.2X), ", t, picto, picto);
}
printf("\n");
idx += ((10*6)/4);
}
break;
}
}
}
}
if(isOption(argc, argv,"encode",(char*)tmp_str, &param_start_index) )
{
unsigned char q;
int size;
genfrm = calloc(sizeof(frame)*1,1);
if(!genfrm)
exit(-1);
i = 0;
while( tmp_str[i] )
{
q = 0;
if(tmp_str[i] >= 'A' && tmp_str[i] <= 'F')
q = (tmp_str[i] - 'A') + 10;
else if(tmp_str[i] >= 'a' && tmp_str[i] <= 'f')
q = (tmp_str[i] - 'a') + 10;
else if(tmp_str[i] >= '0' && tmp_str[i] <= '9')
q = (tmp_str[i] - '0');
else printf("Error : Invalid quartet:%c\n",tmp_str[i]);
genfrm->quartetfrm[i] = q;
set_quartet( (unsigned char*)(genfrm->dcodefrm), i, q);
i++;
}
genfrm->quartets_cnt = i;
if( isOption(argc, argv,"checksum",NULL, NULL) && genfrm->quartets_cnt )
{
int sum;
sum = 0x7;
for(i = 0;i < genfrm->quartets_cnt - 1; i++ )
{
sum = (sum + genfrm->quartetfrm[i]) & 0xF;
}
genfrm->quartetfrm[genfrm->quartets_cnt - 1] = sum;
set_quartet( (unsigned char*)(genfrm->dcodefrm), genfrm->quartets_cnt - 1, sum);
}
size = (genfrm->quartets_cnt*4)/6;
i = 0;
while( i < size )
{
genfrm->frm[i] = raw2char(genfrm->dcodefrm[i]);
printf("%c",genfrm->frm[i]);
i++;
}
if(!quiet)
printf("\n");
free(genfrm);
}
if(isOption(argc, argv,"curtime",(char*)tmp_str, &param_start_index) )
{
genfrm = calloc(sizeof(frame)*1,1);
if(!genfrm)
exit(-1);
genfrm->quartets_cnt = gen_current_time(genfrm->quartetfrm);
i = 0;
while( i < genfrm->quartets_cnt )
{
set_quartet( (unsigned char*)(genfrm->dcodefrm), i, genfrm->quartetfrm[i]);
i++;
}
int size = (genfrm->quartets_cnt*4)/6;
i = 0;
while( i < size )
{
genfrm->frm[i] = raw2char(genfrm->dcodefrm[i]);
printf("%c",genfrm->frm[i]);
i++;
}
if(!quiet)
printf("\n");
free(genfrm);
}
}