Receiver interface for the fischertechnik IR control set

Dependencies:   NeedfulThings

Receiver interface for the fischertechnik IR control set.

An mbed port of the code found on this ft community WIKI page The ft IR remote control uses some kind of RC-MM Protocol . When any of the controls is applied the remote control sends updates at a rate of at 1/120ms or 1/90ms depending on the senders frequency setting. Each message delivers the complete remote control status encoded into 30 bits. The structure of the message can be seen in FtControlSetMessage.h.

I assume that the ft control set works fine with standard 38kHz IR detectors. I have used a CHQ0038 from a broken DVD Player. It can be connected directly to the mbed: GND, VCC->3.3V and the signal line to any of the numbered mbed gpios.

The PDM timing of the ft IR control set isn't that exact. Thus receive errors occur quite frequently. I am observing an error rate somewhere between 3% and 5%. This driver "ignores" up to 3 consecutive receive errors, i.e. it just indicates an error but still provides the last correctly received message, before it resets the message to zero after the fourth error.

Committer:
humlet
Date:
Mon Mar 25 21:50:27 2013 +0000
Revision:
6:3cce31050c90
Parent:
5:7ce37fae13ff
just added NeedfulThings lib dependency; (hopefully)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
humlet 0:a3a07eb0c1dd 1 #include "FtControlSetReceiver.h"
humlet 0:a3a07eb0c1dd 2
humlet 0:a3a07eb0c1dd 3 #include "us_ticker_api.h"
humlet 0:a3a07eb0c1dd 4
humlet 4:c1517188f6ec 5 /// message timeout depends on selected sender frequency
humlet 4:c1517188f6ec 6 const uint32_t FtControlSetReceiver::c_messageTimeout[2] = {89000+20*c_maxPulseTime,118000+20*c_maxPulseTime};
humlet 4:c1517188f6ec 7 /// di-bit discrimination times
humlet 4:c1517188f6ec 8 const uint32_t FtControlSetReceiver::c_pulseWidthLimits[5] = {740,860,940,1055,1150};
humlet 1:3904ef8c606e 9
humlet 1:3904ef8c606e 10 FtControlSetReceiver::FtControlSetReceiver(PinName in):
humlet 0:a3a07eb0c1dd 11 m_pulseIRQ(in),
humlet 0:a3a07eb0c1dd 12 m_rxBuffer(0),
humlet 0:a3a07eb0c1dd 13 m_nPulses(0),
humlet 0:a3a07eb0c1dd 14 m_timeOfLastEdge(0),
humlet 1:3904ef8c606e 15 m_nOnes(0),
humlet 1:3904ef8c606e 16 m_errorCount(0),
humlet 2:1ae8bb468515 17 m_nGracefullyIgnoredErrors(0),
humlet 1:3904ef8c606e 18 m_lastMessage(0)
humlet 1:3904ef8c606e 19 {
humlet 3:038f86bac6cc 20 m_pulseIRQ.mode(PullNone); // the CHQ0038 does't like the default pull down
humlet 3:038f86bac6cc 21 m_pulseIRQ.fall(this, &FtControlSetReceiver::pulseISR); // we are measuring the distances of falling edges
humlet 4:c1517188f6ec 22
humlet 5:7ce37fae13ff 23 // attch the callbacks
humlet 5:7ce37fae13ff 24 m_messageTimeout.attach(this,&FtControlSetReceiver::messageTimeoutISR);
humlet 5:7ce37fae13ff 25 m_receiveTimeout.attach(this,&FtControlSetReceiver::handleReceiveError);
humlet 5:7ce37fae13ff 26 m_recoverTimeout.attach(this,&FtControlSetReceiver::recoverISR);
humlet 1:3904ef8c606e 27 }
humlet 1:3904ef8c606e 28
humlet 4:c1517188f6ec 29 /// called on each falling edge on the IR receivers signal line
humlet 1:3904ef8c606e 30 void FtControlSetReceiver::pulseISR()
humlet 1:3904ef8c606e 31 {
humlet 4:c1517188f6ec 32 // takes 1µs-5µs, 4.1µs on average
humlet 1:3904ef8c606e 33 if(m_nPulses) {
humlet 4:c1517188f6ec 34 // received a messge pulse
humlet 1:3904ef8c606e 35 uint32_t now = us_ticker_read();
humlet 4:c1517188f6ec 36 m_receiveTimeout.remove();
humlet 4:c1517188f6ec 37 uint32_t width = now - m_timeOfLastEdge;
humlet 1:3904ef8c606e 38 m_timeOfLastEdge = now;
humlet 4:c1517188f6ec 39 if(width>=c_pulseWidthLimits[0] && width<c_pulseWidthLimits[4]) {
humlet 4:c1517188f6ec 40 if(width<c_pulseWidthLimits[1]){
humlet 4:c1517188f6ec 41 // m_rxBuffer|=0x0;
humlet 4:c1517188f6ec 42 }else if(width<c_pulseWidthLimits[2]) {
humlet 4:c1517188f6ec 43 m_rxBuffer|=0x1;
humlet 4:c1517188f6ec 44 ++m_nOnes;
humlet 4:c1517188f6ec 45 } else if(width<c_pulseWidthLimits[3]) {
humlet 4:c1517188f6ec 46 m_rxBuffer|=0x2;
humlet 4:c1517188f6ec 47 ++m_nOnes;
humlet 4:c1517188f6ec 48 } else {
humlet 4:c1517188f6ec 49 m_rxBuffer|=0x3;
humlet 4:c1517188f6ec 50 }
humlet 1:3904ef8c606e 51 m_rxBuffer<<=2;
humlet 1:3904ef8c606e 52 if(++m_nPulses<=15) {
humlet 4:c1517188f6ec 53 // still receiving re-attach the pulse timeout
humlet 4:c1517188f6ec 54 m_receiveTimeout.insert(m_timeOfLastEdge+c_maxPulseTime);
humlet 1:3904ef8c606e 55 } else {
humlet 4:c1517188f6ec 56 // we have got a full message
humlet 4:c1517188f6ec 57 FtControlSetMessage::Status status;
humlet 2:1ae8bb468515 58 if(m_nOnes&1) { // message ones + parity one has to be even
humlet 4:c1517188f6ec 59 status = FtControlSetMessage::ParityKO;
humlet 2:1ae8bb468515 60 } else if(m_rxBuffer>>28!=8 || m_rxBuffer&4) { // check header=8 and tail=0
humlet 4:c1517188f6ec 61 status = FtControlSetMessage::FrameKO;
humlet 2:1ae8bb468515 62 } else { // happyhappyjoyjoy
humlet 4:c1517188f6ec 63 status = FtControlSetMessage::OK;
humlet 1:3904ef8c606e 64 }
humlet 4:c1517188f6ec 65 // detach and reattach the message timeout
humlet 4:c1517188f6ec 66 m_messageTimeout.remove();
humlet 4:c1517188f6ec 67 m_messageTimeout.insert(m_timeOfLastEdge+c_messageTimeout[1]);//just take the longer timeout here, otherwise we run into problems
humlet 4:c1517188f6ec 68 if(status == FtControlSetMessage::OK) {
humlet 4:c1517188f6ec 69 m_nGracefullyIgnoredErrors = 0;
humlet 4:c1517188f6ec 70 m_lastMessage = m_rxBuffer;
humlet 4:c1517188f6ec 71 } else {
humlet 4:c1517188f6ec 72 if(++m_nGracefullyIgnoredErrors <= c_errorsToBeGracefullyIgnored) {
humlet 4:c1517188f6ec 73 m_lastMessage &= ~0x3; // just indicate the error but keep the old message
humlet 4:c1517188f6ec 74 m_lastMessage |= status;
humlet 4:c1517188f6ec 75 } else {
humlet 4:c1517188f6ec 76 m_lastMessage = status; // reset the message and indicate the error
humlet 4:c1517188f6ec 77 }
humlet 4:c1517188f6ec 78 ++m_errorCount;
humlet 4:c1517188f6ec 79 }
humlet 4:c1517188f6ec 80 m_callback.call();
humlet 4:c1517188f6ec 81 m_rxBuffer=0;
humlet 4:c1517188f6ec 82 m_nPulses=0;
humlet 4:c1517188f6ec 83 m_nOnes=0;
humlet 1:3904ef8c606e 84 }
humlet 1:3904ef8c606e 85 } else {
humlet 1:3904ef8c606e 86 handleReceiveError();
humlet 1:3904ef8c606e 87 }
humlet 1:3904ef8c606e 88 } else {
humlet 3:038f86bac6cc 89 // the very first edge of a potential message, just memorize time stamp
humlet 1:3904ef8c606e 90 m_timeOfLastEdge = us_ticker_read();
humlet 4:c1517188f6ec 91 m_receiveTimeout.insert(m_timeOfLastEdge+c_maxPulseTime);
humlet 1:3904ef8c606e 92 ++m_nPulses;
humlet 1:3904ef8c606e 93 }
humlet 1:3904ef8c606e 94 }
humlet 1:3904ef8c606e 95
humlet 1:3904ef8c606e 96 void FtControlSetReceiver::messageTimeoutISR()
humlet 1:3904ef8c606e 97 {
humlet 1:3904ef8c606e 98 m_lastMessage = 0;
humlet 4:c1517188f6ec 99 m_callback.call();
humlet 1:3904ef8c606e 100 }
humlet 1:3904ef8c606e 101
humlet 4:c1517188f6ec 102 // called on errors detected in pulseISR or on pulse timeouts
humlet 1:3904ef8c606e 103 void FtControlSetReceiver::handleReceiveError()
humlet 1:3904ef8c606e 104 {
humlet 4:c1517188f6ec 105 // receive errors are not reported via the status bits and the message is not reset here,
humlet 4:c1517188f6ec 106 // because it might have been just a disturbance between two messages.
humlet 3:038f86bac6cc 107 // On severe transmission problems the message timeout will bail us out
humlet 1:3904ef8c606e 108 ++m_errorCount;
humlet 4:c1517188f6ec 109 //m_errorCount+=10000;
humlet 1:3904ef8c606e 110 m_rxBuffer=0;
humlet 1:3904ef8c606e 111 m_nPulses=0;
humlet 1:3904ef8c606e 112 m_nOnes=0;
humlet 1:3904ef8c606e 113 // to be graceful in case of high frequency noise disconnect the ISR for some time
humlet 1:3904ef8c606e 114 m_pulseIRQ.fall(0);
humlet 4:c1517188f6ec 115 m_recoverTimeout.insert(us_ticker_read()+c_recoverTimeout);
humlet 1:3904ef8c606e 116 }
humlet 1:3904ef8c606e 117
humlet 1:3904ef8c606e 118 void FtControlSetReceiver::recoverISR()
humlet 0:a3a07eb0c1dd 119 {
humlet 3:038f86bac6cc 120 // reattach the pulse handler
humlet 0:a3a07eb0c1dd 121 m_pulseIRQ.fall(this, &FtControlSetReceiver::pulseISR);
humlet 0:a3a07eb0c1dd 122 }