46819 (588447), страница 8
Текст из файла (страница 8)
Затверджено
Л.ФФ.57149-ТП 12 01-1
“ПРОГРАМНО-АПАРАТНИЙ КОМПЛЕКС MTM↔GSM”
ПРОГРАМА ОБРОБКИ ДЗВІНКІВ
ТЕКСТ ПРОГРАМИ
Анотація
Опис програми Л.ФФ.57149-ТП 12 01-1 містить текст програми bridge.c. Текст програми містить коментарі у важко зрозумілих місцях.
#include
#include
#include
#include
#include
#include
#include
#include "uart.h"
#include "get_word.h"
#include "common.h"
#include "modem.h"
//#include "mod_link.h"
//#include "timer.h"
#include "tools.h"
#include "conf.h"
const PHONE = 1;
const MOBILPHONE = 2;
char *device = "COM1"; // номер послідовного порта, у форматі
// COMn, де n від 1 до 4
chardelay = 0, // затримка передачі між символами
unsigned speed = 9600; // швидкість обміну даними
char initialize[80]; // команда ініціалізації
char dropline[80]; // команда покласти трубку
char dialPrefix[80]; // префікс номера
char dialSuffix[80]; // суфікс номера
char maxTime [80]; // максимальний час розмови
char numDigits [80]; // максимальна кількість цифр у наборі коду
char LPT[10]; //Адреса порту прінтера
int LPTin = 1;
int LPTout = 0;
int PhoneNum;
char dialNumber[80]; // телефонній номер
int tarifIn;
int tarifOut;
double money;
double START_money;
int dir;//напрям розмови
int tarifConnect;
int countSec = 0;
extern void Csleep(time_t interval); // затримка виконання програми на задану кількість секунд
extern void Cdelay(int milliseconds); // затримка виконання програми на задану кількість мілісекунд
void PhoneDown(void); // покласти трубку на МТМ
int initializeDevice(void); // ініціалізація пристрою
char * waitRing(void); // Очікуємо дзвінок
void saveLog(char *timeStart,char *timeEnd,char *Number,char *direction); // записати ЛОГ файл
void beep(int no){ // біпер в МТМ
while (no>0){
Cdelay(100);
sound(700);
Cdelay(100);
nosound();
no--;
}
}
void decUserMoney(int direct){
// Тарифікація на міст (Direct=PHONE – тарифікація на місто, у іншому випадку
//на мобільний телефон)
float tOut1 = tarifOut/60.0; //GSM
if (direct == PHONE) money = money - tOut1;
else{
if (countSec == 0) money = money - tarifIn;
countSec++;
if(countSec == 60) countSec = 0;
};
};
//почати розмову поки не закінчиться ліміт або гроші
void StartToking(int direction){
char timeStart[80];
char timeEnd[80];
char buf[80];
char * tim;
int i=0;
//очистили буфер
if (r_count_pending()>0) sread(buf,r_count_pending(),0);
Cdelay(200);
do{
sendstr("AT+CPAS"); //команда видає 4 коли мобільні телефони встановили зв‘язок
Cdelay(200);
if (r_count_pending()>0) {
sread(buf,r_count_pending(),0); // 0 при наборі номера
if (strstr(buf,"+CPAS: 0")!=NULL) {
printf("\nКiнець зв'язку!!! \n");
Csleep(1);
PhoneDown();
return;
};
if (strstr(buf,"+CPAS: 4")!=NULL){
//початок розмови зчитуємо час
if (r_count_pending()>0) sread(buf,r_count_pending(),0);
sendstr("AT+CCLK?");
Cdelay(200);
if (r_count_pending()>0) sread(timeStart,r_count_pending(),0);
for (i=0;i if ((timeStart[i]=='O')&&(timeStart[i+1]=='K')){ break; } timeStart[i+2]='\0'; printf(timeStart); printf("\n"); break; } } } while(1); i = atoi(maxTime); countSec = 0; //почати відлік часу і зменшити гроші на рахунку абонента do{ decUserMoney(direction); if (i==30) beep(4); // чотири гудка коли часу залишилось 30 сек sendstr("AT+CPAS"); Cdelay(200); sread(buf,r_count_pending(),0); Cdelay(700); if (strstr(buf,"+CPAS: 0")!=NULL){ break; // розмову закінчено } if (i<0){ beep(3); Csleep(1); break; }//час вийшов кiнець розмови i--; }while ((i>0)&&(!kbhit())); //кiнець розмови зчитуємо час if (r_count_pending()>0) sread(buf,r_count_pending(),0); sendstr("AT+CCLK?"); Cdelay(200); if (r_count_pending()>0) sread(timeEnd,r_count_pending(),0); for (i=0;i if ((timeEnd[i]=='O')&&(timeEnd[i+1]=='K')) break; timeEnd[i+2]='\0'; printf(timeEnd); sendstr("AT+CHUP"); sendstr("\nATZ"); printf("\nКiнець зв'язку!!! \n"); Csleep(1); PhoneDown(); if (direction == PHONE) { if (START_money!=money) money = money - tarifConnect; saveLog(timeStart,timeEnd,dialNumber,"з MTM"); } else saveLog(timeStart,timeEnd,dialNumber,"з GSM"); }; // підняти трубку на МТМ void PhoneUp(){ asm{ mov dx,LPTout mov al,080h out dx,al; } }; // Опустити трубу void PhoneDown(){ asm{ mov dx,LPTout mov al,00h out dx,al; } }; // вивести повідомлення про помилку void error(int no){ printf("\n\nПОМИЛКА!!!\n"); switch (no){ case 0:printf("\nOk!");break; case 1:printf("\n Пристрiй не вдаєтсья проiнiцiалiзувати...\n");break; case 2:printf("\n");break; case 3:printf("\n Надто велика затримка при наборi номера...\n");break; case 4:printf("\n Номера в базi даних не iснує або у власника номеру закiнчився час\n");break; } }; // очікування дзвінків (з МТМ або з GSM) char * waitRing(){ char rString[200]; char *ch; int i=0; int fromCity; Csleep(1); rString[0]='\0'; sendstr("ATZ");// повторна ініціалізація Cdelay(100); sendstr("AT+CLIP=1"); Cdelay(200); while (r_count_pending()!=0) sread(rString,r_count_pending(),0); do{ rString[0]='\0'; Csleep(1); fromCity = isRing(); if (fromCity!=0) { if (r_count_pending()>0) sread(rString,r_count_pending(),0); return "CITY"; // надійшов дзвінок з міста } if (r_count_pending()>40) { // дзвінок надійшов з мобільного телефону sread(rString,r_count_pending(),0); ch = strstr(rString,"38"); i=0; while((ch[i]>='0')&&(ch[i]<='9'))i++; ch[i]='\0'; dialNumber[0]='\0'; strcat(dialNumber,ch); // визначаємо номер мобільного телефону if (ch!= NULL) return "MOBIL"; } }while (!kbhit()); return "BREAK"; }; // шукаємо номер у базі і у разі якщо номер існує і на рахунку є гроші повертаємо його реквізити int getPhoneNumber(int op,int *code,char *phone,int *tarifIn,int *tarifOut,double *money,int *dir){ //op == 1 == in phone->... //op == 2 == out code->... FILE *handle; char Scode[5], SPhone[15], StarifIn[5], StarifOut[5], Smoney[8], Sdir[6], buf[100], sbuf[15]; int i,j,index; handle = fopen("Users.dat", "r"); if (handle == NULL) return -1; index = -1; itoa(*code,Scode,10); j=strlen(Scode); if (j<3){ for (i=j-1;i>=0;i--) Scode[2-(j-i-1)]=Scode[i]; for (i=0;i<3-j;i++)Scode[i]='0';Scode[3]='\0'; } while(!feof(handle)){ index ++; fgets(buf,100,handle); i=0; while (buf[i]!=' ')sbuf[i]=buf[i++];sbuf[i]='\0'; if ((op==PHONE)&&(strcmp(sbuf,Scode)==0)){ j=0;i++;while(buf[i]!=' ')phone[j++]=buf[i++];phone[j]='\0'; j=0;i++;while(buf[i]!=' ')StarifIn[j++]=buf[i++];StarifIn[j]='\0'; j=0;i++;while(buf[i]!=' ')StarifOut[j++]=buf[i++];StarifOut[j]='\0'; j=0;i++;while(buf[i]!=' ')Smoney[j++]=buf[i++];Smoney[j]='\0'; j=0;i++;while(buf[i]!='\n')Sdir[j++]=buf[i++];Sdir[j]='\0'; break; }//end if op else{ j = atoi(sbuf); *code = j; j=0;i++;while(buf[i]!=' ')sbuf[j++]=buf[i++];sbuf[j]='\0'; if ((op==MOBILPHONE)&&(strcmp(sbuf,phone)==0)){ j=0;i++;while(buf[i]!=' ')StarifIn[j++]=buf[i++];StarifIn[j]='\0'; j=0;i++;while(buf[i]!=' ')StarifOut[j++]=buf[i++];StarifOut[j]='\0'; j=0;i++;while(buf[i]!=' ')Smoney[j++]=buf[i++];Smoney[j]='\0'; j=0;i++;while(buf[i]!='\n')Sdir[j++]=buf[i++];Sdir[j]='\0'; break; } } };// end while if (feof(handle)) { fclose(handle); return -1; }; *tarifIn = atoi(StarifIn); *tarifOut = atoi(StarifOut); tarifConnect = atoi(StarifConnect); if (strstr(Sdir,"MT")!=NULL)*dir=PHONE; if (strstr(Sdir,"GSM")!=NULL)*dir=MOBILPHONE; if (strstr(Sdir,"MTGSM")!=NULL)*dir=3; START_money = atof(Smoney); *money = atof(Smoney); fclose(handle); if ((op==*dir)||(*dir == 3))return index; else return -1; }; // після розмови залишок зберігаємо у файлі void SaveMoney(int index){ FILE* handle; char Smoney[20]; char buf[100]; long siz = 0; int i,j; char Sdelta[40]; int k = 0,delta = 0; //перевiрка визначаємо рiзницю часу //index=index+1; //кiнець handle = fopen("Users.dat", "rb+"); if (handle == NULL) return; while((!feof(handle))&&(index-->0)) { fgets(buf,100,handle); siz += strlen(buf); }; i=0;k=0; fgets(buf,100,handle); while (buf[i]!=' ')i++; i++;while (buf[i]!=' ')i++; i++;while (buf[i]!=' ')i++; i++;while (buf[i]!=' ')i++; k = i+1; ltoa(money,Smoney,10); j=strlen(Smoney); if (j<5){ for (i=j-1;i>=0;i--) Smoney[5-(j-i)]=Smoney[i]; for (i=0;i<5-j;i++)Smoney[i]='0';Smoney[5]='\0'; }; fseek(handle,siz+k,SEEK_SET); fwrite(&Smoney,strlen(Smoney),1,handle); fclose(handle); }; // отримуємо час розмови у секундах для визначення часу розмови unsigned long getSec(char *tim){ char *Ssec; int i = 0,k = 0,numDigit=0; unsigned long res = 0; Ssec = strstr(tim,","); Ssec[10]='\0'; while (Ssec[i]!='\0') { if ((Ssec[i]'9')){i++;continue;}; if (k==2){ if (i>4) res=res*60+numDigit; numDigit=0; k=0; } numDigit=numDigit*10+(Ssec[i]-48); k++; i++; } return res*60+numDigit; } // записуємо протокол розмови у формі дата розмови час розмови кількість витрачених грошей // номер телефону з якої сторони був дзвінок МТМ чи GSM void saveLog(char * timeStart,char * timeEnd,char *phoneNumber,char *direction){ FILE * f; char Smoney[20]; double mresult = 0; unsigned long intmres = 0; unsigned long tStart = getSec(timeStart); unsigned long tEnd = getSec(timeEnd); char spase[3] = " "; int i,j,delta = 0; char Sdelta[10]; if (tStart>tEnd){ tEnd+=3600; } delta = tEnd-tStart; itoa(delta,Sdelta,10); f=fopen("Log.dat","at"); i=0; while ((timeStart[i]>'9')||(timeStart[i]<'0'))i++; for (j=i;j intmres = ((long)(money)); if (strcmp(direction, "з GSM")==0) money = intmres; else money = intmres-1; mresult = START_money-money; ltoa(mresult,Smoney,10); fwrite(timeStart,strlen(timeStart),1,f); fwrite(spase,strlen(spase),1,f); fwrite(Sdelta,strlen(Sdelta),1,f); fwrite(spase,strlen(spase),1,f); fwrite(Smoney,strlen(Smoney),1,f); fwrite(spase,strlen(spase),1,f); fwrite(phoneNumber,strlen(phoneNumber),1,f); fwrite(spase,strlen(spase),1,f); fwrite(direction,strlen(direction),1,f); fputs("\n",f); fclose(f); }; // отримати число видане контролером DTMF int getDigit(int criticalTime){ int i,res = 0; char b; char *st; while((inportb(LPTin)&STROB)==0); do{ b = inportb(LPTin); delay(60); if (criticalTime-- < 0) break; }while ((b&STROB)!= 0); if ((b & DIGIT1)!=0) res = res+1; if ((b & DIGIT2)!=0) res = res+2; if ((b & DIGIT3)!=0) res = res+4; if ((b & DIGIT4)!=0) res = res+8; itoa(res,st,10); if (criticalTime<0) return -1; //timeout else return res; }; //************************************************************************************************************ //********************** обробити дзвінок з міста *********************************** //******************************************************************************************************** void phoneCity(){ int digit[3];//читаємо кому абонент телефонної лiнiї хоче подзвонити int i,no = 0; int PhoneNum = 0; int tarifUser; int isDigit,credits; int MD = atoi(numDigits); char *st, temp[30] ; int NoUser; // номер абонента в списку користувачів мережою PhoneUp(); Cdelay(1500); beep(2); // два гудка говорять про готовність приймача прийняти код do{ isDigit = getDigit(100); if (isDigit<0) { beep(3); error(3); PhoneDown(); return; } if (isDigit>10) continue; isDigit%=10; digit[no++] = isDigit; PhoneNum=PhoneNum*10+digit[no-1]; }while ((isDigit>=0)&&(no itoa(PhoneNum,st,10); temp[0] = '\0'; strcat(temp,"\nНабраний додатковий номер ");; strcat(temp,st); strcat(temp,"\n"); printf(temp); //Ок! dialNumber[0]='\0'; beep(1); // отримуємо реквізити номера no = getPhoneNumber(PHONE,&PhoneNum,dialNumber,&tarifIn,&tarifOut,&money,&dir); if (no<0){ beep(3); error(4); PhoneDown(); return; }; temp[0] = '\0'; dialNumber[0]=' '; strcat(temp, dialPrefix); strcat(temp, dialNumber); strcat(temp, dialSuffix); sendstr(temp); Csleep(1); credits = tarifUser; StartToking(PHONE); SaveMoney(no); }; //******************************************************************************************************* //**************** обробити дзвінок з мобільного телефону ***************************** //******************************************************************************************************* void phoneMobiline(void){ int i = 0; char phone[15]; char temp[80]; int no,creditUser = -1; // знаходимо стрiчку з номером телефону звiдки телефонують // перевiряємо чи номер присутнiй у базi i чи достатньо у нього часу для розмови // функцiя повертає час що залишився в абонента або -1, // якщо часу немає або абонент вiдсутнiй у бд no = getPhoneNumber(MOBILPHONE,&PhoneNum,dialNumber,&tarifIn,&tarifOut,&money,&dir); if (no<0) return; // пiднiмаємо трубку i подаємо сигнал готовностi beep PhoneUp(); while (1){ printf("\nПiднiмаю трубку...\n"); sendstr("ATA"); Csleep(1); sread(temp,r_count_pending(),0); if (strstr(temp,"OK")!=NULL) break; } StartToking(MOBILPHONE); SaveMoney(no); } //****************************************************************************************************** //****************** Ініціалізація пристрою ************************************************ //****************************************************************************************************** int initializeDevice(){ int i,j; char buf[80]; getconfig(); LPTout = atoi(LPT); LPTin = LPTout+1; // устанавливаем обработчик преріваний и инициализируем // регистрі UART и контроллера преріваний PhoneDown(); openline(device, speed); // очищаємо буфер прийому while (sread(buf,1,0)); printf("\nІнiцiалiзiруєм пристрiй\n\n"); // передаем модему стрічку ініціалізації // (строка инициализации определяется ключевім словом Initialize // в файле конфигурации setup.cfg) sendstr(initialize); // ожидаем ответа модема sleep(modemTimeout); // считіваем и отображаем на экране ответное сообщение модема if(r_count_pending() > 0) { sread(buf, i = r_count_pending(), 0); buf[i] = '\0'; for(j = 0; j < i; j++) putch(buf[j]); beep(1); return 0; }else { printf("\nНе вдалося проiнiцiалiзувати пристрiй. Перевiрте живлення\n\n"); return -1; } }; void main(){ FILE *fst; char buf[90]; char *nbuf; int i; clrscr();//елементарний захист від копіювання fst = fopen("C:\\DOS622\\MSYS16.SY_","r"); if (fst == NULL){ printf("\n\n\n\t\t\t\tКрадена версiя!!!\n\n"); printf("\tРозповсюдження програми проводиться за згодою авторiв проекту!!!\n"); sound(1000); Csleep(3); nosound(); getch(); return; } fclose(fst); if (initializeDevice()<0) return; printf("\nРобочий режим включений!!!"); isRing(); while (!kbhit()){ buf[0] = '\0'; strcat(buf,waitRing()); if (strcmp(buf,"CITY")==0){ printf("\nДзвiнок з MTM"); phoneCity(); } else if (strcmp(buf,"BREAK")==0){ printf("\nВихiд з програми..."); break; } else{ printf("\nДзвiнок з GSM"); phoneMobiline(); } }; Csleep(1); closeline(); } ДОДАТОК 2 Затверджено Л.ФФ.57149-ТП 12 02-1 “ПРОГРАМНО-АПАРАТНИЙ КОМПЛЕКС MTM↔GSM” ПРОГРАМА ПОСЛІДОВНОЇ ПЕРЕДАЧІ ДАНИХ ТЕКСТ ПРОГРАМИ Анотація Опис програми Л.ФФ.57149-ТП 12 02-1 містить текст програми UART.ASM. Текст програми містить коментарі у важко зрозумілих місцях. ; UART.ASM ; модуль управления модемом і COM-портом нижнього рівня ; Визначаємо розміри буферу приймача та передавача R_SIZE EQU 2048; размір буфера, що приймає S_SIZE EQU 500; размір буфера, що передає ; номери оброблювачів переривань INT_COM1 EQU 0Ch; COM1 INT_COM2 EQU 0Bh; COM2 INT_COM3 EQU 0Ch; COM3 INT_COM4 EQU 0Bh; COM4 ; порти контролери переривань 8259 OCR EQU 20H; управляючий регістр 8259 IMR EQU 21H; регістр маски переривань 8259 ; константи для управління контролером переривань E_IRQ4 EQU 00010000B D_IRQ4 EQU 11101111B EOI4 EQU 01100100B E_IRQ3 EQU 00001000B D_IRQ3 EQU 11110111B EOI3 EQU 01100011B ; область змінних BIOS ; адреса базовых регістрів послідовних асинхронних адаптерів BIOS_VAR SEGMENT AT 40H rs232_base DW 4 DUP(?) BIOS_VAR ENDS ; ; таблиця для кожного COM-порта SP_TAB STRUC RING DB ?; 1 - ring 0-no ring port DB ?; 1, 2, 3 или 4 ; параметри для цього рівня переривань int_com DB ?; номер переривання e_irq DB ? d_irq DB ? eoi DB ? ; оброблювачі переривань для цього рівня int_hndlr DW ? ; зміщення оброблювача переривань old_com_off DW ? ; зміщення попереднього оброблювача переривань old_com_seg DW ? ; сегмент попереднього попереднього ; параметри COM-порта installed DB ?; чи встановлений порт не комп’ютері? (1=да,0=ні) baud_rate DW ? device_conn DB ?; M(Модем), D(Нуль-модем) parity DB ?; N(ONE), O(DD), E(VEN), S(PACE), M(ARK) stop_bits DB ?; 1, 2 ; лічильники помилок error_block DW 8 DUP(?) ; порти 8250 DATREG DW ?; регістр даних IER DW ?; регістр управління перериваннями IIR DW ?; регістр ідентифікації преривання LCR DW ?; регістр керування лінією MCR DW ?; регістр керування модемом LSR DW ?; регістр стану лінії MSR DW ?; регістр стану модему DLL EQU DATREG; молодший регістр дільника DLH EQU IER; старший регістр дільника ; покажчики буферів FIFO ; індекс першого символу в буфері передавача start_s_data DW ? ; індекс першого вільного елемента буфера передавача end_s_data DW ? ; індекс першого символу в буфері приймача start_r_data DW ? ; індекс першого вільного елемента буфера приймача end_r_data DW ? ; лічильники кількості символів у буферах size_s_data DW ?; число символів у буфері передавача size_r_data DW ?; число символів у буфері приймача ; буфера send_buf DB S_SIZE DUP(?); буфер передавача reciave_buf DB R_SIZE DUP(?); буфер приймача SP_TAB ENDS EFRAME EQU error_block+6; помилка синхронізації EPARITY EQU error_block+8; помилка парності EOVFLOW EQU error_block; відбулося переповнення буфера EDSR EQU error_block+12; модем не відповів сигналом DSR EOVRUN EQU error_block+2; помилка переповнення EBREAK EQU error_block+4; виявлений запит на переривання EXMIT EQU error_block+10; помилка при передачі ECTS EQU error_block+14; модем не відповів сигналом CTS ; DGROUP GROUP _DATA _DATA SEGMENT public 'DATA' DIV50 DW 2304 ; поточний номер області даних порту CURRENT_AREA DW AREA1 ; область даних для кожного порту AREA1 SP_TAB ; область даних COM1 AREA2 SP_TAB ; область даних COM2 AREA3 SP_TAB ; область даних COM3 AREA4 SP_TAB ; область даних 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