NEW
  AUTO 3,1
				.LIST OFF
				.OP	65C02
				.OR	$2000
				.TF BIN/PING
*--------------------------------------
				.INB INC/MACROS.I
				.INB INC/A2OSX.I
				.INB INC/ETH.I
				.INB INC/LIBTCPIP.I
*--------------------------------------
TIMEOUT.MAX		.EQ 100					10 sec.
*--------------------------------------
ZPIPCfgPtr		.EQ ZPBIN
ZPTmpPtr		.EQ ZPBIN+2
*--------------------------------------
*			File Header (16 Bytes)
*--------------------------------------
CS.START		cld
				jmp (.1,x)
				.DA #$61				6502,Level 1 (65c02)
				.DA #1					BIN Layout Version 1
				.DA #S.PS.F.EVENT		S.PS.F
				.DA #0
				.DA CS.END-CS.START		Code Length To Relocate
				.DA DS.END-DS.START		Data Segment to Allocate
				.DA #64					SS
				.DA #4					ZP
				.DA 0
*--------------------------------------
.1				.DA CS.INIT
				.DA CS.RUN
				.DA CS.DOEVENT		
				.DA	CS.QUIT
L.LIBTCPIP		.DA LIBTCPIP
L.SA.LOCAL		.DA SA.LOCAL
L.SA.REMOTE		.DA SA.REMOTE
L.SA.REMOTE.AD	.DA SA.REMOTE+S.SOCKADDR.ADDR
L.ICMP.Request	.DA ICMP.Request
L.MSG.IPKO		.DA MSG.IPKO
L.MSG.USAGE		.DA MSG.USAGE
L.MSG.UNKNOWN	.DA MSG.UNKNOWN
L.MSG.HOSTOK	.DA MSG.HOSTOK
L.MSG.SKTKO		.DA MSG.SKTKO
L.MSG.REPLY		.DA MSG.REPLY
L.MSG.UNREACH	.DA MSG.UNREACH
				.DA 0
*--------------------------------------
CS.INIT			>LDYA L.LIBTCPIP
				>SYSCALL LoadLib
				bcs .9
				sta hLIBTCPIP

.9				rts
*--------------------------------------
CS.RUN			>LIBCALL hLIBTCPIP,LIBTCPIP.GETCFG	is TCPIP loaded ?
				>STYA ZPIPCfgPtr
				
				lda (ZPIPCfgPtr)		Configured ?
				bmi CS.RUN.IPOK
				
				>LDYA L.MSG.IPKO
				>SYSCALL puts
				lda #E.SYN
				sec				
				rts
				
CS.RUN.IPOK		
.1				>INC.G ArgIndex
				>SYSCALL ArgV
				bcs .8
				>STYA ZPTmpPtr
				
				lda (ZPTmpPtr)
				cmp #'-'
				bne .21

				ldy #1 
				lda (ZPTmpPtr),y
				beq .9

				cmp #'0'
				bcc .9
				cmp #'9'+1
				bcs .9
				
				and #$0F
				>STA.G PingCount
				bra .1			
				
.21				jsr Init.Timeout
				
.2				>PUSHW L.SA.REMOTE.AD
				>PUSHW ZPTmpPtr
				>LIBCALL hLIBTCPIP,LIBTCPIP.HST.GETBYNAME
				bcc .3
				>SLEEP
				jsr Wait.Timeout
				bcc .2

				>PUSHW ZPTmpPtr
				>PUSHBI 2
				>LDYA L.MSG.UNKNOWN
				bra .99
				
.3				>LDA.G ArgIndex
				>STA.G ArgHostName
				jmp .1
				
.8				lda SA.REMOTE+S.SOCKADDR.ADDR
				bne CS.RUN.ARGSOK
				
.9				>PUSHBI 0
				>LDYA L.MSG.USAGE
				
.99				>SYSCALL printf

				lda #E.SYN
				sec				
				rts

