# Copyright (c) 2021 Satlab A/S <satlab@satlab.com>
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.

from gnuradio import blocks
from gnuradio import digital
from gnuradio import gr
from gnuradio.filter import firdes
from gnuradio.fft import window
from gnuradio import satlab


class srs3_tx(gr.hier_block2):
    def __init__(self, samp_rate=2.56e6, rate=128000, size=217, idnum=0, cc=True, rs=True, crc=True, rand=True, key='\x00'*32, encrypt=False, auth=False, bt=0.5, preamble=8, v1compat=False, idleframes=0, max_in_flight=100):
        gr.hier_block2.__init__(
            self, "SRS-3 Transmitter",
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex),
        )
        self.message_port_register_hier_in("csp_in")
        self.message_port_register_hier_in("ip_in")

        # Parameters
        self.samp_rate = samp_rate
        self.rate = rate
        self.size = size
        self.idnum = idnum
        self.cc = cc
        self.rs = rs
        self.crc = crc
        self.rand = rand
        self.key = key
        self.encrypt = encrypt
        self.auth = auth
        self.bt = bt
        self.preamble = preamble
        self.v1compat = v1compat
        self.idleframes = idleframes
        self.max_in_flight = max_in_flight

        # Variables
        self.sps = int(self.samp_rate / self.rate)
        self.ramp_syms = 2
        self.idleframes = 0

        # Blocks
        self.idle_frame_gen = satlab.idle_frame_gen(satlab.frame_size(self.size, idnum=self.idnum, crypt=self.encrypt, auth=self.auth, crc=False, rs=False, cc=False, cc_term=False, include_asm=False), self.idleframes, self.max_in_flight)
        self.tag_to_trigger = satlab.tag_to_trigger('packet_len')
        self.encoder = satlab.srs3_encode(self.preamble, self.crc, self.cc, self.rand, self.rs, self.v1compat)
        self.encryptor = satlab.srs3_encrypt(self.key, self.encrypt, self.auth)
        self.enframer = satlab.srs3_enframe(self.size, self.idnum)
        self.pduts = blocks.pdu_to_tagged_stream(blocks.byte_t, 'packet_len')
        self.mod = digital.gmsk_mod(
            samples_per_symbol=self.sps,
            bt=self.bt,
            verbose=False,
            log=False)
        self.tsmult = blocks.tagged_stream_multiply_length(gr.sizeof_gr_complex, 'packet_len', 8 * self.sps)
        self.burstshaper = digital.burst_shaper_cc(firdes.window(window.WIN_HANN, self.ramp_syms * 2 * self.sps, 0), 0, self.ramp_syms * self.sps, False, "packet_len")

        # Connections
        self.msg_connect((self, 'csp_in'), (self.enframer, 'csp'))
        self.msg_connect((self, 'ip_in'), (self.enframer, 'ip'))
        self.msg_connect((self.enframer, 'output'), (self.encryptor, 'encrypt'))
        self.msg_connect((self.encryptor, 'output'), (self.idle_frame_gen, 'frame'))
        self.msg_connect((self.idle_frame_gen, 'pdu'), (self.encoder, 'input'))
        self.msg_connect((self.encoder, 'output'), (self.pduts, 'pdus'))
        self.msg_connect((self.tag_to_trigger, 'trigger'), (self.idle_frame_gen, 'trigger'))
        self.connect((self.pduts, 0), (self.mod, 0))
        self.connect((self.mod, 0), (self.tsmult, 0))
        self.connect((self.tsmult, 0), (self.burstshaper, 0))
        self.connect((self.burstshaper, 0), (self, 0))

        # Connect idle frame trigger
        self.connect(self.burstshaper, self.tag_to_trigger)

    def _set_sps(self, sps):
        self.sps = sps
        self.tsmult.set_scalar(8 * self.sps)

    def get_auth(self):
        return self.auth

    def set_auth(self, auth):
        self.auth = auth
        self.encryptor.set_auth(self.auth)

    def get_bt(self):
        return self.bt

    def set_bt(self, bt):
        self.bt = bt

    def get_cc(self):
        return self.cc

    def set_cc(self, cc):
        self.cc = cc
        self.encoder.set_cc(self.cc)

    def get_crc(self):
        return self.crc

    def set_crc(self, crc):
        self.crc = crc
        self.encoder.set_crc(self.crc)

    def get_encrypt(self):
        return self.encrypt

    def set_encrypt(self, encrypt):
        self.encrypt = encrypt
        self.encryptor.set_encrypt(self.encrypt)

    def get_id(self):
        return self.idnum

    def set_id(self, idnum):
        self.idnum = idnum
        self.enframer.set_id(self.idnum)

    def get_key(self):
        return self.key

    def set_key(self, key):
        self.key = key
        self.encryptor.set_key(self.key)

    def get_preamble(self):
        return self.preamble

    def set_preamble(self, preamble):
        self.preamble = preamble
        self.encoder.set_preamble(self.preamble)

    def get_rand(self):
        return self.rand

    def set_rand(self, rand):
        self.rand = rand
        self.encoder.set_rand(self.rand)

    def get_rate(self):
        return self.rate

    def set_rate(self, rate):
        self.rate = rate
        self._set_sps(int(self.samp_rate / self.rate))

    def get_rs(self):
        return self.rs

    def set_rs(self, rs):
        self.rs = rs
        self.encoder.set_rs(self.rs)

    def get_size(self):
        return self.size

    def set_size(self, size):
        self.size = size
        self.enframer.set_size(self.size)

    def get_v1compat(self):
        return self.v1compat

    def set_v1compat(self, v1compat):
        self.v1compat = v1compat
        self.encoder.set_v1compat(self.v1compat)

    def get_frames(self):
        return self.enframer.get_frames()

    def get_bit_rate(self):
        frame_size = satlab.frame_size(self.size, self.crc, self.rs, self.cc, self.idnum, self.encrypt, self.auth, cc_term=True, include_asm=True)
        return self.rate * self.size / frame_size

    def get_modulation(self):
        return 'GMSK'
