data module Bits
begin
    exports
    begin
	sorts
	    BIT
	functions
	    0 : -> BIT
	    1 : -> BIT
	    flip : BIT -> BIT
    end
    equations
    [B1] flip(0) = 1
    [B2] flip(1) = 0
end Bits

data module Data
begin
    exports
    begin
	sorts
	    DATA
	functions
	    'a : -> DATA
	    'b : -> DATA
	    'c : -> DATA
	    'd : -> DATA
	    'e : -> DATA
    end
end Data

data module Frames
begin
    exports
    begin
	sorts
	    FRAME
	functions
	    frame : BIT # DATA -> FRAME
	    frame-error : -> FRAME
	    frame-bit : FRAME -> BIT
	    frame-data : FRAME -> DATA
    end
    imports
	Data, Bits, Booleans
    variables
	d : -> DATA
	b : -> BIT
    equations
    [1] frame-bit(frame(b, d)) = b
    [2] frame-data(frame(b, d)) = d
end Frames

data module Acknowledgements
begin
    exports
    begin
	sorts
	    ACK
	functions
	    ack : BIT -> ACK
	    ack-error : -> ACK
	    ack-bit : ACK -> BIT
    end
    imports
	Bits, Booleans
    variables
	b : -> BIT
    equations
    [1] ack-bit(ack(b)) = b
end Acknowledgements

process module ABPx
begin
    imports
	Bits, Data, Frames, Acknowledgements
    atoms
	input : DATA
	send-frame : FRAME
	receive-ack-or-error : ACK
	receive-frame : FRAME
	send-frame-or-error : FRAME
	receive-frame-or-error : FRAME
	output : DATA
	send-ack : ACK
	receive-ack : ACK
	send-ack-or-error : ACK
	frame-comm : FRAME
	frame-or-error : FRAME
	ack-comm : ACK
	ack-or-error : ACK
    processes
	Sender
	Receive-Message : BIT
	Send-Frame : BIT # DATA
	Receive-Ack : BIT # DATA
	K
	K : BIT # DATA
	Receiver
	Receive-Frame : BIT
	Send-Ack : BIT
	Send-Message : FRAME
	L
	L : BIT
	ABP
    sets
	of atoms
	    H = { send-frame(f), receive-frame(f) | f in FRAME }
		+ { send-frame-or-error(f), receive-frame-or-error(f)
		    | f in FRAME }
		+ { send-ack(a), receive-ack(a) | a in ACK }
		+ { send-ack-or-error(a), receive-ack-or-error(a) | a in ACK }
	    I = { frame-comm(f), frame-or-error(f) | f in FRAME }
		+ { ack-comm(a), ack-or-error(a) | a in ACK }
	of BIT
	    Bit-Set = { 0, 1 }
	of DATA
	    DATA-Set = { 'a, 'b, 'c, 'd, 'e }
    communications
	send-frame(f) | receive-frame(f) = frame-comm(f) for f in FRAME
	send-frame-or-error(f) | receive-frame-or-error(f) =
	    frame-or-error(f) for f in FRAME
	send-ack(a) | receive-ack(a) = ack-comm(a) for a in ACK
	send-ack-or-error(a) | receive-ack-or-error(a) =
	    ack-or-error(a) for a in ACK
    variables
	f : -> FRAME
	b : -> BIT
	d : -> DATA
	a : -> ACK
    definitions
	Sender = Receive-Message(0)
	Receive-Message(b) = sum(d in DATA-Set, input(d) . Send-Frame(b,d))
	Send-Frame(b,d) = send-frame(frame(b,d)) . Receive-Ack(b,d)
	Receive-Ack(b,d) =
		sum(a in ACK,
		    receive-ack-or-error(a) . (
			[flip(ack-bit(a)) = b] -> Send-Frame(b, d)
		    +   [a = ack-error] -> Send-Frame(b, d)
		    +   [ack-bit(a) = b] -> Receive-Message(flip(b))
		    )
		)

	K = sum(d in DATA-Set, sum(b in Bit-Set, receive-frame(frame(b,d)) . K(b,d) ))
	K(b,d) = (
		    skip . send-frame-or-error(frame(b,d))
		+   skip . send-frame-or-error(frame-error)
		) . K

	Receiver = Receive-Frame(0)
	Receive-Frame(b) =
		sum(f in FRAME,
		    receive-frame-or-error(f) . (
			[flip(frame-bit(f)) = b] -> Send-Ack(flip(b))
		    +   [f = frame-error] -> Send-Ack(flip(b))
		    +   [frame-bit(f) = b] -> Send-Message(f)
		    )
		)
	Send-Ack(b) = send-ack(ack(b)) . Receive-Frame(flip(b))
	Send-Message(frame(b,d)) = output(d) . Send-Ack(b)

	L = sum(b in Bit-Set, receive-ack(ack(b)) . L(b) )
	L(b) = (
		    skip . send-ack-or-error(ack(b))
		+   skip . send-ack-or-error(ack-error)
		) . L

	ABP = hide(I, encaps(H, Sender || Receiver || K || L ))
end ABPx
