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/net.tcpip.i
				.INB inc/libtcpip.i
*--------------------------------------
TIMEOUT.MAX		.EQ 40					4 sec.
*--------------------------------------
				.DUMMY
				.OR ZPBIN
ZS.START
ZPIPCfgPtr		.BS 2
ZPTmpPtr		.BS 2
Identifier		.BS 2
Sequence		.BS 2

TimeOut.ms		.BS 2
ArgIndex		.BS 1
ArgHostName		.BS 1
hSocket			.BS 1
hFrame			.BS 1
PingCount		.BS 1
TimeOut			.BS 1

IP.Remote		.BS 4

ZS.END			.ED
*--------------------------------------
*			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 Size (without Constants)
				.DA DS.END-DS.START		Data SegmentSize
				.DA #64					Stack Size
				.DA #ZS.END-ZS.START	Zero Page Size
				.DA 0
*--------------------------------------
.1				.DA CS.INIT
				.DA CS.RUN
				.DA CS.DOEVENT
				.DA	CS.QUIT
L.LIBTCPIP		.DA LIBTCPIP
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 .1

				>LDYA L.MSG.IPKO
				>SYSCALL PutS
				lda #E.SYN
				sec
				rts

.1				ldy #DATA.Len-1

.2				lda ICMP.Request,y
				sta (pData),y
				dey
				bpl .2


CS.RUN.IPOK		inc ArgIndex
				lda ArgIndex
				>SYSCALL ArgV
				bcs .8

				>STYA ZPTmpPtr
				lda (ZPTmpPtr)
				cmp #'-'
				bne .1

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

				cmp #'0'
				bcc .9

				cmp #'9'+1
				bcs .9

				and #$0F
				sta PingCount
				bra CS.RUN.IPOK

.1				lda #TIMEOUT.MAX
				sta TimeOut

.2				>PUSHEA.G SA.REMOTE+S.SOCKADDR.ADDR
				>PUSHW ZPTmpPtr
				>LIBCALL hLIBTCPIP,LIBTCPIP.HST.GetByName
				bcc .3

				>SLEEP
				lda TimeOut
				bne .2

				>PUSHW L.MSG.UNKNOWN
				>PUSHW ZPTmpPtr
				>PUSHBI 2
				bra .99

.3				lda ArgIndex
				sta ArgHostName
				jmp CS.RUN.IPOK

.8				>LDA.G SA.REMOTE+S.SOCKADDR.ADDR
				bne CS.RUN.ARGSOK

.9				>PUSHW L.MSG.USAGE
				>PUSHBI 0

.99				>SYSCALL PrintF

				lda #E.SYN
				sec
				rts

CS.RUN.ARGSOK	>PUSHW L.MSG.HOSTOK

				ldx #4
				ldy #SA.REMOTE+S.SOCKADDR.ADDR

.1				lda (pData),y
				>PUSHA
				iny
				dex
				bne .1

				lda ArgHostName
				>SYSCALL ArgV
				>PUSHYA

				>PUSHBI 6
				>SYSCALL PrintF

CS.RUN.OPENSKT	ldx #3
				ldy #S.IPCFG.IP+3

.1				lda (ZPIPCfgPtr),y
				sta IP.Remote,x
				dey
				dex
				bpl .1

				ldx #3
				ldy #SA.LOCAL+S.SOCKADDR.ADDR+3

