Receiver interface for the fischertechnik IR control set
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.
FtControlSetReceiver.cpp@3:038f86bac6cc, 2013-03-20 (annotated)
- 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?
User | Revision | Line number | New 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 | } |