'
' IcMaster

' V01.00  05.06.12 AD    new started up from imaster 00.36.
'                        + added base ABCL fw upgrade to work with IPAM102.
'                        + added in/out levels.
'                        + added keys/func. for groups 3 to 8.
'                        c chged web UI to new web UI look and feel.
'                        c chged keys mapped to new layout.
'                        ! fixed jump into call reject mode exiting unattended.
'                        ! fixed no key4 leds on entering auto-unattended.
' V01.01  25.06.12 AD    ! fixed web ui syntax errors.
'                        ! fixed bad combined group creation.
'                        + added partial support for A1000, just with A100 layout.
'                        ! fixed file messages streaming method.
'                        ! fixed unattended delivery for HDX using cmd 1.
' V01.02  04.07.12 AD    ! fixed web UI home page help syntax.
' V01.03  10.07.12 AD    c chged audio fifo cleaning, to reduce latency in IC mode, HD.
' V01.04  28.08.12 AD    ! fixed various web ui syntax errors.
'                        ! fixed first part of unattended sometime truncated.
'                        ! fixed last second of custom message truncated.
'                        c chged back to paging subsection after group targets selection.
'                        c chged incoming status routine, used only tmr safe vars.
'                        + added Annuncicom 100/200 allowed to work without USB pen.
'                        + added mechanism to exit for timeout on established call.
' V01.05  30.08.12 AD    ! fixed FD wrong displayed message on PS16 after getting 2 
'                          concurrent call requests.
' V01.06  10.09.12 AD    + added echo cancellation feature (AEC).
' V01.07  26.09.12 AD    ! fixed noise on local custom message using A-law 24Khz.
' V01.08  25.10.12 AD    c chged #110.09 paging/ic method using link.
'                        + added routines with link timoeut mechanism.
'                        + added PS16 selected group message.
'                        ! fixed incorrect custom message delivery timing.
' V01.09  31.01.13 AD    + added new debug trace preprocessor macroes.
'                        + added tuned rtp delay on vlsi1053.
'                        ! fixed #110.07, incorrect paging payload type.
'                        ! fixed #110.16, added BARP flags for extended timout checks.
'                        ! fixed #110.14, hands free mode, paging not closed re-pressing 
'                                button 1.
'                        ! fixed #110.15, PS1 + handsfree/HDX, no client status received, 
'                                exiting to idle
'                        ! fixed issue on gp6map$, typo error, was gp5map$ on stp load.
'                        c chged removed link for paging.
'                        c chged #110.21 PS16 keyboard / functionality changes.
	
	dim ver$(32)
	ver$="1.09 31.01.2013"

	dim nul$

#define TEST_VERSION 1

#define sysi #1 syslog "(i) "+#1
#define sysw #1 syslog "(w) "+#1
#define syse #1 syslog "(e) "+#1
' DEBUG
'#define sysd #1 syslog "(-) "+#1
' else
#define sysd nul$=#1

	syslog "Barix IcMaster "+ver$+" starting..."
	syslog "syslog marks: (-) debug, (i) info, (w) warning, (e) errors"

#define CLEAR_AUDIO_LEVELS  inl=-127:oul=-127

	dim _Mr$(1501)        ' one UDP block
	dim set$              ' Config from EEPROM address 500
	dim set8$             ' Config from EEPROM address 800
	dim set9$             ' Config from EEPROM address 900
	dim state             ' Application state machine
                          '  1 - Idle state
                          '  2 - Incoming call request (plays the ring tone)
                          '  3 - Wait between two rings
                          '  4 - Ongoing call active
                          '  5 - Broadcast (paging) active)
                          '  6 - Unattended mode (entered by button 4, or 10 sec timeout)
                          '  7 - Recording the unattended mode/custom message
                          '  8 - Playing the unattended mode message
                          '  9 - Call forwarding mode (entered by press and hold  button
                          '      4 for 4 seconds)
                          ' -1 - USB media missing

#define STA_IDLE          1
#define STA_INC_CALL_REQ  2
#define STA_WAIT          3
#define STA_OUT_CALL      4
#define STA_PA_BROADCAST  5
#define STA_UNATTENDED    6
#define STA_REC_UNATT     7
#define STA_SEND_UNATT    8
#define STA_CALL_FWD      9
#define STA_SND_CUSTOM    10
#define STA_PLAY_LOCAL    11
#define STA_USB_MISSING   -1

' BARP flags (16-bit bitmask)
#define FLAG_EXTO         1

