	(*********************)
	(*                   *)
	(*     FUNCTIONS     *)
	(*                   *)
	(*********************)


FUNCTION BitToWord : WORD

{ G:"Conversion" }
{ DE:"Compose a word from 16 bits" }

	VAR_INPUT
	b0 : BOOL; 	{ DE:"Bit 0" }
	b1 : BOOL; 	{ DE:"Bit 1" }
	b2 : BOOL; 	{ DE:"Bit 2" }
	b3 : BOOL; 	{ DE:"Bit 3" }
	b4 : BOOL; 	{ DE:"Bit 4" }
	b5 : BOOL; 	{ DE:"Bit 5" }
	b6 : BOOL; 	{ DE:"Bit 6" }
	b7 : BOOL; 	{ DE:"Bit 7" }
	b8 : BOOL; 	{ DE:"Bit 8" }
	b9 : BOOL; 	{ DE:"Bit 9" }
	b10 : BOOL; 	{ DE:"Bit 10" }
	b11 : BOOL; 	{ DE:"Bit 11" }
	b12 : BOOL; 	{ DE:"Bit 12" }
	b13 : BOOL; 	{ DE:"Bit 13" }
	b14 : BOOL; 	{ DE:"Bit 14" }
	b15 : BOOL; 	{ DE:"Bit 15" }
	END_VAR

	{ CODE:IL }
	LD		b15
	TO_UINT
	SHL		15
	ST		BitToWord

	LD		b14
	TO_UINT
	SHL		14
	ADD		BitToWord
	ST		BitToWord

	LD		b13
	TO_UINT
	SHL		13
	ADD		BitToWord
	ST		BitToWord

	LD		b12
	TO_UINT
	SHL		12
	ADD		BitToWord
	ST		BitToWord

	LD		b11
	TO_UINT
	SHL		11
	ADD		BitToWord
	ST		BitToWord

	LD		b10
	TO_UINT
	SHL		10
	ADD		BitToWord
	ST		BitToWord

	LD		b9
	TO_UINT
	SHL		9
	ADD		BitToWord
	ST		BitToWord

	LD		b8
	TO_UINT
	SHL		8
	ADD		BitToWord
	ST		BitToWord

	LD		b7
	TO_UINT
	SHL		7
	ADD		BitToWord
	ST		BitToWord

	LD		b6
	TO_UINT
	SHL		6
	ADD		BitToWord
	ST		BitToWord

	LD		b5
	TO_UINT
	SHL		5
	ADD		BitToWord
	ST		BitToWord

	LD		b4
	TO_UINT
	SHL		4
	ADD		BitToWord
	ST		BitToWord

	LD		b3
	TO_UINT
	SHL		3
	ADD		BitToWord
	ST		BitToWord

	LD		b2
	TO_UINT
	SHL		2
	ADD		BitToWord
	ST		BitToWord

	LD		b1
	TO_UINT
	SHL		1
	ADD		BitToWord
	ST		BitToWord

	LD		b0
	TO_UINT
	ADD		BitToWord
	ST		BitToWord

END_FUNCTION


FUNCTION BitToByte : USINT

{ G:"Conversion" }
{ DE:"Compose a byte from 8 bits" }

	VAR_INPUT
	b0 : BOOL; 	{ DE:"Bit 0" }
	b1 : BOOL; 	{ DE:"Bit 1" }
	b2 : BOOL; 	{ DE:"Bit 2" }
	b3 : BOOL; 	{ DE:"Bit 3" }
	b4 : BOOL; 	{ DE:"Bit 4" }
	b5 : BOOL; 	{ DE:"Bit 5" }
	b6 : BOOL; 	{ DE:"Bit 6" }
	b7 : BOOL; 	{ DE:"Bit 7" }
	END_VAR

	{ CODE:IL }
	LD		b7
	TO_USINT
	SHL		7
	ST		BitToByte

	LD		b6
	TO_USINT
	SHL		6
	ADD		BitToByte
	ST		BitToByte

	LD		b5
	TO_USINT
	SHL		5
	ADD		BitToByte
	ST		BitToByte

	LD		b4
	TO_USINT
	SHL		4
	ADD		BitToByte
	ST		BitToByte

	LD		b3
	TO_USINT
	SHL		3
	ADD		BitToByte
	ST		BitToByte

	LD		b2
	TO_USINT
	SHL		2
	ADD		BitToByte
	ST		BitToByte

	LD		b1
	TO_USINT
	SHL		1
	ADD		BitToByte
	ST		BitToByte

	LD		b0
	TO_USINT
	ADD		BitToByte
	ST		BitToByte

