//
// PT1Core.h
//

#ifndef __RY0_DEVICE_PT1_PT1CORE_H__
#define __RY0_DEVICE_PT1_PT1CORE_H__

#include <stdint.h>
#include <windows.h>
#include <process.h>
#include "EARTH_PT.h"
#include "ry0/device/Tuner.h"

namespace ry0
{
namespace device
{
namespace PT1
{

class PT1Tuner;

class PT1Core
{
    friend class PT1Tuner;

public:
    static const int EXCEPTION_NEW_DEVICE               = 0x00000001;
    static const int EXCEPTION_DELETE                   = 0x00000002;
    static const int EXCEPTION_OPEN                     = 0x00000004;
    static const int EXCEPTION_CLOSE                    = 0x00000008;
    static const int EXCEPTION_INIT_TUNER               = 0x00000010;
    static const int EXCEPTION_SET_TUNER_POWER_RESET    = 0x00000020;
    static const int EXCEPTION_SET_TUNER_SLEEP          = 0x00000040;
    static const int EXCEPTION_SET_STREAM_ENABLE        = 0x00000080;
    static const int EXCEPTION_SET_STREAM_GRAY          = 0x00000100;
    static const int EXCEPTION_OTHER                    = 0x80000000;

    static const int MAX_TUNERS                         = 4;
    static const int PAGE_SIZE                          = 4096;
    static const int PAGE_COUNT                         = 47;
    static const int PACKET_SIZE                        = 188;
    static const int VIRTUAL_SIZE                       = 4;
    static const int VIRTUAL_COUNT                      = 16;
    static const int LOCK_SIZE                          = 4;
    static const int BUFFER_PAGE_COUNT                  = 511;
    static const int BLOCK_COUNT                        = 2;
    static const int BLOCK_SIZE                         = (PAGE_SIZE * BUFFER_PAGE_COUNT / BLOCK_COUNT);


private:
    CRITICAL_SECTION    _cs;
    EARTH::PT::Device * _device;
    char                _name[64];

    PT1Tuner *          _tuners[MAX_TUNERS];
    bool                _locked[MAX_TUNERS];

    // for DMA Transfer
    enum {
        ST_IDLE = 0,
        ST_READY,
        ST_RUN,
        ST_STOP}        _transfer;
    uint32_t            _virtualIndex;
    uint32_t            _imageIndex;
    uint32_t            _blockIndex;
    uint8_t             _buffer[BLOCK_SIZE];

    uint32_t offset(uint32_t imageIndex, uint32_t blockIndex, uint32_t additionalOffset);
    uint32_t offset(uint32_t imageIndex, uint32_t blockIndex);
    uint32_t read(uint32_t virtualIndex, uint32_t imageIndex, uint32_t blockIndex);
    void clearBlock(uint32_t virtualIndex, uint32_t imageIndex, uint32_t blockIndex);
    bool waitBlock();
    void copyBlock();
    bool dispatchBlock();

    //
    PT1Core(EARTH::PT::Bus *bus, const EARTH::PT::Bus::DeviceInfo *deviceInfo, Tuner *tuners[4], HMODULE multi2_dll);
    ~PT1Core();

    void release(Tuner *tuner);

public:
    bool getCnAgc(EARTH::uint tuner, EARTH::uint *cn100, EARTH::uint *agc, EARTH::uint *maxAgc);
    bool setChannel(EARTH::uint tuner, int channel);

    const char *name();

    void transfer();
};

} // PT1
} // device
} // ry0

#endif // __RY0_DEVICE_PT1_PT1CORE_H__