#define H_UDP_STREAM      4
#define H_UDP_BARP        5
#define H_UDP_MCAST       6
#define H_AUDIO           7

	dim myid              ' master ID
	dim id                ' station id of the current partner
	dim idadr$(2)         ' "y" - master addressed by ID, "n" - by IP
	dim newid             ' station id of the client calling while master is in a call (state 3)
	dim ip$(20)           ' IP address of the current partner
	dim mcastip$(20)      ' Mcast IP
	dim mport             ' mcast port
	dim bcast$(20)        ' bcast address
	dim barip$(20)        ' BARP IP. (used to configure the IP used for the status and control ports
	dim prio              ' Message priority (default 127) 
	dim xt                ' timeout for "ringing" playback
	dim audp,ctlp,statp   ' audio, control and status udp ports
	dim srate             ' sample rate
	dim rly               ' relay on while
	dim bps               ' bytes per sample
	dim disp              ' true if display is present
	dim leds              ' true if key LEDs present (paging station)
	dim name$             ' active station name
	dim nname$            ' next (potentially) station name
	dim aud$(24)
	dim fmt,brate
	dim nousb             ' set to 1 for PS1 as master
	dim itype
	dim pltype

    ' functions
	dim do_page         <gosub 1500>
	dim do_ic_start     <gosub 1600>
	dim do_ic_send      <gosub 1700>
	dim do_ic_recv      <gosub 1800>
	dim open_aud_cfg    <gosub 2100>   ' reopen audio in uncompressed mode
	dim aump3           <gosub 2110>   ' reopen audio in mp3
	dim setvol          <gosub 2120>   ' set volume vol
	dim message         <gosub 6000>   ' display a message
	dim close_fix       <gosub 7100>
	dim set_aud_delay   <gosub 9100>
	dim rid_mask        <gosub 8000>   ' recalculate address map from ID while selecting targets
	dim rgp_mask        <gosub 8200>   ' recalculate address map from group map while selecting groups
	dim open_udp        <gosub 8900>

	dim proto$(200)
	
	dim tid1,tid2,tid3,tid4       ' client IDs associated to target buttons 1,2,3,4
	dim fname$(24)
	dim temp$
	dim cfwtm                     ' Call ForWard TiMer. Used to detect how long the unattended mode key 
	                              ' has been kept pressed before switching from unattended to call 
                                  ' forwarding mode

	' boolean and byte string variables (because of 96 variables BCL limit)
	dim dsunt$(2)                 ' DiSable UNaTtended mode
	dim clsts$(1)                 ' calling party status
	dim tm128$(4)                 ' status message send timer
	dim tmp
	dim _Ms8$(161)                ' need to read from file the correct 20msec chunk
	dim _Ms24$(481)               ' need to read from file the correct 20msec chunk
	
	dim i,l,x,y,z
	dim vol_setup,vol,ovol,ad_gain,mic_gain,inp,stereo,enc
	dim inctm,incst,blktm,unatm,blrtm,csttm

	dim record$(14)
	
	' BGM variables
	dim bgmch                     ' BGM channel to be set
	dim bgmst                     ' BGM change set flag (0-temporary, 1-permanent(write in EEPROM))
	dim bgmcl                     ' BGM channel control. If set to 1, keys 14-16 (now assigned to
                                  ' selecting target 2,3,4) will be assignned to switch to BGM
                                  ' channels 0 (BGM off),1 and 2
	
	' client volume variables (to be set with cmd=5)
	dim clvol                     ' client volume to be set
	dim clset                     ' client volume set flag (0-temporary, 1-store to EEPROM)

	' VOX variables
	dim voxto                     ' Stop VOX streaming if no audio is detected for that amount of time
	dim voxtm                     ' VOX last timer update
	dim voxen                     ' VOX feature enabled. A flag for checking the EEPROM configuration option
	dim voxtr                     ' VOX threshold
	dim vxsnd                     ' VoX SeNDing. A flag used to indicate if a streaming is active
	dim voxll,voxlr               ' Current VOX Voice Level (left and right)
	dim _Mvox$(50)
	dim inl,oul
	dim gp1map$(16)
	dim gp2map$(16)
	dim gp3map$(16)
	dim gp4map$(16)
	dim gp5map$(16)
	dim gp6map$(16)
	dim gp7map$(16)
	dim gp8map$(16)
	
	dim grpmap$(128)              ' destination addres map for testing

	dim connid                    ' connected id
	dim tmr_conn
	dim tmr_129                   ' last call request timer. used to force the master to stop ringing
	                              ' not later than xx seconds after the last cmd-129
	dim linkdst(1,1)              ' link destinations
	dim selgrp
	 
	CLEAR_AUDIO_LEVELS

	' keyboard variables
	' in this application a mix of keyevents and IO polling is used for keyboard/button handling
	' keys that are active while pressed (e.g. PA button) are polled by iostate
	' other keys are handled by the subroutine 5000
	' keys are stored in the kbhit array which is accessed by the application and also by the handler
	' the keyboard handler sets the appropriate item of kbhit to 1 if a key is pressed
	' the application monitors kbhit() and triggers on <>0 value
	' after the key is processed, the application clears kbhit
    ' Used Timers:
	' timer ! timeout,ms ! Purpose         -! Subroutine
	' ------+-----------+------------------+-----------
	'   1   ! 20        ! Keyboard handler ! 5000
	'   2   ! 200       ! Display messages ! 6000
	'       !           ! with timeout     !
	'   3   ! 50        ! VAD enable       ! 6500
	
	on timer1 gosub 5000 : timer 1,30       ' keybd handler, run always
	on timer2 gosub 6000 : timer 2,0        ' by default off
	on timer3 gosub 6500 : timer 3,0        ' by default off
	on timer4 gosub 2054 : timer 4,4000     ' cmd-3 send every 4 seconds (only for state 5)

	dim newip$(16)
	dim key$(3)		' string for reading key events
	dim nkeys		' number of keys supported by the system (other keys will be ignored)
	nkeys=15		' keys numbered 0 to 15
	dim kbhit(111)  ' keyboard status; if set to 1 key was pressed and not yet handled 
	dim sticky(111) ' define the sticky keys here, application should turn off key LED
	dim htype
	dim echo
	dim rtp_delay

	htype=iostate(60000)
	itype=iostate(60008)
	
	sticky(4)=1
	
	' 1 to 8 goups
	sticky(8)=1
	sticky(9)=1
	sticky(10)=1
	sticky(11)=1
	sticky(12)=1
	sticky(13)=1
	sticky(14)=1
	sticky(15)=1

	' halfduplex mode variables and functions
	dim halfd               ' half/full duplex (0 - full duplex, 1 - half duplex)
	' dim maxm1               ' maximum number of resent msg 1
	' dim maxm2               ' maximum number of resent msg 2

	' Read the  settings from EEPROM address 500 (256 bytes)
	open "STP:500" as 2
	read 2,set$
	close 2
	
	' And from address 800
	open "STP:800" as 2
	read 2,set8$
	close 2

	echo=midget(set8$,27,1)
	if echo=1 then sysd "echo cancellation is ON" else sysd "echo cancellation is OFF"
	
	' Get master ID
	myid=midget(set$,39,2)
	
	' Addressing masters by IP or ID ?
	if midget(set8$,75,1)=1 then idadr$="y" else idadr$="n"
	
	' Unattended mode disabled?
	if midget(set8$,77,1)=1	then dsunt$="y" else dsunt$="n"
	sysd "unatt disabled ? "+dsunt$
	
	' BGM control enabled?
	bgmcl=midget(set8$,78,1)

	' Check for VOX/VAD
	voxen=midget(set$,21,1)              ' VOX enable?
	sysd "VOX enable="+str$(voxen)

	if voxen=3 then
	   voxto=midget(set$,24,2)/100       ' Read VOX timeout
	   voxtr=midget(set$,22,2)           ' Read VOX threshold
	   timer 3,100 '40                   ' Start VOX timer
	   sysd "VOX timeout="+str$(voxto)
	   sysd "VOX threshold="+str$(voxtr)
	endif
	
	tid1=midget(set8$,1,1)
	tid2=midget(set8$,2,1)
	tid3=midget(set8$,3,1)
	tid4=midget(set8$,4,1)

	mcastip$=sprintf$("%d",midget(set8$,20+1,1))+"."+sprintf$("%d",midget(set8$,21+1,1))+"."+sprintf$("%d",midget(set8$,22+1,1))+"."+sprintf$("%d",midget(set8$,23+1,1))
	
	if mcastip$="0.0.0.0" then 
	   mport=0
	else
	   mport=midget(set8$,24+1,2)
	endif
	
	halfd=midget(set8$,31,1)
	if halfd=0 then sticky(0)=1
	
	' reading groups from 900
	open "STP:900" as 2
	read 2,set9$
	close 2

	midcpy gp1map$,1,16,set9$
	midcpy gp2map$,1,16,set9$,17
	midcpy gp3map$,1,16,set9$,33
	midcpy gp4map$,1,16,set9$,49
	midcpy gp5map$,1,16,set9$,65
	midcpy gp6map$,1,16,set9$,81
	midcpy gp7map$,1,16,set9$,97
	midcpy gp8map$,1,16,set9$,113
	
	' detect Paging Station
	if htype=25 then 
	   leds=1		' found, it has LEDs on the keyboard
	   nkeys=iostate(60007)-1
	   sysi "Number of keys detected: " + sprintf$("%d",nkeys+1)
	else
	   ' master running on annuncicom
	   leds=0
	   nkeys=1
	   sysw "PS16 not detected, keys limited to 2"
	endif
	
	if or(htype=17,htype=42) then 
		sysw "ANN1000/PS1 detected, disabling USB ..."
		nousb=1
	endif
	
	' mark also the extensions as "sticky"
	if nkeys>15 then 
	   for x=16 to nkeys
	       sticky(x)=1
	   next x
	endif
	
	' timer 2 is used to display messages with a timeout
	dim curmsg

	disp=filesize(-2)
	
	' prepare the message header
	midset proto$,1,4,&H00524142	' TOP\0
	midset proto$,5,1,1		' protocol version 1
	midset proto$,23,2,0		' source ID (my ID) ' FIXME

	' usb check
	if nousb=0 then gosub 7000
	
	prio=midget (set$,9,1)          ' audio paging priority, default 127
	
	vol=midget(set$,1,1) : vol_setup = vol
	if vol>20 then vol=20
	clvol=vol

	ad_gain=midget(set$,2,1)
	if ad_gain>15 Then ad_gain=15
	
	mic_gain=midget(set$,3,1)
	if mic_gain>15 then mic_gain=15

	if midget(set$,11,1)=129 then      ' input (129=line, 130=mic)
		inp=1
		stereo=0
	else
		inp=2
		stereo=0
	endif

	enc=midget(set$,12,1)					' encoding
	rly=and(3,shr(midget(set$,30,1),2))			' relay on while...

	srate=8               ' 8kHz
	fmt=0                 ' u-Law
	bps=1                 ' 1 byte per sample
	
	' enc=7 for this one, but this is default (uLaw/8kHz)
	pltype=0
	if enc=6  then pltype=97 : srate=24                         ' uLaw/24kHz
	if enc=8  then pltype=98 : srate=24 : fmt=&H100             ' aLaw/24kHz
	if enc=9  then pltype=8  : fmt=&H100                        ' aLaw/8kHz
	if enc=10 then pltype=99 : bps=2: srate=24: fmt=&H200       ' PCM/24kHz
	if enc=11 then pltype=96 : bps=2 : fmt=&H200                ' PCM/8kHz
	
	inctm=midget(set$,45,1)
	if inctm<3  then inctm=3
	if inctm>60 then inctm=60
	inctm = inctm * 1000
	
	sysd "auto-unattended set to "+str$(inctm) 
	

	' set audio parameters
	x=&Hc00 ' only enc+dec
	if echo=1 then x=&H2c00 ' echo cancellation

	rtp_delay=set_aud_delay()
	sysd "rtp_delay : "+str$(rtp_delay)

	aud$="AUD:11,129,"+str$(x+fmt+srate)+","+str$(rtp_delay)
	open aud$ as H_AUDIO
	' single time setup, to avoid "plump" effects
	write H_AUDIO,str$(ad_gain),-2      'set A/D Gain
	write H_AUDIO,str$(mic_gain),-1     'set Mic Gain
	write H_AUDIO,str$(inp),-3          'set input source to mic/line
	write H_AUDIO,str$(stereo),-4       'set mono/stereo
	close H_AUDIO

	brate=bps*20*srate
	
	' get BARP IP
	barip$=sprintf$("%lA",midget(set8$,79,4))
	
	' if it is multicast, then set also the bcast$ to be the same, otherwise detect the bcast address
	if and(midget(set8$,79,1),240)=224 then bcast$=barip$ else bcast$=sprintf$("%A",5)