END_FUNCTION


FUNCTION ByteToWord : UINT

{ G:"Conversion" }
{ DE:"Compose a word from 2 bytes" }

	VAR_INPUT
	byte0 : BYTE; 	{ DE:"Low byte" }
	byte1 : BYTE; 	{ DE:"High byte" }
	END_VAR

	{ CODE:IL }
	(*---------- WORD in memoria IEEE --------*)
	(*										  *)
	(*	WORD -> | H byte1 | L byte0 |		  *)
	(*										  *)
	(*----------------------------------------*)

	(*	Low byte *)

	LD		byte0
	TO_UINT
	ST		ByteToWord

	(*	High byte *)

	LD		byte1
	TO_UINT
	SHL		8
	ADD		ByteToWord
	ST		ByteToWord

END_FUNCTION

	(***************************)
	(*                         *)
	(*     FUNCTION BLOCKS     *)
	(*                         *)
	(***************************)


FUNCTION_BLOCK Pulse

{ G:"Timers" }
{ DE:"Pulse generator" }

	VAR_INPUT
	enable : BOOL; 	{ DE:"Enable Input" }
	period : UINT; 	{ DE:"Period [number of function block call]" }
	END_VAR

	VAR_OUTPUT
	out : BOOL; 	{ DE:"Pulse Signal" }
	END_VAR

	VAR
	cnt : UINT; 
	END_VAR

	{ CODE:IL }

		LD		enable
		JMPC	l0

		LD		0
		ST		cnt
		LD		FALSE
		ST		out
		RET

l0:

		LD		cnt
		ADD		1
		ST		cnt

		LD		cnt
		GE		period
		ST		out
		RETCN

l1:

		LD		0
		ST		cnt

END_FUNCTION_BLOCK


FUNCTION_BLOCK FF_D

{ G:"Bistable" }
{ DE:"D-type flip-flop" }

	VAR_INPUT
	d : BOOL; 	{ DE:"Input" }
	clk : BOOL; 	{ DE:"Clock" }
	END_VAR

	VAR_OUTPUT
	q : BOOL; 	{ DE:"Out" }
	END_VAR

	VAR
	m : BOOL := TRUE; 
	ok : BOOL; 
	END_VAR

	{ CODE:IL }	
	LD		clk
	ANDN	m
	ST		ok
	
	LD		clk
	ST		m

	LD		ok
	RETCN	

	LD		d
	ST		q

END_FUNCTION_BLOCK


FUNCTION_BLOCK ByteToBit

{ G:"Conversion" }
{ DE:"Split a byte into bits" }

	VAR_INPUT
	byte : BYTE; 	{ DE:"Byte Input" }
	END_VAR

	VAR_OUTPUT
	b0 : BOOL; 	{ DE:"Bit 0" }
	b1 : BOOL; 	{ DE:"Bit 1" }
	b2 : BOOL; 	{ DE:"Bit 2" }
	b3 : BOOL; 	{ DE:"Bit 3" }
	b4 : BOOL; 	{ DE:"Bit 4" }
	b5 : BOOL; 	{ DE:"Bit 5" }
	b6 : BOOL; 	{ DE:"Bit 6" }
	b7 : BOOL; 	{ DE:"Bit 7" }
	END_VAR

	{ CODE:IL }
			LD		byte
			AND		16#0001
			NE		0
			ST		b0

			LD		byte
			AND		16#0002
			NE		0
			ST		b1

			LD		byte
			AND		16#0004
			NE		0
			ST		b2

			LD		byte
			AND		16#0008
			NE		0
			ST		b3

			LD		byte
			AND		16#0010
			NE		0
			ST		b4

			LD		byte
			AND		16#0020
			NE		0
			ST		b5

			LD		byte
			AND		16#0040
			NE		0
			ST		b6

			LD		byte
			AND		16#0080
			NE		0
			ST		b7

