#include <string.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "FunkUsb.h"
Clocktime n;
Frame frame;
void Clocktime::IncSec() {
if (++sec<60) return;
sec=0;
IncMin();
}
void Clocktime::IncMin() {
if (++min<60) return;
min=0;
if (++hour<24) return;
hour=0;
IncDate();
}
void Clocktime::IncDate() {
if (++wday>=7) wday=0;
if (++day<=tage(month+1,year)) return;
day=1;
if (++month<12) return;
month=0;
if (++year<100) return;
year=0; // das wäre dann erst am 1.1.2100
};
// Alle Bits des Bytes xor-verknüpfen, liefert true bei ungerader Parität
// VR: nur W = R25:R24 — leider „sieht“ das der gcc-Optimierer nicht!
static bool parity(byte b) { // xorbits
b^= b>>4|b<<4; // swap X X X X 73 62 51 40
b^= b>>2; // 2× lsr X X X X X X 5173 4062
b^= b>>1; // lsr X X X X X X X 40625173
return bool(b&1); // X-Bits ausblenden
}
// konvertiert BCD-Zahl in Binärform. Liefert >99 bei Pseudotetraden.
// VR: nur W
static byte bcd(byte b) {
byte n = b&0x0F; // Lo-Nibble isolieren
if (n>=10) b=0xFF; // Pseudotetrade = Fehler
b&=0xF0; // Hi-Nibble isolieren
asm("lsr %0 $ add %1,%0 $ lsr %0 $ lsr %0 $ add %0,%1":"+r"(b):"r"(n));
return b; // Multiplikation ×10 nicht mit Laufzeitbibliothek
}
/***********************************
* Taktfrequenz der CPU umschalten *
***********************************/
void CpuSlow() {
if (CLKPR&8) return; // Ist schon langsam
cli();
CLKPR=0x80;
CLKPR=0x08; // /256, 64 kHz Taktfrequenz, reicht zum Zeit messen
TCNT0=GPIOR1; // Nachteiler herausnehmen
sei(); // TODO: ADU
}
void CpuFast() {
if (!CLKPR&8) return; // Schon schnell
cli();
CLKPR=0x80;
CLKPR=0x00; // 16,5 MHz, für USB und rechenintensive Operationen
GPIOR1=TCNT0; // Nachteiler einschieben
sei(); // TODO: ADU
}
static void Vergleich() {
char m = timeReport.t.min;
char h = timeReport.t.hour;
byte d = timeReport.t.ZoneMJD();
if (++m>=60) {
m=0; if (++h>=24) d++;
}
statusReport.someBits&=~4;
if (m==n.min && h==n.hour && d==n.ZoneMJD()) statusReport.someBits|=4;
}
static WORD limits[3];
static unsigned long long *pData, *pOkay;
static void ToggleBit(void*mem,byte bitno) {
byte *m = reinterpret_cast<byte*>(mem);
m[bitno>>3] ^= 1<<(bitno&7);
}
void dcf77Poll() {
if (GPIOR0&0x08) {
GPIOR0&=~0x08;
PRR=0x0A; // ADC aktivieren
ADMUX = 0x90 | (ANA_BIT==5?0:ANA_BIT==2?1:ANA_BIT==4?2:3);
ADCSRA = CLKPR&8 ? 0xD8 : 0xDF;
}
if (GPIOR0&0x04) { // Flanke erkannt, Zeitstempel (8kHz) in T0Capture
n.IncSec();
#if 1
WORD diff = T0Capture-lastStart;
if (joyReport.joyKey) { // Beginn "ganze" Sekunde
if (diff > (WORD)(1.5*F_TMR)) { // Minutenlücke?
n.sec=0;
memset(&frame,0,sizeof(frame));
byte minu = historyReport.nMinu;
if (minu&0x0F<10) minu++;
minu+=0x10; if ((minu&0xF0)==0xA0) minu&=0x0F; // sollte 0x0A ergeben
historyReport.nMinu=minu;
pData = &historyReport.Data[minu>>4];
memset(pData,0xFF,8);
pOkay = &historyReport.Okay[minu>>4];
memset(pOkay,0,8);
Vergleich();
timeReport.t=n; // müsste memcpy() kompilieren
}else{
if (n.sec<63) n.sec++;
}
lastStart = T0Capture;
}else{
unsigned hist_index=diff/(F_TMR/100); // ungefähr
if (hist_index>=50) hist_index=49;
if (~historyReport.histo[hist_index]) historyReport.histo[hist_index]++;
if (limits[0]<=diff && diff<=limits[2]) {
ToggleBit(pOkay,n.sec);
if (diff<limits[1]) {
GPIOR0&=0x04; // kurzer Impuls
ToggleBit(pData,n.sec);
}
}else{
ToggleBit(pData,n.sec);
}
#if 0
if (sync && !frame.recvbit) { // wenn neue Zeit empfangen wurde und 1. Bit nach Syncpause (= Start)
timer0_cnt = 0; // interner Timer auf Anfang
// weitere Prüfung eingebaut
if (n.hour<24 && n.min<60 && (byte)(n.day-1)<31 && (byte)(n.month-1)<12) {
if (comp_count == 1){ // empfangene Werte erstmal in Buffer "vgl"
vgl = n;
vgl.sec = 0;
}
if (comp_count==2) { // neu empfangene Werte mit Buffer "vgl" vergleichen
if (!memcmp(&vgl.min,&n.min,6)) {
cur = n;
cur.sec = 0; // empfangene Uhrzeit für Anzeige übernehmen
send_count ++;
if (send_count == 100) send_count = 1;
sig_available = 99; // Signalgüte hochsetzen
}
comp_count = 0; // neues Spiel egal ob eingelesen oder nicht
}
comp_count++; // nach neuer Runde jetzt: (comp_count = 2)
}
sync = 0;
}
}
LED_Port &= ~(1 << LED_Pin); // LED aus
timer1_stop (); // liefert Impulsmesswert in µs
// 150 ms
#endif
if (GPIOR0&0x04) ToggleBit(&frame.data,frame.recvbit);
switch (++frame.recvbit) {
case 16: {
if (timeReport.t.min==0) frame.GrabWetter0();
else if (timeReport.t.min==2) frame.GrabWetter2();
}break;
case 21: frame.recvbit=24; break;
case 39: frame.recvbit=42; break;
case 42: frame.recvbit=41; break;
case 41: {
if (frame.wl&0x01
|| ((frame.inf&0x16)!=0x12 && (frame.inf&0x16)!=0x14)
|| parity(frame.min)
|| parity(frame.hod)
|| parity(frame.day ^ frame.wdm ^ frame.rok)) {
// nichts tun!
}else{ // Empfangene Zeit gültig => Interne Zeit setzen
n.info = frame.inf&0x0F;
n.min = bcd(frame.min&0x7F);
n.hour = bcd(frame.hod&0x3F);
n.day = bcd(frame.day>>2);
n.wday = frame.wdm&7;
n.month = bcd(frame.wdm>>3);
n.year = bcd(frame.rok);
if (timeReport.t.min==1) frame.GrabWetter1();
}
}break;
case 64: frame.recvbit=40; break;
}
}
#endif
GPIOR0&=0x04;
}
}
| Detected encoding: UTF-8 | 0
|