' handle 1: USB file with the station number
' handle 2: Read EEPROM settings
' handle 3: not used
' handle 4: udp audio port
' handle 5: udp status port
' handle 6: not used
' handle 7: used for audio
 
	audp =midget(set8$,53,2)	' default 5555
	ctlp =midget(set8$,55,2)	' default 5556
	statp=midget(set8$,57,2)	' default 5557
	
	open "UDP:"+barip$+":"+str$(statp) as H_UDP_BARP	' status port
	
	if mport<>0 then open "UDP:"+mcastip$+":"+str$(mport) as H_UDP_MCAST

	' go as idle
	state=STA_IDLE : goto 1019

1000
	gosub 3200 ' send status
	on state goto 1010,1020,1030,1040,1050,1060,1070,1080,1090,1100,1110
	goto 1000

1019
	' clear any existing link
	linkdst(0,0)=0
	linkdst(0,1)=0
	' idle state-display idle message
	CLEAR_AUDIO_LEVELS
	aump3	()
	message	(1)
	' immediate status change
	gosub 3210

1010	' idle state
	id=0
	gosub 2030
	
	' button 2: Page Selected
	if voxen=3 then 
		if kbhit(1) then goto 1011
	else
		if or(iostate(202)=0,iostate(202)=2) then
			' if not running on PS16, preselect group1
1011
			if leds=0 then rgp_mask (1,1)
			' check if we have any selection
			tmp=0
			for x=0 to 3
				if midget(grpmap$,x*4+1,4)<>0 then tmp=1
			next x
			if tmp<>0 then
				if voxen=3 then kbhit(1)=0
				state=STA_PA_BROADCAST
				goto 1059
			else
				message (13,1000)
				kbhit(1)=0
			endif
		endif
	endif
	
	' button 4 : Clear selection/Cancel
	' Clear sticky keys
	' reset the selection bitmap
	if kbhit(3) then
		' clear all groups / id's
		for x=8 to nkeys
			ioctl 1001+x, 0
		next x
		sysd "clear current group selection, always"
		' clear grpmask map
		for x=0 to 3
			midset grpmap$,x*4+1,4,0
		next x
		kbhit(3)=0
	endif
	
	' button 5 : go in unattended mode
	if kbhit(4) then
		kbhit(4)=0
		if dsunt$="y" then 
			state=9 : goto 1099 
		else 
			state=STA_UNATTENDED : cfwtm=_TMR_(0) : goto 1069
		endif
	endif
	
	' button 6 : listen unattended locally / record
	if kbhit(5) then
		kbhit(5)=0
		' key 6 also pressed?
		if or(iostate(2008)=0,iostate(2008)=2) then
			sysd "recording unattended"
			state=STA_REC_UNATT : message(8)
			record$="/unattsnd"
			goto 1079
		else
			' play locally
			if mediatype(1) then close 1
			open "C_R:usb:///unattsnd" as 1
			ioctl 1006,1
			open_aud_cfg() : csttm=_TMR_(0) : message(23) : state=STA_PLAY_LOCAL
			goto 1110
		endif
	endif

	' button 7: send and listen custom message / record
	if kbhit(6)=1 then
		kbhit(6)=0
		' key 8 also pressed
		if or(iostate(2008)=0,iostate(2008)=2) then
			sysd "recording custom"
			state=STA_REC_UNATT : message(15)
			record$="/customsg"
			goto 1079
		else
			tmp=0
			for x=0 to 31
				if midget(grpmap$,x*4+1,4)<>0 then tmp=1
			next x
			'anything selected?
			if tmp<>0 then
				gosub 2500
				if mediatype(1) then
					state=STA_SND_CUSTOM
					ioctl 1007,1
					' break any link
					if mediatype(H_UDP_STREAM) then close H_UDP_STREAM
					' and go
					ip$=bcast$
					' send cmd-3 now
					gosub 2055
					' let remotes move to paging RX
					delay 200
					open_aud_cfg()
					open_udp()
					' go
					csttm=_TMR_(0)
					goto 1100
				endif
			else
				' play locally
				if mediatype(1) then close 1
				open "C_R:usb:///customsg" as 1
				ioctl 1007,1
				open_aud_cfg() : csttm=_TMR_(0) : message(24) : state=STA_PLAY_LOCAL
			endif
		endif
	endif
	
	' button 8 : Record
	if kbhit(7) then
		message(22,1500)
		kbhit(7)=0
	endif

	' button  9 to 16 : Select group 1 to 8
	for i = 8 to 15
		if kbhit(i)=1 then
			rgp_mask(i-7,iostate(1001+i))
			kbhit(i)=0
		endif
	next i

1016
	' button 17-64 (assigned to IDs 17-64)
	for x=16 to nkeys
	    if kbhit(x) then rid_mask (x+1,iostate(1001+x)) : kbhit(x)=0
	next x

	' status message came in
	if lastlen(5)<0 then gosub 4000
	' incoming call ?
	
	if id then sysd "call friom id :"+str$(id) : incst=_TMR_(0) : state=2 : blrtm=_TMR_(0) : goto 1029
	
	goto 1000

' incomming call, play audio message
1029
	' immediate status change
	gosub 3210
	
	if and(rly,1) then ioctl 1,1 ' relay on
	message(2)		' station calling
	kbhit(0)=0
	kbhit(2)=0
	' we may have target specific ringtones, check it here ...
	fname$="/imaster/"+sprintf$("%03u",id)+".mp3"
	if mediatype(1) then close 1
	if nousb=0 then open "C_R:usb://"+fname$ as 1
	if mediatype(1)=0 then
		sysw "Specific ringtone not found-looking for the default ringtone in flash"
		open "F_R:baring.mp3" as 1
		if mediatype(1)=0 then
			if nousb=0 then
		        	sysw "No default ring tone in flash, checking USB ..."
		        	open "C_R:usb:///baring.mp3" as 1
			endif
			if mediatype(1)=0 then state=3 : syse "No ringtone found! " : goto 1039	' file doesn't exist
		endif
	endif
	' paranoid check, sometime (but not reproduced here) seems PS16 doesn't ring
	if mediatype(H_AUDIO) then
		if vol_setup<>vol then vol=vol_setup : setvol()
	endif