END_FUNCTION_BLOCK


FUNCTION_BLOCK WordToBit

{ G:"Conversion" }
{ DE:"Split a word into bits" }

	VAR_INPUT
	word : WORD; 	{ DE:"Word Input" }
	END_VAR

	VAR_OUTPUT
	b0 : BOOL; 	{ DE:"Bit 0" }
	b1 : BOOL; 	{ DE:"Bit 1" }
	b2 : BOOL; 	{ DE:"Bit 2" }
	b3 : BOOL; 	{ DE:"Bit 3" }
	b4 : BOOL; 	{ DE:"Bit 4" }
	b5 : BOOL; 	{ DE:"Bit 5" }
	b6 : BOOL; 	{ DE:"Bit 6" }
	b7 : BOOL; 	{ DE:"Bit 7" }
	b8 : BOOL; 	{ DE:"Bit 8" }
	b9 : BOOL; 	{ DE:"Bit 9" }
	b10 : BOOL; 	{ DE:"Bit 10" }
	b11 : BOOL; 	{ DE:"Bit 11" }
	b12 : BOOL; 	{ DE:"Bit 12" }
	b13 : BOOL; 	{ DE:"Bit 13" }
	b14 : BOOL; 	{ DE:"Bit 14" }
	b15 : BOOL; 	{ DE:"Bit 15" }
	END_VAR

	{ CODE:IL }
			LD		word
			AND		16#0001
			NE		0
			ST		b0

			LD		word
			AND		16#0002
			NE		0
			ST		b1

			LD		word
			AND		16#0004
			NE		0
			ST		b2

			LD		word
			AND		16#0008
			NE		0
			ST		b3

			LD		word
			AND		16#0010
			NE		0
			ST		b4

			LD		word
			AND		16#0020
			NE		0
			ST		b5

			LD		word
			AND		16#0040
			NE		0
			ST		b6

			LD		word
			AND		16#0080
			NE		0
			ST		b7

			LD		word
			AND		16#0100
			NE		0
			ST		b8

			LD		word
			AND		16#0200
			NE		0
			ST		b9

			LD		word
			AND		16#0400
			NE		0
			ST		b10

			LD		word
			AND		16#0800
			NE		0
			ST		b11

			LD		word
			AND		16#1000
			NE		0
			ST		b12

			LD		word
			AND		16#2000
			NE		0
			ST		b13

			LD		word
			AND		16#4000
			NE		0
			ST		b14

			LD		word
			AND		16#8000
			NE		0
			ST		b15

END_FUNCTION_BLOCK


FUNCTION_BLOCK WordToByte

{ G:"Conversion" }
{ DE:"Split a word into two bytes" }

	VAR_INPUT
	w : UINT; 	{ DE:"Word Input" }
	END_VAR

	VAR_OUTPUT
	byte0 : USINT; 	{ DE:"Low byte" }
	byte1 : USINT; 	{ DE:"High byte" }
	END_VAR

	{ CODE:IL }
	(*---------- WORD in memoria IEEE --------*)
	(*										  *)
	(*	WORD -> | H byte1 | L byte0 |		  *)
	(*										  *)
	(*----------------------------------------*)

	(*	Low byte *)

	LD		w
	TO_USINT
	ST		byte0

	(*	High byte *)

	LD		w
	SHR		8
	TO_USINT
	ST		byte1

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTD

	{ G:"Counters" }
	{ DE:"Down counter" }

	VAR_INPUT
	CD : BOOL; 	{ DE:"Count-down on input rising edge" }
	LD : BOOL; 	{ DE:"Preset counter input" }
	PV : INT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Count-down output" }
	CV : INT; 	{ DE:"Counter current value" }
	END_VAR

	VAR
	CDEDGE : BOOL; 
	MEMCD : BOOL; 
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		LD
	JMPCN	l0
	
	LD		PV
	ST		CV
	JMP		l1

	(*	Check for increment enable *)
