/*************************************************************************** * Copyright (C) 2011 by semico * * mail@semico.ru * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Коды возврата BSD from @(#)sysexits.h 8.1 (Berkeley) 6/2/93 Copyright (c) 1987, 1993 The Regents of the University of California. All rights reserved. */ #define EX_USAGE 64 /* command line usage error */ #define EX_DATAERR 65 /* data format error */ #define EX_NOINPUT 66 /* cannot open input */ #define EX_NOUSER 67 /* addressee unknown */ #define EX_NOHOST 68 /* host name unknown */ #define EX_UNAVAILABLE 69 /* service unavailable */ #define EX_SOFTWARE 70 /* internal software error */ #define EX_OSERR 71 /* system error (e.g., can't fork) */ #define EX_OSFILE 72 /* critical OS file missing */ #define EX_CANTCREAT 73 /* can't create (user) output file */ #define EX_IOERR 74 /* input/output error */ #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ #define EX_PROTOCOL 76 /* remote error in protocol */ #define EX_NOPERM 77 /* permission denied */ #define EX_CONFIG 78 /* configuration error */ /* end sysexits.h */ #define EX_256 256 /* Последовательный порт - тайм-аут */ #define EX_257 257 /* Последовательный порт - ошибка КС или формата команды */ #define EX_258 258 /* Последовательный порт не открыт */ #define EX_MKDIRERR 300 /* Ошибка в структуре каталогов ЭКВМ */ #define EX_MKFILEERR 310 /* Константа для вывода ошибкок ДОС ЭКВМ = 311-317 */ #define LINUX 0 /* #define DOS 1 */ /* #define WIN 2 */ int dos=0; /* 0-GNU/Linux 1-DOS 2-WIN (Функции драйвера порта для разных ОС различны и расположены в разных файлах) */ int mkiocharset=1; /* 0=CP866|1=CP1251|2=KOI8R|3=UTF8|4=UCS2 кодировка ввода-вывода */ char mkversion[]="Version 0.21"; /* 0.01-0.08 - отладка подпрограмм 0.09 - 09.01.10 - приём и передача команд kom_mtest для GNU/Linux. 0.10 - 12.02.10 - чтение и запись файлов MKP-100. 0.11 - 30.05.10 - изменён алгоритм приёма команды; - таймаут порта по poll() для GNU/Linux; - исключена ошибка при обработке управляющих символов '3','26','28' для GNU/Linux; - добавлены параметры настройки порта, отсутствующие в POSIX (через #ifdef, но не все!). 0.12 - 11.06.10 - обработка файлов других типов и ключей -bdtni командной строки. 0.13 - 20.05.11 - работа с ДОС ЭКВМ, обход дерева каталогов, считывание информации о дисках 0-255. 0.14 - 01.11.11 - в pmkfile перенесена работа с ДОС, в т.ч. все функции записи/чтения файлов и каталогов; - добавлен -ri 1 для чтения основного экрана (ЭКР). 0.15 - 08.11.11 - изменены параметры команды Z, R для чтения основного экрана (ЭКР). 0.16 - 16.01.12 - изменен способ задания параметров порта, кроме чтения CFG введены ключи: --p[ort], --a[ddress], --s[peed]. 0.17 - 18.01.12 - в отдельные файлы выделен код драйвера порта, специфичный для ОС; - скомпилирована версия EXE-файла для win32. 0.18 - 13.09.13 - ключ j; - поддержка чтения файлов MKJ-8. 0.19 - 11.12.13 - ключ --name - наименование устройства порта передаётся в виде строки. 0.20 - 14.08.14 - вывод информации о ходе обмена (для динамического вывода используется fflush (stdout)). 0.21 - 23.10.15 - удалён вывод информации о ходе обмена; - изменён алгоритм обмена с устройством, введены дополнительные проверки и задержки; - не используется файл конфигурации "mk.cfg", а также связанные с ним структуры, переменные и подпрограммы. */ char mes0[8]; /* Окончание строк для конкретной ОС*/ char meserror[24]; /* Строка ошибки с v0.21 */ FILE *fp1; /* fp0 - CFG-file (не используется с v0.21), fp1 - MK-file */ int mkblock=0; /* блокировка клавиатуры 1-установлена, 0-нет */ int otladka=0; /* 0 - без сообщений, 1- отладка, 2 - вывод сообщения о неготовности данных, 3 - печать профилирующих сообщений */ int speed=0; // скорость обмена бит/с int speedn=0; // устанавливаемая скорость обмена - код 0-13 unsigned char sbuf[1024]; unsigned char lbuf[1024]; int pf; // дескриптор порта char portname[512]; // наименование порта в ОС char str[512]; // текстовая строка char str1[512]; // текстовая строка unsigned char kbuf[1024]; // буфер передаваемой команды unsigned char dbuf[1024]; // буфер данных передаваемой команды unsigned char rbuf[1024]; // буфер принимаемого ответа int maxlbuf=1020; // максимальная длина пакета - зависит от размера буферов (в ЭКВМ МК-1XX - 256 байт) int lenkbuf; // количество передаваемых байт int lenrbuf; // количество принимаемых и принятых байт int com; // номер последовательного порта от 0 - COM1 и т.д. для ttySX int nom; // номер ЭКВМ double dd; /* Принятое значение FLOAT (в ЭКВМ нет)*/ int f_dd; /* Наличие принятого значения 1-есть, 0-нет */ char mstr[512]; /* Принятая от ЭКВМ строка */ int f_str; /* Наличие принятой строки 1-есть, 0-нет */ char fname[512]; /* имя файла для обмена МК с компьютером */ char fname1[512]; /* имя файла 1 для обмена МК с компьютером */ char fname2[512]; /* имя последовательного порта в ОС () */ char fportname[512]; /* v0.19 наименование порта из командной строки */ int chislo[16]; /* переданные в строке целые параметры */ int uchislo=0; /* количество числовых параметров */ int fkluch=0; /* наличие числовых параметров */ int fdata[10024]; /* данные файла для обмена МК с компьютером */ /* Ключи */ int kl_w=0; int kl_r=0; int kl_p=0; int kl_b=0; int kl_d=0; int kl_t=0; int kl_n=0; int kl_i=0; int kl_j=0; /* v0.18 - mkj */ int kl_a=0; /////////////////////////////////////////////////////////// char ctemp[512]; /* вспомогательная строка */ long mkcharset[68][5]= //а=0 я=32 А=33 Я=65 0-866 1-1251 2-koi8 3-utf8 4-ucs2 {0xA0,0xE0,0xC1,0xD0B0,0x0430, // а 0xA1,0xE1,0xC2,0xD0B1,0x0431, // б 0xA2,0xE2,0xD7,0xD0B2,0x0432, 0xA3,0xE3,0xC7,0xD0B3,0x0433, 0xA4,0xE4,0xC4,0xD0B4,0x0434, 0xA5,0xE5,0xC5,0xD0B5,0x0435, // е 0xF1,0xB8,0xA3,0xD191,0x0451, // ё 0xA6,0xE6,0xD6,0xD0B6,0x0436, // ж 0xA7,0xE7,0xDA,0xD0B7,0x0437, 0xA8,0xE8,0xC9,0xD0B8,0x0438, 0xA9,0xE9,0xCA,0xD0B9,0x0439, 0xAA,0xEA,0xCB,0xD0BA,0x043A, 0xAB,0xEB,0xCC,0xD0BB,0x043B, 0xAC,0xEC,0xCD,0xD0BC,0x043C, 0xAD,0xED,0xCE,0xD0BD,0x043D, 0xAE,0xEE,0xCF,0xD0BE,0x043E, 0xAF,0xEF,0xD0,0xD0BF,0x043F, // п 0xE0,0xF0,0xD2,0xD180,0x0440, // р 0xE1,0xF1,0xD3,0xD181,0x0441, 0xE2,0xF2,0xD4,0xD182,0x0442, 0xE3,0xF3,0xD5,0xD183,0x0443, 0xE4,0xF4,0xC6,0xD184,0x0444, 0xE5,0xF5,0xC8,0xD185,0x0445, 0xE6,0xF6,0xC3,0xD186,0x0446, 0xE7,0xF7,0xDE,0xD187,0x0447, 0xE8,0xF8,0xDB,0xD188,0x0448, 0xE9,0xF9,0xDD,0xD189,0x0449, 0xEA,0xFA,0xDF,0xD18A,0x044A, 0xEB,0xFB,0xD9,0xD18B,0x044B, 0xEC,0xFC,0xD8,0xD18C,0x044C, 0xED,0xFD,0xDC,0xD18D,0x044D, 0xEE,0xFE,0xC0,0xD18E,0x044E, 0xEF,0xFF,0xD1,0xD18F,0x044F, // я 0x80,0xC0,0xE1,0xD090,0x0410, // А 0x81,0xC1,0xE2,0xD091,0x0411, 0x82,0xC2,0xF7,0xD092,0x0412, 0x83,0xC3,0xE7,0xD093,0x0413, 0x84,0xC4,0xE4,0xD094,0x0414, 0x85,0xC5,0xE5,0xD095,0x0415, 0xF0,0xA8,0xB3,0xD081,0x0401, // Ё 0x86,0xC6,0xF6,0xD096,0x0416, 0x87,0xC7,0xFA,0xD097,0x0417, 0x88,0xC8,0xE9,0xD098,0x0418, 0x89,0xC9,0xEA,0xD099,0x0419, 0x8A,0xCA,0xEB,0xD09A,0x041A, 0x8B,0xCB,0xEC,0xD09B,0x041B, 0x8C,0xCC,0xED,0xD09C,0x041C, 0x8D,0xCD,0xEE,0xD09D,0x041D, 0x8E,0xCE,0xEF,0xD09E,0x041E, 0x8F,0xCF,0xF0,0xD09F,0x041F, // П 0x90,0xD0,0xF2,0xD0A0,0x0420, // Р 0x91,0xD1,0xF3,0xD0A1,0x0421, 0x92,0xD2,0xF4,0xD0A2,0x0422, 0x93,0xD3,0xF5,0xD0A3,0x0423, 0x94,0xD4,0xE6,0xD0A4,0x0424, //Ф 0x95,0xD5,0xE8,0xD0A5,0x0425, 0x96,0xD6,0xE3,0xD0A6,0x0426, 0x97,0xD7,0xFE,0xD0A7,0x0427, 0x98,0xD8,0xFB,0xD0A8,0x0428, 0x99,0xD9,0xFD,0xD0A9,0x0429, 0x9A,0xDA,0xFF,0xD0AA,0x042A, 0x9B,0xDB,0xF9,0xD0AB,0x042B, 0x9C,0xDC,0xF8,0xD0AC,0x042C, 0x9D,0xDD,0xFC,0xD0AD,0x042D, 0x9E,0xDE,0xE0,0xD0AE,0x042E, 0x9F,0xDF,0xF1,0xD0AF,0x042F, // Я 0,0,0,0,0}; /*------------------------------------------------------ Перекодировка --------------*/ void mkstrcpy (char* str2, char* str1, int chset2, int chset1) { // перенос из str1 в str2 в кодировках chset1 chset2 соответственно //chset= 0=CP866|1=CP1251|2=KOI8R|3=UTF-8|4=UCS-2 int i,j,k,m; long l,l1,l2; if (chset1==chset2) {strcpy(str2,str1); goto end;} k=strlen(str1); if ((k==0) ||(chset1<0)||(chset1>4)||(chset2<0)||(chset2>4)) {str2[0]=0; goto end; } i=0; j=0; if (chset1==4) i=2; if (chset2==4) {str2[0]=0xFF; str2[1]=0xFE; j=2; } ci: if ((chset1==0)||(chset1==1)||(chset1==2)) {l=str1[i]; i++; if (l<0) l+=256; goto ci1; } if (chset1==3) {l1=str1[i]; l2=str1[i+1]; if (l1<0) l1+=256; if (l1<128) {i+=1; l=l1;} else {if (l2<0) l2+=256; i+=2; l=l1*256+l2; } goto ci1; } if (chset1==4) {l1=str1[i]; l2=str1[i+1]; if (l1<0) l1+=256; if (l2<0) l2+=256; i+=2; l=l1+l2*256; goto ci1; } ci1: l2=l; // поиск по массиву. если ничего не будет найдено - не перекодировать for (m=0; m<66; m++) { l1=mkcharset[m][chset1]; if (l1==l) l2=mkcharset[m][chset2]; } if ((chset2==0)||(chset2==1)||(chset2==2)) { // вставить один байт в строку str2[j]=(char)(l2%256); j++; goto cinext; } if (chset2==3) { if (l2<128) { // вставить один байт в строку str2[j]=(char)(l2%256); j++; goto cinext; } str2[j]=(char)((l2/256)%256); str2[j+1]=(char)(l2%256); j+=2; goto cinext; } if (chset2==4) { str2[j]=(char)(l2%256); str2[j+1]=(char)((l2/256)%256); j+=2; } cinext: if ((i>=k)||(j>254)) { str2[j]=0; str2[j+1]=0; goto end; } else goto ci; end: return; } /*---------------------------------*/ int init_msg (void) { // инициализация списка сообщений p=0-только конец строки int re=0; if (dos==0) {strcpy(mes0,"\n"); // Linux, UNIX - только ПС strcpy(portname,"/dev/ttyS"); } if ((dos==1)||(dos==2)) {strcpy(mes0,"\r\n"); // DOS & Win - ВК + ПС strcpy(portname,"COM"); } strcpy(meserror,"error "); end: return(re); } /*-------------------------------------------------------------MKFILE ----------*/ void mkfile (char* fn1, char* fn, char* fex) { /*сделать имя fn1 из fn и расширения fex проверить, чтобы в fn этого расширения уже не было */ int i,j,k,f; j=strlen(fn); k=strlen(fex); if (j==0) {f=1; strcpy(fn,"noname"); goto m1;} if (k==0) {f=0; goto m1;} if (j<=k) {f=1; goto m1;} f=0; for (i=k; i>=0; i--) { if ((j-k+i)<0) goto m1; if (fex[i]!=fn[j-k+i]) f=1; if (fex[i]=='.') goto m1; } m1: if (f==0) {strncpy(fn1,fn,256); } else {strncpy(fn1,fn,256-k); strcat(fn1,fex); } return; } /* ----------------------------------------------------------------- ПОРТ */ #ifdef LINUX #include "pmkcom-linux.c" #endif #ifdef DOS #include "pmkcom-dos.c" #endif #ifdef WIN #include "pmkcom-win.c" #endif /*=============================================== Вспомогательные подпрограммы ==============*/ /*------------------- KOM ERROR ----------------------*/ void kom_error(int n, int k, int z, int r, int e) { if (otladka==0) return; if ((otladka<2)&&(e==4)) return; printf("\nN=%d, K=%Xh, Z=%Xh, R=%Xh, DBUF[0]=%d, %s %d\n",n,k,z,r,dbuf[0],meserror,e); /* meserror - ошибка */ return; } /*-------------------- KOM_MTEST3 ---------------*/ int kom_mtest3(int n, int k, int z, int r, int len) { /* перед выводом ошибки команда повторяется трижды */ int re=0; int j,t; j=0; a1: t=kom_mtest(n,k,z,r,len); if (t==0) goto end; if ((j<3)&&(t!=0)) {j++; goto a1;} kom_error(n,k,z,r,t); re=t; end: return(re); } /*-------------------------- опрос -----------------------------------*/ int opros(int nmin, int nmax, int z) { /* Z=0 - краткая информация, Z=1 - полная информация*/ int i,j,k; int x; if (nmin<0) nmin=0; if (nmax>255) nmax=255; if (nmax2) printf("MK_SPEED %d\n",s); if (s<0) s=0; // исправлено в v0.17 switch (s) { case 0: case 9: s1=9; l=9600; break; /* 9600 */ case 1: case 2: s1=1; l=600; break; /* 600, 900 */ case 3: case 4: s1=3; l=1200; break; /* 1200, 1800 */ case 5: case 6: s1=5; l=2400; break; /* 2400, 3600 */ case 7: case 8: s1=7; l=4800; break; /* 4800, 7200 */ case 10: s1=9; l=9600; break; /* 14400 */ case 11: s1=11; l=19200; break; /* 19200 */ case 12: s1=12; l=38400; break; /* 38400 */ case 13: s1=13; l=57600; break; /* 57600 */ default: s1=9; l=9600; } /* сменить скорость на ЭКВМ */ dbuf[0]=s1%256; t=kom_mtest3(nom,48,160,1,1); if (t!=0) {re=t; goto end;} t=mk_wait(); if (t!=0) {re=t; goto end;} /* сменить скорость порта */ port_speed(l); end: if (otladka>2) printf("END_MK_SPEED %d\n",re); return(re); } /*---------------------------------------------- MK WAIT Ожидание ----------------*/ int mk_wait(void) { /* Ожидание выполнения операции */ int re=0; int t; int j; if (otladka>2) printf("MK_WAIT\n"); j=0; a1: t=kom_mtest3(nom,16,160,0,0); /* ТЕСТ */ if ((t==0)&&((rbuf[7] & 2) ==2)) {rbuf[7]=0; goto a1;} /* бит 1 первого байта состояния */ if ((t==4)&&(j<100)) {t=0; j++; goto a1;} /* спросить 100 раз */ if (t!=0) re=t; end: if (otladka>2) printf("END_MK_WAIT %d\n",re); return(re); } /*----------------------------------------------- MK BLOCK Блокировка клавиатуры ----------------*/ int mk_block(int x) { /* Установить x=1 и снять x=0 блокировку клавиатуры */ int re=0; int t; if (otladka>2) printf("MK_BLOCK %d\n",x); if (x<0) x=0; if (x>1) x=1; if (x==mkblock) goto end; /* уже */ if (x==0) { t=kom_mtest3(nom,48,160,129,0); /* Снять */ if (t!=0) {re=t; goto end;} t=mk_wait(); if (t!=0) {re=t; goto end;} mkblock=0; } else { t=kom_mtest3(nom,48,160,128,0); /* Установить */ if (t!=0) {re=t; goto end;} t=mk_wait(); if (t!=0) {re=t; goto end;} mkblock=1; } end: if (otladka>2) printf("END_MK_BLOCK %d\n",re); return(re); } /*-------------------------------------------------------- MK_RUN Запуск и останов программы */ int mk_run(int x) { /* Запустить (x==1) или остановить (x==0) программу пользователя на ЭКВМ */ int re=0; int j,t; if (otladka>2) printf("MK_RUN %d\n",x); j=0; m0: t=kom_mtest3(nom,16,160,0,0); /* ТЕСТ */ if (t==0) { /* Проверить состояние ЭКВМ, чтобы не возникало ошибки 4 - отсутствие готовности */ if ((x==1)&&(((rbuf[7] & 128) ==128))) goto end; /* Программа уже запущена */ if ((x==0)&&(((rbuf[7] & 128) ==0))) goto end; /* Программа уже остановлена */ } if ((t==4)&&(j<100)) {j++; goto m0;} else {re=t; goto end;} if (x==0) { t=kom_mtest3(nom,48,160,131,0); /* Остановить */ if (t!=0) {re=t; goto end;} j=0; m1: t=kom_mtest3(nom,16,160,0,0); /* ТЕСТ */ if ((t==0)&&((rbuf[7] & 128) ==128)) {rbuf[7]=0; goto m1;} /* бит 7 - исполнение - ожидать останова */ if ((t==4)&&(j<100)) {j++; goto m1;} if (t!=0) {re=t; goto end;} } else { t=kom_mtest3(nom,48,160,130,0); /* Запустить */ if (t!=0) {re=t; goto end;} j=0; m2: t=kom_mtest3(nom,16,160,0,0); /* ТЕСТ */ if ((t==0)&&((rbuf[7] & 128) ==0)) {rbuf[7]=0; goto m2;} /* бит 7 - исполнение - ожидать запуск */ if ((t==4)&&(j<100)) {j++; goto m2;} if (t!=0) {re=t; goto end;} } end: if (otladka>2) printf("END_MK_RUN %d\n",re); return(re); } /*------------------------------------------------- MK_EEPROM ----------------------*/ int mk_eeprom(int x, char c) { /* Чтение-запись из/в ЭСППЗУ x==0 - чтение, x==1 - запись; c=='p','d','b','t' - тип файла. */ int re=0; int z,r,t; if (otladka>2) printf("MK_EEPROM %d\n",x); if (x==0) r=128; else r=129; switch (c) { case 'p': z=128; break; case 'd': z=129; break; case 'b': z=130; break; case 't': z=131; break; default: re=EX_257; goto end; } t=kom_mtest3(nom,48,z,r,0); /* Сохранить/восстановить данные в/из ЭСППЗУ */ if (t!=0) {re=t; goto end;} t=mk_wait(); /* Ждать */ if (t!=0) {re=t; goto end;} end: if (otladka>2) printf("END_MK_EEPROM %d\n",re); return(re); } /*================================================== Команды для работы с файлами ============*/ /*--------------------------------------------------------------- MKP LOAD -------------------*/ int mkpload(int s, int h) { /* s - начальная страница 0-99, h - размер файла, страниц 1-100 */ int re=0; int i,j,j1,k,t; /* Запись MKP файла одновременно с чтением из ЭКВМ */ mkfile(fname1,fname,".mkp"); fp1=fopen(fname1,"wb"); /* открыть файл для записи */ if (fp1!=NULL) { /* записать заголовок MKP-файла (номер начальной страницы) */ k=s%256; t=fputc(k,fp1); if (t==EOF) re=EX_IOERR; } else {re=EX_CANTCREAT; goto end;} /* проверка корректности входных данных */ if (s<0) s=0; if (s>99) s=99; if (h<1) h=1; if (h>100) h=100; j=s+h; if (j>100) j=100; for (i=s; i255) k=255; com=k; } if ((c=='a')||(c=='A')) { k=atoi(argv[i+1]); if (k<0) k=0; if (k>255) k=255; nom=k; } if ((c=='s')||(c=='S')) { k=atoi(argv[i+1]); if (k<0) k=0; if (k>13) k=13; speedn=k; } if ((c=='n')||(c=='N')) { strncpy(fportname,argv[i+1],256); } i++; goto next_i; } for (j=1; j0) i=chislo[0]; else i=0; if (uchislo>1) j=chislo[1]; else j=255; if (uchislo>2) k=chislo[2]; else k=0; opros(i,j,k); goto end1; } if ((kl_n!=0)&&(kl_r!=0)) { if (uchislo>0) i=chislo[0]; else i=0; if (uchislo>1) j=chislo[1]; else j=16384; mknload(i,j); goto end1; } if ((kl_i!=0)&&(kl_r!=0)) { if (uchislo>0) i=chislo[0]; else i=0; mkiload(i); goto end1; } if ((kl_j!=0)&&(kl_r!=0)) { i=0; mkjload(i); // v0.18, в данной версии параметр i не используется goto end1; } /* остальные можно считывать пакетом типа -rpbdt */ if ((kl_p!=0)&&(kl_r!=0)) { if (uchislo>0) i=chislo[0]; else i=0; if (uchislo>1) j=chislo[1]; else j=1; mkpload(i,j); } if ((kl_b!=0)&&(kl_r!=0)) { mkbload(); } if ((kl_d!=0)&&(kl_r!=0)) { mkdload(); } if ((kl_t!=0)&&(kl_r!=0)) { mktload(); } if (kl_r!=0) goto end1; /* чтение окончено */ /* Запись */ i=mk_block(1); /* установить блокировку клавиатуры */ if (i!=0) {re=i; goto end_w;} sleep(1); /* v0.21 */ if ((kl_p!=0)&&(kl_w!=0)) { mkpsend(); mk_eeprom(1,'p'); goto end_w; } if ((kl_b!=0)&&(kl_w!=0)) { mkbsend(); mk_eeprom(1,'b'); goto end_w; } if ((kl_d!=0)&&(kl_w!=0)) { mkdsend(); mk_eeprom(1,'d'); goto end_w; } if ((kl_t!=0)&&(kl_w!=0)) { mktsend(); mk_eeprom(1,'t'); goto end_w; } if ((kl_n!=0)&&(kl_w!=0)) { mknsend(); goto end_w; } end_w: i=mk_block(0); /* снять блокировку клавиатуры */ if (i!=0) {re=i; goto end1;} end1: port_close(); end: if (otladka>2) {printf("RETURN %d\n",re);} return (re); }