' buzzer ring, waiting to accept
1020
	if lastlen(5)<0 then gosub 4000
	' is time of unattended ?
	if and(dsunt$="n", _TMR_(0)-incst>inctm) then
		sysd "timeout, auto-unattended mode"
		state=STA_UNATTENDED : goto 1069
	endif
	' button 1: call accepted
	if kbhit(0) then close 1 : kbhit(0)=0 : state=STA_OUT_CALL : goto 1049
	' if button from the extension blinking (16 < ID < numkeys), accept the call
	' also with it
	if and(id>16,id<nkeys+1) then 
		if kbhit(id-1) then 
			close 1
			kbhit(id-1)=0: ioctl 1001,1: ioctl 1000+id,1 : state=STA_OUT_CALL : goto 1049
		endif
	endif
	' reject button - end the call
	if kbhit(2) then close 1 : open_aud_cfg() : kbhit(2)=0 : state=STA_IDLE :  gosub 2060:  goto 1019	 
	gosub 2030 ' discard audio messages
	if filesize(7)>2000 then
		read 1,_Mr$
		l=lastlen(1)
		if l>0 then write 7,_Mr$,l else close 1: state=STA_WAIT : goto 1039
	endif
	' calling party stopped ringing?
	if midget (clsts$,1,1) <> 3 then sysi "calling party stopped ringing" : state=STA_IDLE : goto 1019
	' last cmd-129 timer elapsed? Then stop ringing
	' note, clients resends about every 5.7
	if tmr_129+6500<_TMR_(0) then sysi "cmd-129 timer elapsed, stop ringing" : state=STA_IDLE : goto 1019

	goto 1000

1039
	' incoming call, waiting between rings
	xt=_TMR_(0)
1030
	if lastlen(5)<0 then gosub 4000

	' is time of unattended ?
	if and(dsunt$="n",_TMR_(0)-incst>inctm) then
		sysd "timeout, auto-unattended mode"
		state = STA_UNATTENDED : goto 1069
	endif
	
	' blink the fixed target button
	if and (id>16, id<nkeys+1, _TMR_(0)>blrtm+600) then
	      blrtm=_TMR_(0)
	      ioctl 1000+id, _DTS_%2
	endif

	' discard status/audio messages
	' gosub 4999
	gosub 2030
	' button 1 ? call accepted
	if kbhit(0) then kbhit(0)=0 : state=STA_OUT_CALL : goto 1049
	' reject button ? end the call 
	if kbhit(2) then
		kbhit(2)=0 
		open_aud_cfg() 
		state=STA_IDLE
		gosub 2060
		if id>16 then ioctl 1000+id,0 
		goto 1019
	endif
	
	' calling party stopped ringing?
	if midget(clsts$,1,1)<>3 then state=STA_IDLE : goto 1019

	' last cmd-129 timer + 5s elapsed? Then stop ringing
	if tmr_129+6500<_TMR_(0) then sysi "cmd-129 timer elapsed, stop ringing" : state=STA_IDLE : goto 1019

	if _TMR_(0)-xt>8000 then state=STA_INC_CALL_REQ : goto 1029	' ring again
	goto 1000

'PRE-STATE 4: setup call accepted (not called from unattended)
1049
	' immediate status change
	gosub 3210

	' if there was a second party calling, ignore this call when entering in the call state
	' if it continues calling, then it will appear again. but then we will have to either 
	' cancel it, or leave it to give up calling
	if newid>0 then 
		sysi "new id="+str$(newid)+", resetting it ..."
		newid=0
	endif
	
	' send cmd=3 to establish the call, always
	gosub 2055

	message(3)					' talking to client ...
	if rly=1 then ioctl 1,0				' relay off
	if rly=2 then ioctl 1,1				' relay on

	xt=_TMR_(0)
	' setup to call accepted, master listen, always
	gosub 2050
	kbhit(0)=0
	kbhit(1)=0
	kbhit(2)=0

	do_ic_start()

	' set up connected id
	connid=id : tmr_conn=_TMR_(0)

1040
	' for both HDX and FDX let's check for client still up 
	' (from IC status update sent every 4 secs from client).
	if _TMR_(0)-tmr_conn>10000 then
		' terminate for timeout (client crashed)
		sysi "no client status received, exiting to idle"
		close_fix()
		state=STA_IDLE : goto 1019
	endif

	' get audio info
	if mediatype(H_AUDIO) then
		read H_AUDIO,_Mr$,-15 : oul=lastlen(H_AUDIO)
		read H_AUDIO,_Mr$,-13 : inl=lastlen(H_AUDIO)
	endif
	
	' jump to FD ?
	if halfd=0 then goto 1043

	' PROCESS HD MODE
	
	' call reject or call hang up
	if kbhit(2) then goto 1041
	
	' call hang up when run on Ann with 2 buttons only
	' (Simultaneous keypress of keys 0 and key 1)
	if and(nkeys=1,iostate(201)=0,iostate(202)=0) then
		close_fix()
		state=STA_IDLE : ioctl 1,0 : gosub 2070
		' give some time to the operator to remove
		' the fingers from the buttons, otherwise 
		' the device will page to group one when it
		' goes in idle state
		delay 1500
		kbhit(0)=0 : kbhit(1)=0 : goto 1019
	endif
	' check if some ext key is pressed
	if and (id>16,id<nkeys+1) then 
		if kbhit(id-1) then goto 1041
	endif
	goto 1042
	
	' key correspondent to id (id>16) has been pressed
1041
	kbhit(4)=0

	' signal extension led
	if and(id>16,id<nkeys+1) then kbhit(id-1)=0 : ioctl 1000+id,0
	' new call ? send reject call message to newid
	if and(newid<>id,newid>0,kbhit(2)) then
		kbhit(2)=0
		gosub 2060
		newid=0
		message(3)
		close 1
	else
		sysd "HD, closing the call"
		kbhit(2)=0
		ioctl 1001,0
		close_fix()
		state=STA_IDLE : ioctl 1,0 : gosub 2070 : goto 1019
	endif

' key 0 will not close the call, but used as PTT button
' use key 2 to close the call 
1042
	' Send audio on VOX
	if and(voxen=3,mediatype(7)) then 
		read 7,_Mvox$,-1 : voxll=lastlen(7)
		read 7,_Mvox$,-2 : voxlr=lastlen(7)
		if or(voxll>voxtr,voxlr>voxtr) then vxsnd=voxto 
	endif
	' state switch, IC RX or TX
	if or(iostate(201)=0,iostate(201)=2,vxsnd>1) then
		' HD, if not already go transmit now
		if linkdst(0,1)=0 then do_ic_send()
		if _TMR_(0)-xt>1000 then gosub 2045 : xt=_TMR_(0)
		if curmsg<>3 then message(3)
	else 
		if linkdst(0,1)<>0 then do_ic_recv()
		if _TMR_(0)-xt>1000 then gosub 2050 : xt=_TMR_(0)
		if curmsg<>18 then message(18)
	endif
	goto 1046

' Process FDX mode
1043
	if or(kbhit(2),kbhit(0)) then goto 1044
	
	if and(id > 16, id < nkeys+1) then
		if kbhit(id-1) then goto 1044
	endif
	
	goto 1045
	