l0:
	LD 	CD
	ANDN 	MEMCD
	ST 		CDEDGE
	
	LD 		CD
	ST 		MEMCD
	
	LD 		CDEDGE
	AND(	CV
	GT		-32768
	)
	JMPCN	l1
	
	LD		CV
	SUB		1
	ST		CV
	
l1:

	(*	Counter output	*)
	LD		CV
	LE		0
	ST		Q
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTD_DINT

	{ G:"Counters" }
	{ DE:"Down counter with DINT data type" }

	VAR_INPUT
	CD : BOOL; 	{ DE:"Count-down on input rising edge" }
	LD : BOOL; 	{ DE:"Preset counter input" }
	PV : DINT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Count-down output" }
	CV : DINT; 	{ DE:"Counter current value" }
	END_VAR

	VAR
	CDEDGE : BOOL; 
	MEMCD : BOOL; 
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		LD
	JMPCN	l0
	
	LD		PV
	ST		CV
	JMP		l1

	(*	Check for increment enable *)
l0:
	LD 	CD
	ANDN 	MEMCD
	ST 		CDEDGE
	
	LD 		CD
	ST 		MEMCD
	
	LD 		CDEDGE
	AND(	CV
	GT		-2147483648
	)
	JMPCN	l1
	
	LD		CV
	SUB		1
	ST		CV
	
l1:

	(*	Counter output	*)
	LD		CV
	LE		0
	ST		Q
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTD_UDINT

	{ G:"Counters" }
	{ DE:"Down counter with UDINT data type" }

	VAR_INPUT
	CD : BOOL; 	{ DE:"Count-down on input rising edge" }
	LD : BOOL; 	{ DE:"Preset counter input" }
	PV : UDINT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Count-down output" }
	CV : UDINT; 	{ DE:"Counter current value" }
	END_VAR

	VAR
	CDEDGE : BOOL; 
	MEMCD : BOOL; 
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		LD
	JMPCN	l0
	
	LD		PV
	ST		CV
	JMP		l1

	(*	Check for increment enable *)
l0:
	LD 	CD
	ANDN 	MEMCD
	ST 		CDEDGE
	
	LD 		CD
	ST 		MEMCD
	
	LD 		CDEDGE
	AND(	CV
	GT		0
	)
	JMPCN	l1
	
	LD		CV
	SUB		1
	ST		CV
	
l1:

	(*	Counter output	*)
	LD		CV
	LE		0
	ST		Q
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTU

	{ G:"Counters" }
	{ DE:"Up counter" }

	VAR_INPUT
	CU : BOOL; 	{ DE:"Count-up on input rising edge" }
	R : BOOL; 	{ DE:"Reset counter input" }
	PV : INT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Count-up output" }
	CV : INT; 	{ DE:"Counter current value" }
	END_VAR

	VAR
	CUEDGE : BOOL; 
	MEMCU : BOOL; 
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		R
	JMPCN	l0
	
	LD		0
	ST		CV
	JMP		l1

	(*	Check for increment enable *)
l0:
	LD		CU
	ANDN 	MEMCU
	ST 		CUEDGE
	
	LD 		CU
	ST 		MEMCU
	
	LD 		CUEDGE
	AND(	CV
	LT		16#7FFF
	)
	JMPCN	l1
	
	LD		CV
	ADD		1
	ST		CV
	
l1:

	(*	Counter output	*)
	LD		CV
	GE		PV
	ST		Q
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTU_DINT

	{ G:"Counters" }
	{ DE:"Up counter with DINT data type" }

	VAR_INPUT
	CU : BOOL; 	{ DE:"Count-up on input rising edge" }
	R : BOOL; 	{ DE:"Reset counter input" }
	PV : DINT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Count-up output" }
	CV : DINT; 	{ DE:"Counter current value" }
	END_VAR

	VAR
	CUEDGE : BOOL; 
	MEMCU : BOOL; 
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		R
	JMPCN	l0
	
	LD		0
	ST		CV
	JMP		l1

	(*	Check for increment enable *)
