; ; TFTP Wave Player ; ; Compile with FASM for Menuet ; ; ; 12.7.2002 - Audio system calls by VT ; use32 org 0x0 db 'MENUET01' ; header dd 0x01 ; header version dd START ; entry point dd I_END ; image size dd I_END+0x10000 ; required memory dd I_END+0x10000 ; esp dd 0x0 , 0x0 ; I_Param , I_Path include 'lang.inc' include '..\..\..\macros.inc' delay dd 145 wait_for dd 0x0 START: ; start of execution mov dword [prompt], p9 mov dword [promptlen], p9len - p9 red: call draw_window ; at first, draw the window still: mov eax,10 ; wait here for event mcall cmp eax,1 ; redraw request ? jz red cmp eax,2 ; key in buffer ? jz key cmp eax,3 ; button in buffer ? jz button jmp still key: ; Keys are not valid at this part of the mov eax,2 ; loop. Just read it and ignore mcall jmp still button: ; button mov eax,17 ; get id mcall cmp ah,1 ; button id=1 ? jnz noclose ; close socket before exiting mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0 or eax,-1 ; close this program mcall noclose: cmp ah,2 ; copy file to local machine? jnz nocopyl mov dword [prompt], p5 mov dword [promptlen], p5len - p5 call draw_window ; ; Copy File from Remote Host to this machine call translateData ; Convert Filename & IP address mov edi, tftp_filename + 1 mov [edi], byte 0x01 ; setup tftp msg call copyFromRemote jmp still nocopyl: cmp ah,4 jz f1 cmp ah,5 jz f2 jmp nof12 f1: mov [addr],dword source mov [ya],dword 35 jmp rk f2: mov [addr],dword destination mov [ya],dword 35+16 rk: mov ecx,15 mov edi,[addr] mov al,' ' rep stosb call print_text mov edi,[addr] f11: mov eax,10 mcall cmp eax,2 jz fbu jmp still fbu: mov eax,2 mcall ; get key shr eax,8 cmp eax,8 jnz nobs cmp edi,[addr] jz f11 sub edi,1 mov [edi],byte ' ' call print_text jmp f11 nobs: cmp eax,dword 31 jbe f11 cmp eax,dword 95 jb keyok sub eax,32 keyok: mov [edi],al call print_text add edi,1 mov esi,[addr] add esi,15 cmp esi,edi jnz f11 jmp still print_text: mov eax,13 mov ebx,103*65536+15*6 mov ecx,[ya] shl ecx,16 mov cx,8 mov edx,0x224466 mcall mov eax,4 mov ebx,103*65536 add ebx,[ya] mov ecx,0xffffff mov edx,[addr] mov esi,15 mcall ret nof12: jmp still ;*************************************************************************** ; Function ; translateData ; ; Description ; Coverts the filename and IP address typed in by the user into ; a format suitable for the IP layer. ; ; The filename, in source, is converted and stored in tftp_filename ; The host ip, in destination, is converted and stored in tftp_IP ; ;*************************************************************************** translateData: ; first, build up the tftp command string. This includes the filename ; and the transfer protocol ; First, write 0,0 mov al, 0 mov edi, tftp_filename mov [edi], al inc edi mov [edi], al inc edi ; Now, write the file name itself, and null terminate it mov ecx, 15 mov ah, ' ' mov esi, source td001: lodsb stosb cmp al, ah loopnz td001 cmp al,ah ; Was the entire buffer full of characters? jne td002 dec edi ; No - so remove ' ' character td002: mov [edi], byte 0 inc edi mov [edi], byte 'O' inc edi mov [edi], byte 'C' inc edi mov [edi], byte 'T' inc edi mov [edi], byte 'E' inc edi mov [edi], byte 'T' inc edi mov [edi], byte 0 mov esi, tftp_filename sub edi, esi mov [tftp_len], edi ; Now, convert the typed IP address into a real address ; No validation is done on the number entered ; ip addresses must be typed in normally, eg ; 192.1.45.24 xor eax, eax mov dh, 10 mov dl, al mov [tftp_IP], eax ; 192.168.24.1 1.1.1.1 1. 9.2.3. mov esi, destination mov edi, tftp_IP mov ecx, 4 td003: lodsb sub al, '0' add dl, al lodsb cmp al, '.' je ipNext cmp al, ' ' je ipNext mov dh, al sub dh, '0' mov al, 10 mul dl add al, dh mov dl, al lodsb cmp al, '.' je ipNext cmp al, ' ' je ipNext mov dh, al sub dh, '0' mov al, 10 mul dl add al, dh mov dl, al lodsb ipNext: mov [edi], dl inc edi mov dl, 0 loop td003 ret ;*************************************************************************** ; Function ; copyFromRemote ; ; Description ; ;*************************************************************************** copyFromRemote: mov eax,0x20000-512 mov [fileposition], eax ; Get a random # for the local socket port # mov eax, 3 mcall mov ecx, eax shr ecx, 8 ; Set up the local port # with a random # ; open socket mov eax, 53 mov ebx, 0 mov edx, 69 ; remote port mov esi, [tftp_IP] ; remote IP ( in intenet format ) mcall mov [socketNum], eax ; make sure there is no data in the socket - there shouldn't be.. cfr001: mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall ; any more data? cmp eax, 0 jne cfr001 ; yes, so get it ; Now, request the file mov eax, 53 mov ebx, 4 mov ecx, [socketNum] mov edx, [tftp_len] mov esi, tftp_filename mcall cfr002: mov eax,23 ; wait here for event mov ebx,1 ; Time out after 10ms mcall cmp eax,1 ; redraw request ? je cfr003 cmp eax,2 ; key in buffer ? je cfr004 cmp eax,3 ; button in buffer ? je cfr005 ; Any data to fetch? mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall cmp eax, 0 je cfr002 push eax ; eax holds # chars ; Update the text on the display - once mov eax, [prompt] cmp eax, p3 je cfr008 mov dword [prompt], p3 mov dword [promptlen], p3len - p3 call draw_window ; cfr008: ; we have data - this will be a tftp frame ; read first two bytes - opcode mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte pop eax ; bl holds tftp opcode. Can only be 3 (data) or 5 ( error ) cmp bl, 3 jne cfrerr push eax ; do data stuff. Read block #. Read data. Send Ack. mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte mov [blockNumber], bl mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte mov [blockNumber+1], bl cfr007: mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte mov esi, [fileposition] mov [esi], bl mov [esi+1],bl add dword [fileposition],2 mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall ; any more data? cmp eax, 0 jne cfr007 ; yes, so get it cmp [fileposition],0x20000+0xffff jb get_more_stream wait_more: mov eax,5 ; wait for correct timer position ; to trigger new play block mov ebx,1 mcall mov eax,26 mov ebx,9 mcall cmp eax,[wait_for] jb wait_more add eax,[delay] mov [wait_for],eax mov esi,0x20000 mov edi,0x10000 mov ecx,65536 cld rep movsb mov eax,55 mov ebx,0 mov ecx,0x10000 mcall mov eax,55 mov ebx,1 mcall mov [fileposition],0x20000 get_more_stream: ; write the block number into the ack mov al, [blockNumber] mov [ack + 2], al mov al, [blockNumber+1] mov [ack + 3], al ; send an 'ack' mov eax, 53 mov ebx, 4 mov ecx, [socketNum] mov edx, ackLen - ack mov esi, ack mcall ; If # of chars in the frame is less that 516, ; this frame is the last pop eax cmp eax, 516 je cfr002 ; Write the file mov eax, 33 mov ebx, source mov edx, [filesize] mov ecx, I_END + 512 mov esi, 0 mcall jmp cfrexit cfrerr: ; simple implementation on error - just read all data, and return mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall ; any more data? cmp eax, 0 jne cfrerr ; yes, so get it jmp cfr006 ; close socket and close app cfr003: ; redraw request call draw_window jmp cfr002 cfr004: ; key pressed mov eax,2 ; just read it and ignore mcall jmp cfr002 cfr005: ; button mov eax,17 ; get id mcall cmp ah,1 ; button id=1 ? jne cfr002 ; If not, ignore. cfr006: ; close socket mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0 mov eax,-1 ; close this program mcall jmp $ cfrexit: ; close socket mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0 mov dword [prompt], p4 mov dword [promptlen], p4len - p4 call draw_window ; ret ; ********************************************* ; ******* WINDOW DEFINITIONS AND DRAW ******** ; ********************************************* draw_window: mov eax,12 ; function 12:tell os about windowdraw mov ebx,1 ; 1, start of draw mcall ; DRAW WINDOW mov eax,0 ; function 0 : define and draw window mov ebx,100*65536+230 ; [x start] *65536 + [x size] mov ecx,100*65536+170 ; [y start] *65536 + [y size] mov edx,0x14224466 ; color of work area RRGGBB mov edi,title mcall mov eax,8 ; DELETE BUTTON mov ebx,20*65536+190 mov ecx,111*65536+15 mov edx,2 mov esi,0x557799 mcall mov ebx,200*65536+10 mov ecx,34*65536+10 mov edx,4 mcall mov ecx,50*65536+10 mov edx,5 mcall ; Copy the file name to the screen buffer ; file name is same length as IP address, to ; make the math easier later. cld mov esi,source mov edi,text+13 mov ecx,15 rep movsb ; copy the IP address to the screen buffer mov esi,destination mov edi,text+40+13 mov ecx,15 rep movsb ; copy the prompt to the screen buffer mov esi,[prompt] mov edi,text+280 mov ecx,[promptlen] rep movsb ; Re-draw the screen text cld mov eax,4 mov ebx,25*65536+35 ; draw info text with function 4 mov ecx,0xffffff mov edx,text mov esi,40 newline: mcall add ebx,16 add edx,40 cmp [edx],byte 'x' jnz newline mov eax,12 ; function 12:tell os about windowdraw mov ebx,2 ; 2, end of draw mcall ret ; DATA AREA source db 'HEAT8M22.WAV ' destination db '192.168.1.24 ' tftp_filename: times 15 + 9 db 0 tftp_IP: dd 0 tftp_len: dd 0 addr dd 0x0 ya dd 0x0 fileposition dd 0 ; Points to the current point in the file filesize dd 0 ; The number of bytes written / left to write fileblocksize dw 0 ; The number of bytes to send in this frame text: db 'SOURCE FILE: xxxxxxxxxxxxxxx ' db 'HOST IP ADD: xxx.xxx.xxx.xxx ' db ' ' db 'WAVE FORMAT: 8 BIT,MONO,22050HZ ' db ' ' db ' SERVER -> PLAY FILE ' db ' ' db ' ' db 'x' ; <- END MARKER, DONT DELETE title db 'TFTP Wave Player',0 prompt: dd 0 promptlen: dd 0 p1: db 'Waiting for Command ' p1len: p9: db 'Define SB with setup' p9len: p2: db 'Sending File ' p2len: p3: db 'Playing File ' p3len: p4: db 'Complete ' p4len: p5: db 'Contacting Host... ' p5len: p6: db 'File not found. ' p6len: ack: db 00,04,0,1 ackLen: socketNum: dd 0 blockNumber: dw 0 ; This must be the last part of the file, because the blockBuffer ; continues at I_END. blockBuffer: db 00, 03, 00, 01 I_END: