-
Notifications
You must be signed in to change notification settings - Fork 0
/
RawSignal.ino
executable file
·406 lines (337 loc) · 19 KB
/
RawSignal.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
#define ESP_PULSE_0 500 // PWM: Tijdsduur van de puls bij verzenden van een '0' in uSec.
#define ESP_PULSE_MID 1000 // PWM: Pulsen langer zijn '1'
#define ESP_PULSE_1 1500 // PWM: Tijdsduur van de puls bij verzenden van een '1' in uSec. (3x ESP_PULSE_0)
#define ESP_SPACE 500 // PWM: Tijdsduur van de space tussen de bitspuls bij verzenden van een '1' in uSec.
/*********************************************************************************************\
* Deze routine zendt een RAW code via RF.
* De inhoud van de buffer RawSignal moet de pulstijden bevatten.
* RawSignal.Number het aantal pulsen*2
\*********************************************************************************************/
void RawSendRF(void)
{
int x;
digitalWrite(PIN_RF_RX_VCC,LOW); // Spanning naar de RF ontvanger uit om interferentie met de zender te voorkomen.
digitalWrite(PIN_RF_TX_VCC,HIGH); // zet de 433Mhz zender aan
delay(TRANSMITTER_STABLE_TIME); // kleine pauze om de zender de tijd te geven om stabiel te worden
// LET OP: In de Arduino versie 1.0.1 zit een bug in de funktie delayMicroSeconds(). Als deze wordt aangeroepen met een nul dan zal er
// een pause optreden van 16 milliseconden. Omdat het laatste element van RawSignal af sluit met een nul (omdat de space van de stopbit
// feitelijk niet bestaat) zal deze bug optreden. Daarom wordt deze op 1 gezet om de bug te omzeilen.
RawSignal.Pulses[RawSignal.Number]=1;
for(byte y=0; y<RawSignal.Repeats; y++) // herhaal verzenden RF code
{
x=1;
noInterrupts();
while(x<RawSignal.Number)
{
digitalWrite(PIN_RF_TX_DATA,HIGH);
delayMicroseconds(RawSignal.Pulses[x++]*RawSignal.Multiply-5); // min een kleine correctie
digitalWrite(PIN_RF_TX_DATA,LOW);
delayMicroseconds(RawSignal.Pulses[x++]*RawSignal.Multiply-7); // min een kleine correctie
}
interrupts();
delay(RawSignal.Delay);// Delay buiten het gebied waar de interrupts zijn uitgeschakeld! Anders werkt deze funktie niet.
}
delay(TRANSMITTER_STABLE_TIME); // kleine pause zodat de ether even schoon blijft na de stopbit
digitalWrite(PIN_RF_TX_VCC,LOW); // zet de 433Mhz zender weer uit
digitalWrite(PIN_RF_RX_VCC,HIGH); // Spanning naar de RF ontvanger weer aan.
}
/*********************************************************************************************\
* Deze routine zendt een RawSignal via IR.
* De inhoud van de buffer RawSignal moet de pulstijden bevatten.
* RawSignal.Number het aantal pulsen*2
* Pulsen worden verzonden op en draaggolf van 38Khz.
*
* LET OP: Deze routine is speciaal geschreven voor de Arduino Mega1280 of Mega2560 met een
* klokfrequentie van 16Mhz.
\*********************************************************************************************/
void RawSendIR(void)
{
int pulse; // pulse (bestaande uit een mark en een space) uit de RawSignal tabel die moet worden verzonden
int mod; // pulsenteller van het 38Khz modulatie signaal
delay(10); // kleine pause zodat verzenden event naar de USB poort gereed is, immers de IRQ's worden tijdelijk uitgezet
// LET OP: In de Arduino versie 1.0.1 zit een bug in de funktie delayMicroSeconds(). Als deze wordt aangeroepen met een nul dan zal er
// een pause optreden van 16 milliseconden. Omdat het laatste element van RawSignal af sluit met een nul (omdat de space van de stopbit
// feitelijk niet bestaat) zal deze bug optreden. Daarom wordt deze op 1 gezet om de bug te omzeilen.
RawSignal.Pulses[RawSignal.Number]=1;
for(int repeat=0; repeat<RawSignal.Repeats; repeat++) // herhaal verzenden IR code
{
pulse=1;
noInterrupts();
while(pulse<(RawSignal.Number))
{
// Mark verzenden. Bereken hoeveel pulsen van 26uSec er nodig zijn die samen de lengte van de mark/space zijn.
mod=(RawSignal.Pulses[pulse++]*RawSignal.Multiply)/26; // delen om aantal pulsen uit te rekenen
while(mod)
{
// Hoog
#if ESP_MEGA
bitWrite(PORTH,0, HIGH);
#else
// todo bitWrite(PORTB,3, HIGH);
#endif
delayMicroseconds(12);
// todo __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");// per nop 62.6 nano sec. @16Mhz
// Laag
#if ESP_MEGA
bitWrite(PORTH,0, LOW);
#else
// todo bitWrite(PORTB,3, LOW);
#endif
delayMicroseconds(12);
// todo __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");// per nop 62.6 nano sec. @16Mhz
mod--;
}
// Laag
delayMicroseconds(RawSignal.Pulses[pulse++]*RawSignal.Multiply);
}
interrupts(); // interupts weer inschakelen.
delay(RawSignal.Delay);// Delay buiten het gebied waar de interrupts zijn uitgeschakeld! Anders werkt deze funktie niet
}
}
/*********************************************************************************************\
* Deze routine berekend de RAW pulsen van een Nodo event en plaatst deze in de buffer RawSignal
* RawSignal.Bits het aantal pulsen*2+startbit*2
\*********************************************************************************************/
// Definieer een datablock die gebruikt wordt voor de gegevens die via de ether verzonden moeten worden.
struct DataBlockStruct
{
byte Version;
byte SourceUnit;
byte DestinationUnit;
byte Flags;
byte Type;
byte Command;
byte Par1;
unsigned long Par2;
byte Checksum;
};
void ESP_2_RawSignal(struct NodoEventStruct *Event)
{
struct DataBlockStruct DataBlock;
byte BitCounter = 1;
RawSignal.Repeats = 1; // 1 pulsenreeks. Nodo signaal heeft geen herhalingen
RawSignal.Delay = 0; // Geen repeats, dus delay tussen herhalingen ook niet relevant
RawSignal.Multiply = 25;
Checksum(Event);
DataBlock.SourceUnit = Event->SourceUnit | (HOME_ESP<<5);
DataBlock.DestinationUnit = Event->DestinationUnit;
DataBlock.Flags = Event->Flags;
DataBlock.Type = Event->Type;
DataBlock.Command = Event->Command;
DataBlock.Par1 = Event->Par1;
DataBlock.Par2 = Event->Par2;
DataBlock.Checksum = Event->Checksum;;
DataBlock.Version = ESP_VERSION_MINOR;
byte *B=(byte*)&DataBlock;
// begin met een lange startbit. Veilige timing gekozen zodat deze niet gemist kan worden
RawSignal.Pulses[BitCounter++]=(ESP_PULSE_1 *2)/RawSignal.Multiply;
RawSignal.Pulses[BitCounter++]=(ESP_SPACE *2)/RawSignal.Multiply;
for(byte x=0;x<sizeof(struct DataBlockStruct);x++)
{
for(byte Bit=0; Bit<=7; Bit++)
{
if((*(B+x)>>Bit)&1)
RawSignal.Pulses[BitCounter++]=ESP_PULSE_1/RawSignal.Multiply;
else
RawSignal.Pulses[BitCounter++]=ESP_PULSE_0/RawSignal.Multiply;
RawSignal.Pulses[BitCounter++]=ESP_SPACE/RawSignal.Multiply;
}
}
RawSignal.Pulses[BitCounter-1]=ESP_SPACE/RawSignal.Multiply; // pauze tussen de pulsreeksen
RawSignal.Number=BitCounter;
}
// De while() loop waar de statemask wordt getest doorloopt een aantal cycles per milliseconde. Dit is afhankelijk
// van de kloksnelheid van de Arduino. Deze routine is in de praktijk geklokt met een processorsnelheid van
// 16Mhz. Naast de doorlijktijd van de while() loop en er ook nog overhead die moet worden opgetelt bij de
// uiteindelijk gemeten pulstijd. Tijden zijn in de praktijk uitgeklokt met een analyser, echter per arduino
// kunnen er kleine verschillen optreden. Timings gemeten aan de IR_RX_DATA en RF_RX_DATA ingangen. Eigenschappen
// van de ontvangers kunnen eveneens van invloed zijn op de pulstijden.
const unsigned long LoopsPerMilli=345;
const unsigned long Overhead=0;
/**********************************************************************************************\
* Haal de pulsen en plaats in buffer.
* bij de TSOP1738 is in rust is de uitgang hoog. StateSignal moet LOW zijn
* bij de 433RX is in rust is de uitgang laag. StateSignal moet HIGH zijn
*
\*********************************************************************************************/
// Omdat deze routine tijdkritisch is halen we de gebruikte variabelen op globaal niveau
// zodat ze niet bij iedere functie-call opnieuw geinitialiseerd hoeven te worden. dit scheelt
// verwerkingstijd. Als er geen signaal is, neemt deze funktie (incl. de call)
int RawCodeLength=0;
unsigned long PulseLength=0;
unsigned long numloops=0;
unsigned long maxloops=0;
boolean Ftoggle=false;
uint8_t Fbit=0;
uint8_t Fport=0;
uint8_t FstateMask=0;
boolean FetchSignal(byte DataPin, boolean StateSignal)
{
uint8_t Fbit = digitalPinToBitMask(DataPin);
uint8_t Fport = digitalPinToPort(DataPin);
uint8_t FstateMask = (StateSignal ? Fbit : 0);
if((*portInputRegister(Fport) & Fbit) == FstateMask) // Als er signaal is
{
// Als het een herhalend signaal is, dan is de kans groot dat we binnen hele korte tijd weer in deze
// routine terugkomen en dan midden in de volgende herhaling terecht komen. Daarom wordt er in dit
// geval gewacht totdat de pulsen voorbij zijn en we met het capturen van data beginnen na een korte
// rust tussen de signalen.Op deze wijze wordt het aantal zinloze captures teruggebracht.
if(RawSignal.Time) // Eerst een snelle check, want dit bevindt zich in een tijdkritisch deel...
{
if(RawSignal.Repeats && (RawSignal.Time+SIGNAL_REPEAT_TIME)>millis()) // ...want deze check duurt enkele micro's langer!
{
// digitalWrite(PIN_WIRED_OUT_2,HIGH); // DEBUG: Wired-2 hoog gedurende capturing data
PulseLength=micros()+SIGNAL_TIMEOUT*1000; // Wachttijd
while((RawSignal.Time+SIGNAL_REPEAT_TIME)>millis() && PulseLength>micros())
if((*portInputRegister(Fport) & Fbit) == FstateMask)
PulseLength=micros()+SIGNAL_TIMEOUT*1000;
while((RawSignal.Time+SIGNAL_REPEAT_TIME)>millis() && (*portInputRegister(Fport) & Fbit) != FstateMask);
// digitalWrite(PIN_WIRED_OUT_2,LOW); // DEBUG: Wired-2 hoog gedurende capturing data
}
}
RawCodeLength=1; // We starten bij 1, dit om legacy redenen. Vroeger had element 0 een speciaal doel.
Ftoggle=false;
maxloops = SIGNAL_TIMEOUT * LoopsPerMilli;
// digitalWrite(PIN_WIRED_OUT_2,HIGH); // DEBUG:Wired-2 hoog gedurende capturing data
do{ // lees de pulsen in microseconden en plaats deze in de tijdelijke buffer RawSignal
numloops = 0;
while(((*portInputRegister(Fport) & Fbit) == FstateMask) ^ Ftoggle) // while() loop *A*
if(numloops++ == maxloops)
break; // timeout opgetreden
PulseLength=((numloops + Overhead)* 1000) / LoopsPerMilli; // Bevat nu de pulslengte in microseconden
if(PulseLength<MIN_PULSE_LENGTH)
break;
Ftoggle=!Ftoggle;
RawSignal.Pulses[RawCodeLength++]=PulseLength/(unsigned long)(Settings.RawSignalSample); // sla op in de tabel RawSignal
}
while(RawCodeLength<RAW_BUFFER_SIZE && numloops<=maxloops); // Zolang nog ruimte in de buffer, geen timeout en geen stoorpuls
// digitalWrite(PIN_WIRED_OUT_2,LOW); //DEBUG:
if(RawCodeLength>=MIN_RAW_PULSES)
{
///digitalWrite(PIN_WIRED_OUT_4,HIGH); // DEBUG: Een Spike op Wired-4 bevestigd een capture van een geldig signaal
RawSignal.RepeatChecksum=false; //
RawSignal.Repeats=0; // Op dit moment weten we nog niet het type signaal, maar de variabele niet ongedefinieerd laten.
RawSignal.Multiply=Settings.RawSignalSample; // Ingestelde sample groote.
RawSignal.Number=RawCodeLength-1; // Aantal ontvangen tijden (pulsen *2)
RawSignal.Pulses[RawSignal.Number]=0; // Laatste element bevat de timeout. Niet relevant.
RawSignal.Time=millis();
// digitalWrite(PIN_WIRED_OUT_4,LOW); // DEBUG:
return true;
}
else
RawSignal.Number=0;
}
return false;
}
boolean AnalyzeRawSignal(struct NodoEventStruct *E)
{
ClearEvent(E);
boolean Result=false;
if(RawSignal_2_ESP(E)) // Is het een Nodo signaal?
{
// Als er een Nodo signaal is binnengekomen, dan weten we zeker dat er een Nodo in het landschap is die tijd nodig heeft om
// weer terug te schakelen naar de ontvangstmode. Dit kost (helaas) enige tijd. Zorg er voor dat er gedurende deze tijd
// even geen Nodo event wordt verzonden anders wordt deze vrijwel zeker gemist.
HoldTransmission=millis()+ESP_TX_TO_RX_SWITCH_TIME;
Result=true;
}
if(!Transmission_ESPOnly)
{
if(!Result && PluginCall(PLUGIN_RAWSIGNAL_IN,E,0)) // Loop de devices langs. Indien een device dit nodig heeft, zal deze het rawsignal gebruiken en omzetten naar een geldig event.
Result=true;
if(!Result && RawSignal_2_32bit(E)) // als er geen enkel geldig signaaltype uit de pulsenreeks kon worden gedestilleerd, dan resteert niets anders dan deze weer te geven als een RawSignal.
{
if(Settings.RawSignalReceive==VALUE_ON // Signaal event als de setting RawSignalReceive op On staat
)
Result=true;
}
}
return Result;
}
/**********************************************************************************************\
* Deze functie genereert uit een willekeurig gevulde RawSignal afkomstig van de meeste
* afstandsbedieningen een (vrijwel) unieke bit code.
* Zowel breedte van de pulsen als de afstand tussen de pulsen worden in de berekening
* meegenomen zodat deze functie geschikt is voor PWM, PDM en Bi-Pase modulatie.
* LET OP: Het betreft een unieke hash-waarde zonder betekenis van waarde.
\*********************************************************************************************/
boolean RawSignal_2_32bit(struct NodoEventStruct *event)
{
int x;
unsigned int MinPulse=0xffff;
unsigned int MinSpace=0xffff;
unsigned long CodeM=0L;
unsigned long CodeS=0L;
// In enkele gevallen is uitzoeken van het RawSignal zinloos
if(RawSignal.Number < MIN_RAW_PULSES) return false;
// zoek de kortste tijd (PULSE en SPACE). Start niet direct vanaf de eerste puls omdat we anders kans
// lopen een onvolledige startbit te pakken. Ook niet de laatste, want daar zit de niet bestaande
// space van de stopbit in.
for(x=5;x<RawSignal.Number-2;x+=2)
{
if(RawSignal.Pulses[x] < MinPulse)MinPulse=RawSignal.Pulses[x]; // Zoek naar de kortste pulstijd.
if(RawSignal.Pulses[x+1]< MinSpace)MinSpace=RawSignal.Pulses[x+1]; // Zoek naar de kortste spacetijd.
}
// De kortste pulsen zijn gevonden. Dan een 'opslag' zodat alle korte pulsen er royaal
// onder vallen maar niet de lengte van een lange puls passeren.
MinPulse+=(MinPulse*RAWSIGNAL_TOLERANCE)/100;
MinSpace+=(MinSpace*RAWSIGNAL_TOLERANCE)/100;
// Data kan zowel in de mark als de space zitten. Daarom pakken we beide voor data opbouw.
for(x=3;x<=RawSignal.Number;x+=2)
{
CodeM = (CodeM<<1) | (RawSignal.Pulses[x] > MinPulse);
CodeS = (CodeS<<1) | (RawSignal.Pulses[x+1] > MinSpace);
}
// Data kan zowel in de mark als de space zitten. We nemen de grootste waarde voor de data.
if(CodeM > CodeS)
event->Par2=CodeM;
else
event->Par2=CodeS;
event->SourceUnit=0;
event->DestinationUnit=0;
event->Type=ESP_TYPE_RAWSIGNAL;
event->Command=EVENT_RAWSIGNAL;
event->Par1=0;
RawSignal.Repeats = 1; // het is een herhalend signaal. Bij ontvangst herhalingen onderdukken
RawSignal.RepeatChecksum = false;
return true;
}
/*********************************************************************************************\
* Deze routine berekent de uit een RawSignal een NODO code
* Geeft een false retour als geen geldig NODO signaal
\*********************************************************************************************/
boolean RawSignal_2_ESP(struct NodoEventStruct *Event)
{
byte b,x,y,z;
if(RawSignal.Number!=16*sizeof(struct DataBlockStruct)+2) // Per byte twee posities + startbit.
return false;
struct DataBlockStruct DataBlock;
byte *B=(byte*)&DataBlock; // B wijst naar de eerste byte van de struct
z=3; // RawSignal pulse teller: 0=niet gebruiktaantal, 1=startpuls, 2=space na startpuls, 3=1e pulslengte. Dus start loop met drie.
for(x=0;x<sizeof(struct DataBlockStruct);x++) // vul alle bytes van de struct
{
b=0;
for(y=0;y<=7;y++) // vul alle bits binnen een byte
{
if((RawSignal.Pulses[z]*RawSignal.Multiply)>ESP_PULSE_MID)
b|=1<<y; // LSB in signaal wordt als eerste verzonden
z+=2;
}
*(B+x)=b;
}
if(DataBlock.SourceUnit>>5!=HOME_ESP)
return false;
RawSignal.Repeats = 0; // het is geen herhalend signaal. Bij ontvangst hoeven herhalingen dus niet onderdrukt te worden.
Event->SourceUnit=DataBlock.SourceUnit&0x1F; // Maskeer de bits van het Home adres.
Event->DestinationUnit=DataBlock.DestinationUnit;
Event->Flags=DataBlock.Flags;
Event->Type=DataBlock.Type;
Event->Command=DataBlock.Command;
Event->Par1=DataBlock.Par1;
Event->Par2=DataBlock.Par2;
Event->Version=DataBlock.Version;
Event->Checksum=DataBlock.Checksum;
if(Checksum(Event))
return true;
return false;
}