Last active
October 27, 2018 00:29
-
-
Save Jacajack/03ead9ee02321841e33a5ac131a3bfe8 to your computer and use it in GitHub Desktop.
DCF77 frame parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "dcf.h" | |
#include <time.h> | |
#include <inttypes.h> | |
// 8-bit BCD decoder | |
static inline int dcf_decode_bcd( uint8_t bits ) | |
{ | |
return ( bits & 0x0f ) + 10 * ( ( bits >> 4 ) & 0x0f ); | |
} | |
// Checks parity of `n' bits starting at `start' | |
static int dcf_parity( uint64_t frame, int start, int n ) | |
{ | |
int parity = 0; | |
uint64_t b; | |
for ( b = ( 1ull << start ); b != ( 1ull << ( start + n ) ); b <<= 1 ) | |
parity ^= !!( frame & b ); | |
return parity; | |
} | |
// Convert DCF77 frame to `struct tm` | |
static int dcf_parse( struct tm *t, uint64_t frame ) | |
{ | |
if ( t == NULL ) return 0; | |
// Validate frame | |
if ( frame & ( 1 << 0 ) ) return 0; // Start of minute - 0 | |
if ( ~frame & ( 1ul << 20 ) ) return 0; // Start of time - 1 | |
if ( ~( frame ^ ( frame >> 1 ) ) & ( 1ul << 17 ) ) return 0; // Exclusive CET / CEST | |
if ( dcf_parity( frame, 21, 8 ) ) return 0; // Minute parity | |
if ( dcf_parity( frame, 29, 7 ) ) return 0; // Hour parity | |
if ( dcf_parity( frame, 36, 23 ) ) return 0; // Date parity | |
// Construct time struct | |
t->tm_sec = 0; | |
t->tm_min = dcf_decode_bcd( ( frame >> 21 ) & 0x7f ); // 7 bits | |
t->tm_hour = dcf_decode_bcd( ( frame >> 29 ) & 0x3f ); // 6 bits | |
t->tm_mday = dcf_decode_bcd( ( frame >> 36 ) & 0x3f ); // 6 bits | |
t->tm_mon = dcf_decode_bcd( ( frame >> 45 ) & 0x1f ) - 1; // 5 bits | |
t->tm_year = dcf_decode_bcd( ( frame >> 50 ) & 0xff ) + 100; // 8 bits | |
t->tm_wday = dcf_decode_bcd( ( frame >> 42 ) & 0x07 ) - 1; // 3 bits | |
t->tm_yday = 0; // FIXME? | |
t->tm_isdst = !!( frame & ( 1ul << 17 ) ); // CEST | |
return 1; | |
} | |
// Enqueues an incoming data bit for parsing | |
int dcf_pushbit( struct tm *t, int state, int duration ) | |
{ | |
static uint64_t buffer = 0; // Frame buffer | |
static int length = 0; // Number of bits received so far | |
int bit = 0; // Received bit value. Ignore if `err' is set | |
int err = 0; // Set if impulse has invalid duration | |
// Determine bit value | |
if ( state == 0 ) | |
{ | |
if ( duration < 600 || duration > 1400 ) err = 1; | |
} | |
else | |
{ | |
if ( duration >= 40 && duration <= 130 ) bit = 0; // 0 - 100ms | |
else if ( duration >= 140 && duration <= 250 ) bit = 1; // 1 - 200ms | |
else err = 1; | |
} | |
// Check bit error | |
if ( err ) | |
{ | |
if ( length == 59 ) | |
{ | |
err = dcf_parse( t, buffer ); | |
buffer = 0; | |
length = 0; | |
return err; | |
} | |
else | |
{ | |
buffer = 0; | |
length = 0; | |
return 0; | |
} | |
} | |
else if ( state == 1 ) | |
{ | |
buffer >>= 1; | |
buffer |= ( (uint64_t) bit << 58 ); | |
length++; | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef DCF_H | |
#define DCF_H | |
#include <time.h> | |
/** | |
\brief Enqueues incoming data bit from DCF77 for parsing | |
\param t Pointer to `tm` struct that shall be written upon succesful parsing | |
\param state The input state (high/low) | |
\param duration The duration of the input state | |
\returns A non-zero value if a meaningful frame was parsed | |
*/ | |
extern int dcf_pushbit( struct tm *t, int state, int duration ); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment