Helmut Schmücker / FtControlSet

Dependencies:   NeedfulThings

FtControlSetReceiver.h

Committer:
humlet
Date:
2013-03-23
Revision:
4:c1517188f6ec
Parent:
3:038f86bac6cc
Child:
5:7ce37fae13ff

File content as of revision 4:c1517188f6ec:

#ifndef FTCONTROLSETRECEIVER_H
#define FTCONTROLSETRECEIVER_H

#include "FtControlSetMessage.h"
#include "InterruptIn.h"
#include "FunctionPointer.h"
#include "Timeout.h"

using namespace mbed;

/// Tweaked Timeout class, that publishes the protected TimerEvent methods
/// remove and insert, which are a bit faster than detach and attach.
struct TimeoutTweaked : public Timeout {
    /// calls protected TimerEvent::remove()that
    /// just removes the timer event from the schedule but keeps the handler attached before
    inline void remove() {
        TimerEvent::remove();
    }
    /// calls proteccted TimerEvent::insert() that inserts a new timeout event to the schedule at the given timestamp 
    inline void insert(unsigned int timestamp) {
        TimerEvent::insert(timestamp);
    }
};

/// Receiver interface for the fischertechnik IR control set
///
/// An mbed port of the code found on this <A HREF="http://www.ftcommunity.de/wiki.php?action=show&topic_id=36">ft community WIKI page</a>
/// The ft IR remote control uses some kind of <A HREF="http://www.sbprojects.com/knowledge/ir/rcmm.php"> RC-MM Protocol </A>.
/// 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.
/// The protocol uses Pulse Distance Modulation (PDM) with two bits (di-bit) per pulse, hence four different
/// distances. A transmission consists of 16 pulses (15 distances) for a total of 30 bits.
///
/// 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 onnected directly to the mebed: 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.
///
/// Some fluorescent energy saving lamp might disturb the transmision quite heavily.


class FtControlSetReceiver
{
    InterruptIn m_pulseIRQ;

    uint32_t m_rxBuffer;  /// receive message buffer
    uint32_t m_nPulses;   /// receive pulse counter (15 pulses per message)
    uint32_t m_timeOfLastEdge; /// signal edge time stamp memory
    uint8_t  m_nOnes;     /// number of received high bits for parity calculation

    volatile uint32_t m_errorCount;    /// counter of observed receive errors
    uint8_t  m_nGracefullyIgnoredErrors;  /// error counter that reset on successful message reception

    volatile uint32_t m_lastMessage; /// last message received correctly

    FunctionPointer m_callback; ///callback for user code that is called afetr successful message reception

    TimeoutTweaked m_messageTimeout; /// Timeout for message reset when sender is inactive
    TimeoutTweaked m_receiveTimeout; /// receive timeout
    TimeoutTweaked m_recoverTimeout; /// error recovery timeout

    static const uint32_t c_pulseWidthLimits[5]; /// di-bit discrimination times
    static const uint32_t c_pulseWidthDelta = 100;//101;  /// di-bit discrimination pulse width delta
    static const uint32_t c_pulseWidthOffset = 795;//793; /// di-bit common pulse width base
    static const uint32_t c_maxPulseTime = c_pulseWidthOffset+7*c_pulseWidthDelta/2;  /// reveive timeout
    static const uint32_t c_messageTimeout[2]; /// message timeout depends on selected sender frequency
    static const uint8_t  c_errorsToBeGracefullyIgnored = 3; /// number of consecutive errors after which the message is reset
    static const uint32_t c_recoverTimeout = c_maxPulseTime; /// receiver is deactivated for this time after a receive error (IRQ burst suppression)

    void pulseISR(); /// pulse handler
    void messageTimeoutISR(); /// message time out handler
    void recoverISR();  /// reactivates the pulse handler after recover timeout

    void handleReceiveError();

public:

    /// Create a receiver
    /// @parameter in: The pin the IR detector's message line is connected to
    FtControlSetReceiver(PinName in);

    /// get the last received message
    FtControlSetMessage getMessage()const {
        return FtControlSetMessage(m_lastMessage);
    };

    /// get number of receive errors
    uint32_t getErrorCount()const {
        return m_errorCount;
    }

    /// hook a call back into the receiver ISR e.g. for sending a RTOS message.
    /// called on each update or receive error
    void setCallback(const FunctionPointer& callback) {
        m_callback=callback;
    };
};


#endif