(* D'après le code Lucid Synchrone de Gwenael Delaval *)

let node xor (a, b) = o where
  rec o = (a && (not b)) || (b && (not a))

(************************* cyclic_encoding *******************************)

(*
let node div_X3_X_1 i = (reg0,reg1,reg2) where 
  rec reg0 = false fby (xor(i, back)) 
  and reg1 = false fby reg0 
  and reg2 = false fby (xor(reg1, back))
  and back = reg2
*)

let node add_tail_bits_50_3 i = merge (1^50 0^3) i false

let node div_X3_X_1 p = (reg0,reg1,reg2) where 
  rec p' =  add_tail_bits_50_3 p
  and reg0 = false fby (xor(p', back)) 
  and reg1 = false fby reg0
  and reg2 = false fby (xor(reg1, back)) 
  and back = add_tail_bits_50_3 (reg2 when (1^50 0^3))

(* remainder of the division by X^3 + X + 1 *)
let node redundancy i = (bit0,bit1,bit2) where
  rec (reg0,reg1,reg2) = div_X3_X_1 i
  and bit0 = reg0  when (0^50 100)
  and bit1 = reg1  when (0^50 100)
  and bit2 = reg2  when (0^50 100)

(* join data and redundancy *)
let node join_50_3 (i, bit0, bit1, bit2) = o3 where 
  rec o1 = merge (1^50 0) i  bit0
  and o2 = merge (1^51 0) o1 bit1
  and o3 = merge (1^52 0) o2 bit2

(* cyclic encoder: X^3 + X + 1 *)
let node cyclic_encoding i = o where 
  rec (bit0, bit1, bit2) = redundancy i
  and o = join_50_3 (i, buffer bit0, 
                        buffer bit1, 
                        buffer bit2)


(*************************** convolutional_encoding ************************)
let node add_tail_bits_185_4 i = merge (1^185 0^4) i false

let node mult_polys i = (o1, o2) where
  rec i' = add_tail_bits_185_4 i
  and reg0 = false fby i'
  and reg1 = false fby reg0
  and reg2 = false fby reg1
  and reg3 = false fby reg2
  and o1 = xor (xor (xor (i', reg0), reg2), reg3)  (* X^4 + X^3 + X + 1 *)
  and o2 = xor (xor (i', reg2), reg3)              (* X^4 + X^3 + 1 *)

(* to merge the two flows of redundancy *)
let node multiplexer (i1, i2) = o where
  rec o = merge (10) i1 i2

(* convolutional encoder: X^4 + X^3 + 1 and X^4 + X^3 + X + 1 *)
let node convolutional_encoding i = o where
  rec (p1, p2) = mult_polys i
  and o = multiplexer (p1, buffer p2)


(********** split_speech **********)

let node split_speech i = (o_Ia, o_Ib, o_II) where
  rec o_Ia = i when (1^50 0^210)
  and o_Ib = i when (0^50 1^132 0^78)
  and o_II = i when (0^182 1^78) 


(********** gsm_encoding ***********)

let node gsm_encoding_with_buffers i = o where
  rec (part_Ia, part_Ib, part_II) = split_speech i
  and part_Ia_enc = cyclic_encoding (buffer part_Ia)
  and part_I = merge (1^53 0^132) part_Ia_enc (buffer part_Ib)
  and part_I_enc = convolutional_encoding part_I
  and o = merge (1^378 0^78) part_I_enc (buffer part_II)


(******************************************************************************)
(******************************** decodeur GSM ********************************)
(******************************************************************************)

(********** cyclic decoding **********)

let node stutter_50 i = o where
  rec o =  merge (1 0^49) i (buffer (o when (1^49 0)))

let node split3 i = i when (100), i when (010), i when (001)

let node and_by_3 i = o where
  rec i1, i2, i3 = split3 i
  and o = ((buffer ((buffer i1) && i2)) && i3)

let node cyclic_decoding i = o where
  rec (data, redundancy) = (i when (1^50 0^3) , i whenot (1^50 0^3))
  and reencoded_data = cyclic_encoding data
  and code = reencoded_data whenot (1^50 0^3)
  and frame_ok = and_by_3 (code = redundancy) 
  and data_ok = stutter_50 frame_ok
  and current_frame = buffer(data)
  and last_frame = merge 1^50(0) true (buffer(current_frame))
  and o = if data_ok then current_frame else last_frame


(********** convolutional decoding **********) 
(* hamming distance *)
let node hamming_dist ((x1,x2),(y1,y2)) =
  (if x1 = y1 then 0 else 1) + (if x2 = y2 then 0 else 1)

let node convolutional_decoding x = (* non implemente *)
  (x when (01)) when 0^188(1^185 0^4) 
(* code factice, avec le bon type de sortie *)

(********** join speech **********) 
let node join_speech (part_Ia, part_Ib, part_II) = o where
  rec o = merge (1^50 0^210) part_Ia (merge (1^132 0^78) part_Ib part_II)

(********** split encoded speech **********) 
let node split_I_II i = (i when (1^378 0^78), i whenot (1^378 0^78))
let node split_Ia_Ib part_I = 
  (part_I when (1^53 0^132), part_I whenot (1^53 0^132))

let node decode_with_3_buffers i = o where
  rec part_I_enc, part_II = split_I_II i
  and part_I = convolutional_decoding part_I_enc
  and part_Ia_enc, part_Ib = split_Ia_Ib part_I
  and part_Ia = cyclic_decoding part_Ia_enc
  and o = join_speech (buffer(part_Ia), buffer(part_Ib), buffer(part_II))