.2				lda IP.Remote,x
				sta (pData),y
				dey
				dex
				bpl .2

				lda A2osX.R16
				eor A2osX.T16+1
				>STA.G SA.LOCAL+S.SOCKADDR.PORT
				>STA.G SA.REMOTE+S.SOCKADDR.PORT
				sta Identifier

				lda A2osX.R16+1
				eor A2osX.T16
				>STA.G SA.LOCAL+S.SOCKADDR.PORT+1
				>STA.G SA.REMOTE+S.SOCKADDR.PORT+1
				sta Identifier+1

				>PUSHBI S.SOCKET.T.RAW
				>PUSHBI S.IP.PROTOCOL.ICMP
				>LIBCALL hLIBTCPIP,LIBTCPIP.Socket
				bcs .9

				sta hSocket

				>PUSHB hSocket
				>PUSHEA.G SA.LOCAL
				>LIBCALL hLIBTCPIP,LIBTCPIP.Bind
				bcs .9

				>PUSHB hSocket
				>PUSHEA.G SA.REMOTE
				>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
				>SLEEP

				lda Identifier
				>STA.G Request+S.ICMP.IDENTIFIER-S.IP+1

				lda Identifier+1
				dey
				sta (pData),y

				inc Sequence
				bne .1

				inc Sequence+1

.1				lda Sequence
				>STA.G Request+S.ICMP.SEQUENCE-S.IP+1

				lda Sequence+1
				dey
				sta (pData),y

				>PUSHB hSocket
				>PUSHW pData
				>PUSHWI ICMP.RequestLen
				>LIBCALL hLIBTCPIP,LIBTCPIP.Send
				bcs CS.RUN.ERR

				lda #TIMEOUT.MAX
				sta 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 hSocket
				>LIBCALL hLIBTCPIP,LIBTCPIP.Recv
				bcc .2

				lda TimeOut
				bne CS.RUN.WAIT.REPLY

				jsr CS.Print.UNREACH
				bcs CS.RUN.ERR
				bra .7

.2				sta hFrame
				>SYSCALL GetMemPtr
				>STYA ZPTmpPtr

				ldy #S.ICMP.SEQUENCE
				lda (ZPTmpPtr),y
				cmp Sequence+1
				bne .3

				iny
				lda (ZPTmpPtr),y
				cmp Sequence
				beq .4

.3				jsr CS.FrameDiscard
				bra CS.RUN.WAIT.REPLY

.4				jsr CS.Print.REPLY
				bcs CS.RUN.ERR

				jsr CS.FrameDiscard

.7				lda PingCount
				beq .8

				dec	PingCount
				dec						A=0
				beq .80

.8				jmp CS.RUN.SEND.ECHO

.80				sec
CS.RUN.ERR		rts
*--------------------------------------
CS.DOEVENT		lda (pEvent)
				bpl .9					is it a TIMER event?

				lda TimeOut
				beq .9

				dec TimeOut

.9				sec						do not discard TIMER event
				rts
*--------------------------------------
CS.Print.UNREACH
				>PUSHW L.MSG.UNREACH

				ldx #4
				ldy #SA.REMOTE+S.SOCKADDR.ADDR

.1				lda (pData),y
				>PUSHA
				iny
				dex
				bne .1

				>PUSHBI 4
				>SYSCALL PrintF
				rts
*--------------------------------------
CS.Print.REPLY	lda #TIMEOUT.MAX
				sec
				sbc TimeOut

				stz TimeOut.ms
				stz TimeOut.ms+1
				tax
				beq .3

.1				lda TimeOut.ms
				clc
				adc #100
				sta TimeOut.ms
				bcc .2

				inc TimeOut.ms+1

.2				dex
				bne .1

.3				>PUSHW L.MSG.REPLY

				ldx #4
				ldy #S.IP.SRC

.4				>PUSHB (ZPTmpPtr),y
				iny
				dex
				bne .4

				ldy #S.ICMP.SEQUENCE
				>PUSHB (ZPTmpPtr),y
				iny
				>PUSHB (ZPTmpPtr),y

				ldy #S.IP.TTL
				>PUSHB (ZPTmpPtr),y

				>PUSHW TimeOut.ms
				>PUSHBI 9

				>SYSCALL PrintF
				rts
*--------------------------------------
CS.QUIT			jsr CS.FrameDiscard

				lda hSocket
				beq .2

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

.8				clc
				rts
*--------------------------------------
CS.FrameDiscard	lda hFrame
				beq .1

				stz hFrame

				>SYSCALL FreeMem

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