1044	
	kbhit(0)=0
	kbhit(4)=0

	if and(id>16, id<nkeys+1) then kbhit(id-1)=0 : ioctl 1000+id,0
	if and(newid<>id,newid>0,kbhit(2)) then
		' send reject call message to newid
		kbhit(2)=0
		gosub 2060
		newid=0
		message(3)
		close 1
	else
		kbhit(2)=0 : ioctl 1001,0
		close_fix()
		state=STA_IDLE : ioctl 1,0 
		'send end of page message to close the call
		gosub 2070 : goto 1019
	endif

1045	
	' "fdx on" every second (could be lost)
	if _TMR_(0)-xt>1000 then gosub 2050 : xt=_TMR_(0)
1046
	' button 2: open the door
	if kbhit(1) then kbhit(1)=0 : gosub 2040

	' another client calling?
	if lastlen(5)<0 then gosub 4000 : if and(id <> newid,newid>0) then message(2)

	' the second client stopped calling? Then reset newid ...
	if and(id<>newid,newid>0) then
		if tmr_129+6500<_TMR_(0) then newid=0
	endif

	goto 1000

' prepare PA state, print message
1059
	' immediate status change
	gosub 3210
	message(4)
	' ioctl 102, 1
	
1058
	do_page()

	' PA state
1050
	gosub 4999	' discard status messages
	gosub 2030	' discard incoming audio

	' get audio info
	read H_AUDIO,_Mr$,-13 : inl=lastlen(H_AUDIO)
	
	' constant bitrate
	read H_AUDIO,_Mr$,brate
	l=lastlen(H_AUDIO)
	if l>0 then 
		if mport<>0 then
			write H_UDP_MCAST,_Mr$,l,mcastip$,mport
		else
			write H_UDP_STREAM,_Mr$,l,ip$,audp
		endif
	endif

	' handsfree enabled? Then blink Paging button if active (ignore custom message playback)
	if voxen=3 then ioctl 1002, _DTS_%2
 
 	' button 2 has been pressed, now released: end of message
	' If handsfree is activated, then check for a key press (kbhit(1)=1)
	if or(and(voxen=3,kbhit(1)),and(iostate(202)<>0,iostate(202)<>2,voxen<>3)) then 
		state=STA_IDLE
		close H_AUDIO
		gosub 2070
		kbhit(1)=0
		ioctl 1002,0
		goto 1019
	endif
	goto 1000

' PRE-STATE 6: prepare for unattended
1069
	if nousb>0 then 
		sysw "No USB available, ignoring unattended mode! "
		state=1 : goto 1019
	endif
	' immediate status change
	gosub 3210

	message(7) : ioctl 105, 1
	sysd "entering unattended mode"

' STATE 6 : unattended mode
1060
	' check if the unattended key is kept pressed
	if and (kbhit(4)=0,iostate(2005)=0) then
	   if _TMR_(0)-cfwtm > 4000 then state=9 : goto 1099
	else
		cfwtm=_TMR_(0)
	endif

	if lastlen(5)<0 then
		id=0 : gosub 4000
		if id>0 then state=STA_SEND_UNATT : goto 1089
	endif

	goto 1000

' PRE-STATE 7 : prepare for recording unattended/custom message
1079
	' immediate status change
	gosub 3210
	' recording
' STATE 7 : recording unattended/custom message
1070
	gosub 2200
	goto 1000

' PRE-STATE 8: prepare for unattended message delivery
1089
	' send status, for immediate status change
	gosub 3210
	' unattended setup
	gosub 2300
	goto  1000

' STATE 8: STA_SEND_UNATT
1080
	' must blink fast sending unattended
	if _TMR_(0)>blktm+500 then
		blktm=_TMR_(0)
		ioctl 1005, _DTS_%2
	endif
	if _TMR_(0)-unatm > 20 then
		' sending chunks
		gosub 2400
		' IMPORTANT, don't use _TMR_(0) here
		' to keep constant bitrate
		unatm=unatm+20
	endif
	goto 1000
	
1099
    ' call forwarding mode
	' in this mode, the master replies with call reject message to the incoming calls
	' The iclient should then call the next available master in its list
	' NB! No connection is established as for the unattended mode

	' immediate status change
	gosub 3210

	message(19)
	sysd "entering call forwarding mode"
	
1090
	' status message came in
	if lastlen(5)<0 then gosub 4000
	
	' incoming call? Reject it!
	if id then gosub 2060 : id=0
	
	goto 1000

' state SND_CUSTOM
1100
	' DG asked discarding of keys here
	if lastlen(-2)<>0 then read -2,key$,0
	' constant bitrate
	if _TMR_(0)-csttm<20 then goto 1000
	csttm=csttm+20
	' blink LED
	ioctl 1007, _DTS_%2
	
	if srate=8 then read 1,_Ms8$ else read 1,_Ms24$
	l=lastlen(1)
	if l<=0 then
		linkdst(0,1)=0
		if mediatype(1) then close 1
		ioctl 1007, 0
		' send the stop command
		state=STA_IDLE
		' wait end of custom message to be played on clients side
		delay 1000
		gosub 2070
		' invalidate any kbhit set previous to playing
		kbhit(6)=0
		' clear button LED
		ioctl 1006,0
		goto 1019
	endif
	if srate=8 then
		write H_AUDIO,_Ms8$,l
		if mport<>0 then write H_UDP_MCAST,_Ms8$,l,mcastip$,mport else write H_UDP_STREAM,_Ms8$,l,ip$,audp
	else
		write H_AUDIO,_Ms24$,l
		if mport<>0 then write H_UDP_MCAST,_Ms24$,l,mcastip$,mport else write H_UDP_STREAM,_Ms24$,l,ip$,audp
	endif
	' read input level only while sending
	read H_AUDIO,_Mr$,-13 : inl=lastlen(7)
	goto 1000
	
' state PLAY_LOCAL_MSG (locally)
1110
	' DG asked discarding of keys here
	if lastlen(-2)>0 then read -2,key$,0
	' constant bitrate
	if _TMR_(0)-csttm<20 then goto 1000
	csttm=csttm+20
	
	if srate=8 then read 1,_Ms8$ else read 1,_Ms24$
	
	l=lastlen(1)
	if l<=0 then
		if mediatype(1) then close 1
		' send the stop command
		state=STA_IDLE
		' wait end of the message to be played
		close H_AUDIO,1
		' clear button LED
		ioctl 1006,0
		ioctl 1007,0
		' invalidate any kbhit set previous to playing
		kbhit(5)=0
		kbhit(6)=0
		goto 1019
	endif
	if srate=8 then
		write H_AUDIO,_Ms8$,l
	else
		write H_AUDIO,_Ms24$,l
	endif
	' read output level
	read H_AUDIO,_Mr$,-13 : oul=lastlen(7)
	goto 1000

	return


2030	' discard incomming audio messages
	if lastlen(4)<0 then read 4, _Mr$ : goto 2030
	return

2040	' open the door
	sysd "sending open the door"
	midset proto$,6,1,4		' message=4 (activate relay)
	midset proto$,23,2,myid	        ' master ID
	midset proto$,25,2,id	        ' station ID
	midset proto$,35,2,&H3201	' activation time 50*100ms, relay 1
	write 5,proto$,37,ip$,ctlp
	message(6,1000)			' door message
	return

' MSGSEND stop streamback (in hdx switch rx audio)
2045
	' stop streamback (message=1)
	sysd "sending stop streamback"
	midset proto$,6,1,1		' message=1 (stop streamback)
	midset proto$,23,2,myid	        ' master ID
	midset proto$,25,2,id	        ' station ID
	write 5,proto$,35,ip$,ctlp
	return

' MSGSEND start streamback
2050
	sysd "sending start streamback"
	midset proto$,6,1,2       ' message=2 (start streamback)
	midset proto$,23,2,myid   ' master ID
	midset proto$,25,2,id     ' station ID
	midset proto$,35,2,audp   ' port number 0 - answer to the audio sending port 
	write 5,proto$,37,ip$,ctlp
	return
	
