Дипломная работа: Апаратно–програмний комплекс GSM-МТМ
DIV50 DW 2304
; поточний номер області даних порту
CURRENT_AREA DW AREA1
; область даних для кожного порту
AREA1 SP_TAB <0,1,INT_COM1,E_IRQ4,D_IRQ4,EOI4>; область даних COM1
AREA2 SP_TAB <0,2,INT_COM2,E_IRQ3,D_IRQ3,EOI3>; область даних COM2
AREA3 SP_TAB <0,3,INT_COM3,E_IRQ4,D_IRQ4,EOI4>; область даних COM3
AREA4 SP_TAB <0,4,INT_COM4,E_IRQ3,D_IRQ3,EOI3>; область даних COM4
_DATA ENDS
COM_TEXT SEGMENT PARA public 'CODE'
ASSUME cs:COM_TEXT,ds:DGROUP,es:NOTHING
public _select_port
public _save_com
public _install_com
public _restore_com
public _open_com
public _close_com
public _dtr_on
public _dtr_off
public _r_count
public _s_count
public _receive_com
public _send_com
public _break_com
public _com_errors
public _com_ring
; вибір активного порту
; [bp+6] - номер порту
_select_port PROC FAR
push bp
mov bp, sp
mov ax, [bp+6];одержуємо в ax аргумент функції
cmp al,1; установлений порт 1?
je port1; да
cmp al,2; установлений порт 2?
je port2; да
cmp al,3; установлений порт 3?
je port3; да
cmp al,4; установлений порт 4?
je port4; да
jmp set_carrent_area
port1:
mov ax,OFFSET DGROUP:AREA1; вибираємо область даних COM1
jmp short set_carrent_area
port2:
mov ax,OFFSET DGROUP:AREA2; вибираємо область даних COM2
jmp short set_carrent_area
port3:
mov ax,OFFSET DGROUP:AREA3; вибираємо область даних COM3
jmp short set_carrent_area
port4:
mov ax,OFFSET DGROUP:AREA4; вибираємо область даних COM4
set_carrent_area:
; записуємо в перемінної CURRENT_AREA зсув
; поточно області даних
mov CURRENT_AREA,ax
mov sp,bp
pop bp
ret
_select_port ENDP
;
; збереження поточного вектора COM переривання
_save_com PROC FAR
push bp
mov bp,sp
push si
; записуємо в si покажчик на поточну область даних
mov si,CURRENT_AREA
push es
mov AREA1.int_hndlr,OFFSET int_hndlr1
mov AREA2.int_hndlr,OFFSET int_hndlr2
mov AREA3.int_hndlr,OFFSET int_hndlr3
mov AREA4.int_hndlr,OFFSET int_hndlr4
; зберігаємо старий вектор переривання
mov ah,35H
mov al,int_com[si]; номер переривання
int 21h
; записуємо в перемінні old_com_off і old_com_seg
; відповідно сегмент і зсув старого вектора переривання
mov old_com_off[si],bx
mov bx,es
mov old_com_seg[si],bx
pop es
pop si
mov sp,bp
pop bp
ret
_save_com ENDP
; install_com: установити активний порт
; повертає в регістрі ax - 1 при успішній установці
; і 0 у випадку помилки
_install_com PROC FAR
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
push es
cmp installed[si],1
jne go_install
jmp alredy_ok
; очищаємо лічильники помилок
go_install:
mov WORD PTR EOVFLOW[si],0; переповнення буфера передавача
mov WORD PTR EOVRUN[si],0; помилка переповнення при прийомі
mov WORD PTR EBREAK[si],0; виявлений запит на переривання
mov WORD PTR EFRAME[si],0; помилка синхронізації
mov WORD PTR EPARITY[si],0; помилка парності
mov WORD PTR EXMIT[si],0; помилка при передачі
mov WORD PTR EDSR[si],0; не отриманий сигнал DSR
mov WORD PTR ECTS[si],0; не отриманий сигнал CTS
; визначаємо базова адреса використовуваного COM порту
mov bx,BIOS_VAR
mov es,bx
ASSUME es:BIOS_VAR
cmp port[si],1; порт 1?
je adr_3F8
cmp port[si],2; порт 2?
je adr_2F8
cmp port[si],3; порт 3?
je adr_3E8
cmp port[si],4; порт 4?
je adr_2E8
int 20H
adr_3F8:
mov ax,3F8H
jmp cmp_bios
adr_2F8:
mov ax,2F8H
jmp cmp_bios
adr_3E8:
cmp rs232_base+4,0
je adr_3E8_A
mov ax,rs232_base+4
jmp cmp_bios
adr_3E8_A:
mov ax,3E8H
mov rs232_base+4,ax
jmp cmp_bios
adr_2E8:
cmp rs232_base+6,0
je adr_2E8_A
mov ax,rs232_base+6
jmp cmp_bios
adr_2E8_A:
mov ax,2E8H
mov rs232_base+6,ax
; перевіряємо чи існує визначена відповідна змінна
; BIOS
cmp_bios:
cmp ax,rs232_base
je set_reg_adr
cmp ax,rs232_base+2
je set_reg_adr
cmp ax,rs232_base+4
je set_reg_adr
cmp ax,rs232_base+6
jne bad_exit
set_reg_adr:
mov bx,DATREG
mov cx,7
set_next_reg_adr:
mov WORD PTR [si][bx],ax
inc ax
add bx,2
loop set_next_reg_adr
; установлюємо вектор переривання на наш оброблювач
mov AREA1.int_hndlr,OFFSET int_hndlr1
mov AREA2.int_hndlr,OFFSET int_hndlr2
mov AREA3.int_hndlr,OFFSET int_hndlr3
mov AREA4.int_hndlr,OFFSET int_hndlr4
mov ah,25H
mov al,int_com[si]; номер переривання
mov dx,OFFSET DGROUP:int_hndlr[si]
push ds
push cs
pop ds
int 21h
pop ds
; піднімаємо прапор - порт установлений
alredy_ok:
mov installed[si],1
pop es
; повертаємо 1
mov ax,1
pop si
mov sp,bp
pop bp
ret
; порт не встановлений
bad_exit:
mov installed[si],0
pop es
; повертаємо 0
mov ax,0
pop si
mov sp,bp
pop bp
ret
_install_com ENDP
; відновлення векторів переривань
_restore_com PROC FAR
push bp
mov bp,sp
push si
; відзначаємо COM порт як не активний
mov si,CURRENT_AREA
mov installed[si],0
; відновлюємо вектор переривання
mov ah,25H
mov al,int_com[si]
mov dx,old_com_off[si]
mov bx,old_com_seg[si]
push ds
mov ds,bx
int 21h
pop ds
pop si
mov sp,bp
pop bp
ret
_restore_com ENDP
; відкрити COM порт
; скидання буферів передавача і приймача,
; ініціалізація регістрів UART 8250
; дозвіл переривань від UART 8250
; (програмування контролера переривань)
; [bp+6] = швидкість обміну
; [bp+8] = спосіб з'єднання - M(Модем), D(Нуль-модем)
; [bp+10] = парність - N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
; [bp+12] = кількість стопових бітів 1, 2
_open_com PROC FAR
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
; забороняємо переривання
cli
mov ax,[bp+6]
mov baud_rate[si],ax
mov bh,[bp+8]
mov device_conn[si],bh
mov bl,[bp+10]
mov parity[si],bl
mov ch,[bp+12]
mov stop_bits[si],CH
; скидаємо буфери і покажчики
mov start_s_data[si],0
mov end_s_data[si],0
mov start_r_data[si],0
mov end_r_data[si],0
mov size_s_data[si],0
mov size_r_data[si],0
; чи перевіряємо установлений вже оброблювач переривань
test installed[si],1
jnz reset_uart
jmp exit_open
reset_uart:
; установлюємо регістри UART 8250
; скидаємо регістр керування модемом
mov al,0
mov dx,MCR[si]
out dx,al
jmp $+2
; скидаємо регістр стану лінії
mov dx,LSR[si]
in al,dx
jmp $+2
; скидаємо регістр даних
mov dx,DATREG[si]
in al,dx
jmp $+2
; скидаємо регістр стану модему
mov dx,MSR[si]
in al,dx
; визначаємо дільник частоти тактового генератора
mov ax,50
mul DIV50
div baud_rate[si]
mov bx,ax
; переключаємо регістир даних і регістр керування перериваннями
; для введення дільника частоти тактового генератора
mov dx,LCR[si]
mov al,80H
out dx,al
jmp $+2
; уводимо молодший байт дільника частоти тактового генератора
mov dx,WORD PTR DLL[si]
mov al,bl
out dx,al
jmp $+2
; уводимо старший байт дільника частоти тактового генератора
mov dx,WORD PTR DLH[si]
mov al,bh
out dx,al
jmp $+2
; визначаємо парність і кількість стоп-бітів
mov al,03H
cmp parity[si],'O'
jne next1
mov al,0ah
jmp short next3
next1:
cmp parity[si],'E'
jne next2
mov al,1ah
jmp short next3
next2:
cmp parity[si],'M'
jne next3
mov al,2ah
next3:
test stop_bits[si],2
jz stop1
or al,4
stop1:
mov dx,LCR[si]
out dx,al
; дозволяємо переривання для 8259 і 8250
; установлюємо регістр маски переривань щоб
; дозволити переривання від асинхронного порту
in al,IMR
and al,d_irq[si]
out IMR,al
; дозволяємо генерацію переривань при готовності прийнятих
; даних, по стані "BREAK" і помилково
mov dx,IER[si]
mov al,0Dh
out dx,al
jmp $+2
; установлюємо DTR, RTS, OUT2
mov dx,MCR[si]
mov al,0bh
out dx,al
exit_open:
sti
pop si
mov sp,bp
pop bp
ret
_open_com ENDP
; забороняємо переривання від асинхронного порту
_close_com PROC FAR
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_close
; забороняємо переривання UART 8250
mov dx,IER[si]
mov al,0
out dx,al
; маскуємо переривання від UART
mov dx,IMR
in al,dx
or al,e_irq[si]
jmp $+2
out dx,al
exit_close:
pop si
mov sp,bp
pop bp
ret
_close_com ENDP
;процедура повертає 1 якщо з МТМ надійшов дзвінок
_com_ring proc far
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_com_ring
xor ax,ax
mov al,BYTE PTR RING[si]
nop
mov RING[si],0
nop;
exit_com_ring:
pop si
mov sp,bp
pop bp
ret
_com_ring endp
; ДОПОМІЖНІ ФУНЦІЇ
; знімаємо сигнал DTR
_dtr_off PROC FAR
push bp
mov bp,sp
push si
pushf
push ax
push dx
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_dtr_off
; установлюємо регістр керування модемом,
; скидаємо сигнали DTR і RTS
mov dx,MCR[si]
mov al,08H
out dx,al
exit_dtr_off:
pop si
pop dx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_dtr_off ENDP
; установлюємо сигнал DTR
_dtr_on PROC FAR
push bp
mov bp,sp
push si
pushf
push ax
push dx
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_dtr_on
; установлюємо регістр керування модемом,
; установлюємо сигнали DTR, RTS, OUT2
mov dx,MCR[si]
mov al,0bh
out dx,al
exit_dtr_on:
pop si
pop dx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_dtr_on ENDP
;
; повертаємо в регістрі ax число байтів у регістрі приймача,
; а в регістрі dx загальний розмір буфера приймача
_r_count PROC FAR
push bp
mov bp,sp
push si
pushf
push si
mov si,CURRENT_AREA
mov ax,0
mov dx,R_SIZE
test installed[si],1
jz exit_r_count
; записуємо в регістр ax число символів у буфері приймача
mov ax,size_r_data[si]
exit_r_count:
pop si
popf
pop si
mov sp,bp
pop bp
ret
_r_count ENDP
; одержуємо черговий символ з буфера приймача,
; отриманий символ віддаляється з буфера
_receive_com PROC FAR
push bp
mov bp,sp
push si
pushf
push bx
push si
mov si,CURRENT_AREA
mov ax,-1
test installed[si],1
jz exit_receive_com
; повертаємося якщо буфер приймача порожній
cmp size_r_data[si],0
je exit_receive_com
mov ah,0
mov bx,start_r_data[si]
mov al,reciave_buf[si][bx]
cmp parity[si],'N'
je no_parity
; якщо виробляється перевірка на парність, то маскуємо старший біт
and al,7FH
no_parity:
inc bx
cmp bx,R_SIZE
jb rec_ptr_no_max
mov bx,0
rec_ptr_no_max:
mov start_r_data[si],bx
dec size_r_data[si]
exit_receive_com:
pop si
pop bx
popf
pop si
mov sp,bp
pop bp
ret
_receive_com ENDP
; функція повертає в регістрі ax число вільних байт у
; буфер передавача, а в регістрі dx загальний розмір буфера передавача
_s_count PROC FAR
push bp
mov bp,sp
push si
pushf
push si
mov si,CURRENT_AREA
mov ax,0
mov dx,S_SIZE
test installed[si],1
jz exit_s_count
mov ax,S_SIZE
sub ax,size_s_data[si]
exit_s_count:
pop si
popf
pop si
mov sp,bp
pop bp
ret
_s_count ENDP
; помістити символ у буфер передавача
; [bp+6] - символ
_send_com PROC FAR
push bp
mov bp,sp
push si
mov al,[bp+6]
pushf
push ax
push bx
push dx
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_send_com
cmp size_s_data[si],S_SIZE
jl no_s_EOVFLOW
; відбулося переповнення буфера передавача
inc WORD PTR EOVFLOW[si]
jmp short exit_send_com
no_s_EOVFLOW:
mov bx,end_s_data[si]
mov send_buf[si][bx],al
inc bx
cmp bx,S_SIZE
jl no_send_ptr_max
mov bx,0
no_send_ptr_max:
mov end_s_data[si],bx
inc size_s_data[si]
; зчитуємо регістр керування перериваннями
mov dx,IER[si]
in al,dx
; завершуємо функцію якщо дозволені переривання після передачі байта
test al,2
jnz exit_send_com
; дозволяємо переривання після передачі байта, після прииема байта,
; при виявленні стану "BREAK" і при виникненні помилки
mov al,7
out dx,al
exit_send_com:
pop si
pop dx
pop bx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_send_com ENDP
; передаємо вилученому модему сигнал "BREAK"
_break_com PROC FAR
push bp
mov bp,sp
push si
pushf
push ax
push cx
push dx
mov si,CURRENT_AREA
test installed[si],1
jz exit_break_com
; передаємо сигнал "BREAK"
mov dx,LCR[si]
in al,dx
jmp $+2
or al,40h
out dx,al
mov cx,0C000h
do_BREAK:
loop do_BREAK
and al,0BFh
out dx,al
exit_break_com:
pop dx
pop cx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_break_com ENDP
; повертаємо в dx:ax покажчик на лічильники помилок
_com_errors PROC FAR
push bp
mov bp,sp
mov ax,OFFSET DGROUP:CURRENT_AREA
add ax,error_block
mov dx,ds
mov sp,bp
pop bp
ret
_com_errors ENDP
; заповнюємо лічильники помилок
set_err PROC NEAR
test al,2
jz test1
inc WORD PTR EOVRUN[si]
test1:
test al,4
jz test2
inc WORD PTR EPARITY[si]
test2:
test al,8
jz test3
inc WORD PTR EFRAME[si]
test3:
test al,16
jz exit_set_err
inc WORD PTR EBREAK[si]
exit_set_err:
ret
set_err ENDP
; протокол модему для передачі даних
modem_protocol PROC NEAR
cmp device_conn[si],'M'
jne no_modem
; установлюємо сигнали DTR, RTS і OUT2
mov dx,MCR[si]
mov al,00001011B
out dx,al
jmp $+2
; очікуємо поки модем відповість про готовність сигналом DSR
mov cx,1000
mov dx,MSR[si]
wait_dsr:
in al,dx
test al,20H
jnz test_cts
loop wait_dsr
; модем не відповів сигналом DSR
inc WORD PTR EDSR[si]
jmp short no_modem
test_cts:
; очікуємо поки модем відповість про готовність сигналом CTS
mov cx,1000
wait_cts:
in al,dx
test al,10H
jnz test_lcr
loop wait_cts
; модем не відповів сигналом CTS
inc WORD PTR ECTS[si]
test_lcr:
no_modem:
; чи перевіряємо порожній регситр збереження передавача
mov dx,LSR[si]
in al,dx
test al,20H
jnz s_reg_empty
; помилка при передачі
inc WORD PTR EXMIT[si]
s_reg_empty:
ret
modem_protocol ENDP
; оброблювач переривань від COM1
int_hndlr1 PROC FAR
push si
mov si,OFFSET DGROUP:AREA1
jmp short handle_int
; оброблювач переривань від COM2
int_hndlr2 PROC FAR
push si
mov si,OFFSET DGROUP:AREA2
jmp short handle_int
; оброблювач переривань від COM3
int_hndlr3 PROC FAR
push si; SAVE si
mov si,OFFSET DGROUP:AREA3
jmp short handle_int
;
; оброблювач переривань від COM4
int_hndlr4 PROC FAR
push si; SAVE si
mov si,OFFSET DGROUP:AREA4
;
; оброблювач переривань
handle_int:
push ax
push bx
push cx
push dx
push bp
push di
push ds
push es
mov ax,DGROUP
mov ds,ax
next_pr:
; передаємо контролеру переривань команду кінця обробки
; переривання
mov dx,OCR
mov al,eoi[si]
out dx,al
next_inter:
; зчитуємо значення регістра ідентифікації переривання
mov dx,IIR[si]
in al,dx
; визначаємо причину переривання
; виявлено сотояние "BREAK" чи відбулася помилка
cmp al,0
je MSTAT_int
; дан прийняті і доступні для читання
cmp al,4
je RX_int
; буфер передавача порожній
cmp al,2
je TX_int
; змінився стан ліній CTS, RI, DCD, DSR
cmp al,6
je LSTAT_int
; завершуємо обробку переривань
jmp FAR PTR exit_handler
LSTAT_int:
; зчитуємо регістр стану лінії і викликаємо функцію
; set_err, що визначить причину переривання
mov dx,LSR[si]
in al,dx
mov al,0FFh
mov RING[si],al
call set_err
jmp next_inter
MSTAT_int:
; зчитуємо регістр стану модему
mov dx,MSR[si]
in al,dx
mov al,0FFh
mov RING[si],al
jmp next_inter
TX_int:
; дивимося сти чи дані для передачі модему
cmp size_s_data[si],0
jg have_data_for_send
; якщо буфер передавача порожній переустановлюємо регістр
; керування перериваннями
mov dx,IER[si]
mov al,0Dh
out dx,al
jmp next_inter
have_data_for_send:
; передаємо символ модему відповідно до стану
; ліній RS-232-З
call modem_protocol
; передаємо черговий символ з буфера передавача
mov bx,start_s_data[si]
mov al,send_buf[si][bx]
mov dx,DATREG[si]
out dx,al
inc bx
cmp bx,S_SIZE
jb ptr_no_max
mov bx,0
ptr_no_max:
mov start_s_data[si],bx
dec size_s_data[si]
jmp next_inter
; дан прийняті і доступні для читання
RX_int:
; зчитуємо прийнятий байти із регістра даних UART
mov dx,DATREG[si]
in al,dx
cmp size_r_data[si],R_SIZE
jl no_r_EOVFLOW
; буфер приймача переповнений, збільшуємо відповідний
; лічильник помилок
inc WORD PTR EOVFLOW[si]
jmp next_inter
no_r_EOVFLOW:
mov bx,end_r_data[si]
mov reciave_buf[si][bx],al
inc size_r_data[si]
inc bx
cmp bx,R_SIZE
jb no_max_r_ptr
mov bx,0
no_max_r_ptr:
mov end_r_data[si],bx
jmp next_inter
exit_handler:
mov al,20h
out 20h,al
pop es
pop ds
pop di
pop bp
pop dx
pop cx
pop bx
pop ax
pop si
iret
int_hndlr4 ENDP
int_hndlr3 ENDP
int_hndlr2 ENDP
int_hndlr1 ENDP
COM_TEXT ENDS
END