# Copyright (c) 2016-2017 Satlab Aps <satlab@satlab.com>
# All rights reserved. Do not distribute without permission.

import os
import ctypes

import propnode
import cspnode

# Load test library
testlib = ctypes.CDLL(os.environ['SL_TESTLIB'])

# const struct prop_subsys_spec polaris_adsb_props
_sl_polaris_props = propnode.prop_subsys_spec.in_dll(testlib, "polaris_props")

# #define SL_POLARIS_COPYFRAMES_DATALEN	135
SL_POLARIS_COPYFRAMES_DATALEN = 135


# typedef struct {
# 	uint8_t type;
# 	uint8_t error;
# 	uint32_t seq;
# 	uint64_t time;
# 	uint8_t channel;
# 	uint16_t scale;
# 	int16_t mean;
# 	uint8_t length;
# 	uint8_t data[SL_POLARIS_COPYFRAMES_DATALEN];
# } __packed sl_polaris_store_frame_t;
class sl_polaris_store_frame_t(ctypes.Structure):
    # Flexible length arrays are not supported in ctypes
    _pack_ = 1
    _fields_ = [
        ("type", ctypes.c_uint8),
        ("error", ctypes.c_uint8),
        ("seq", ctypes.c_uint32),
        ("time", ctypes.c_uint64),
        ("channel", ctypes.c_uint8),
        ("scale", ctypes.c_uint16),
        ("mean", ctypes.c_int16),
        ("length", ctypes.c_uint8),
        ("data", ctypes.c_uint8 * SL_POLARIS_COPYFRAMES_DATALEN)]


# typedef int (*sl_polaris_frame_cb_t)(sl_polaris_store_frame_t *frame, void *arg);
_sl_polaris_frame_cb_t = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.POINTER(sl_polaris_store_frame_t), ctypes.c_void_p)


class PolarisException(Exception):
    pass


class Polaris(propnode.PropertyNode, cspnode.CSPNode):
    SL_POLARIS_SAMPLEBUF_SOURCE_RAW = 0x00
    SL_POLARIS_SAMPLEBUF_SOURCE_CH1 = 0x01
    SL_POLARIS_SAMPLEBUF_SOURCE_CH2 = 0x02
    SL_POLARIS_SAMPLEBUF_SOURCE_CH3 = 0x03
    SL_POLARIS_SAMPLEBUF_SOURCE_CH4 = 0x04

    def __init__(self, addr=20, timeout=2500):
        # Get function references from lib
        global testlib

        # int sl_polaris_sample_read(uint8_t node, uint32_t timeout, uint8_t source, uint32_t *out, size_t outlen, bool wait_pps);
        self._sl_sample_read = testlib.sl_polaris_sample_read
        self._sl_sample_read.argtypes = [ctypes.c_uint8, ctypes.c_uint32, ctypes.c_uint8, ctypes.POINTER(ctypes.c_uint32), ctypes.c_size_t, ctypes.c_bool]
        self._sl_sample_read.restype = ctypes.c_int

        # int sl_polaris_mirror_recv(uint8_t node, uint32_t timeout, sl_polaris_frame_cb_t cb, void *arg);
        self._sl_store_mirror_recv = testlib.sl_polaris_store_mirror_recv
        self._sl_store_mirror_recv.argtypes = [ctypes.c_uint8, ctypes.c_uint32, _sl_polaris_frame_cb_t, ctypes.c_void_p]
        self._sl_store_mirror_recv.restype = ctypes.c_int

        self.addr = addr
        self.timeout = timeout
        self.prop = propnode.PropertyNode(addr, _sl_polaris_props, timeout)
        self.csp = cspnode.CSPNode(addr)

    def sample_read(self, source=SL_POLARIS_SAMPLEBUF_SOURCE_RAW, wait_pps=False):
        out = (8192 * ctypes.c_uint32)()
        length = 8192 * ctypes.sizeof(ctypes.c_uint32)
        ret = self._sl_sample_read(self.addr, self.timeout, source, out, length, wait_pps)
        if ret < 0:
            raise PolarisException('Failed to read sample')
        return bytearray(out)

    def store_mirror_recv(self, cb, arg=None):
        ret = self._sl_store_mirror_recv(self.addr, self.timeout, _sl_polaris_frame_cb_t(cb), arg)
        if ret < 0:
            raise PolarisException('Failed to request store mirror')
        return ret