2054	' timer4 call for page request every 4 seconds (for state 5)	
	if and (state<>5,state<>8) then return

' MSGSEND page group request
2055
	midset proto$,6,1,3             ' message=3 (page request)
	x = or(0,FLAG_EXTO)
	' using bytes 6 and 7 as FLAGS
	midset proto$,7,2,x             ' setup flags to use Extended Timeout
	midset proto$,23,2,myid	        ' master (source) ID
	if or(state=4,state=8) then 
		' in case of incoming call do not use bitmap but remote ID
		midset proto$,25,2,id
	else
		' page request for the selection, use address bitmap
		midset proto$,25,2,0        ' desination ID=0 (client should use the bitmap)
	endif
	if mport<> 0 then 
		midset proto$,35,2,mport    ' UDP port for broadcast 
	else
		midset proto$,35,2,audp     ' use default audio port for broadcast
	endif
	midset proto$,37,1,prio         ' Message priority
	midset proto$,38,1,pltype       ' audio encoding type, as RTP payload
	if mport<>0 then
		midset proto$,39,4,RESOLVE(mcastip$)     ' add the multicast address
	else
		midset proto$,39,4,0                     ' 0 - use broadcast address/port to listen
	endif
	if or(state=4, state=8) then			' we should send the correct ID for intercom, and unnattended mode
		' incase of incoming call, send empty bitmap
		for i = 1 to 32
			midset proto$,43+(i*4),4,0
		next i
	else
		' send the map with the selected targets
		midcpy proto$,43,128,grpmap$ 
	endif
	sysi "Sent cmd=3 to ip: "+ip$+" and port: "+str$(ctlp)
	write 5,proto$,170,ip$,ctlp

	return

' MSGSEND change BGM channel
2057
	midset proto$,6,1,6             ' message=6 (Change BGM channel)
	midset proto$,23,2,myid	        ' master ID
	midset proto$,25,2,0            ' destination ID=0 (client should use the bitmap)
	midset proto$,35,1,bgmch        ' BGM channel to be used
	midset proto$,36,1,bgmst        ' make it permanent, or temporary
	midcpy proto$,43,128,grpmap$
	sysi "Sent cmd=6: Set BGM Channel="+str$(bgmch)+", set flag="+str$(bgmst)
	write 5,proto$,170,bcast$,ctlp
	return

' MSGSEND call reject
2060
	midset proto$,6,1,7		' message=7 (reject call)
	midset proto$,23,2,myid         ' master ID
	if and(state=4,newid<>id) then
	   midset proto$,25,2,newid	' new station ID
	else
	   midset proto$,25,2,id	' station ID
	endif
	if state=9 then 
	   midset proto$,35,1,2		' reason: Not available, call next in list!
	else
	   midset proto$,35,1,1		' reason: Rejected by user
	endif
	if and(state=4,newid<>id) then
	   write 5,proto$,35,newip$,ctlp 
	else
	   write 5,proto$,35,ip$,ctlp
	endif
	sysi "sent cmd=7: call reject: "+"to IP: "+ip$+"and port: "+str$(ctlp)
	return

' MSGSEND end page request
2070
	midset proto$,6,1,8		' message=8 (end group request)
	midset proto$,23,2,myid	        ' master ID
	midset proto$,25,2,id	        ' station ID
	midset proto$,35,2,mport	' mcast port
	midset proto$,35+2,1,0          ' six bytes reserved (not used)
	midset proto$,35+2+1,1,0
	midset proto$,35+2+1+1,1,0
	midset proto$,35+2+1+1+1,1,0
	midset proto$,35+2+1+1+1+1,1,0
	midset proto$,35+2+1+1+1+1+1,1,0
	midcpy proto$,35+2+6,128,grpmap$  ' the address map
	write 5,proto$,171,ip$,ctlp
	sysi "sent cmd=8: end page request to IP: "+ip$+" and port: "+str$(ctlp)
	return

' MSG 5 change volume
2080
	ip$=bcast$
	midset proto$,6,1,5             ' message=5 (Change volume)
	midset proto$,23,2,myid	        ' master ID
	midset proto$,25,2,0            ' destination ID=0 (client should use the bitmap)
	midset proto$,35,1,clvol*5       ' volume to be set
	midset proto$,36,1,clset        ' make it permanent, or temporary
	midcpy proto$,43,128,grpmap$
	sysi "Sent cmd=5: Set volume="+str$(clvol)+", set flag="+str$(clset)
	write 5,proto$,170,ip$,ctlp
	return


' open_aud_cfg() reopen audio as uncompressed
2100
	sysd "open_aud_cfg() : opening audio as preconfigured"
	if mediatype(H_AUDIO) then
		ovol=vol : vol=0 : setvol()
		write H_AUDIO, "", 0 : delay 50
		close H_AUDIO
	endif
	sysd "open_aud_cfg() : aud$="+aud$
	open aud$ as H_AUDIO
	vol=ovol
	setvol()
	return

2110	' reopen audio as mp3
	sysd "opening audio as mp3"

	if mediatype(H_AUDIO) then
		' in some cases (custom message terminated) we must wait
		' the buffer to be empty.
2111
		read H_AUDIO,_Mr$,-6
		if lastlen(H_AUDIO)>4 then goto 2111
		' save current vol
		y=vol
		' low blub
		for x = 1 to 10
			if vol>0 then setvol()
			delay 50 : vol = vol - 1
		next x
		vol=y
		' this seems cousing problem to audio
		write 7, "", 0 : delay 50
		close 7
	endif
	open "AUD:1,0,0,0" as 7
	setvol()
	return

' set volume vol
2120
	setvol=0

	write 7,str$(vol),-12		        	'set volume to vol
	' set also the client volume start value to be the same as the imaster one
	' so next time we want to modify the iclient volume, we start from it
	clvol=vol
	return

' record unattended/custom sound
2200
	delete "usb//"+record$
	if mediatype(1) then close 1  
	open "C_W:usb://"+record$ as 1
	' unattended exist ?
	if mediatype(1)=0 then state=1 : goto 1000
	' recording using same audio codec
	sysd "recording " + record$ + " message ..."
	open_aud_cfg()

2210
	' check for stop, key 8 released
	if or(iostate(2008)=1,iostate(2008)=3) then message(1) : state=1 : CLEAR_AUDIO_LEVELS : goto 2220
	read 7, _Mr$
	l=lastlen(7)
	if l>0 then
		write 1, _Mr$, l
		read 7,_Mr$,-13 : inl=lastlen(7)
	endif
	delay 10
	goto 2210
2220
	sysd "message recorded"
	aump3()
	close 1
	' discard all
	gosub 2030
	gosub 4999
	return

' unattended message setup
2300
	open_udp()
	' getting the file
	if mediatype(1) then close 1
	open "C_R:usb:///unattsnd" as 1
	sysd "opening unattended file..."
	if mediatype(1)=0 then
2301
		message(12)
		delay 1000
		' advise for unattended, (if unattsnd is missing !)
		gosub 2070
		gosub 4999
		state = 1
		CLEAR_AUDIO_LEVELS
		return
	else
		if filesize(1)=0 then syse "error : bad 0 bytes unattended sound" : goto 2301
	endif
	sysd "sending unattended message"
	' send cmd-3 now
	gosub 2055
	' enable full dx
	if halfd=0 then	gosub 2050
	' be sure client is ok before go
	delay 1000
	' start the timing
	unatm=_TMR_(0)
	
	return

' sending unattended message chunk
2400
	if srate=8 then read 1,_Ms8$ else read 1,_Ms24$
	x=lastlen(1)
	if x>0 then
		if srate=8 then write 4,_Ms8$,x,ip$,audp else write 4,_Ms24$,x,ip$,audp
		delay 0
	else
		' end of unattended
		delay 1000
		' discarding status queue
		gosub 4999
		close 1
		ioctl 1005, 1
		message(7) : gosub 2070 : state=6
	endif
	return

