1 /* Programm für ATtiny45, „h#s“ Henrik Haftmann, TU Chemnitz
2 * tabsize = 8, encoding = utf-8 (ohne Windows-Header BOM)
3 090331 Erster Anfang als mfv2.c
4 +190531 CLIP funktioniert
5 ~190610 CLIP funktioniert nicht am Telekom-Anschluss
6 +190617 phoneParallel() — Tiefentladeschutz für Elko
7 ?190626 Nummer des Anrufers kann immer noch nicht mit 7³ gespeichert werden
8 210206 Bei Binärgleichheit Kommentierung erweitert
9 220320 Umstellung auf C++14
10 220328 Gleicher Quelltext für CLIP: c: mit ADC, d: mit Analogvergleicher
11 -220421 Kurzen letzten nsi-Impuls detektieren (Österreicher Wählscheibe)
12 */
13 #include <avr/io.h>
14 #include <avr/pgmspace.h>
15 #include <avr/interrupt.h>
16 #include <avr/sleep.h>
17 #include <avr/wdt.h>
18 #include <util/delay.h>
19 #include <avr/fuse.h> // avr-size: 3 Bytes bei .data (falsch)
20 #include <avr/signature.h> // avr-size: 3 Bytes bei .text (falsch)
21 #include <string.h>
22
23 FUSES={
24 0x5C, // Taktteiler /8, kein Taktausgang, schnellster Startup, Resonator 3..8 MHz
25 0x57, // kein RESET, EEPROM-Inhalt behalten, kein Brownout
26 0xFF, // Keine Selbstprogrammierung
27 }; // {Startup: Reset = 272 CK + 64 ms (64068 µs), PowerDown = 258 CK (64 µs)}
28
29 /************
30 * Hardware *
31 ************/
32 /*
33 Anschlüsse:
34 PB0 (5) - Wählscheiben-Kontakte "nsi"+"nsa", 1 = unterbrochen
35 AIN0 d: Empfindlichere Clip-Dekodierung via 4,7 nF (Fritzbox)
36 und internem Pullup, f_HP = 1/(2πRC) = 850 Hz
37 PB1 (6) OC1A PWM-Tonausgang, reichlich (125 kHz) Trägerfrequenz
38 AIN1 d: Gegenpol (als 5V-Ausgang) für den Analogvergleicher
39 PB2 (7) ADC1 Amtsader La = Telefonader a, über 680 kΩ zur
40 Abhebe- und Klingel-Detektierung, Minimalstromversorgung,
41 c: CLIP-Dekodierung
42 PB3 (2) XIN Resonator 4 MHz
43 PB4 (3) XOUT Resonator 4 MHz
44 PB5 (1) !RESET LVISP-Zugang
45 - Erdtaste, LED-Flash, Debug-Ausgang
46 GND (4) Telefonader b
47 Ucc (8) Amtsader Lb; Z-Diode 5,6 V und Elko 470 µF nach GND
48
49 Der Analogvergleicher kommt auch mit Spannungen von 0,3 V jenseits der
50 Betriebsspannungsgrenzen zurecht. Getestet am ATtiny13, okay.
51 Die CLIP-Wechselspannung beträgt (-13,5±1,5)dBm an "BT3 termination" (600 Ω),
52 macht P = U*I = U*U/R = -13,5 dBm = 10^-1,35 mW = 45 µW; U = sqrt(P*R) = 160 mV = 450 mVss.
53 Für den A/D-Wandler (10 Bit, 5 V) 40 Count.
54 Die Terminierung ergibt sich durch das parallel geschaltete Läutewerk (Telefonklingel).
55 Sowie zuschaltbar durch Fixierung von PB1 (auf High-Pegel) via R1.
56
57 CLIP-Dekodierung mit Analogvergleicher ist Energie sparender:
58 I(ADC) = 170 µA; I(AC) = 40 µA; also nur ein Viertel.
59 Auch die CPU hat weniger zu tun, hält sie mit 1 mA/MHz den Löwenanteil.
60 Keiner der Timer hat eine Capture-Funktion; die Zeitmessung muss
61 von der CPU (am besten via Energie sparenden Timer0) ausgeführt werden.
62 Die Offsetspannung des Analogvergleichers ist nicht angegeben.
63
64 # Es ist schwieriger, einen Adapter zum Zwischenschalten
65 # (ohne Modifikation des Telefonapparates) zu bauen.
66 # Ein möglicher Trick dabei besteht darin, das Telefon zwischen W2 und b
67 # zu betreiben und den nsi-Kontakt an a abzugreifen.
68 # Das erspart das Unterdrücken der Wählimpulse,
69 # muss aber nicht mit jedem Telefon funktionieren, je nach Innenschaltung.
70
71 Die Erdtaste ist optional und ermöglicht einen schnellen Weg zum Rückruf.
72 (Sonst ist es die 6 in der dritten Shift-Ebene, also kurz 6³.)
73
74 Der EEPROM des AVR ermöglicht das Abspeichern von Nummern zur Kurzwahl.
75 Sonderfunktionen:
76 LANG am Finger-Anschlag halten (bis zum ersten Piep): Speichermodus:
77 1..9,0 = Kurzwahl K1..K9, K0 Kurzwahl K0..9
78 LANG×2 am Finger-Anschlag halten (bis zum zweiten Piep):
79 1..8 = Kurzwahl M1..M8 Kurzwahl M1..8
80 9 = '*' wählen Ortsvorwahl
81 0 = '#' wählen Autowahl
82 LANG×3 am Finger-Anschlag halten (bis zum dritten Piep):
83 1..4 = 3. Kurzwahl A..D mit 'A' bis 'D' vorbelegt Kurzwahl A..D
84 5 = Wahlwiederholung 'A'
85 6 = Rückruf 'B'
86 7 = Speichern der zuletzt gewählten Rufnummer (Ziffer folgt) 'C'
87 8 = Speichern einer neuen Rufnummer (Nummer folgt, dann LANG + Ziffer) 'D'
88 9 = Letzte Rufnummer löschen (= Wahlwiederholung verhindern) '*'
89 0 = Rückrufliste löschen '#'
90
91 Die Autowahl = Wahl beim Abnehmen des Telefonhörers ist mit Vorsicht zu nutzen.
92 Sie kann nur unterbunden werden durch:
93 - Wahl bei aufgelegtem Telefonhörer
94 - Eingehender Telefonanruf (Klingeln)
95 - Mindestens 1 entgangener Anruf
96 Die Autowahl ist für den Einsatz als Oma-Telefon gedacht.
97 Andererseits kommen Omas gut mit Wählscheiben zurecht. Gerade weil's so zeitraubend ist.
98
99 Wahlen aus dem Kurzwahlspeicher gehen nicht in die Wahlwiederholung ein.
100 D.h. der Wahlwiederholungsspeicher merkt sich nur explizit gewählte Nummern.
101
102 Folgende interne Peripherie wird verwendet:
103 Ports: 2 Eingabe mit Pull-Up, 1 Ausgabe via Hardware-PWM
104 Timer 0: Frequenzsynthese = Stetige PWM-Änderung für Timer 1
105 Timer 1: High-Speed-Timer mit 32-MHz-PLL: Hardware-PWM-Ausgabe, mono
106 Totzeitgenerator, USI, Flash-Selbstprogrammierung: ungenutzt
107 Taktgenerator: Keramikoszillator mit bei Bedarf zugeschalteter High-Speed-PLL
108 Power-Management: Power-Save (onhook), Idle (offhook), CPU-Taktdrosselung
109 Analog-Digital-Wandler:
110 Messung Spannung an PB2: onhook/offhook/Klingel-Detektion
111 Messung der Betriebsspannung: Erkennung parallelgeschaltetes Telefon
112 c: CLIP-Flankenmessung
113 Analogvergleicher:
114 d: CLIP-Flankenmessung
115 Interrupts:
116 Zählerüberlauf Timer 0 => Nächster PWM-Wert,
117 Watchdog-Timer => verschiedene Timeouts,
118 c: ADC fertig => CPU aufwecken (nur für CLIP)
119 d: Analogvergleicher-Flanke => CPU aufwecken (nur für CLIP)
120 EEPROM: Nummernspeicher für Wahlwiederholung, 22 Kurzwahlen, Autowahl, Ortsvorwahl
121 feste Adressen
122 Beim ATtiny85 wird die gesamte CLIP-Nachricht im EEPROM abgelegt.
123 Da die Fritzbox auch den Namen aus dem Telefonbuchspeicher übermittelt,
124 steht dann hier der Name des letzten Anrufers im Klartext drin.
125 Auslesbar mit einem AVR-Programmiergerät.
126 RAM: Nummernspeicher für CLIP, als Liste hintereinanderweg
127 Flash-Selbstprogrammierung: ungenutzt
128
129 In dieser Firmware ist die Resonatorfrequenz variabel gehalten;
130 getestet habe ich's aber nur mit 4 MHz.
131 */
132
133 // Signal-Zeiten in Sekunden
134 constexpr float TON=0.14;
135 constexpr float PAUSE=0.06;
136
137 typedef unsigned char byte;
138 typedef unsigned short word;
139 #define NOINIT __attribute__((section(".noinit")))
140 #define SINTAB __attribute__((section(".sintab")))
141
142 // Sinustabelle, Mittelwert und Amplitude = 73
143 extern const struct sintab_t{
144 byte a[256] {};
145 constexpr sintab_t() {
146 constexpr float PI=__builtin_atan(1)*4;
147 for (size_t x=0; x<256; x++)
148 a[x]=__builtin_round(__builtin_sin(x*2*PI/256)*73)+73;
149 }
150 }SinTab SINTAB;
151 // Mit der gewählten Amplitude läuft die Signal-Addition
152 // mit 100 % (hoher Ton) + 75 % (tiefer Ton) geradeso nicht über.
153 const sintab_t SinTab SINTAB;
154
155 // Etwa 32 kHz Trägerfrequenz bei jeder Resonatorfrequenz (bis 8 MHz) realisieren
156 constexpr byte T0DIV = F_CPU/32000;
157
158 constexpr word FREQ(float x) {return x*65536*T0DIV/F_CPU+0.5;}
159 // DDS-Inkremente = Additionswerte auf Phasenwert alle F_CPU/T0DIV
160 static PROGMEM const word Frequencies[20] = {
161 FREQ( 697), // Zeile mit 1 2 3 A
162 FREQ( 770), // Zeile mit 4 5 6 B
163 FREQ( 852), // Zeile mit 7 8 9 C
164 FREQ( 941), // Zeile mit * 0 # D
165 FREQ(1209), // Spalte mit 1 4 7 *
166 FREQ(1336), // Spalte mit 2 5 8 0
167 FREQ(1477), // Spalte mit 3 6 9 #
168 FREQ(1633), // Spalte mit A B C D
169 FREQ(1046), //c³ Ab Index 9 gleichstufige Tonleiter aus 12 „Sekunden“
170 FREQ(1109), //cis³/des³
171 FREQ(1175), //d³
172 FREQ(1245), //dis³/es³
173 FREQ(1319), //e³
174 FREQ(1397), //f³ (Halbtonschritt)
175 FREQ(1480), //fis³/ges³
176 FREQ(1568), //g³
177 FREQ(1661), //gis³/as³
178 FREQ(1760), //a³ = 440*4
179 FREQ(1865), //ais³/b³
180 FREQ(1975), //h³
181 };
182
183 // Funktionsprinzip: DDS = Digitale Frequenzsynthese
184 #define DDS_REG
185 #ifdef DDS_REG
186 volatile register word
187 addA asm("r8"),
188 phaA asm("r10"), // hoher Ton
189 addB asm("r12"),
190 phaB asm("r14"); // tiefer Ton
191 #else
192 volatile word addA,phaA,addB,phaB NOINIT;
193 #endif
194
195 // Häufig benutzte globale Bytes werden in freien I/O-Adressen gehalten,
196 // wobei nur die GPIORx bitadressierbar sind
197 #define Flags GPIOR0 // Bits für NSK() u.a.
198 // 7 Watchdog-Interrupt aufgetreten: 16 ms vergangen
199 // 6 Anruf beginnt: Wenn's klingelt oder gewählt wird
200 // 5 Blitz-LED wurde eingeschaltet; Debug: CLIP: TLEVEL bestimmt
201 // 4 Erdtaste solo gedrückt
202 // 3 8³ = wahlfreie Nummer speichern
203 // 2 7³ = letzte gewählte oder rückgerufene Nummer speichern
204 // 1:0 Ebenenzähler 0..3 durch Festhalten am Fingeranschlag
205 #define pb2 GPIOR1 // Aktivitätszustand (> 75 % A/D-Wert) an PB2 mit Historie in variabler Schrittweite
206 #define buf_r GPIOR2 // Puffer-Lesezeiger
207 #define T_on OCR0B // Rest-Ton/Pausenlänge, in 16 ms
208 #define anrufe OCR1B // Anrufzähler
209 #define Zeit8 DT1A // Zeitzähler für nsi+nsa
210 #define NSI DT1B // Steigende Flanken an PB0 (nsi + einer extra für nsa)
211
212 static byte pb0,pb5; // Invertierter Zustand an PB0 und PB5 mit Historie in Watchdog-Schrittweite (16 ms)
213 static byte Zeit16; // Zeitzähler zum Abspeichern der letzten Rufnummer (für Wahlwiederholung)
214 static byte rend NOINIT;// Wähl-Timeout, Klingel-Timeout, Flash-Timeout (onhook)
215
216 static byte wahl[11]; // Puffer für bis zu 20 Wählziffern
217 #define buf_w wahl[0]
218 // 1. Byte = Füllstand (buf_w)
219 // '*'=14, '#'=15, wie im EEPROM-Kurzwahlspeicher
220 // Keine Vorsehung von Wählpausen oder Flash-Impulsen
221
222 extern void PutNib(byte*z,byte idx,char v);
223
224 // Puffer füllen, c=0..15
225 static void PutBuf(char c) {
226 if (buf_w<20) PutNib(wahl+1,buf_w++,c);
227 }
228
229 extern char GetNib(const byte*z,byte idx);
230
231 // Puffer lesen, nicht aufrufen wenn leer!
232 // Aufruf mit freigegeben Interrupts (aus Hauptschleife) OK
233 static char GetBuf() {
234 return GetNib(wahl+1,buf_r++);
235 }
236
237 extern byte x10(byte);
238
239 /******************
240 * EEPROM-Zugriff *
241 ******************/
242 // Um im EEPROM möglichst viele Kurzwahlen unterbringen zu können,
243 // werden die Ziffern nibbleweise gespeichert, das verdoppelt die Kapazität,
244 // erschwert aber die Verarbeitung. Sie sind als Klartext im Hexdump erkennbar.
245 // Die Kurzwahlen liegen allesamt an festen Adressen.
246
247 //Belegung des EEPROM: Index Kurzwahl
248 //x00 10 Letzte Nummer 0 5³
249 //x0A 10 K1 1 1¹
250 //x14 10 K2 2 2¹
251 //x1E 10 K3 3 3¹
252 //x28 10 K4 4 4¹
253 //x32 10 K5 5 5¹
254 //x3C 10 K6 6 6¹
255 //x46 10 K7 7 7¹
256 //x50 10 K8 8 8¹
257 //x5A 10 K9 9 9¹
258 //x64 10 K0 10 0¹
259 //x6E 10 M1 11 1²
260 //x78 10 M2 12 2²
261 //x82 10 M3 13 3²
262 //x8C 10 M4 14 4²
263 //x96 10 M5 15 5²
264 //xA0 10 M6 16 6²
265 //xAA 10 M7 17 7²
266 //xB4 10 M8 18 8²
267 //xBE 10 A 19 1³
268 //xC8 10 B 20 2³
269 //xD2 10 C 21 3³
270 //xDC 10 D 22 4³
271 //xE6 10 Vorwahl 23
272 //xF0 10 Autowahl 24
273 //xFA 2 frei
274 //xFC 1 Anzahl entgangener Anrufe (= <anrufe>)
275 //xFD 1 Abhebezähler
276 //xFE 1 Watchdog-Timeout-Reset-Zähler (= kein CLIP oder Fehler)
277 //xFF 1 Sonstige-Reset-Zähler (Stromausfälle, Steckzyklen oder Bugs)
278 //Debug-Daten, nur ATtiny85
279 //x100 64 CLIP-Daten wie empfangen + summierte Prüfsumme (muss 0 sein)
280 // 0x80, gLen, { 1, 8, Datum+Uhrzeit },
281 // { 2, nLen, Nummer },// Nummer des Anrufers
282 // { 4, 1, [OP] }, // Grund für das Fehlen der Nummer
283 // { 7, tLen, Text }, // Name vom Fritzbox-Telefonbuch
284 // { 8, 1, O }, checksum
285 //x140 30 Histogramm der Nulldurchgangszeiten, sollte 2 Höcker aufweisen
286 //x15E 1 1 (Start) + 1 (1010-Phase) + 1 (1111-Phase) + Empfangene Bytes
287 //x15F 1 Mittelwert der Nulldurchgangs-Zeiten während 1010-Phase,
288 // sollte mit der Delle zwischen den Höckern zusammenfallen
289 //x160 128 lea = Liste entgangener Anrufe
290
291 static inline void eewait() {
292 while (EECR&2);
293 }
294 #define eeread() (EECR|=1,EEDR)
295 //static inline byte eeread() {
296 // EECR|=1;
297 // return EEDR;
298 //}
299 static inline void eewrite() {
300 cli();
301 EECR|=4;
302 EECR|=2;
303 sei();
304 }
305 void eechange(byte b) {
306 byte k=eeread();
307 if (k==b) return;
308 if (b==0xFF) EECR|=0x10; // erase only
309 else if (k==0xFF) EECR|=0x20; // write only
310 EEDR=b;
311 eewrite();
312 eewait();
313 EECR=0;
314 }
315
316
317 // Speichern der Nummer ab EEARL im kopflosen Format (FF-terminiert)
318 static void numSave(byte*z) {
319 byte i=*z++;
320 // 1. Ziffernpuffer in ganzer Länge mit 0x0F auffüllen,
321 // mit dem Sonderfall '#' am Ende, dann 0x0D als 'falsches' Ende
322 if (i && i!=20 && GetNib(z,i-1)==0x0F) PutNib(z,i++,0x0D);
323 while (i!=20) PutNib(z,i++,0x0F);
324 // 2. Komplette Nummer speichern (nur Änderungen)
325 for (i=0;i<10;i++) {
326 eechange(z[i]);
327 EEARL++;
328 }
329 }
330
331
332 // <max> muss gerade sein!
333 static void numLoad(byte*z,byte max=20) {
334 z++;
335 // 1. Nibbles vom EEPROM laden
336 byte i;
337 for (i=0;i<max>>1;i++) {
338 z[i]=eeread();
339 EEARL++;
340 }
341 // 2. tatsächliche Rufnummern-Länge ermitteln
342 for (i=max;i;) {
343 char c=GetNib(z,--i);
344 if (c!=0x0F) {
345 if (c==0x0D && i && GetNib(z,i-1)==0x0F) --i;
346 i++;
347 break;
348 }
349 }
350 *--z=i; // 0..max möglich
351 }
352
353 /****************************
354 * Rückruf-Liste bearbeiten *
355 ****************************/
356 // Organisation der Rückruf-Liste:
357 // Nahtlose Aneinanderreihung entgangener und noch nicht "abgearbeiteter" Anrufe
358 // 1 Byte Länge (5 Bit) + Grund der Null-Länge (2 Bit):
359 // 0x00 = kein oder fehlerhaft empfangenes CLIP
360 // 0x20 = Grund 'O' = keine Durchleitung (bspw. vom Ausland)
361 // 0x40 = Grund 'P' = unterdrückt vom Anrufer
362 // 0x60 = sonstiger Grund
363 // Darauf folgen <Länge> Hex-Nibbles Rufnummer.
364 // Die gespeicherte Ortsvorwahl wird bei Gleichheit abgeschnitten.
365 // Bei ungerader Länge folgt ein ungenutztes Nibble (0) zur Byteausrichtung
366 // Bei drohendem Pufferüberlauf wird nicht mehr gespeichert.
367 // Der Puffer reicht für durchschnittlich 25 Anrufe.
368 static byte lea[128] NOINIT; // Liste entgangener Anrufe
369 static byte ovw[5] NOINIT; // Ortsvorwahl (max. 8-stellig, 1. Byte = Länge)
370
371 static byte ealen(byte l) { // Längen-Byte in Byte-Länge der Nummer inkl. Längenbyte
372 return ((l&0x1F)+1>>1)+1;
373 }
374
375 static byte*eaindex(byte i) { // Zum gegebenen Index „vorspulen“
376 byte*z=lea;
377 if (i) do z+=ealen(*z); while(--i);
378 return z;
379 }
380
381 extern byte CompareN(const byte*,const byte*);
382 extern byte KillVorwahl(byte*,const byte*);
383
384 // Ryckruf statt Rückruf um mit avr-gcc 5.3 compilierbar zu bleiben
385 static byte IstRyckruf(const byte*z) { // liefert buf_w wenn die aktuelle Nummer
386 return CompareN(z,wahl) ? 0 : buf_w;
387 }
388
389 // <clipbuf> zeigt auf 2 (Nummer des Anrufenden) oder 4 (Grund für das Fehlen)
390 // <z> zeigt in <lea>
391 static void ClipToLea(byte*z,const byte*clipbuf) {
392 byte type=*clipbuf++;
393 byte len=*clipbuf++;
394 if (z+ealen(len)>lea+sizeof lea) return; // Überlauf (in den Stack) verhindern
395 byte i,j=0;
396 if (type==2) { // Rückrufnummer vorhanden
397 if (len>20) return; // Fehler
398 for (i=0;i<len;i++) {
399 byte c=*clipbuf++;
400 if ('0'<=c && c<='9') c-='0';
401 else if ('A'<=c && c<='D') c-='A'-10;
402 else if (c=='*') c=14;
403 else if (c=='#') c=15;
404 else continue;
405 PutNib(z+1,j++,c);
406 }
407 *z=j;
408 // Testen ob die Rufnummer mit Ortsvorwahl beginnt, und Ortsvorwahl wegnehmen
409 KillVorwahl(z,ovw);
410 }else{ // keine Rückrufnummer
411 if (len!=1) return; // Fehler
412 byte reason=*clipbuf;
413 switch (reason) {
414 case 'O': j|=0x20; // “unavailable”
415 case 'P': j|=0x40; // “private”
416 default: j|=0x60; // unknown reason
417 }
418 *z=j;
419 }
420 }
421
422 static void DelRyckruf() {
423 byte *x=lea,*z=x,a=anrufe;
424 if (a) do{
425 byte l=ealen(*z);
426 if (IstRyckruf(z)) {
427 z+=l; // Quellzeiger vorrücken = Nummer löschen
428 --anrufe;
429 }else do *x++=*z++; while(--l); // Bytes vorrücken
430 }while(--a);
431 }
432
433 // liefert Nummer der Kurzwahl (1..24), 0 für keinen Treffer
434 static byte FindInKurzwahl(const byte*z) {
435 byte idx;
436 for (idx=24;idx;--idx) {
437 EEARL=x10(idx);
438 numLoad(wahl);
439 if (!CompareN(z,wahl)) break;
440 }
441 buf_w=0;
442 return idx;
443 }
444
445 /****************************
446 * Kurzwahl laden/speichern *
447 ****************************/
448
449 // 10 Bytes Puffer pro Nummer (20 Ziffern)
450 // idx zwischen 0 (letzte Nummer) und 24 (Autowahl)
451 static void KurzSpeichern(byte idx) {
452 EEARL=x10(idx); // × 10
453 numSave(wahl);
454 if (idx==23) memcpy(ovw,wahl,5);
455 }
456
457 static void KurzLaden(byte idx) {
458 EEARL=x10(idx); // × 10
459 numLoad(wahl); // 0..20 Ziffern
460 DelRyckruf();
461 buf_r=0; // mit dem Abspielen beginnen
462 }
463
464 /**************************************
465 * Frequenzsynthese = Sinustonausgabe *
466 **************************************/
467 constexpr char LOG2(unsigned v) {return 15-__builtin_clz(v);}
468 // CLOG2 = Clock Logarithmus zur Basis 2
469 constexpr char CLOG2 = LOG2(F_CPU/1000000);
470 // 0 wenn F_CPU = 1..1,99 MHz
471 // 1 wenn F_CPU = 2..3,99 MHz
472 // 2 wenn F_CPU = 4..7,99 MHz (Standard)
473 // 3 wenn F_CPU = 8..15,99 MHz
474 // Bei (fest) 32 kHz Abtastrate (Syntheserate) muss die Resonatorfrequenz
475 // >=2 MHz sein, damit die ISR schnell genug abgearbeitet wird.
476
477 extern void clock_set(byte div);
478
479 static void clock_max() {clock_set(0);}
480 static void clock_1MHz() {clock_set(CLOG2);} // Taktfrequenz 1..1,99 MHz
481 static void clock_16us() {clock_set(CLOG2+4);}
482
483 constexpr byte WDT_SEC(float s) {return s/0.016;}
484
485 // ADC-Taktteiler während onhook() - je schneller desto besser
486 constexpr char ALOG2 = LOG2(1000/500); // 1 = ÷2 → 500 kHz → 38 kSa/s
487 // ADC-Taktteiler während offhook() - Strom ist genug da
488 constexpr char BLOG2 = LOG2(1000/125); // 3 = ÷8 → 125 kHz → 9,6 kSa/s
489
490 static void tonEin() {
491 ADCSRA = 0xA0|BLOG2+CLOG2; // ADC-Takt anpassen
492 clock_max();
493 PLLCSR|= 0x82; // Low-Speed-Modus: 32 MHz (reicht)
494 _delay_us(100);
495 while (!(PLLCSR&1));
496 PLLCSR|= 0x04;
497 TCCR1 = 0x61;
498 OCR0A = T0DIV-1; // rund 32 kHz
499 TIMSK = 0x10; // Compare-Interrupt
500 TCCR0A = 0x02; // Timer0: CTC
501 TCCR0B = 0x01; // Timer0 mit Vorteiler 1 starten
502 T_on=WDT_SEC(TON+PAUSE);// Länge setzen
503 DDRB |= 0x02; // Ausgang aktivieren
504 }
505
506 static void tonAus() {
507 TIMSK = 0; // Timer0: Kein Interrupt
508 TCCR0A = 0; // kein PWM
509 TCCR0B = 0; // aus
510 DDRB &=~0x02; // Ausgang hochohmig
511 TCCR1 = 0; // Timer1 aus
512 PLLCSR = 0; // PLL aus
513 clock_1MHz();
514 ADCSRA = 0xA0|BLOG2; // ADC-Takt anpassen
515 }
516
517 // Startet Wählton für Ziffer z ("*"=14, "#"=15)
518 static void StartDTMF(char z) {
519 if (MCUCR&0x10) return; // niemals im aufgelegten Zustand
520 if (!(Flags&0x40)) {
521 Flags|=0x40;
522 if (anrufe) --anrufe; // Anrufliste abbauen
523 }
524 static PROGMEM const byte Nr2HiLo[16]={
525 // 0 1 2 3 4 5 6 7 8 9 A B C D * #
526 0x53,0x40,0x50,0x60,0x41,0x51,0x61,0x42,0x52,0x62,0x70,0x71,0x72,0x73,0x43,0x63};
527 // High-Nibble 4 5 6 7
528 // Low-Nibble ┌───────────
529 // 0 │ 1 2 3 A
530 // 1 │ 4 5 6 B
531 // 2 │ 7 8 9 C
532 // 3 │ * 0 # D
533 byte i=pgm_read_byte(Nr2HiLo+z); // umrechnen in die 2 Frequenzen
534 addA=pgm_read_word(Frequencies+(i>>4)); // hoher Ton im High-Nibble
535 addB=pgm_read_word(Frequencies+(i&15)); // tiefer Ton im Low-Nibble
536 tonEin();
537 }
538
539 // Startet Hinweiston, z=0 für c³
540 static void StartTon(char z) {
541 if (MCUCR&0x10) return; // niemals im aufgelegten Zustand
542 char okt=0; // Oktave
543 for (;z<0;z+=12) --okt; // Mit div_t ist's umständlicher
544 for (;z>=12;z-=12) ++okt; // jetzt 0<=z<12
545 word a=pgm_read_word(Frequencies+8+z);
546 for (;okt<0;++okt) a>>=1;
547 for (;okt;--okt) a<<=1;
548 addB=addA=a;
549 phaB=phaA; // addieren lassen
550 tonEin();
551 }
552
553 // Kernroutine der Frequenzsynthese
554 // Aufruf mit F_CPU/256 oder F_CPU/128, 20..40 kHz, reicht für HiFi-Ton
555 // Mit F_CPU/64 kommt der Controller nicht mehr hinterher,
556 // obwohl noch Rechenleistung frei sein müsste.
557 ISR(TIM0_COMPA_vect) {
558 // Tonlänge nominell 70 ms, Pause 30 ms
559 // T_on>=0 = Tonausgabe, sonst Pause
560 // if (T_on>=(byte)WDT_SEC(PAUSE)) {
561 #ifdef DDS_REG
562 asm(
563 " add r10,r8 \n"
564 " adc r11,r9 \n"
565 " add r14,r12 \n"
566 " adc r15,r13 \n"
567 " push ZH \n"
568 " push ZL \n"
569 " ldi ZH,hi8(SinTab)\n"
570 " mov ZL,r11 \n"
571 " lpm \n"
572 " mov ZL,r15 \n"
573 " lpm r1,z \n"
574 " pop ZL \n"
575 " pop ZH \n"
576 " add r0,r1 \n"
577 " lsr r1 \n" // (kompensiert Kabeldämpfung für höhere Frequenzen)
578 " lsr r1 \n"
579 " sbc r0,r1 \n" // "sbc" ist der Trick fürs Abrunden
580 " out %0,r0 \n"
581 ::"I" (_SFR_IO_ADDR(OCR1A))); // Undokumentiert: Leeres Constraint = Pointer
582 #else
583 byte a=pgm_read_byte(SinTab.a+((phaA+=addA)>>8));
584 byte b=pgm_read_byte(SinTab.a+((phaB+=addB)>>8));
585 OCR1A=a+b-(b>>2); // hier ohne Runden
586 #endif
587 }
588
589 /***********************************
590 * Nummernschaltkontakt-Auswertung *
591 ***********************************/
592 // Abarbeitung nach dem LIFO-Prinzip
593 static void Ryckruf() {
594 byte *z;
595 for (byte l,i=anrufe;;) {
596 if (!i) {
597 if (!(DDRB&2)) StartTon(-6);
598 return; // Nichts (mehr) rückzurufen
599 }
600 z=eaindex(--i); // Zum letzten Rückruf vorspulen
601 l=*z&0x1F;
602 if (l) break;
603 *z=0; // Unmögliche Rückrufe von hinten allesamt löschen
604 --anrufe;
605 if (!(DDRB&2)) StartTon(-12); // Rückruf (der letzten Anrufe) nicht möglich
606 }
607 memcpy(wahl,z,11);
608 DelRyckruf();
609 KurzSpeichern(0);
610 buf_r=0; // mit dem Abspielen beginnen
611 }
612
613 static void clearBuf() {
614 buf_r=buf_w=0;
615 }
616
617 static void ledOn() {
618 if (PB5DEBUG) return; // Nicht im Debugmodus
619 if (DDRB&0x20) return; // Nicht wenn bereits an oder aus
620 if (!(PINB&0x20)) return; // Nicht wenn Erdtaste gedrückt
621 PORTB&=~0x20;
622 DDRB |= 0x20;
623 Flags|= 0x20; // merken
624 }
625
626 static void ledOff() {
627 if (!(Flags&0x20)) return; // nicht eingeschaltet
628 DDRB &=~0x20;
629 PORTB|= 0x20; // Pullup restaurieren
630 Flags&=~0x20; // zurücknehmen
631 }
632
633 // Konvertiert Impulszahl nach Ziffer; hier: 10 Pulse = 10, nicht 0
634 // Hier muss <i> für schwedische oder neuseeländische Telefone angepasst werden
635 static byte nsi_transcode(byte i) {
636 // Schweden: Anordnung 0-1-2-3-4-5-6-7-8-9 (Quelle: Wikipedia)
637 // if (!--i) i = 10;
638 // Neuseeland: Anordnung 0-9-8-7-6-5-4-3-2-1
639 // i = 11-i;
640 return i;
641 }
642
643 // Nummernschaltkontakt an PB0 sowie Erdtaste an PB5 auswerten.
644 // Die Historie dieser beiden Bits befindet sich in Schieberegistern.
645 // Aufruf alle 16 ms per Watchdog-Interrupt aus onhook- oder offhook-Schleife.
646 static void NSK() {
647 Flags&=~0x80; // Watchdog-Interrupt quittieren
648 byte nsi=NSI; // Lokales nsi
649 // Entprellfunktion: Mindestens 32 ms Hi
650 if ((pb0&7)==0b100) { // nsi oder nsa öffnet [typ. 62 ms]
651 ++nsi; // Lo-Hi-Flanken zählen
652 GIFR=0x20; // Erkannte Pegelwechsel quittieren
653 rend=0; // Offhook-Wähl-Timeout setzen
654 Zeit8=WDT_SEC(0.2); // zur Feststellung ob nsa oder nsi
655 }else if (nsi && (pb0&3)==0b01) { // nsi schließt (kein extra Entprellen) [typ. 38 ms]
656 Zeit8=0; // Kein Timeout wenn Lo nach 1. nsi
657 }else if (!nsi && (pb0&15)==0b0111) { // nsa schließt: Mindestens 48 ms Lo
658 if (Flags&0x10) { // Erdtaste solo gedrückt?
659 Flags&=~0x10; // Solofunktion zurücknehmen
660 Flags|= 1; // Ebene 3 ansteuern
661 Flags|= 2;
662 }else{
663 Flags&=~1; // Ebene 0 ansteuern
664 Flags&=~2; // Etappenzähler für „nsa halten“ rücksetzen
665 }
666 Zeit8=WDT_SEC(1.5);
667 }else{ // keine Flanke
668 if (Zeit8 && !--Zeit8) { // Timeout
669 if (nsi) { // Nummernscheibe abgelaufen (nur bei Hi-Pegel)
670 if (!(GIFR&0x20) // Kein < 16 ms kurzes letzes („übersehenes“) Low?
671 && !--nsi) { // Letzte Lo-Hi-Flanke durch nsa-Kontakt abziehen
672 StartTon(-2); // Fehler: Nur 1 langes Low detektiert: Wählscheibe weniger als 30° aufgezogen = Fehlbedienung
673 goto raus; // Oder soll man das als Sonderfunktion interpretieren?
674 }
675 if (nsi>10) { // Zu viele Impulse?
676 StartTon(-3); // Fehler: Mehr als 10 Impulse, Sonderwählscheibe?
677 goto raus;
678 }
679 nsi=nsi_transcode(nsi);
680 // Eigentliche Aktion
681 if (Flags&8 && !(Flags&1) && !(Flags&2)) goto putbuf0;
682 if (Flags&8 || Flags&4) { // nsi = Ziffer zum Kurzwahl-Speichern
683 if (Flags&2) {
684 if (Flags&1) { // n³
685 if (nsi<5) nsi+=18; // 19..22 = Speicherplätze A-D
686 else {nsi+=5; goto putbuf1;} // 10..15 = Möglichkeit des Abspeicherns von A,B,C,D,* und #
687 }else{ // n²
688 nsi+=10; // 11..18
689 if (nsi>18) nsi+=4; // 23..24 (Ortsvorwahl, Autowahl)
690 }
691 }
692 KurzSpeichern(nsi);
693 StartTon(5);
694 Flags&=~0x0F;
695 goto raus; // nicht wählen
696 }else if (Flags&2) {
697 if (Flags&1) switch (nsi) {// n³ = ganz lange halten am Fingeranschlag
698 case 5: KurzLaden(0); goto raus; // Wahlwiederholung
699 case 6: Ryckruf(); goto raus;
700 case 7: Flags|=4; StartTon(5); goto raus; // Letzte Nummer speichern: Kurzwahlspeicherplatz-Ziffer folgt
701 case 8: Flags|=8; clearBuf(); StartTon(0); goto raus; // Nummer einspeichern: Nummer + Kurzwahlspeicherplatz-Ziffer folgen
702 case 9: clearBuf(); KurzSpeichern(0); goto raus; // Wahlwiederholung verhindern
703 case 10: anrufe=0; goto raus;
704 default: KurzLaden(18+nsi); goto raus; // 19..22 (A,B,C,D) wählen
705 }else switch (nsi) { // n²
706 case 9:
707 case 10: nsi+=14-9; break; // '*' oder '#'
708 default: KurzLaden(10+nsi); goto raus;
709 }
710 }else if (Flags&1) { // n¹
711 KurzLaden(nsi); // wählen lassen (1..10), Hauptschleife generiert Töne
712 goto raus;
713 }else
714 putbuf0: if (nsi==10) nsi=0;
715 putbuf1: PutBuf(nsi); // Zählergebnis abspeichern (Hauptschleife generiert Ton anschließend)
716 if (Flags&8) {
717 buf_r=buf_w; // Nicht wählen (Hauptschleife nicht in Aktion treten lassen)
718 StartTon(4);
719 }else Zeit16=WDT_SEC(2); // Wahlwiederholungs-Abspeicher-TimeOut setzen (4 Sekunden)
720 raus:
721 nsi=0;
722 }else if (pb0&1) { // Vor nsi-Impulsen (Lo-Pegel)
723 if (!(Flags&1 && Flags&2)) ++Flags; // Zu lange gehalten: ignorieren, weiterpiepen
724 StartTon(1+(Flags&3)); // Töne d-dis-e
725 ledOn(); // Bei jedem Timeout mitblitzen
726 Zeit8=WDT_SEC(1);
727 }
728 }
729 }
730 NSI=nsi;
731 // Entprellfunktion: Mindestens 4 × 16 ms = 64 ms Lo)
732 if (!T_on && (pb5&31)==0b01111) { // Erdtaste gedrückt
733 if (!pb0) Flags|=0x10; // Solo: Vermerken (n³ ansteuern lassen)
734 else if (pb0==255) Flags|=1; // Beim Festhalten des Nummernschalters: n¹
735 else Flags|=2; // Während Ablauf des Nummernschalters: n²
736 // Entprellfunktion: Mindestens 4 × 16 ms = 64 ms Hi)
737 }else if (!(pb5&15) && Flags&0x10) { // Nummernschalter nicht zwischendurch betätigt?
738 Flags&=~0x10; // Flag löschen
739 if (anrufe) Ryckruf(); // Solo-Aktion = Rückruf oder Wahlwiederholung
740 else KurzLaden(0);
741 }
742 EEARL=252;
743 eechange(anrufe); // im EEPROM nachführen, falls geändert (auch im aufgelegten Zustand)
744 }
745
746 // Bei Ablauf des Watchdog-Timers (meist 16 ms) wird die CPU geweckt
747 // und das Bit 7 im Flag-Register (GPIOR0) gesetzt.
748 ISR(WDT_vect,ISR_NAKED) {
749 Flags|=0x80;
750 reti();
751 }
752
753 static void readPb2(byte adc1value) {
754 constexpr byte offhooklevel=0xC0; // High bei 75 %
755 pb2 = pb2<<1 | (adc1value>=offhooklevel); // High bei 75 %
756 }
757
758 static void readPins() {
759 byte npinb = ~PINB; // invertiert
760 pb0 = pb0<<1 | npinb&1;
761 #if PB5DEBUG
762 if (DDRB&0x20) return; // Wenn Ausgang dann Erdtaste NICHT einlesen
763 pb5 = pb5<<1 | npinb>>5&1;
764 #else
765 if (Flags&0x20) { // Wenn LED ein
766 DDRB &=~0x20; // LED aus, auf Eingang schalten
767 PORTB|= 0x20; // Pullup aktivieren
768 _delay_us(100); // etwas warten (Entladelast onhook selten, vertretbar)
769 }
770 pb5 = pb5<<1 | npinb>>5&1; // Erdtaste einlesen
771 if (Flags&0x20) {
772 PORTB&=~0x20; // Pullup aus
773 DDRB |= 0x20; // LED ein
774 }
775 #endif
776 }
777
778 // Da einige Zeit vergangen ist, seit die Pullups aktiviert wurden,
779 // wird zunächst PINB eingelesen und der Analogwert an PB2 ausgewertet.
780 // Dann wird in Schritten von 48 µs (max. 12 ms)
781 // oder per Watchdog fest 16 ms gewartet.
782 // Die kürzere Zeit wird für die Klingel-Detektion
783 // = Wechselspannung 25 oder 50 Hz an PB2 benötigt; Flanken alle 20 oder 10 ms.
784 // In beiden Fällen mit abgeschaltetem A/D-Wandler und minimalem Stromverbrauch:
785 // Bei us48!=0 durch Heruntersetzen des Oszillatortakts und einer Busy-Loop
786 // bei us48==0 durch maximale(!) Oszillatorfrequenz und kürzester Hochlaufzeit.
787 // Heraus kommt die Funktion mit 1 MHz CPU-Takt, aktivierten Pullups
788 // und mit gestartetem A/D-Wandler, immer an PB2,
789 // sowie ausgewertetem Nummernschalter.
790 static void waitforwatchdog(byte us48=0) {
791 while (!(ADCSRA&0x10));// warten auf Ende, kann bis zu 50 µs dauern
792 readPb2(ADCH);
793 readPins(); // einlesen, nachdem sich alle Pegel eingeschwungen haben
794 ADCSRA= 0; // ADC abschalten — sonst gibt's zusätzlichen Stromverbrauch.
795 if (!(DDRB&0x20)) PORTB&=~0x20; // Gedrückte Erdtaste soll Elko nicht entladen
796 PORTB&=~0x01; // Aufgezogene Wählscheibe soll Elko nicht entladen
797 PORTB&=~0x04; // kein Pullup: Versorgungsstrom 120 µA fließt über die negative Gateschutzdiode
798 DDRB |= 0x04; // Floating-Eingang auf Low festnageln, um Gateschutzdiode zu schonen
799 if (us48) {
800 clock_16us(); // Taktvorteiler erhöhen für minimalen Stromverbrauch
801 _delay_loop_1(us48); // jede Runde dieses Delays benötigt 3×16µs
802 DDRB &=~0x04; // Pullup für A/D-Wandler früh vorbereiten
803 PORTB|= 0x04;
804 }else{
805 clock_max(); // kürzestmögliche Hochlaufzeit spart am meisten Strom (!)
806 sleep_cpu(); // Oszillator aus bis zum nächsten Watchdog-Interrupt
807 DDRB &=~0x04; // dann umgehend Pin 7 zur Messung vorbereiten
808 PORTB|= 0x04;
809 clock_16us(); // 16 µs pro Takt, gaanz langsam (4 × 16 µs), etwas warten
810 }
811 // Die Unterprogrammaufrufe genügen zur Verzögerung.
812 // Warten mit dem A/D-Konverter, bis sich der Pegel an Pin 7 stabilisiert hat.
813 // Der Kondensator am Pin 7 (wenn bestückt) wirkt als Tiefpass.
814 clock_1MHz(); // (10 × 16 µs)
815 PORTB|= 0x01; // Restliche Pullups (in umgekehrter Reihenfolge) aktivieren
816 if (!(DDRB&0x20)) PORTB|= 0x20; // bei aktivem DDRB ist's die LED oder der Debug-Ausgang: Unbeeinflusst lassen
817 ADCSRA= 0xD0|ALOG2; // Start mit Teiler 2: 500 kHz, 2µs, ×25 = 50 µs, einmalig, ohne Interrupt
818 if (Flags&0x80) {
819 ledOff(); // LED hat nun 16 ms geleuchtet: Aus!
820 NSK(); // (d: Irrtümliche Wählimpulse durch Klingeln werden später gekillt)
821 }
822 }
823
824 /********************
825 * CLIP-Dekodierung *
826 ********************/
827
828 // Der Interrupt dient nur zum Aufwecken; Interrupts werden/bleiben gesperrt.
829 // Dieser wird nur für die CLIP-Detektion benötigt, das ist Energie sparender
830 // als die Auswertung von ADCSRA.ADIF, denn während der CLIP-Erkennung
831 // steht nur die Ladung im Elko als Energiequelle zur Verfügung.
832 ISR(ADC_vect,ISR_NAKED) {
833 asm volatile("ret");
834 }
835 ISR(ANA_COMP_vect,ISR_NAKED) {
836 asm volatile("ret");
837 }
838
839 static byte clip[64] NOINIT; // letztes Byte = Prüfsumme
840 // CLIP-Dekodierung verlangt vom Mikrocontroller alles ab, daher ist's
841 // in Assembler (extern) geschrieben.
842
843 // Steckt die aktuelle Rufnummer in „lea“ (nicht in EEPROM)
844 static void saveClip(byte*z) {
845 byte i=2,j=clip[1]+2; // j = Endindex der Nachricht
846 if (j>sizeof clip) j=sizeof clip;
847 do{
848 if (clip[i]==2 || clip[i]==4) {
849 ClipToLea(z,clip+i);
850 return;
851 }else i+=clip[i+1]+2; // Länge des unbekannten Chunks
852 }while(i<j);
853 }
854
855 extern void acInit();
856 extern byte acMean();
857 //Beim ATtiny85 gibt es Debug-Funktionalität: Logging im EEPROM
858 #ifdef __AVR_ATtiny85__
859 static byte histo[32] NOINIT;
860 extern void acHisto(byte data[],byte len);
861 #endif
862 extern void acOnes();
863 extern byte acByte();
864 extern void acDone();
865
866 // mit 1..2 MHz CPU-Takt
867 static void clipRead(byte*z) {
868 // STELLSCHRAUBE, die entscheidend für die nötige Kapazität von C1 ist
869 byte i=34; // 34 trifft am Thomson-Modem den Anfang der Schwingungen.
870 // Laut Standard sind es 250 ms nach dem Klingeln. Daher Minimum = 5.
871 // Laut „102s10.pdf“ sind's 500 ms, und das stimmt auch für's Thomson-Kabelmodem.
872 // Kleinere Zahlen fressen mehr Zeit und mehr Strom für die Detektierung
873 // d: Exakt platziert fällt die 470-µF-Elko-Spannung von 4,3 auf 3,2 V (642 ms)
874 // Das macht 805 µA mittlere Stromaufnahme, immerhin. Im Interruptbetrieb.
875 // Zu frühes Starten des Analogvergleichers frisst mehr Strom
876 // weil Interrupts sehr dicht kommen. Siehe Oszillogramm.
877 do{
878 waitforwatchdog(); // je 16 ms, aber das stimmt irgendwie nicht: 34×16 » 500!
879 if (pb2&1) return; // (Zweites Klingeln oder) Abheben
880 }while (--i); // weitere ms energiesparend warten
881 #ifdef __AVR_ATtiny85__
882 memset(histo,0,sizeof histo);
883 # if 0
884 memset(clip,0xFF,sizeof clip); // memset mit Füllbyte!=0 wird nicht wegoptimiert
885 # else
886 asm(
887 " mov r0,%1 \n"
888 " com r1 \n"
889 "0: st %a0+,r1 \n"
890 " dec r0 \n"
891 " brne 0b \n"
892 " com r1 \n"
893 ::"e"(clip),"r"(sizeof clip));
894 # endif
895 #endif
896 cli();
897 wdt_reset();
898 // STELLSCHRAUBE, die entscheidend für die nötige Kapazität von C1 ist
899 WDTCR = 0x0E; // Watchdog mit Reset, 1 s (war am ATmega85 erforderlich)
900 acInit();
901 #ifdef __AVR_ATtiny85__
902 histo[30]=1;
903 histo[31]=acMean(); // 256 valide Nulldurchgänge detektieren, Mittelwert liefern
904 acHisto(histo,30); // 256 Nulldurchgänge messen und im Histogramm verteilen
905 histo[30]=2;
906 #else
907 acMean();
908 #endif
909 acOnes(); // Folge von 100 tieffrequenten Nulldurchgängen finden
910 #ifdef __AVR_ATtiny85__
911 histo[30]=3;
912 #endif
913 wdt_reset(); // nach 100 langen Nulldurchgängen
914 byte sum=0;
915 for (i=0;; i++) {
916 byte c=acByte(); // Das erste Byte wird nicht auf 0x80 geprüft
917 #ifdef __AVR_ATtiny85__
918 histo[30]++;
919 #endif
920 sum+=c;
921 if (i<sizeof clip-1) clip[i]=c;
922 if (i && i==clip[1]+2) break; // Gesamtnachrichtenlänge erreicht
923 }
924 #ifdef __AVR_ATtiny85__
925 if (i<sizeof clip-1) clip[i]=sum;
926 #endif
927 acDone();
928 WDTCR = 0x1E;
929 WDTCR = 0xC0; // Watchdog normal (gemessen 16,4 ms)
930 MCUCR = 0xB4;
931 MCUCR = 0xB0; // Sleep-Modus: PowerDown, kein BrownOut
932 sei();
933 if (!sum) saveClip(z); // Nur bei korrekter Prüfsumme akzeptieren
934 }
935
936 /************************************
937 * Routinen für aufgelegten Zustand *
938 ************************************/
939 // Handelt es sich beim Pegel an PB2 um Gleichspannung
940 // (permanent High oder auch Low) oder Klingelwechselspannung 25 Hz?
941 // Routine kehrt erst nach Ende des Klingelns zurück.
942 // Liefert Anzahl detektierter Schwingungen.
943 static byte wait_ringend() {
944 byte i=0,j=0; // geht mit PB2 = High in die Routine, d.h. pb2&1 ist nach waitforwatchdog() = 1
945 for(;;){
946 waitforwatchdog(100); // 5 ms
947 if ((pb2&3)==0b01) { // (Erneuter) Lo-Hi-Wechsel
948 ++j; i=0; // Diese Flanken zählen
949 }else if ((pb2&3)==0b10) { // Hi-Lo-Wechsel
950 i=0; // sollte der Compiler wegoptimieren
951 }else{ // gleich geblieben
952 if (++i==10) break; // 16 ms × 10 = 160 ms ist ungefähr die Zeit, die das Kabelmodem braucht, um das Freizeichen aufzuschalten
953 }
954 }
955 return j;
956 }
957
958 static void onhook() {
959 MCUCR = 0xB4;
960 MCUCR = 0xB0; // Sleep-Modus: PowerDown, kein BrownOut
961 ADMUX = 0x21; // ADLAR, ADC1 = PB2
962 ADCSRA= 0xD0|ALOG2; // einmalig (wird in waitforwatchdog erneut gestartet)
963 clearBuf(); // Rufnummer tilgen
964 for(;;){ // warte bis 75% Spannung an PB2 == ADC1
965 waitforwatchdog(); // wertet Wählscheibe und Erdtaste aus
966 if (pb2&1) { // Spannung >= 75%: Wechsel- oder Gleichspannung?
967 // Das Ansteigen der Spannung am PB2 kann 3 Gründe haben:
968 // * Klingeln, * Hörer abheben, * Paralleles Telefon nimmt Hörer ab
969 // 16 ms und 75% sind zur Klingeldetektion möglicherweise knapp!
970 // In der Konstellation mit PB1 an 'a'-Ader statt am Mikrofon ist es besser,
971 // dort (via Pullup und kapazitiver Kopplung) Pegelwechsel zu detektieren.
972 /*byte j=*/wait_ringend(); // kehrt erst nach 160 ms Ruhe zurück
973 if (pb2&1) return; // raus wenn statisch >75%: Abgehoben oder Paralleles Telefon
974 // TODO: Zusätzlich sollte beim Abheben das Freizeichen detektiert werden, wenn Flags.6 gesetzt
975 // Es ist hier Sache von offhook(), den Fall „Paralleles Telefon“ zu verarbeiten,
976 // obwohl der Hörer /dieses Telefons/ immer noch auf der Gabel liegt (=onhook).
977 NSI=0; // Durch AC-Kopplung „gewählte“ Nummer tilgen
978 rend=0; // 4 Sekunden nach dem letzten Klingeln sei ein (verpasster) Anruf zu Ende
979 // if (j<4) continue; // Weniger als 4 Pegelwechsel: Störung, kein Klingeln (was soll das sein??)
980 if (!(Flags&0x40)) { // Erstes Klingeln?
981 Flags|=0x40; // bemerken
982 byte*z=eaindex(anrufe);
983 *z=0; // Eintrag „Keine Rufnummer“ — noch nicht
984 EEARL=252;
985 eechange(++anrufe); // Anruf verpasst (5 ms Schreibzeit) - einzige Stelle die inkrementiert!
986 clipRead(z); // CLIP einlesen, KANN FALLWEISE NICHT ZURÜCKKEHREN
987 }
988 // TODO: Lässigere 5 Sekunden passen derzeit nicht in <rend>
989 }else{ // Spannung < 75%: 2 Zähler auswerten und in Schleife bleiben
990 if (!++rend) {
991 Flags&=~0x40; // Klingel-Ende
992 // Sofort mit dem Ablauf des Klingel-Timeouts losblitzen, so sieht man das Timeout
993 // Es kann aber auch sein, dass das Gespräch bei zeitigerem Abheben weg ist
994 if (anrufe) ledOn(); // LED 16 ms aufblitzen lassen, dann 4 s aus
995 buf_w=0; // Timeout für's Wählen bei aufgelegtem Telefonhörer: 256×16ms=4s
996 }
997 }
998 }
999 }
1000
1001 /****************************
1002 * Feststellung Freizeichen *
1003 ****************************/
1004 // Testen (mit dem A/D-Wandler) ob das High an Pin 7 tatsächlich mit einer
1005 // ausreichenden, steigenden Betriebsspannung einhergeht.
1006 // Wenn nicht ist es ein parallel geschaltetes Telefon,
1007 // ein gezogener Stecker oder ein totes Amt;
1008 // dann muss mit gaaanz langer Watchdog-Spanne
1009 // auf das Ende dieses irregulären Zustandes gewartet werden,
1010 // um den Elko möglichst nicht zu entladen.
1011 // Dass währenddessen keine Wahl bei aufgelegtem Telefonhörer unterstützt wird
1012 // ist kaum tragisch und erwartungsgemäß.
1013 // Denn wenn dieser erst mal leer ist, kann der Mikrocontroller nicht mehr
1014 // hochlaufen und bspw. Anrufe zählen.
1015 // Das geht dann nur durch Abnehmen des Telefonhörers.
1016
1017 // Im Prinzip ein Designfehler des Mikrocontrollers: Es gibt keine
1018 // Fuse-Einstellung, mit der der Mikrocontroller ab einer bestimmten Spannung
1019 // loslegt UND mit einer deutlich niedrigeren weiterarbeiten kann (= Hysterese)
1020 // UND wenig Strom dafür braucht; der Brown-Out-Detektor ist zu hungrig.
1021
1022 // Daten etwa:
1023 // Mikrocontroller bei 3 V im PowerDown ohne Watchdog: max. 2 µA
1024 // ... mit Watchdog: max. 10 µA
1025 // ... dazu BrownOut: + 15 µA
1026 // ... arbeitend bei 1 MHz: 500 µA
1027 // Vom 680-kΩ-Widerstand kommen bei 45 V Amtsspannung: 60 µA
1028 constexpr byte DOWNLEVEL=0x40;
1029 // Nachdem der Abfall der Speisespannung bei High an PB2 (vermeintlich abgehoben,
1030 // aber eher parallel geschaltetes Telefon abgehoben, daher keine Durchstromung)
1031 // bemerkt wurde, mit extrem geringer Stromaufnahme in langen Intervallen testen
1032 // und verweilen, bis dieser Zustand beendet und genügend Spannung da ist.
1033 // Andernfalls wird der Mikrocontroller abstürzen und kommt erst durch Abnehmen
1034 // des Telefonhörers = Herstellung des Schleifenstroms wieder hoch.
1035 static void phoneParallel() {
1036 tonAus();
1037 PORTB = 0; // Keine ohmschen Verbraucher: Keine Pullups!
1038 DDRB = 0x05; // Eingänge zu Ausgängen machen und festnageln: Gateschutzdioden entlasten
1039 do{
1040 ADCSRA= 0; // ADC aus
1041 WDTCR = 0xE1; // 8 s (Maximum)
1042 MCUCR = 0xB4;
1043 MCUCR = 0xB0; // Sleep-Modus: PowerDown, kein BrownOut
1044 sleep_cpu(); // bis zum Watchdog
1045 ADCSRA= 0xF4; // Start mit Teiler 16: 16 µs, ×13 = 208 µs
1046 WDTCR = 0xC0; // 16 ms (für den ADC wird offenbar 1 ms benötigt!! Sonst kommt Murks weil Referenzspannung falsch.)
1047 MCUCR = 0x28; // ADC-Störunterdrückung
1048 sleep_cpu(); // bis zum Watchdog
1049 }while (ADCH>=DOWNLEVEL-2); // 0x3E: Hysterese von 2 (gegenüber 0x40)
1050 }
1051
1052 // Anscheinend dauert es lange bis die Referenzspannung steht.
1053 // Daher wird zwischen adPin7 und adRef alle 16 ms hin- und hergeschaltet.
1054 static void handleADC() {
1055 static byte adRef NOINIT;
1056 switch (ADMUX) {
1057 case 0x01: { // maß ADC1 = PB2 bzgl. Speisespannung?
1058 ADMUX |= 0x20;
1059 readPb2(ADCH);
1060 ADMUX = 0x2C; // umschalten auf Referenzspannung 1,1 V
1061 }break;
1062 case 0x2C: { // maß Referenzspannung bzgl. Speisespannung?
1063 byte b = adRef;
1064 byte a = ADCH;
1065 adRef = a;
1066 if (a>=DOWNLEVEL && a>b) {// Ucc < 4,4 V (Uref > Ucc × 25%) und fallend
1067 phoneParallel(); // hinterlässt DDRB.0 gesetzt
1068 }
1069 }/*nobreak*/;
1070 default: ADMUX = 0x01; // umschalten auf ADC1 = PB2
1071 }
1072 }
1073
1074 static byte f425; // Alle 32 ms ein Bit, 8 Bit = 256 ms
1075 extern bool mess425();
1076
1077 static void m425() { // Messung 425 Hz, c: mit ADC oder d: mit AC
1078 if (f425&1) ledOn(); // bei vorherigem Freizeichen
1079 f425=f425<<1|mess425(); // ggf. Abbruch wenn Messung nicht möglich
1080 while (!(Flags&0x80)) sleep_cpu(); // warten bis Watchdog-Interrupt (16 ms)
1081 handleADC();
1082 }
1083
1084 /************************************
1085 * Routinen für abgehobenen Zustand *
1086 ************************************/
1087
1088 // Für die zyklische Ausgabe von Kenntönen für verpasste Anrufe
1089 static byte pause,index NOINIT; // nur offhook verwendet
1090
1091 // Zyklisch aufzurufen: Arbeitet alle <anrufe> ab und generiert Zweiton-Töne
1092 static void piepAnrufe() {
1093 if (Flags&0x40) return; // Anruf wurde entgegen genommen: Nichts tun
1094 if (!anrufe) return; // Keine Anrufe seit letztem Auflegen: Nichts tun
1095 if (NSI) return;
1096 if (Zeit8) return;
1097 if (buf_w) return;
1098 switch (--pause) { // zunächst 256 Aufrufe nichtstun, zwischen den Pieptönen weniger
1099 case (byte)WDT_SEC(0.25): StartTon(0); return;
1100 case 0: break;
1101 default: return;
1102 }
1103 const byte*z=eaindex(index);
1104 byte l=*z;
1105 char f;
1106 if (--l>=19) f=-(1+(++l>>5)); // kein Rückruf möglich
1107 else f=FindInKurzwahl(z); // Rückwärtssuche im „Telefonbuch“
1108 StartTon(f); // CLIP-Eintrag auf diese Weise hörbar machen
1109 if (++index>=anrufe) index=0;
1110 else pause=WDT_SEC(0.5);
1111 }
1112
1113 static void offhook() { // CPU-Taktfrequenz: 1..2 MHz
1114 // Mögliches Problem: Speicheraktionen wenn paralleles Telefon abgehoben entlädt Elko unnötig
1115 // Aber: Anders als durch (u.a. dadurch verursachten) Speisespannungsabfall ist's eh' nicht feststellbar
1116 EEARL = 253;
1117 eechange(eeread()+1); // Abhebe-Zähler
1118 #ifdef __AVR_ATtiny85__
1119 EEARH = 1;
1120 EEARL = 0;
1121 byte i;
1122 for (i=0; i<sizeof clip; i++) {
1123 eechange(clip[i]);
1124 ++EEARL;
1125 }
1126 for (i=0; i<sizeof histo; i++) {
1127 eechange(histo[i]);
1128 ++EEARL;
1129 }
1130 byte j=eaindex(anrufe)-lea;
1131 for (i=0; i<j; i++) {
1132 eechange(lea[i]);
1133 ++EEARL;
1134 }
1135 for (;EEARL;++EEARL) eechange(0xFF); // Rest löschen
1136 EEARH = 0;
1137 #endif
1138 MCUCR = 0x20; // Sleep-Modus: Idle (Timer kann laufen, Strom ist genug da)
1139 ADCSRA= 0xF0|BLOG2; // /8 = 125 kHz / 13 = 9,6 kSa/s
1140 T_on = 0;
1141 byte no_dial=WDT_SEC(1); // besser: auf Freizeichen warten
1142 byte a=anrufe;
1143 byte b=0;
1144 if (Flags&0x40) { // assert(a)
1145 // Beim Abheben während des Klingelns nachgucken, ob CLIP im Rückrufspeicher liegt.
1146 // Wenn ja dann alle Kopien davon aus dieser Liste tilgen.
1147 // Eine möglicherweise (bei aufgelegtem Hörer, vor dem Klingeln)
1148 // bis dahin gewählte Nummer wird überschrieben.
1149 byte*z=eaindex(a-1);
1150 byte l=*z;
1151 if (--l<19) { // 0 < l < 20
1152 buf_r=++l;
1153 memcpy(wahl,z,11); // Für Vergleichsvorgang innerhalb DelRyckruf() in den Wahlspeicher kopieren
1154 DelRyckruf(); // reduziert <anrufe>
1155 b=a-anrufe; // sollte >=1 sein, wenn CLIP erfolgreich
1156 if (b) --b; // Wenn mehr als 1 Anruf von derselben Nummer, dann piepsen, sonst nicht
1157 // Dann weiß man, dass dieser Anrufer bereits vorher versucht hatte anzurufen.
1158 // Den Ton hören beide Partner.
1159 KurzSpeichern(0); // Zur „Wahlwiederholung“ speichern
1160 // (Als Ausnahme von der Regel, dass da nur selbst gewähltes hinein darf.
1161 // Der Grund ist, dass man diese Nummer während oder nach dem Gespräch
1162 // in einen Kurzwahlspeicher mit 7³ legen kann.)
1163 }
1164 }
1165 pause=WDT_SEC(1);
1166 index=0;
1167 for(;;) { // Hauptschleife
1168 m425(); // blockiert bis zum Watchdog-Interrupt
1169 ledOff();
1170 // Sonst funktioniert der Vergleich mit der Referenzspannung nicht!!
1171 if (DDRB&1) { // wenn handleADC() phoneParallel() festgestellt hatte, dann raus hier
1172 DDRB&=~1; // PB0 = Ausgang = Kennung dafür, wegnehmen
1173 break;
1174 }
1175 readPins();
1176 if ((pb2&7)==0b100) break; // Low durch Auflegen
1177 if (T_on) {
1178 if (--T_on==(byte)WDT_SEC(PAUSE)-1) tonAus(); // Tonlänge reduzieren
1179 }
1180 if (no_dial && !--no_dial && !buf_w && !(Flags&0x40) && !anrufe) {
1181 #ifndef DEBUG
1182 KurzLaden(24); // Automatische Wahl beim Abheben
1183 #endif
1184 }
1185 NSK(); // Nummernschaltkontakt-Auswertung
1186 if (Zeit16 && !--Zeit16) KurzSpeichern(0);
1187 piepAnrufe();
1188 if (T_on) continue; // Ton- oder Pausenausgabe läuft
1189 if (no_dial) continue;
1190 if (b) {StartTon(b); b=0;} // Tonhöhe je nach Anzahl der Anrufversuche
1191 else if (buf_r!=buf_w) StartDTMF(GetBuf()); // Nächsten Ton + Pause ausgeben
1192 }
1193 if (T_on>=(byte)WDT_SEC(PAUSE)) tonAus();
1194 }
1195
1196 /*************************************
1197 * Initialisierung und Hauptschleife *
1198 *************************************/
1199 extern "C" void __init() __attribute__((naked,section(".init2")));
1200 extern "C" void __init() {
1201 asm volatile("clr r1");// Stack nicht initialisieren, um gleichermaßen auf ATtiny45 und ATtiny85 lauffähig zu sein
1202 // SPH:SPL ist bereits mit RAMEND initialisiert
1203 Flags = MCUSR&0x08 ? 0x40 : 0; // Reset-Ursache = Watchdog bedeutet: Timeout beim CLIP-Empfang
1204 MCUSR = 0;
1205 WDTCR|= 0x18;
1206 WDTCR = 0xC0; // Watchdog auf Interrupt, 16 ms = 62 Hz (einzige Interruptquelle)
1207 PORTB = 0x25; // Pullup für 3 Eingänge
1208 }
1209
1210 static void hardwareInit() {
1211 eewait();
1212 EEARH = 0; // Auch für ATtiny25/45 so compilieren für Portierbarkeit; EEARH ist nach Reset uninitialisiert
1213 EEARL = Flags&0x40 ? 254 : 255;
1214 eechange(eeread()+1); // Reset- oder Watchdog-Reset-Zähler, macht sei()
1215 EEARL = 252;
1216 byte a=eeread();
1217 if (a>32) a=0;
1218 anrufe= a;
1219 if (!(Flags&0x40)) {
1220 rend=0; // Nach normalem Reset den ersten Blitz verzögern
1221 #ifdef __AVR_ATtiny85__
1222 EEARH = 1;
1223 EEARL = sizeof clip+sizeof histo;
1224 for (byte i=0; i<sizeof lea; i++) {
1225 lea[i]=eeread(); // Luxus ATtiny85: Anrufliste wiederherstellen
1226 ++EEARL;
1227 }
1228 EEARH = 0;
1229 #else
1230 memset(lea,0,a); // Anrufliste besteht aus unbekannten Anrufen
1231 #endif
1232 EEARL = 230; // 23×10: Ortsvorwahl
1233 numLoad(ovw,8);
1234 } // Bei Watchdog-Reset bleibt <rend> und <lea> bestehen
1235 ACSR |= 0x80; // Analogvergleicher ausschalten
1236 DIDR0 = 0b011110; // diese digitalen Eingänge nicht nutzen
1237 PCMSK = 0x01; // Nur PB0 = Wählscheibe überwachen (ohne Interrupt)
1238 }
1239
1240 int main() __attribute__((OS_main));
1241 int main() {
1242 hardwareInit();
1243 for(;;) {
1244 onhook(); // Aufgelegter Hörer: Minimaler Stromverbrauch
1245 offhook(); // Abgehobener Hörer: Normale Funktion
1246 Flags&=~0x40; // Aktiven Anruf beenden
1247 rend=0xFF; // Sofort blitzen
1248 }
1249 }
1250
Detected encoding: UTF-8 | 0
|