/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef INCLUDE_ECXX_PLATFORM_BCM_OUTPUT_TPP
#error "this file cannot be included directly"
#endif
#undef INCLUDE_ECXX_PLATFORM_BCM_OUTPUT_TPP


#ifndef ECXX_PLATFORM_BCM_OUTPUT_TPP
#define ECXX_PLATFORM_BCM_OUTPUT_TPP


//
// A simple BCM (binary code modulation) waveform generator
//
template <uint8_t ChannelN>
inline BCMOutput<ChannelN>::BCMOutput(const uint8_t (&pin)[NumberOfChannels]) noexcept
: _bcmPhase  (0b10000000)
, _bcmCounter(0)
{
    for(uint8_t i = 0; i < NumberOfChannels; ++i) {
        _channelValue[BackBuffer ][i] = 0;
        _channelValue[FrontBuffer][i] = 0;
        Application::_preparePinFDW( _pinFDW[i], pin[i] );
    }
}


template <uint8_t ChannelN>
inline uint8_t& BCMOutput<ChannelN>::operator[](uint8_t channelIndex) noexcept
{ return _channelValue[BackBuffer][channelIndex]; }


template <uint8_t ChannelN>
inline uint8_t BCMOutput<ChannelN>::operator[](uint8_t channelIndex) const noexcept
{ return _channelValue[BackBuffer][channelIndex]; }


template <uint8_t ChannelN>
inline void BCMOutput<ChannelN>::update() noexcept
{
    // If the BCM counter is not zero yet, decrement it and return
    if(_bcmCounter) {
        --_bcmCounter;
        return;
    }

    // Select the next BCM phase
    _bcmPhase <<= 1;

    // Check if the current BCM cycle has completed
    if(!_bcmPhase) {
        // Reset the BCM phase to the beginning
        _bcmPhase = 0b00000001;
        // Copy back buffer values to front buffer
        for(uint8_t i = 0; i < NumberOfChannels; ++i) {
            _channelValue[FrontBuffer][i] = _channelValue[BackBuffer][i];
        }
    }

    // Reset the BCM counter
    _bcmCounter = _bcmPhase;

    // Output the bit values
    for(uint8_t i = 0; i < NumberOfChannels; ++i) {
        const bool bit = _channelValue[FrontBuffer][i] & _bcmPhase;
        _pinFDW[i](bit);
    }
}


#endif