CS.RUN.ARGSOK	>LDA.G ArgHostName
				>SYSCALL ArgV
				>PUSHYA
				
				ldx #3
				
.1				lda SA.REMOTE+S.SOCKADDR.ADDR,x
				>PUSHA
				dex
				bpl .1
				
				>PUSHBI 6
				>LDYA L.MSG.HOSTOK
				>SYSCALL printf
		
CS.RUN.OPENSKT	ldx #3
				ldy #S.IPCFG.IP+3
				
.1				lda (ZPIPCfgPtr),y
				sta SA.LOCAL+S.SOCKADDR.ADDR,x
				dey
				dex
				bpl .1
				
				ldy #Identifier
				lda A2OSX.RANDOM16
				sta SA.LOCAL+S.SOCKADDR.PORT
				sta SA.REMOTE+S.SOCKADDR.PORT
				sta (pData),y
				iny
				lda A2OSX.RANDOM16+1
				sta SA.LOCAL+S.SOCKADDR.PORT+1
				sta SA.REMOTE+S.SOCKADDR.PORT+1
				sta (pData),y
				
				>PUSHBI S.IP.PROTOCOL.ICMP
				lda #S.SOCKET.T.RAW
				>LIBCALL hLIBTCPIP,LIBTCPIP.socket
				bcs .9
				
				>STA.G hSocket
				pha
				>PUSHW L.SA.LOCAL
				pla
				>LIBCALL hLIBTCPIP,LIBTCPIP.Bind
				bcs .9
				
				>PUSHW L.SA.REMOTE
				>LDA.G hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Connect
				
				bcc CS.RUN.SEND.ECHO
				
.9				>LDYA L.MSG.SKTKO
				>SYSCALL puts
				lda #E.SYN
				sec				
				rts

CS.RUN.SEND.ECHO				
				>LDA.G Identifier
				sta ICMP.Request.ID
				iny
				lda (pData),y
				sta ICMP.Request.ID+1
				
				>LDA.G Sequence
				sec
				adc #0
				sta (pData),y
				sta ICMP.Request.SQ

				iny
				lda (pData),y
				adc #0
				sta (pData),y
				sta ICMP.Request.SQ+1

				jsr Init.Timeout
				
				>PUSHWI ICMP.RequestLen
				>PUSHW L.ICMP.Request
				>LDA.G hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.send
				bcs CS.RUN.ERR
				
				jsr Init.Timeout
				
CS.RUN.WAIT.REPLY
				>SLEEP
				ldy #S.PS.hStdIn
				lda (pPS),y
				>SYSCALL feof
				bcs CS.RUN.ERR
				
				tay
				bne	.1		
				
				>SYSCALL GetChar
				bcs CS.RUN.ERR
				cmp #3					Ctrl-C
				beq CS.RUN.ERR			CS
				
.1				>LDA.G hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Recv
				bcc .2
				jsr Wait.Timeout
				bcc CS.RUN.WAIT.REPLY

				jsr CS.Print.UNREACH
				bcs CS.RUN.ERR
				bra .7
				
.2				>STA.G hFrame
				>SYSCALL GetMemPtr
				>STYA ZPTmpPtr
				jsr CS.Print.REPLY
				bcs CS.RUN.ERR

				>LDA.G hFrame
				>SYSCALL FreeMem
				
				>STZ.G hFrame

.7				>LDA.G PingCount
				beq .8
				dec
				beq .9					A=0
				sta (pData),y

.8				jmp CS.RUN.SEND.ECHO
				
.9				sec
CS.RUN.ERR		rts
*--------------------------------------
CS.DOEVENT		lda (pEvent)
				bpl .9					is it a TIMER event?
				
				>LDA.G TimeOut
				beq .9
				
				dec
				sta (pData),y
				
.9				sec						do not discard TIMER event
				rts
*--------------------------------------
CS.Print.UNREACH
				ldx #3
				
.1				>PUSHB SA.REMOTE+S.SOCKADDR.ADDR,x
				dex
				bpl .1
				
				>PUSHBI 4
				>LDYA L.MSG.UNREACH
				>SYSCALL printf
				rts