' opening  custom message
2500
	if mediatype(1) then close 1
	open "C_R:usb:///customsg" as 1
	sysd "opening customsg file..."
	if mediatype(1)=0 then
2501 
		message(16)
		delay 1000
		syse "No custom message found!"
		gosub 4999
		state=STA_IDLE
		return
	else
		if filesize(1)=0 then 
			syse "error : bad 0 bytes custom sound" : goto 2501
		else
			sysd "custom file found!"
		endif
	endif
	return

'----------------- message parsing

4999	' discard incomming status messages
	if lastlen(5)<0 then read 5, _Mr$ : goto 4999
	return

' incomming status message, read and parse
4000	
	' tmr safe vars
	dim i$(16),e,f,g,h,t,p

	i$=rmthost$(5)
	p=rmtport(5)
	e=-lastlen(5)
	read 5, _Mr$
	if e<34 then return    ' message too short - garbage


	' BAR \0   | vers | msg | rsvd | src ID | dst ID | seq | rsvd | params
	' 1        | 5    | 6   | 7    | 23     | 25     | 27  | 29   | 35
	' 4B       | 1B   | 1B  | 16B  | 2B     | 2B     | 2B  | 6B   | 

	if midget(_Mr$,1,4)<>&H00524142 then return	' magic mismatch
	if midget(_Mr$,5,1)<>1 then return		' unsupported protocol version 
	f=midget(_Mr$,23,2)    ' ID
	' FIXME receiver ID check
	g=midget(_Mr$,6,1)     ' message number
	
	on g-127 goto 4128,4129
	' unknown message
	return

4128	' MSG 128, status report
	t=midget(_Mr$,35,1)		' status
	h=midget(_Mr$,36,1)		' priority
	sysd "status message from "+i$+":"+str$(p)+" client ID="+str$(f)+", status="+str$(t)+", priority="+str$(h)
	
	' check the status if we have incoming call
	if and(or(state=2,state=3),f=id) then
		' store the status of the calling party
		midset clsts$,1,1,t
		sysi "setting the calling party status to " + str$(t)
	endif
	if state=4 then
		' reset timeout here
		if id=connid then tmr_conn=_TMR_(0)
	endif
	goto 4100

4129	' MSG 129, call request
	sysd "received msg call requet"
	h=midget(_Mr$,35,1)		' priority
	t=midget(_Mr$,36,1)		' name length
	' command not for me
	if and(idadr$="y",midget (_Mr$,25,2) <> myid) then sysi "call request ignored!, dest id="+str$(midget (_Mr$,25,2))+", my id="+str$(myid) : return
	' reset cmd-129 timer
	tmr_129=_TMR_(0)
	if state<>STA_OUT_CALL then 
		id=f
		ip$=i$
		midcpy name$,1,t,_Mr$,37     ' copy name
		midset name$,t+1,1,0         ' terminate
	else
		newid=f
		newip$=i$
		midcpy nname$,1,t,_Mr$,37    ' copy name
		midset nname$,t+1,1,0        ' terminate
	endif
	
	' set the calling party status to 3 before we get the real status message
	' thus allowing the master to get the call. If the call is not answered by the master
	' and the status message from the client is <>3, the master will stop ringing
	if id then  midset clsts$,1,1,3

	sysd "call request from "+i$+":"+str$(p)+" client ID="+str$(f)+", name="+name$+", priority="+str$(h)
	goto 4100

4100
	' ignore other messages at the moment
	return

' do_page()
1500
	' preconfigured audio
	open_aud_cfg()
	open_udp()
	
	sysd "do_page() : dest:"+bcast$+":"+str$(audp)

	' DG asked, no link/AEC for paging
	ip$=bcast$
	gosub 2055
	return

' do_ic_start()
1600
	do_ic_start=0

	open_aud_cfg()
	open_udp()

	' direct unicast stream
	linkdst(0,0)=resolve(ip$)

	' start stream immediately for FD
	if halfd=0 then 
		linkdst(0,1)=audp
	else
		' HD startup, no stream
		linkdst(0,1)=0
	endif

	sysd "do_ic_start() : setting link, dest:"+ip$+":"+str$(audp)
	
	link H_UDP_STREAM,H_AUDIO,linkdst
	
	return

' do_ic_send()
1700
	do_ic_send=0

	sysd "do_ic_send()"
	' go
	linkdst(0,1)=audp
	' send stop streamback
	gosub 2045
	return

' do_ic_recv()
1800
	do_ic_send=0
	
	sysd "do_ic_recv()"
	' stop sending
	linkdst(0,1)=0
	' send start streamback
	gosub 2050
	return

3200 ' send status message
	if midget (tm128$,1,4)+30000 > _TMR_(0) then return
	midset tm128$,1,4,_TMR_(0)

3210 ' jump here for immediate send (no timer dependent)
	midset proto$,6,1,128       ' master status report
	midset proto$,23,2,myid     ' master ID
	midset proto$,37,2,0        ' channel=0
	midset proto$,39,1,vol      ' current volume is
	midset proto$,40,1,0

	if state=1 then midset proto$,35,2,0		        ' idle: status=0, prio=0
	if or(state=2,state=3) then midset proto$,35,2,128	' getting call request
	if state=4 then midset proto$,35,2,2			' direct connection: status=2, prio=0
	if state=5 then midset proto$,35,1,130 : midset proto$,36,1,prio	' sending paging message: status=129, prio=prio
	if state=6 then midset proto$,35,2,132  	        ' unattended mode: status=,prio=0
	if state=7 then midset proto$,35,2,133          	' recording unattended message: status=,prio=0
	if state=8 then midset proto$,35,2,131                  ' sending unattended message: status=,prio=0
	if state=9 then midset proto$,35,2,134          	' call reject mode: status=,prio=0

	sysd "Master status 0x"+sprintf$("%x",midget(proto$,35,1))+" sent to "+bcast$
	
	' always send status as broadcast
	write 5, proto$, 40, bcast$, statp

	return

'----------------- keyboard handling ----------------------------
' note : this routine reads key events and sets the appropriate
' kbhit() variable to 1 if pressed. No reset to 0 is done on key
' release, clearing must be done from application.
'----------------------------------------------------------------
5000
	' timer safe variables
	dim q, r
	' key input ? if not, process selected key events
	if lastlen(-2)=0 then goto 5110
5001
	read -2,key$,0
	
	q=midget(key$,1,1)
	r=and	(q,127)
	' is a valid key ?
	if r>nkeys then goto 5000
	if and(q,128) then 
		kbhit(r)=1
		if leds then
			if and(sticky(r)=1,iostate(1001+r)=1) then 
				ioctl 1001+r,0
			else
				ioctl 1001+r,1
			endif
		endif
		' always, exit unattended on every whatever key
		if or(state=STA_UNATTENDED,state=STA_SEND_UNATT,state=STA_CALL_FWD) then
			kbhit(r)=0
			' exiting unattended
			ioctl 1005,0
			sysd "exiting unattended/call forwarding mode"
			' discard messages and go to idle
			gosub 4999 : cfwtm=_TMR_(0) : state=1 : CLEAR_AUDIO_LEVELS : incst=0 : message(1) : return
		endif
	else
		if leds then 
			if sticky(r)<>1 then 
				ioctl 1001+r,0
			endif
		endif
	endif
	
	if lastlen(-2)=0 then goto 5110
	goto 5001

5110
	return

'----------------- display functions