l0:
	LD		CU
	ANDN 	MEMCU
	ST 		CUEDGE
	
	LD 		CU
	ST 		MEMCU
	
	LD 		CUEDGE
	AND(	CV
	LT		16#7FFFFFFF
	)
	JMPCN	l1
	
	LD		CV
	ADD		1
	ST		CV
	
l1:

	(*	Counter output	*)
	LD		CV
	GE		PV
	ST		Q
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTU_UDINT

	{ G:"Counters" }
	{ DE:"Up counter with UDINT data type" }

	VAR_INPUT
	CU : BOOL; 	{ DE:"Count-up on input rising edge" }
	R : BOOL; 	{ DE:"Reset counter input" }
	PV : UDINT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Count-up output" }
	CV : UDINT; 	{ DE:"Counter current value" }
	END_VAR

	VAR
	CUEDGE : BOOL; 
	MEMCU : BOOL; 
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		R
	JMPCN	l0
	
	LD		0
	ST		CV
	JMP		l1

	(*	Check for increment enable *)
l0:
	LD		CU
	ANDN 	MEMCU
	ST 		CUEDGE
	
	LD 		CU
	ST 		MEMCU
	
	LD 		CUEDGE
	AND(	CV
	LT		16#FFFFFFFF
	)
	JMPCN	l1
	
	LD		CV
	ADD		1
	ST		CV
	
l1:

	(*	Counter output	*)
	LD		CV
	GE		PV
	ST		Q
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTUD

	{ G:"Counters" }
	{ DE:"Up/down counter" }

	VAR_INPUT
	CU : BOOL; 	{ DE:"Count-up input" }
	CD : BOOL; 	{ DE:"Count-down input" }
	R : BOOL; 	{ DE:"Reset counter input" }
	LD : BOOL; 	{ DE:"Preset counter input" }
	PV : INT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	QU : BOOL; 	{ DE:"Count-up output" }
	QD : BOOL; 	{ DE:"Count-down output" }
	CV : INT; 	{ DE:"Counter current value" }
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		R
	JMPCN	l0
	
	LD		0
	ST		CV
	JMP		l10

l0:
	(*	Check for reset input *)
	LD		LD
	JMPCN	l1
	
	LD		PV
	ST		CV
	JMP		l10


	(*	Check for simultaneous inputs on *)
l1:
	LD		CU
	AND		CD
	JMPC	l10

	(*	Check for increment enable *)
	LD		CU
	AND(	CV
	LT		16#7FFF
	)
	JMPCN	l2
	
	LD		CV
	ADD		1
	ST		CV

	(*	Check for decrement input *)
l2:

	LD		CD
	AND(	CV
	GT		-32768
	)
	JMPCN	l10
	
	LD		CV
	SUB		1
	ST		CV
	
l10:

	(*	Up counter output	*)
	LD		CV
	GE		PV
	ST		QU

	(*	Down counter output	*)
	LD		CV
	LE		0
	ST		QD
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTUD_DINT

	{ G:"Counters" }
	{ DE:"Up/down counter with DINT data type" }

	VAR_INPUT
	CU : BOOL; 	{ DE:"Count-up input" }
	CD : BOOL; 	{ DE:"Count-down input" }
	R : BOOL; 	{ DE:"Reset counter input" }
	LD : BOOL; 	{ DE:"Preset counter input" }
	PV : DINT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	QU : BOOL; 	{ DE:"Count-up output" }
	QD : BOOL; 	{ DE:"Count-down output" }
	CV : DINT; 	{ DE:"Counter current value" }
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		R
	JMPCN	l0
	
	LD		0
	ST		CV
	JMP		l10

l0:
	(*	Check for reset input *)
	LD		LD
	JMPCN	l1
	
	LD		PV
	ST		CV
	JMP		l10


	(*	Check for simultaneous inputs on *)
l1:
	LD		CU
	AND		CD
	JMPC	l10

	(*	Check for increment enable *)
	LD		CU
	AND(	CV
	LT		16#7FFFFFFF
	)
	JMPCN	l2
	
	LD		CV
	ADD		1
	ST		CV

	(*	Check for decrement input *)
l2:

	LD		CD
	AND(	CV
	GT		-2147483648
	)
	JMPCN	l10
	
	LD		CV
	SUB		1
	ST		CV
	
