import sys
sys.path.append("..")

from pydsp import Signal
import pydsp.misc as misc
import pydsp.Modulation as Modulation
import pydsp.Window as Window
import pydsp.Filter as Filter
import math
import random
from pydsp.misc import *
import oss
import string
import struct
import os

deg45 = math.pi / 4
deg135 = math.pi/2 + deg45
deg225 = math.pi/2 + deg135
deg315 = math.pi/2 + deg225

def calcpdiff(phase1, phase2):
        phasediff = phase2 - phase1
        if phasediff < 0: phasediff = 2*math.pi + phasediff    
        return phasediff

def pskreceive(fs, freq, baudrate, signal, lo_phase = 0):
    # Calculate number of samples per symbol
    samplespersymbol = int(fs / baudrate)
    
    # Downconvert the signal from freq to a cplx baseband signal
    # We use a fixed frequency here, so any frequency drift on the signal
    # will break our demodulation.
    m = Modulation.Quadrature(fs)
    s = m.demodulate(signal, freq, phase=lo_phase, lpf=False)
    bb_sig = s.signal

    # Run through pulse-shape filter to remove out-of-band components
    # and also ISI. This filter coupled with the filter in the transmitter
    # create a Raised-Cosine filter.
    f = Filter.FIR(fs, cplx=True)
    f.make_rrc(baudrate, 0.5, gain=4)
    bb_shaped = f.filter(bb_sig)

    # Detect the carrier by measuring the signal power.
    # If it goes above a threshold we have a carrier
    s.signal = [r.real for r in bb_shaped]
    pw = s.power(fi = 150)
    cr = False
    for i in range(0, len(pw)):
        if pw[i] > 0.00001:
            cr = i
            break
    if not cr:
        print "No carrier detected"
        return pw,bb_shaped,None,None,None
    print "Carrier detected at sample "+str(cr)

    # Detect end of carrier
    for i in range(cr, len(pw)):
        if pw[i] < 0.000005:
            ce = i
            break
    print "Carrier lost at sample "+str(ce)

    # We need at least 5 symbols of carrier
    cr += samplespersymbol * 5;


    # Detect start of data. We do so by waiting for a 180deg phase
    # change, since the start-signal is lots of zeros and a 11-dibit.
    for i in range(cr, ce):
        phase1 = ang(bb_shaped[i - samplespersymbol])
	phase2 = ang(bb_shaped[i])
        phasediff = calcpdiff(phase1, phase2)
        if phasediff >= deg135 and phasediff <= deg225:
            cr = i
            break
    print "Phase jump detected at sample "+str(cr)

    # Trivial sample-position estimate. This works for low baudrates
    # but it's quite inadequate for high baudrates or dense
    # signal constellations
    cr += int(samplespersymbol/2)
    print "Determined middle of baud at "+str(cr)


    # Pre-set lastphase to our current phase, needed for differential decoding
    lastphase = ang(bb_shaped[cr])
        
    # Put us in the middle of the next symbol
    cr += int(samplespersymbol)
    print "Estimate first data symbol midpoint at "+str(cr)


    # Sample the symbol midpoints to get the symbol sent
    # This is a very simple approach, where we pick samples that
    # are 'samplespersymbol' apart. For real applications this would need
    # to be more robust.
    syms = [bb_shaped[cr + int(samplespersymbol*i)]
            for i in range(0, int((ce-cr) / samplespersymbol))]

    # Differentially decode into dibits
    dibits = []
    for s in syms:
        phase = ang(s)
        phasediff = calcpdiff(lastphase, phase)
        lastphase = phase

        # Simple phase->dibit decoder. Just test that the phase difference
        # is within a specified range. Look at sendit.py to see how the
        # constellation looks like.
        if phasediff <= deg45 or phasediff > deg315: dibit = 0
        elif phasediff <= deg135 and phasediff > deg45: dibit = 1
        elif phasediff <= deg225 and phasediff > deg135: dibit = 3
        elif phasediff <= deg315 and phasediff > deg225: dibit = 2

        dibits.append(dibit)

    # Byte-decode the dibits
    bytes = ''
    for i in range(0, len(dibits) / 4):
        z = i*4
        b = dibits[z] << 6
        b+= dibits[z+1] << 4
        b+= dibits[z+2] << 2
        b+= dibits[z+3]
        bytes += chr(b)

    return pw, bb_shaped, syms, dibits, bytes



##
# This reads the signal for demodulation.
# You may select reading it from a file or from your soundcard
from_soundcard = False
filename = 'outfile'
sec = 10
fs = 44100
carrier_freq = 10000
baudrate = 2321


if from_soundcard:
    a = oss.open_audio("/dev/dsp",os.O_RDONLY )
    a.format(oss.AFMT_S16_LE)
    a.stereo(False)
    a.speed(fs)
    a.sync()
    print "Go!"
    u = a.read(fs * 20)
    print "Gone!"
    fmt = 'h' * (len(u) / 2)
    out = struct.unpack(fmt, u)
    s = [float(z) / 32767 for z in out]
else:
    f = open(filename, "r")
    s = []
    l = f.readline()
    l = f.readline()
    while len(l) > 2:
        s.append(float(l.strip().split(' ',1)[1]))
        l = f.readline()
    f.close()
z = s

# Feed the sampled data into the modem
pw,bb,s,d,b = pskreceive(fs = fs,             # Sample frequency
                         freq = carrier_freq, # Carrier frequency
                         baudrate = baudrate,
                         signal = s
            )


constelplot(s)

#f = open("clean", "r")
#s = []
#l = f.readline()
#l = f.readline()
#while len(l) > 2:
#    s.append(float(l.strip().split(' ',1)[1]))
#    l = f.readline()
#f.close()

#pwc,bbc,sc,dc,bc = pskreceive(fs=fs,     # Sample frequency
#               freq=12800,    # Carrier frequency
#               baudrate=3392,
#               signal = s
#            )

def segplot(v, sp):
    p1 = sp - 7 - 52
    p2 = sp + 7 + 130
    angplot(v[p1:p2])