*--------------------------------------
CS.Print.REPLY	lda #TIMEOUT.MAX
				sec
				ldy #TimeOut
				sbc (pData),y
				
				>STZ.G TimeOut.ms
				>STA.G TimeOut.ms+1
				
				tax
				beq .3
				
.1				>LDA.G TimeOut.ms
				clc 
				adc #100
				>STA.G TimeOut.ms
				bcc .2
				
				>INC.G TimeOut.ms+1
.2				dex
				bne .1
				
.3				>PUSHW.G TimeOut.ms

				ldy #S.IP.TTL
				>PUSHB (ZPTmpPtr),y
				
				ldy #S.ICMP.SEQUENCE+1
				>PUSHB (ZPTmpPtr),y
				dey 
				>PUSHB (ZPTmpPtr),y
				
				ldx #4
				ldy #S.IP.SRC+3
				
.4				>PUSHB (ZPTmpPtr),y
				dey
				dex
				bne .4
				
				>PUSHBI 9
				>LDYA L.MSG.REPLY
				>SYSCALL printf
				rts
*--------------------------------------
CS.QUIT			>LDA.G hFrame
				beq .1
				
				>SYSCALL FreeMem

.1				>LDA.G hSocket
				beq .2

				>LIBCALL hLIBTCPIP,LIBTCPIP.Shutdown
				
.2				lda hLIBTCPIP
				beq .8
				
				>SYSCALL UnloadLib

.8				clc
				rts
*--------------------------------------
Init.Timeout	lda #TIMEOUT.MAX
				>STA.G TimeOut
				rts
*--------------------------------------
Wait.TimeOut	sec
				>LDA.G TimeOut
				beq .9

				clc
.9				rts
*--------------------------------------
CS.END
LIBTCPIP		.AZ "libtcpip"
MSG.IPKO		.AZ "TCP/IP Not Loaded/Configured."
MSG.USAGE		.AS "Usage : PING <ip|host>\r\n"
				.AZ " -1-9 : Ping Count\r\n"
MSG.UNKNOWN		.AZ "%s: Unknown host\r\n"
MSG.HOSTOK		.AZ "PING %d.%d.%d.%d (%s)\r\n"
MSG.SKTKO		.AZ "Failed to Open Socket."
MSG.UNREACH		.AZ "%d.%d.%d.%d: TimeOut/Host unreachable\r\n"
MSG.REPLY		.AZ "32 bytes from %d.%d.%d.%d, icmp_seq=%D, ttl=%d, time=%D ms\r\n"
hLIBTCPIP		.BS 1
*--------------------------------------
SA.LOCAL		.DA #AF.INET			S.SOCKADDR.AF
				.BS 1
				.BS 4					S.SOCKADDR.ADDR
				.BS 2					S.SOCKADDR.PORT
*--------------------------------------
SA.REMOTE		.DA #AF.INET			S.SOCKADDR.AF
				.BS 1
				.BS 4					S.SOCKADDR.ADDR
				.BS 2
*--------------------------------------
ICMP.Request	.DA #S.ICMP.TYPE.ECHOREQ
				.DA #0					CODE
				.DA 0					CHECKSUM
ICMP.Request.ID	.BS 2
ICMP.Request.SQ	.BS 2		
				.AS "ABCDEFGHIJKLMNOP"
				.AS "QRSTUVWXYZ012345"
ICMP.RequestLen	.EQ *-ICMP.Request
*--------------------------------------
				.DUMMY
				.OR 0
DS.START
ArgIndex		.BS 1
PingCount		.BS 1
ArgHostName		.BS 1
hSocket			.BS 1
hFrame			.BS 1
Identifier		.BS 2
Sequence		.BS 2
TimeOut			.BS 1
TimeOut.ms		.BS 2
DS.END
				.ED
*--------------------------------------
MAN
SAVE USR/SRC/BIN/PING.S
ASM