l10:

	(*	Up counter output	*)
	LD		CV
	GE		PV
	ST		QU

	(*	Down counter output	*)
	LD		CV
	LE		0
	ST		QD
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK CTUD_UDINT

	{ G:"Counters" }
	{ DE:"Up/down counter with UDINT data type" }

	VAR_INPUT
	CU : BOOL; 	{ DE:"Count-up input" }
	CD : BOOL; 	{ DE:"Count-down input" }
	R : BOOL; 	{ DE:"Reset counter input" }
	LD : BOOL; 	{ DE:"Preset counter input" }
	PV : UDINT; 	{ DE:"Preset value" }
	END_VAR

	VAR_OUTPUT
	QU : BOOL; 	{ DE:"Count-up output" }
	QD : BOOL; 	{ DE:"Count-down output" }
	CV : UDINT; 	{ DE:"Counter current value" }
	END_VAR

	{ CODE:IL }
	(*	Check for reset input *)
	LD		R
	JMPCN	l0
	
	LD		0
	ST		CV
	JMP		l10

l0:
	(*	Check for reset input *)
	LD		LD
	JMPCN	l1
	
	LD		PV
	ST		CV
	JMP		l10


	(*	Check for simultaneous inputs on *)
l1:
	LD		CU
	AND		CD
	JMPC	l10

	(*	Check for increment enable *)
	LD		CU
	AND(	CV
	LT		16#FFFFFFFF
	)
	JMPCN	l2
	
	LD		CV
	ADD		1
	ST		CV

	(*	Check for decrement input *)
l2:

	LD		CD
	AND(	CV
	GT		0
	)
	JMPCN	l10
	
	LD		CV
	SUB		1
	ST		CV
	
