AX = 37C0h
DX - 1001h
DS:SI --> packet
do an INT 21h
Carry clear if sent successfully
The packet pointed to by DS:SI must have the following format:
; ds:si--> dw type ;+0 master owner TSR
; db target node ;+2
; dw len ;+3 (of remainder of packet)
; db ? dup(?) ;+5 data - user specific
The byte at +2 (target node) is the node to which you are sending the packet.
If it is 0 then the message will be sent to all nodes.
The word at +0 (type) is used by the system to permit different TSRs or user programs to use the same messaging system to send and receive messages meant for it only. The TSR must register its type with the system. The type number is completely arbitrary but type 0 has a special meaning so must not be used.
To register your type:
AX = 37C0h
DX - 1002h
DS:SI --> type description
do an INT 21h
Type description format:
; ds:si--> dw flags ;+0
; dw type ;+2 master owner
; dd code address ;+4 address called when a packet comes
; dd ring address ;+8 where to put it
; dw ring bufsize ;+12
; dd link ;+14 (used by system)
Now, when a message packet is received, the message server (in NET21) will get
the message type field, then look through the type list for a match. If found,
the code address is called (far call) and DS:SI points to the message (exact
format as sent), and es:di points to a buffer to be sent in answer.
If, you set ax>0 then no data will be returned.
If there is no code address, the data is copied to the ring address (+6) and
the least significant bit of the flags is set. The user must poll that bit and
take care of the ring. The first two bytes of the ring buffer is a flags word.
The least significant bit is set when a packet is put there, and the next
double word points to the next ring buffer. So the actual packet is placed at
ring buffer start +6. When that buffer is filled, the ring address advances to
the next ring buffer. It is up to the polling program to get packets out of the
ring faster than the system receives them. If there is an overflow, the second
bit of ths ring's flag is set. When the buffer is emptied, those two lower bIts
must be cleared by the user.
RING example: (four 100 byte buffers)
ringbuf0 dw 0
dw ringbuf1
dw seg ringbuf1
db 100 dup(?)
ringbuf1 dw 0
dw ringbuf2
dw seg ringbuf2
db 100 dup(?)
ringbuf2 dw 0
dw ringbuf3
dw seg ringbuf3
db 100 dup(?)
ringbuf3 dw 0
dw ringbuf0
dw seg ringbuf0
db 100 dup(?)
To unregister your type:
AX = 37C0h
DX - 1003h
DS:SI --> type description
do an INT 21h
(the type description is unlinked from the system list)
Now the application can terminate.
Keep going for Source Code, or...
Top of Programmer Stuff
-or-
Main Table of Contents
-or-
Top of Form
Messaging API source example
title tmsg.asm
cseg segment para public 'code'
org 100h
assume cs:cseg,ds:cseg,es:nothing
; This simple test program demonstrates how to send LBL messages
; to your program running on a remote node.
;
;
; SYNTAX:
;
; d>TMSG targnode
;
; targnode is the node you are communicating with
;
; This program will send the keys you type to the
; target node. It's an ultra-simple chat program.
;
;
; Batch to assemble this code:
;
; asm tmsg,tmsg,nul,nul
; link tmsg
; del tmsg.obj
; exe2bin tmsg, tmsg.com
; del tmsg.exe
entry proc far
su1:
jmp init
targnode db 0 ;node to send to
gotit db 0 ;flag indicates we got a message
gotkey dw 0 ;message (one keystroke)
gotcnt dw 0 ;msg len
;data stucture you must supply to LBL:
mytype dw 0 ;flags
dw 1 ;type (user number indicates ownership if these packets)
dw 0 ;exec ofs ;upcall routine
dw 0 ;exec seg
dw 0 ;ring buffer ;not used here
dw 0 ; "
dw 0 ; "
dw 0 ;link ;internal use
dw 0 ; "
buffer1 db 100 dup(0)
;........................... got_msg .....................................
;Called by LBL when the packet type you have registered is received
got_msg:
;fill in the answer packet pointed to by es:di
;this will be sent back to the original sender
mov word ptr es:[di],1 ;msg owner "type"
mov al,0FFh
mov byte ptr es:[di+2],al ;node
mov word ptr es:[di+3],6 ;count
mov word ptr es:[di+5],"et" ;data (dummy)
mov word ptr es:[di+7],"ts"
;now process the received message
mov ax,[si+3]
mov cs:gotcnt,ax
mov ax,[si+5]
mov cs:gotkey,ax
mov es:[di+9],ax
or cs:gotit,1 ;set a flag, handle packet later
xor ax,ax
ret ;this is a far return
entry endp
subs proc near
;........................... register ................................
;register our "type" so that all messages of this type are sent to us.
register:
push cs
pop ds
mov si,offset mytype
mov ax,offset got_msg
mov [si+4],ax
mov [si+6],cs
mov dx,1002h ;register
mov ax,37c0h
int 21h
ret
;........................... unregister ...................................
;stop receiving our messages (because our code will be gone!)
unregister:
mov dx,1003h ;unregister
mov ax,37c0h
push cs
pop ds
mov si,offset mytype
int 21h
ret
;........................... sendmsg ................................
;send the message in buffer1
sendmsg:
push cs
pop ds
mov si,offset buffer1
mov dx,1001h
mov ax,37c0h
int 21h
ret
;........................... init .......................................
init:
call register ;start receiving messages
call parms ;get the targnode
push cs
pop ds
mov dx,offset string1 ;signon
mov ah,9
int 21h
;. . . . . . . . . . . . . . MAIN LOOP:
init2:
sti
mov ah,1 ;get kb status
int 16h ;any key waiting?
jnz init3 ;no: yes-->
cli ;ints off for test, etc...
test cs:gotit,1 ;got a packet?
jz init2 ;yes: no--> loop back
;. . . . . . . . . . . . . . got a packet
mov cs:gotit,0 ;for next
push cs:gotkey ;save key
sti ;ints okay
mov ax,cs:gotkey ;print key
mov ah,14
int 10h
; mov ax,cs:gotcnt
; call hexax
; call crlf
pop ax ;restore the key
cmp al,13 ;was a CR?
jne init2 ;yes: no-->
mov ah,14 ;do a LF too
mov al,10
int 10h
jmp init2 ;loop back for more-->
;. . . . . . . . . . . . . . got a keystroke
;1st, print it locally
init3:
mov ah,0 ;get the key
int 16h
cmp al,27 ;is esc key?
je init9 ;no: yes-->
push ax ;save key
mov ah,14 ;print it
int 10h
pop ax
push ax
cmp al,13 ;is CR?
jne init4 ;no-->
mov ah,14 ;do LF
mov al,10
int 10h
;. . . . . . . . . . . . . . send the keystroke
init4:
push cs
pop ds
mov si,offset buffer1
mov ax,1 ;our type
mov [si],ax
mov al,targnode ;to ...
mov [si+2],al
mov cx,22 ;message length
mov [si+3],cx
pop ax ;keystroke
mov word ptr [si+5],ax
call sendmsg ;send it
; (you could check return packet for same key)
jmp init2 ;loop back
init5:
init9:
call unregister
mov ax,4c00h
int 21h
;........................... parms ....................................
parms:
cld
push cs
pop ds
xor cx,cx ;cx will = # of chars in line
mov si,81h ;ds:si --> command line
mov cl,[si-1] ;get count
parms2:
call nxtchar
jc parms9
cmp al," "
je parms2
dec si
inc cx
call getnum
mov cs:targnode,dl
parms9:
ret
nulsep db " "
;........................... Next char ........................................
nxtchar:
jcxz nc10 ;if no more chars in buffer -->
lodsb ;get next char
cmp al,0 ;fix:1/3/90, toshiba 2.11 like ti
jne nc1
mov al,0
xchg al,cs:nulsep
nc1:
dec cx ;decrement count remaining
cmp al,13 ;is CR ?
jz nc9 ;no: yes-->
cmp al,10 ;is LF ?
jz nc9 ;no: yes-->
cmp al,9 ;is tab?
je nc8a ;no: yes-->
cmp al,"a" ;force to CAPs
jc nc8
cmp al,"z"+1
jnc nc8
xor al,20h
nc8:
clc ;return good
ret
nc8a:
mov al," " ;use space
clc ;return good
ret
nc9:
dec si ;don't go passed CR
xor cx,cx ;no more chars
mov al," "
nc10:
stc ;return, none found
ret
;page
;........................... Get number .......................................
getnum:
xor dx,dx ;init number = 0
gn1:
jcxz gn9 ;are any chars left? no-->
lodsb ;yes, get next one
dec cx ;dec # left
mov ah,al ;save char
sub ah,"0" ;adjust ascii to number
jc gn8 ;was char < "0" ? yes-->
cmp ah,10 ;is char > "9" ?
jnc gn8 ; yes-->
push ax
mov ax,10 ;decimal shift left
mul dx
mov dx,ax
pop ax
add dl,ah ;add in ones
adc dh,0
jmp gn1 ;see if more
gn8:
dec si ;restore buffer ptr
inc cx ;restore # remaining
gn9:
ret
string1 db "Waiting for keystrokes, ESC will exit ...",13,10,"$"
;.......................... video ............................
video:
push ax
mov ah,14
push si
push di
int 10h
pop di
pop si
pop ax
ret
hexax:
push ax
mov al,ah
call hexal
pop ax
call hexal
ret
hexal:
push ax
push cx
mov ch,al
mov cl,4
shr al,cl
add al,"0"
cmp al,3Ah
jc hxal2
add al,7
hxal2:
call video
mov al,ch
and al,0fh
add al,"0"
cmp al,3Ah
jc point4
add al,7
point4:
call video
pop cx
pop ax
ret
crlf:
push ax
mov al,0Dh
call video
mov al,0Ah
call video
pop ax
ret
subs endp
cseg ends
end su1
Click here to download the assembled program.
Top of Programmer Stuff
-or-
Main Table of Contents
-or-
Top of Form