6000	' print status on display
	' displays the message msg and remembers it in curmsg if msgto is 0
	' if msg is empty (called without parameters) displays curmsg (recovery from a temporary message)
	' if msgto is set, the message is displayed temporarily for the given number of milliseconds
	' in that case message is not remembered in curmsg
	local msg,msgto
	timer 2,0			' if called from a timer, stop the timer
	if disp=0 then return		' no display
	if msg=0 then msg=curmsg 
	if msgto=0 then curmsg=msg
	write -2,"\x1b[2J",0		' clear screen
	on msg gosub 6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024
	if msgto then timer 2,msgto	' if timeout set, start timer which restores the curmsg
	return

6001	' idle message
	temp$="IcMaster"
	if halfd=1 then temp$=temp$+", HDX" else temp$=temp$+", FDX"
	if voxen=3 then temp$=temp$+", Handsfree"
	temp$=temp$+"\n"+ver$+","+str$(nkeys+1)+" keys"
	write -2,temp$,0
	return

6002	' Station >id< calling
	if state<>4 then
		write -2,"Station "+str$(id)+" calling\n"+name$,0
	else
		write -2,"Station "+str$(newid)+" calling\n"+nname$,0
	endif
	return

6003	' Talking to >id<
	write -2,"Talking to client "+str$(id)+"\n"+name$,0
	return

6004	' Broadcasting
	write -2,"PA broadcast",0
	return

6005	' Volume %
	write -2,"Volume "+str$(vol*5)+"%",0
	return

6006	' Door open
	write -2,"Door open",0
	return

6007
	write -2,"Unattended mode",0
	return

6008	
	write -2,"Recording unattended",0
	return

6009
	write -2,"Checking USB sanity",0 
	return

6010
	write -2,"Check successful",0 
	return

6011
	write -2,"Bad USB stick fs",0 
	return

6012
	write -2,"Missing unattended",0 
	return

6013
	write -2, "Nothing selected!",0
	return

6014
	write -2, "No incoming call!",0
	return

6015
	write -2, "Recording custom msg",0
	return

6016
    write -2, "No custom msg recorded!",0
	return
	
6017	' Client Volume %
	write -2, "Client Volume: "+str$(clvol*5)+"%",0
	return
	
6018	' Listening to >id<
	write -2, "Listening to client "+str$(id)+"\n"+name$,0
	return

6019	' Call forwarding (by sending call reject,reason=2)
	write -2, "Call reject mode ",0
	return

6020	' Change BGM channel
	write -2, "Changed to BGM channel "+str$(bgmch),0
	return

6021	' Change BGM channel
	write -2, "Selected group "+str$(selgrp),0
	return

6022
	write -2, "Keep record key pressed \nand press key 6 or 7",0
	return

6023
	write -2, "Playing Unattended\nmessage",0
	return
	
6024
	write -2, "Playing Custom message",0
	return

6500    ' VAD timer routine
        ' Do not check for voice level here, do it in the main 
	' loop, otherwise the delay is audible. In the loop,
	' send audio only when vxsnd>0
	' Here just decrement the counter
	
	if vxsnd>1 then vxsnd=vxsnd-1            ' 100 ms passed     
	return

' test USB
7000
	temp$ = "test.usb"

	message(9)
	delay 300
	
	delete "usb:///" + temp$
	open   "C_W:usb:///" + temp$ as 1
	if mediatype(1) = 0 then
		' we want allow here 
		if or(htype=7,htype=19) then 
			sysw "No USB key, Annuncicom100/200 allowed to work."
			goto 7010
		endif
		message(11)
		syse "cannot access usb on fs:write, terminating"
		state = -1 ' web UI errors
		end
	else
		close 1
		open   "C_R:usb:///" + temp$ as 1
		if mediatype(1) = 0 then
			message(11)
			syse "cannot access usb on fs:read"
			end
		else
			message(10)
			delay 300
		endif
	endif
	close 1

7010
	return

' close_fix()
' NOTE: terminate IC/LINK session, on ABCL1.09 there is an 
' abcl/song bug open, if this closing order is not respected, 
' (udp, audio) next page session will fail.
7100
	' dest array cleaning
	linkdst(0,0)=0
	linkdst(0,1)=0

	close H_UDP_STREAM
	close H_AUDIO
	
	return

' recalculate 128 byte address map from a given client ID

8000
	local rm_id,lt_on,wbyte,ebyte,b2sft

	if rm_id=0 then return      
	' find in which byte it is ...
	wbyte=shr(rm_id-1,3)
	' extract that byte from the current mask
	ebyte=midget(grpmap$,wbyte+1,1)
	' find how many bits to shift (Bits2ShiFT)
	b2sft=(rm_id-1)%8
	' now add this bit if the corresponding target LED is on
	if lt_on=1 then
		' LED ON (Sticky key still active) ?
		' Then just add it to the bitmap
		ebyte=or(ebyte, shr(128,b2sft))
	else
		' Otherwise just remove it
		' Beware that it will remove it from the group!
		ebyte=xor(ebyte, shr(128,b2sft))
	endif   
	' and store it back
	midset grpmap$,wbyte+1,1,ebyte

	return

' recalculate 128 bit address map from a group key with assigned bitmap
8200
	local rgpn,lg_on,dbyte,sbyte
	
	if lg_on then selgrp=rgpn : message(21,500)

	for x = 0 to 3
		' find destination and source bytes
		if rgpn=1 then sbyte=midget(gp1map$,x*4+1,4)
		if rgpn=2 then sbyte=midget(gp2map$,x*4+1,4)
		if rgpn=3 then sbyte=midget(gp3map$,x*4+1,4)
		if rgpn=4 then sbyte=midget(gp4map$,x*4+1,4)
		if rgpn=5 then sbyte=midget(gp5map$,x*4+1,4)
		if rgpn=6 then sbyte=midget(gp6map$,x*4+1,4)
		if rgpn=7 then sbyte=midget(gp7map$,x*4+1,4)
		if rgpn=8 then sbyte=midget(gp8map$,x*4+1,4)
		' get original
		dbyte=midget(grpmap$,x*4+1,4)
		' toggle bits
		if lg_on=1 then
		' LED ON (Sticky key still active) ?
		' Then just add this bitmap to the current one
			dbyte=or(dbyte,sbyte)
		else
			dbyte=xor(dbyte,sbyte)
		endif
		' store it
		midset grpmap$,x*4+1,4,dbyte
	next x
	return

' open_udp()
8900
	if mediatype(H_UDP_STREAM) then close H_UDP_STREAM
	open "UDP:"+barip$+":"+str$(audp) as H_UDP_STREAM
	return

' fix auto setup of RTP delay. Needed because default (0) don't work fine 
' with some IPAM's like 300, vlsi1053
#define IPAM101 1
#define IPAM102 2
#define IPAM301 3
#define IPAM302 4
' set_aud_delay()
9100
	set_aud_delay=0
	' u-aLaw/24kHz
	if or(enc=6,enc=8) then
		' unknow IPAM, we can't assume micronas, can be 100,200,or 300
		if itype=0 then
			' using hw type here
			if or(htype=25,htype=7,htype=19) then set_aud_delay=60 else set_aud_delay=188
		endif
		if or(itype=IPAM101,itype=IPAM301) then set_aud_delay=188
		' IPAM 102/302, set a uniform 100
		if or(itype=IPAM102,itype=IPAM302) then set_aud_delay=100
	endif
	' u-aLaw/8kHz
	if or(enc=7,enc=9) then
		' unknow IPAM, we can't assume micronas, can be 100,200,or 300
		if itype=0 then
			' using hw type here
			if or(htype=25,htype=7,htype=19) then set_aud_delay=80 else set_aud_delay=444
		endif
		if or(itype=IPAM101,itype=IPAM301) then set_aud_delay=444
		' IPAM 102/302, set a uniform 100
		if or(itype=IPAM102,itype=IPAM302) then set_aud_delay=100
	endif

	return