l10:

	(*	Up counter output	*)
	LD		CV
	GE		PV
	ST		QU

	(*	Down counter output	*)
	LD		CV
	LE		0
	ST		QD
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK TOF

	{ G:"Timers" }
	{ DE:"Off-delay timer" }

	VAR_INPUT
	IN : BOOL; 	{ DE:"Timer input source" }
	PT : UDINT; 	{ DE:"Preset time value [ms]" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Timer output" }
	ET : UDINT; 	{ DE:"Timer current value [ms]" }
	END_VAR

	VAR_EXTERNAL
	sysTimer : UDINT; 	{ DE:"1 ms system timer" }
	END_VAR

	VAR
	timStart : UDINT; 	{ DE:"Time value at start of counting" }
	END_VAR

	{ CODE:IL }
	(*	Check if in counting	*)

	LD		IN
	JMPC	l10
	
	(*	Check if falling edge of IN	*)
	LD		Q
	RETCN
	
	(*	Check if already in counting *)
	LD		timStart
	EQ		0
	JMPCN	l0
	
	(*	Start of counting *)
	LD		sysTimer
	ST		timStart

l0:
	
	(*	Update timer and check if time elapsed *)
	LD		sysTimer
	SUB		timStart
	ST		ET
	GE		PT
	STN		Q
	JMPCN	l1
	
	(*	Limit actual time value *)
	LD		PT
	ST		ET

l1:
	
	RET

l10:

	(*	Reset status *)
	LD		0
	ST		ET
	ST		timStart
	LD		TRUE
	ST		Q

END_FUNCTION_BLOCK


FUNCTION_BLOCK TON

	{ G:"Timers" }
	{ DE:"On-delay timer" }

	VAR_INPUT
	IN : BOOL; 	{ DE:"Timer input source" }
	PT : UDINT; 	{ DE:"Preset time value [ms]" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Timer output" }
	ET : UDINT; 	{ DE:"Timer current value [ms]" }
	END_VAR

	VAR_EXTERNAL
	sysTimer : UDINT; 	{ DE:"1 ms system timer" }
	END_VAR

	VAR
	timStart : UDINT; 	{ DE:"Time value at start of counting" }
	END_VAR

	{ CODE:IL }
	(*	Check if in counting	*)

	LD		IN
	JMPCN	l10

	(*	Check if Q is TRUE *)
	LD		Q
	JMPC	l1
	
	(*	Check if already in counting *)
	LD		timStart
	EQ		0
	JMPCN	l0

	(*	Start of counting *)
	LD		sysTimer
	ST		timStart
	
l0:

	(*	Update timer and check if time elapsed *)
	LD		sysTimer
	SUB		timStart
	ST		ET
	GE		PT
	ST		Q
	JMPCN	l1

	(*	Limit actual time value *)
	LD		PT
	ST		ET

l1:

	RET

l10:

	(*	Reset status *)
	LD		0
	ST		ET
	ST		timStart
	LD		FALSE
	ST		Q

END_FUNCTION_BLOCK


FUNCTION_BLOCK TP

	{ G:"Timers" }
	{ DE:"Pulse timing" }

	VAR_INPUT
	IN : BOOL; 	{ DE:"Timer input source" }
	PT : UDINT; 	{ DE:"Preset time value [ms]" }
	END_VAR

	VAR_OUTPUT
	Q : BOOL; 	{ DE:"Pulse output" }
	ET : UDINT; 	{ DE:"Actual timer value [ms]" }
	END_VAR

	VAR_EXTERNAL
	sysTimer : UDINT; 	{ DE:"1 ms system timer" }
	END_VAR

	VAR
	timStart : UDINT; 	{ DE:"Time value at start of counting" }
	END_VAR

	{ CODE:IL }
	(*	Check if in counting	*)

	LD		Q
	JMPCN	l10
	
	(*	Update actual time *)
	LD		sysTimer
	SUB		timStart
	ST		ET	
	
	(*	Update output *)
	LD		ET
	LT		PT
	ST		Q
	RET
	
l10:

	(*	Check for input status *)

	LD		IN
	JMPCN	l11
	
	LD		ET
	GE		PT
	RETC

	LD		sysTimer
	ST		timStart
	
	LD		TRUE
	ST		Q
	
l11:
	
	(*	No input and no counting active *)
	LD		0
	ST		ET
	

END_FUNCTION_BLOCK


FUNCTION_BLOCK SR

	{ G:"Bistable" }
	{ DE:"Bistable, set dominant" }

	VAR_INPUT
	s1 : BOOL; 	{ DE:"Set" }
	r : BOOL; 	{ DE:"Reset" }
	END_VAR

	VAR_OUTPUT
	q1 : BOOL; 	{ DE:"Out" }
	END_VAR

	{ CODE:IL }	
	LDN		r
	AND		q1
	OR		s1
	ST		q1

END_FUNCTION_BLOCK


FUNCTION_BLOCK RS

	{ G:"Bistable" }
	{ DE:"Bistable, reset dominant" }

	VAR_INPUT
	s : BOOL; 	{ DE:"Set" }
	r1 : BOOL; 	{ DE:"Reset" }
	END_VAR

	VAR_OUTPUT
	q1 : BOOL; 	{ DE:"Out" }
	END_VAR

	{ CODE:IL }
	LD		s
	OR		q1
	ANDN	r1
	ST		q1

END_FUNCTION_BLOCK


FUNCTION_BLOCK R_TRIG

	{ G:"Edge detection" }
	{ DE:"Rising edge detector" }

	VAR_INPUT
	clk : BOOL; 	{ DE:"Clock" }
	END_VAR

	VAR_OUTPUT
	q : BOOL; 	{ DE:"Out" }
	END_VAR

	VAR
	m : BOOL := TRUE; 
	END_VAR

	{ CODE:IL }
	LD		clk
	ANDN	m
	ST		q

	LD		clk
	ST		m

END_FUNCTION_BLOCK


FUNCTION_BLOCK F_TRIG

	{ G:"Edge detection" }
	{ DE:"Falling edge detector" }

	VAR_INPUT
	clk : BOOL; 	{ DE:"Clock" }
	END_VAR

	VAR_OUTPUT
	q : BOOL; 	{ DE:"Out" }
	END_VAR

	VAR
	m : BOOL := FALSE; 
	END_VAR

	{ CODE:IL }
	LDN		clk
	AND		m
	ST		q

	LD		clk
	ST		m

END_FUNCTION_BLOCK

