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:
Wed Mar 20 21:55:20 2013 +0000
Revision:
3:038f86bac6cc
Parent:
2:1ae8bb468515
Child:
4:c1517188f6ec
runs smoothly

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 3:038f86bac6cc 5 const uint32_t FtControlSetReceiver::c_messageTimeout[2] = {89000+20*c_maxPulseTime,118000+20*c_maxPulseTime};
humlet 3:038f86bac6cc 6 //const uint32_t FtControlSetReceiver::c_pulseWidthLimits[5] = {740,860,940,1055,1150};
humlet 1:3904ef8c606e 7
humlet 1:3904ef8c606e 8 FtControlSetReceiver::FtControlSetReceiver(PinName in):
humlet 0:a3a07eb0c1dd 9 m_pulseIRQ(in),
humlet 0:a3a07eb0c1dd 10 m_rxBuffer(0),
humlet 0:a3a07eb0c1dd 11 m_nPulses(0),
humlet 0:a3a07eb0c1dd 12 m_timeOfLastEdge(0),
humlet 1:3904ef8c606e 13 m_nOnes(0),
humlet 1:3904ef8c606e 14 m_errorCount(0),
humlet 2:1ae8bb468515 15 m_nGracefullyIgnoredErrors(0),
humlet 1:3904ef8c606e 16 m_lastMessage(0)
humlet 1:3904ef8c606e 17 {
humlet 3:038f86bac6cc 18 m_pulseIRQ.mode(PullNone); // the CHQ0038 does't like the default pull down
humlet 3:038f86bac6cc 19 m_pulseIRQ.fall(this, &FtControlSetReceiver::pulseISR); // we are measuring the distances of falling edges
humlet 1:3904ef8c606e 20 }
humlet 1:3904ef8c606e 21
humlet 1:3904ef8c606e 22 void FtControlSetReceiver::pulseISR()
humlet 1:3904ef8c606e 23 {
humlet 2:1ae8bb468515 24 // needs 4-8µs
humlet 1:3904ef8c606e 25 uint32_t dt=us_ticker_read();
humlet 1:3904ef8c606e 26 if(m_nPulses) {
humlet 1:3904ef8c606e 27 uint32_t now = us_ticker_read();
humlet 1:3904ef8c606e 28 m_receiveTimeout.detach();
humlet 1:3904ef8c606e 29 uint32_t diBit = now - m_timeOfLastEdge;
humlet 1:3904ef8c606e 30 m_timeOfLastEdge = now;
humlet 3:038f86bac6cc 31 diBit -= c_pulseWidthOffset-c_pulseWidthDelta/2;
humlet 3:038f86bac6cc 32 diBit /= c_pulseWidthDelta;
humlet 1:3904ef8c606e 33 if(diBit<4) {
humlet 2:1ae8bb468515 34 /*
humlet 2:1ae8bb468515 35 uint32_t w=diBit;
humlet 3:038f86bac6cc 36 if(w>c_pulseWidthLimits[0] && w<c_pulseWidthLimits[4]){
humlet 3:038f86bac6cc 37 if(w<c_pulseWidthLimits[1])
humlet 2:1ae8bb468515 38 diBit=0;
humlet 3:038f86bac6cc 39 else if(w<c_pulseWidthLimits[2])
humlet 2:1ae8bb468515 40 diBit=1;
humlet 3:038f86bac6cc 41 else if(w<c_pulseWidthLimits[3])
humlet 2:1ae8bb468515 42 diBit=2;
humlet 2:1ae8bb468515 43 else
humlet 2:1ae8bb468515 44 diBit=3;
humlet 2:1ae8bb468515 45 */
humlet 1:3904ef8c606e 46 m_rxBuffer|=diBit;
humlet 1:3904ef8c606e 47 m_rxBuffer<<=2;
humlet 1:3904ef8c606e 48 const uint8_t ones[4]= {0,1,1,2};
humlet 1:3904ef8c606e 49 m_nOnes+=ones[diBit];
humlet 1:3904ef8c606e 50 if(++m_nPulses<=15) {
humlet 3:038f86bac6cc 51 // still receiving re-attach the pulse timeout
humlet 1:3904ef8c606e 52 m_receiveTimeout.attach_us(this,&FtControlSetReceiver::handleReceiveError, c_maxPulseTime);
humlet 1:3904ef8c606e 53 } else {
humlet 3:038f86bac6cc 54 // we got a full message
humlet 2:1ae8bb468515 55 if(m_nOnes&1) { // message ones + parity one has to be even
humlet 2:1ae8bb468515 56 messageReceived(FtControlSetMessage::ParityKO);
humlet 2:1ae8bb468515 57 } else if(m_rxBuffer>>28!=8 || m_rxBuffer&4) { // check header=8 and tail=0
humlet 2:1ae8bb468515 58 messageReceived(FtControlSetMessage::FrameKO);
humlet 2:1ae8bb468515 59 } else { // happyhappyjoyjoy
humlet 2:1ae8bb468515 60 messageReceived(FtControlSetMessage::OK);
humlet 1:3904ef8c606e 61 }
humlet 1:3904ef8c606e 62 }
humlet 1:3904ef8c606e 63 } else {
humlet 3:038f86bac6cc 64 // receive errors are not reported
humlet 3:038f86bac6cc 65 // In case of repeated receive errors the message timeout will trigger and reset the data
humlet 1:3904ef8c606e 66 handleReceiveError();
humlet 1:3904ef8c606e 67 }
humlet 1:3904ef8c606e 68 } else {
humlet 3:038f86bac6cc 69 // the very first edge of a potential message, just memorize time stamp
humlet 1:3904ef8c606e 70 m_timeOfLastEdge = us_ticker_read();
humlet 1:3904ef8c606e 71 m_receiveTimeout.attach_us(this,&FtControlSetReceiver::handleReceiveError, c_maxPulseTime);
humlet 1:3904ef8c606e 72 ++m_nPulses;
humlet 1:3904ef8c606e 73 }
humlet 1:3904ef8c606e 74 }
humlet 1:3904ef8c606e 75
humlet 2:1ae8bb468515 76 void FtControlSetReceiver::messageReceived(FtControlSetMessage::Status status)
humlet 1:3904ef8c606e 77 {
humlet 3:038f86bac6cc 78 // detach and reattach the message timeout
humlet 1:3904ef8c606e 79 m_messageTimeout.detach();
humlet 1:3904ef8c606e 80 m_messageTimeout.attach_us(this,
humlet 1:3904ef8c606e 81 &FtControlSetReceiver::messageTimeoutISR,
humlet 3:038f86bac6cc 82 //c_messageTimeout[m_lastMessage.getSwitch1()]);
humlet 3:038f86bac6cc 83 c_messageTimeout[1]); //just take the longer timeout here, otherwise we run into problems
humlet 3:038f86bac6cc 84 // check for errors and copy the result and the message data to m_lastMessage
humlet 2:1ae8bb468515 85 if(status == FtControlSetMessage::OK) {
humlet 2:1ae8bb468515 86 m_nGracefullyIgnoredErrors = 0;
humlet 2:1ae8bb468515 87 m_lastMessage = m_rxBuffer;
humlet 2:1ae8bb468515 88 } else {
humlet 2:1ae8bb468515 89 if(++m_nGracefullyIgnoredErrors <= c_errorsToBeGracefullyIgnored) {
humlet 2:1ae8bb468515 90 m_lastMessage = m_lastMessage.getRawMessage() | status; // just indicate the error but keep the old message
humlet 2:1ae8bb468515 91 } else {
humlet 2:1ae8bb468515 92 m_lastMessage = status; // reset the message and indicate the error
humlet 2:1ae8bb468515 93 }
humlet 2:1ae8bb468515 94 ++m_errorCount;
humlet 2:1ae8bb468515 95 }
humlet 1:3904ef8c606e 96 m_callBack.call();
humlet 1:3904ef8c606e 97 m_rxBuffer=0;
humlet 1:3904ef8c606e 98 m_nPulses=0;
humlet 1:3904ef8c606e 99 m_nOnes=0;
humlet 1:3904ef8c606e 100 }
humlet 1:3904ef8c606e 101
humlet 1:3904ef8c606e 102 void FtControlSetReceiver::messageTimeoutISR()
humlet 1:3904ef8c606e 103 {
humlet 1:3904ef8c606e 104 m_lastMessage = 0;
humlet 1:3904ef8c606e 105 m_callBack.call();
humlet 1:3904ef8c606e 106 }
humlet 1:3904ef8c606e 107
humlet 1:3904ef8c606e 108 void FtControlSetReceiver::handleReceiveError()
humlet 1:3904ef8c606e 109 {
humlet 3:038f86bac6cc 110 // don't reset the message here, it might have been just a disturbance between two messages
humlet 3:038f86bac6cc 111 // On severe transmission problems the message timeout will bail us out
humlet 1:3904ef8c606e 112 ++m_errorCount;
humlet 1:3904ef8c606e 113 m_rxBuffer=0;
humlet 1:3904ef8c606e 114 m_nPulses=0;
humlet 1:3904ef8c606e 115 m_nOnes=0;
humlet 1:3904ef8c606e 116 // to be graceful in case of high frequency noise disconnect the ISR for some time
humlet 1:3904ef8c606e 117 m_pulseIRQ.fall(0);
humlet 3:038f86bac6cc 118 m_receiveTimeout.attach_us(this,&FtControlSetReceiver::recoverISR, c_recoverTimeout);
humlet 1:3904ef8c606e 119 }
humlet 1:3904ef8c606e 120
humlet 1:3904ef8c606e 121
humlet 1:3904ef8c606e 122 void FtControlSetReceiver::recoverISR()
humlet 0:a3a07eb0c1dd 123 {
humlet 3:038f86bac6cc 124 // reattach the pulse handler
humlet 0:a3a07eb0c1dd 125 m_pulseIRQ.fall(this, &FtControlSetReceiver::pulseISR);
humlet 0:a3a07eb0c1dd 126 }