ZX Format #06
29 июля 1997

Программистам - MMD - драйвер. Описание структуры драйвера модема для терминальной программы MMD.

<b>Программистам</b> - MMD - драйвер. Описание структуры драйвера модема для терминальной программы MMD.
  Структура драйвера модема
для программы MMD 2.20

music by DNK
(C) MAS
_______________________________

Для  работы  терминалки  "Macro Modem
v2.20"  необходим  драйвер модема. Данный
драйвер  выполняет все функции приёма/пе-
редачи  информации,  а также обрабатывает
состояние  телефонной  линии  и системных
часов.

Драйвер  находиться на 6-й странице с
адреса 49152 (#C000). Под его нужды отво-
диться  все  16Кб данной страницы. Вход в
драйвер  производиться через ТОЧКИ ВХОДА,
расположеные  в  самом  начале  драйвера,
т.е. с адреса 49152.



           Внимание!
      ДРАЙВЕР_НЕ_ДОЛЖЕН:

 - портить  содержимое  регистров IX, IY,
SP;
 - изменять любые  ячейки памяти основной
программы за исключением специально выде-
леного буфера для обмена информацией;
, - менять режим прерывания (статус преры-
вания  можно менять - всё равно оно будет
запрещено).



 Входные точки драйвера:

      УСТАНОВКА ДРАЙВЕРА

D_INSTAL   EQU #C000
При  вызове функции в регитровой паре
[HL]  будет находиться адрес рабочего бу-
фера  для  приема/передачи данных. Данный
буфер  расположен  в  основной  памяти, и
имеет размер около 270 байт вверх, и око-
ло  30  вниз от указаного значения. Обмен
данными между основной программой и драй-
вером производиться только через этот бу-
фер.

При  инсталяци  в  этот буфер драйвер
должен  записать  в  ASCII форме значение
существующих  скоростей.  На  каждую ско-
рость  отводиться 5 байт, всего скоростей
- 8. Должна быть описана КАЖДАЯ скорость,
если  драйвер  поддерживает меньшее коли-
чество,  то описатели несуществующих ско-
ростей заполняются кодом #00. Пример опи-
сателя скоростей:

DEFB " 600 " ;1-я скорость 600 бод
DEFB "1800 " ;2-я скорость 1800 бод
DEFB "2400 " ;3-я скорость 2400 бод
DEFS 25      ;всего 3 скорости,
                 ;остальные 5 отсутствуют



В  программе  учтено  то, что драйвер
модема  может быть упакован. Поэтому про-
цедура инсталяции вызывается ДВАЖДЫ. Т.е.
при  первом  вызове происходит распаковка
драйвера,  а  при  втором его инсталяция.
Программа  использует  фляг  переноса для
того, чтобы сообщить драйверу какой вызов
происходит:
 - если флаг переноса установлен - первый
                                   вызов
 - если флаг переноса сброшен - второй.

ПОЛУЧЕНИЕ ИНФОРМАЦИИ О ДРАЙВЕРЕ

D_COPYREQU #C003
Данная функция помещает в рабочий бу-
фер  информацию о драйвере. Данной инфор-
мацией  является  название драйвера и имя
его  автора.  Размер  буфера  -  50 байт,
строка  должна  заканчиваться  кодом  #00
Пример функции D_COPYR:

 LD DE,(WORK_ADR)  ;адрес буфера
        LD HL,TEXT        ;адрес строки
        LD BC,ETEXT-TEXT  ;длина строки
        LDIR              ;перенесли и
        RET               ;вернулись
TEXTDEFB "Vicomm-driver v2.95 " 
        DEFB "(C) 1997 *MAS*" 
        DEFB 0 
ETEXT 



 ЧТЕНИЕ СТАТУСА ЛИНИИ/ДРАЙВЕРА

D_RD_STAT  EQU #C006
Данная  функция  возвращает параметры
драйвера и линии, а также производит кор-
  рекцию данных для порта #FE.
При вызове данной функции в [A] нахо-
дится текущий цвет бордюра.

 При возврате из функции:
-  В регистре [B] различные биты харак-
теризуют:

 bit0 - статус линии: "1" модем подключен
         к линии, "0" -отключен
 bit1 
 bit2 
, bit3 если "1", то драйвер может набирать
        номер тоновым способом.
 bit4  если  "1"  -  нужно выключать TUR-
       BO-режим  при вызове драйвера (для
       всех модемов кроме XTR - нужно)
 bit5 если "1", то драйвер позволяет уп-
       равлять линией (подключать модем к
       линии и отключать)
- bit6 если "1",то в драйвере имеются часы
- bit7 если "1",то в драйвере имеется тай-
       мер

  В регистре [A] будут находится данные
для  порта  #FE.  Если  драйвер для своих
нужд  не использует порт #FE, то содержи-
мое  аккумулятора  не  должно изменяться.
Например: Vicomm с "прибамбасом" v1.2 пе-
редает  данные  и  управляет линией через
порт #FE, и при вызове данная функция ус-
тановит 3-й и 5-й биты аккумулятора в со-
ответствии со своими нуждами.



 УСТАНОВКА ПЕРЕД ОПРОСОМ ЛИНИИ

D_WAIT_INS EQU #C009
Данная  функция вызывается непосредс-
твенно перед циклом вызовов функций опро-
са линии. Если в драйвере необходимо выс-
тавить   какие-либо  переменные,  то  эта
функция этим и занимается.
При вызове данной функции в аккумуля-
торе  будет  находиться число от 0 до 15,
характеризующее громкость с которой функ-
ции опроса линии должны выводить звук ли-
нии на встроеный динамик.
Выдор  устройства для вывода звука не
оговаривается (можно использовать beeper,
AY, COVOX, и т.д.) При выводе звука на AY
есть одно ограничение: если звук выводить
не  нужно,  т.е. [A]=#00, то изменять со-
держимое регистров музпроцессора не реко-
мендуется.



          ОПРОС ЛИНИИ

D_WAIT_LN  EQU #C00C
Данная функция производит опрос линии
в течении некоторого небольшого промежут-
ка времени.

Данная функция возвращает на выходе:

Если флаг переноса установлен, то ни-
чего  не  произошло,  при этом в регистре
[B]  указывается количество произведенных
опросов линии, а в регистре [C] - сколько
всого  должно  быть опросов. Данные в ре-
гистрах  [B]  и [C] позволяют более-менее
ритмично  мигать  курсором  и  опрашивать
клавиатуру.
Например,  если  функция осуществляет
15  опросов  линии,  и при наличии шума в
линии  в любом из циклов опроса возвраща-
ется. При этом в регистре [B] указывается
сколько опросов функция успела выполнить.
Если  функция  опроса  линии  выполняется
всегда  строго  фиксированое  время, то в
регистр [B] заносится #01
Содержимое регистра [C] позволяет ре-
гулировать  частору мугания курсора и оп-
роса  клавиш.  Чем  больше это число, тем
 реже и ритмичнее мигает курсор.

Если при возврате из функции D_WAIT_LN
флаг  переноса  сброшен, то произошло ка-
кое-то событие. В регистре [A] указывает-
ся его код:

  #01: был принят блок. Принятых блок на-
ходится  в  буфере  модема, а его длина в
регистровой  паре [BC] В регистре [D] на-
ходится  скорость, на которой был передан
данный  блок. Если скорость определить не
 удалось, то в [D] заноситься #80
  #02: были обнаружены короткие гудки
  #03: был обнаружен вызов (звонок)



        ДОЛГОЕ ОЖИДАНИЕ

D_WAIT_BLC EQU #C00F
Данная  функция производит долгий оп-
рос  линии  примерно  1...4  секунды. При
возврате функции:

Если флаг  переноса установлен, то ни-
чего не было принято
,Если флаг переноса сброшен, то приняли
блок:
   Принятых блок находится в буфере моде-
ма, а его длина в регистровой паре [BC] В
регистре [D] находится скорость, на кото-
рой  был  передан  данный блок. Если ско-
рость определить не удалось, то в [D] за-
носиться #80



        ПЕРЕДАЧА ДАННЫХ

D_TRANSMIT EQU #C012
Данная  функция передает блок данных.
Сами данные находяться в буфере модема, в
регистровой паре [BC] находится длина пе-
редаваемого блока, в [A] - скорость пере-
дачи.



   ПОДКЛЮЧИТЬ МОДЕМ К ЛИНИИ

D_ON_LINE  EQU #C015

   ОТКЛЮЧИТЬ МОДЕМ ОТ ЛИНИИ

D_OFF_LINE EQU #C018

Данные  функции  просто "снимают" или
"кладут"  трубку. В функцию ничего не пе-
редается и функции ничего не возвращают.



         НАБРАТЬ НОМЕР

D_CALL     EQU #C01B
Данная функция осуществляет набор но-
мера.  При вызове функции модем уже подк-
лючен  к линии, и в регистровой паре [HL]
находится адрес буфера с телефонным номе-
ром,   который   следует  набрать.  Номер
представляет собой ASCII строку, заканчи-
вающуюся  кодом #00. Если в строке встре-
тится символ "-", то при наборе его необ-
ходимо  пропустить. Во время набора необ-
ходимо  анализировать  нажатие на клавиши
<ПРОБЕЛ>, и при её нажатии произвести вы-
од из функции.

 Также при входе в функцию:
в  регистре  [A]  указан способ набора
номера:  "0"  - импульсный, "1" - тональ-
ный.
,в регистре [B] указан  период импульса
в ms
-в регистре [C] межцифровая пауза ms/10

 Данная функция возвращает:
Флаг переноса сброшен - набор номера
     произведён успешно.
Флаг переноса установлен - ошибка,
     код ошибки в [A]:
   #00 ОШИБКА НАБОРА
   #01 НЕТ ДЛИННОГО ГУДКА
   #02 ВЫПОЛНЕНИЕ ПРЕРВАНО,нажат <ПРОБЕЛ>



   ДАННАЯ ФУНКЦИЯ ВЫЗЫВАЕТСЯ
  ПРИ ОБНАРУЖЕНИИ ЗВОНКА.
 МОДЕМ ПОДКЛЮЧАЕТСЯ К ЛИНИИ И
      ОПРЕДЕЛЯЕТСЯ НОМЕР.

D_AON      EQU #C01E
           При вызове функции:
 [A] число запровое
   [B] пауза перед запросом
 [C] количество цифр в номере
 [D] чувствительность к ответу АТС
 [E] чувствительность линии

При выходе из функции в буфере модема
находиться ASCII строка с сообщением, за-
канчивающаяся кодом #00.

     УСТАНОВКА СОЕДИНЕНИЯ

           АКТИВНАЯ

SET_CON_A  EQU #C021

           ПАСИВНАЯ

SET_CON_P  EQU #C024

Данные  функции пытаются выбрать наи-
лудшую  скорость обмена. Функция активной
установки  передает  на  разных скоростях
данные,  а потом проверяет как они приня-
лись. Функция пассивной установки вначале
принимает  данные, а затем сообщает об их
приеме.   Конктерная   реализация  данных
функций не оговаривается.

Обе  функции возвращают текстовое со-
общение  о  выбраной  скорости. Сообщение
находиться в буфере модема и заканчивает-
ся кодом #00. Также при возврате из функ-
ции в аккумулятор записывается номер выб-
раной  скорости,  или  #80, если скорость
выбрать не удалось.
В   случае  невозможности  выполнения
функции возвращаются с установленным фла-
гом переноса.

       УСТАНОВИТЬ ВРЕМЯ

D_SET_TIME EQU #C027
Данная  функция  позволяет установить
текущее  время. При вызове функции данные
находится  в регистрах [A], [B], [C]: [A]
- часы, [B] - минуты, [C] - секунды. Дан-
ные представлены в двоично-десятичном ви-
де.
В  случае ошибки функция возвращается
с установленным флагом переноса.

         СЧИТАТЬ ВРЕМЯ

D_RD_TIME  EQU #C02A
Данная функция позволяет узнать теку-
щее время. При возврате из функции данные
должны  находится  в  регистрах [A], [B],
[C]  в  двоично-десятичном  виде. В [A] -
часы, [B] - минуты, [C] - секунды. В слу-
чае  ошибки  функция возвращается с уста-
новленным флагом переноса.

       КОРРЕКЦИЯ ВРЕМЕНИ
D_CALC_TIM EQU #C02D
Данная  функция  вызывается несколько
раз  в  минуту. Если используемые часы не
являются  полностью автономными (например
часы представляют собой счетчик секундных
импульсов,  подключенный  к  паралельному
порту), и требуется коррекция времени, то
для этого используется данная функция.
Внимание!  Данная функция должна сох-
 ранять значение ВСЕХ регистров!

       УСТАНОВИТЬ ТАЙМЕР

D_SET_ALR  EQU #C036
Если  драйвер поддерживает режим тай-
мера, то данная функция должна установить
таймер  на  указаное  в  регистровой паре
[BC] секунд.
В  случае ошибки функция возвращается
с установленным флагом переноса.

      ДОБАВИТЬ К ТАЙМЕРУ

D_ADD_ALR  EQU #C039
Данная функция добавляет к оставшему-
ся  времени  указаное  в регистровой паре
[BC] секунд.
В  случае ошибки функция возвращается
с установленным флагом переноса.

        ВРЕМЯ ИСТЕКЛО?

D_RD_ALR   EQU #C03C
Данная функция проверяет подошло-ли к
концу время, установленое в таймере. Если
время  вышло,  то  функция возвращается с
установленым флагом переноса.



Внимание! 
В программе Macro Modem v2.20 функции
работы с часами/таймером не используются,
они зарезервированы под будующие версии.

             _____

 Мы  предлагаем  Вашему  вниманию  пример
драйвера  под  самый  простейший "Модем",
распространенный в С-Пб.



CALLING EQU 01 

;ФЛАГ РАЗРЕШЕНИЯ НАБОРА НОМЕРА 
;ЕСЛИ "1", ТО ДРАЙВЕР БУДЕТ НАБИРАТЬ 
;НОМЕР И РЕАГИРОВАТЬ НА ЗВОНКИ 
;ЕСЛИ "0" - НЕ БУДЕТ, НО И НЕ БУДЕТ 
;ЗАВИСАТЬ ПРИ ОТСУТСТВИИ "ПРИБАМБАСА" 

 ORG #C000 

;КЕРНАЛЬ ПОДПРОГРАММ 

 JP D_INSTAL 
        JP D_NAME 
        JP D_RD_STAT 
        JP D_WAIT_INS 
        JP D_WAIT_LN 
        JP D_WAIT_BLC 
        JP D_TRANSMIT 
        JP D_ON_LINE 
        JP D_OFF_LINE 
        JP D_CALL 
 JP D_AON 
        JP SET_CON_A 
        JP SET_CON_P 
        JP D_SET_TIME 
        JP D_RD_TIME 
        JP D_CAL_TIM 
        JP D_SET_ALR 
        JP D_ADD_ALR 
        JP D_RD_ALR 

;РАБОЧИЕ ПЕРЕМЕННЫЕ ДРАЙВЕРА 

LINE_STATUS DB 0
SPEED       DB 0
LCOUNT_ADB 0
LCOUNT_BDB 0
LCOUNT_CDB 0
ZERO_BYTE   DB 0 ;БАЙТ ИДУЩИЙ ПЕРЕД 
                 ;ДЛИНОЙ В БЛОКЕ 
SYNC_TABL   DS 15 

;УСТАНОВКА ДРАЙВЕРА 
 ;in: [HL] АДРЕС БУФЕРА МОДЕМА 
;out: В БУФЕРЕ В ASCII ФОРМЕ ЗНАЧЕНИЯ 
;СКОРОСТЕЙ. 
;НА КАЖДУЮ СКОРОСТЬ ПО 4 БАЙТА, 
;КОЛ-ВО СКОРОСТЕЙ 8, ЗАКАНЧИВАЕТСЯ #00 

D_INSTAL RET C 

;ЕСЛИ ДРАВЕР ВЫЗЫВАЕТСЯ С УСТАНОВЛЕНЫМ 
 ;ФЛАГОМ CY - ТО ЭТО ЗАПУСК ДЛЯ 
;РАСПАКОВКИ, И ЕГО ИГНОРИРУЕМ 

 LD (MOD_BUFF1),HL ;ЗАПИСАЛИ В 
        LD (MOD_BUFF2),HL ;НУЖНЫЕ МЕСТА
        LD (MOD_BUFF3),HL ;АДРЕС 
        LD (MOD_BUFF4),HL ;БУФЕРА 

;ПЕРЕБРАСЫВАЕМ В БУФЕР СКОРОСТИ ДРАЙВЕРА

 EX DE,HL 
        LD HL,SPD_MODEM 
        LD BC,ESPD_MODEM-SPD_MODEM 
        LDIR 
        RET 

SPD_MODEM 
        DB " 600 ","1800 ","2400 " 
        DS 5*5
ESPD_MODEM 

;ЧТЕНИЕ ИНФОРМАЦИИ О ДРАЙВЕРЕ 
;out: ПО [DE] ЗАПИСЫВАЕТСЯ НАЗВАНИЕ 
;ДРАЙВЕРА (ДО 80-ТИ СИМВОЛОВ), 
;ЗАКАНЧИВАЕТСЯ КОДОМ #00 

D_NAME   LD HL,NAME_MODEM 
         LD BC,ENAME_MODEM-NAME_MODEM 
         LD DE,(MOD_BUFF1) 
         LDIR 
         RET 

NAME_MODEM 
        DB "Vicomm-modem driver v1.04  "
        DB "(C) 1997 *MAS*",0 
GENAME_MODEM 

;ЧТЕНИЕ СТАТУСА ЛИНИИ/ДРАЙВЕРА 
;in: [A] ЦВЕТ БОРДЮРА 

;out: [A] - ДАННЫЕ ДЛЯ ПОРТА #FE 
;     Т.К. ЦВЕТ БОРДЮРА + БИТЫ УПРАВЛЕНИЯ
  ;     ЛИНИЕЙ И ВЫХОД ЛИНИИ 
;[B]: ПО БИТАМ: 
;   0 СТАТУС ЛИНИИ (СВОБОДНА/ЗАНЯТА) 
;   3 наличие тонового набора 
,;   4 ВЫКЛЮЧАТЬ TUBRO ПРИ ВЫЗОВЕ ДРАЙВЕРА
;   5 УПРАВЛЕНИЕ ЛИНИЕЙ 
;   6 НАЛИЧИЕ ТАЙМЕРА 
;   7 НАЛИЧИЕ ЧАСОВ 

D_RD_STAT 
        AND 7: LD C,A 
        LD A,(LINE_STATUS) 
        LD B,A: OR C 
        OUT (#FE),A: LD (BORDER_0+1),A 
        OR  #08: LD (BORDER_1+1),A 
        PUSH AF 
        XOR A: INC B: DEC B 
        JR Z,$+3: INC A 

 IF CALLING 

;ВЫКЛЮЧАТЬ TURBO, ЕСТЬ УПРАВЛЕНИЕ ЛИНИЕЙ,
;НЕТ ЧАСОВ, ТАЙМЕРА 

 OR %00110000 
      ELSE 

;ВЫКЛЮЧАТЬ TURBO, НЕТ УПРАВЛЕНИЯ ЛИНИЕЙ,
;НЕТ ЧАСОВ, ТАЙМЕРА, ТРУБКА СНЯТА 

 OR %00010001 
      ENDIF 
        LD B,A 
        POP AF: RET 

;СНЯТЬ ТРУБКУ 

D_ON_LINE  LD A,#20: JR ON_OFF_L 

;ПОЛОЖИТЬ ТРУБКУ 

D_OFF_LINE XOR A 

ON_OFF_L 

;ИЗМЕНЕНИЕ СТАТУСА ЛИНИИ, ЕСЛИ НЕТ 
;УПРАВЛЕНИЯ ЛИНИЕЙ - СРАЗУ ВОЗВРАТ 

 IF CALLING 
         LD (LINE_STATUS),A 
         LD B,A: LD A,(BORDER_0+1) 
         OR B: LD (BORDER_0+1),A 
         OUT (#FE),A 
         OR #08: LD (BORDER_1+1),A 
      ENDIF 
         RET 

;НАБРАТЬ НОМЕР, ТРУБКА УЖЕ СНЯТА 
; in: 
; [HL] - АДРЕС БУФЕРА С НОМЕРОМ 
;  [A] - 0 pulse,  1 tone 
;  [B] период импульса ms, станд. 100 
;  [C] межцифровая пауза ms/10 
; CY=1 ОШИБКА, КОД ОШИБКИ В [A]: 
;    0 ОШИБКА НАБОРА 
;    1 НЕТ ДЛИННОГО ГУДКА 
;    2 ПРЕРЫВАНИЕ 
; CY=0 СОЕДИНЕНИЕ УСТАНОВЛЕНО: 
;ВОЗВРАЩАЮТСЯ ДАННЫЕ КАК ИЗ SET_CON_P 

D_CALL 
      IF CALLING 
        LD (ID_CALL+1),HL 
        PUSH BC 

;УСТАНАВЛИВАЕМ П/П СКАНИРОВАНИЯ ЛИНИИ 

 XOR A: CALL D_WAIT_INS 
        POP BC 
        LD A,C: LD (CDEL_COD+1),A 

;ЗАДАН ПЕРИОД ИМПУЛЬСА, ПО СТАНДАРТУ 
;ДАЕТСЯ 2/5 ПЕРИОДА ЛИНИЯ ЗАМКНУТА, 
;И 3/5 ПЕРИОДА ЛИНИЯ РАЗОМКНУТА 
;ДЕЛИМ ПЕРИОД НА 5 

 LD A,B: LD B,0 
DIV5SUB 5: JR C,EDIV5 
        INC B: JR DIV5 
-EDIV5   INC B: DEC B: JR NZ,$+3: INC B 

 LD A,B: RLCA;2/5 ПЕРИОДА 
        LD (CDEL_1+1),A 

 ADD A,B         ;3/5 ПЕРИОДА 
        LD (CDEL_0+1),A 

;ЗАПИСЫВАЕМ ЗНАЧЕНИЯ ВЫДАВАЕМЫЕ В ПОРТ 
;#FE ДЛЯ ЗАМЫКАНИЯ/РАЗМЫКАНИЯ ЛИНИИ 

 LD A,(BORDER_0+1): AND #0F 

        LD (DCAL_OFF+1),A 
        LD A,(BORDER_1+1): OR #20 
        LD (DCAL_ON+1),A 

;МАСЕНЬКАЯ ПАУЗА ПЕРЕД НАБОРОМ 

 EI: LD B,45: HALT: DJNZ $-1 

;КОНТРОЛЬ ДЛИННОГО ГУДКА: 
;ДЕЛАЕМ 200 ОПРОСОВ ЛИНИИ, ЕСЛИ 
;ПОЙМАЕМ 30 РАЗ ПОДРЯД ГУДОК - ВСЕ ОК 

 LD BC,200*256+30 
WAIT_DIA CALL WAIT_CALL 
          JR C,DWAIT_R   ;ГУДКА НЕТ 
         DEC C 
         JR Z,ID_CALL ;ПОЙМАЛИ 30 РАЗ 
         JR DWAIT_N 

;ЕСЛИ ХОТЬ РАЗ ПОТЕРЯЛИ ГУДОК - УСТАНО- 
;ВИТЬ СЧЕТЧИК ЗАНОВО НА 30 

DWAIT_R  LD C,30 

;ЕСЛИ НАЖАТ ПРОБЕЛ - ВЫХОД 

DWAIT_N LD A,#7F: IN A,(#FE) 
        RRCA: JR NC,BRK_CALL 
        DJNZ WAIT_DIA 

NO_DIAL   LD A,1: SCF: RET ;НЕТ СИГНАЛА
-BRK_CALL  LD A,2: SCF: RET ;ПРЕРЫВАНИЕ 
ERRD_CALL XOR A: SCF: RET  ;ОШИБКА 

ED_CALL XOR A: RET ;НОМЕР НАБРАН

;СОБСТВЕННО НАБОР НОМЕРА
/ID_CALL LD HL,0 ;ЗДЕСЬ БУДЕТ АДРЕС БУФЕРА
        LD A,(HL): INC HL
        LD (ID_CALL+1),HL

 OR A         ;НАЙДЯ КОД #00
        JR Z,ED_CALL ;ОКАНЧИВАЕМ НАБОР
;СИМВОЛЫ "-", "(", ")", " " ИГНОРИРУЕМ
        CP "-": JR Z,ID_CALL
        CP "(": JR Z,ID_CALL
        CP ")": JR Z,ID_CALL
        CP " ": JR Z,ID_CALL

 SUB "0": JR C,ERRD_CALL
;ЕСЛИ ЭТО НЕ ЦИФРА - ОШИБКА НАБОРА

;ЦИФРЕ "0" СООТВЕТСТВУЕТ 10 ИМПУЛЬСОВ
        JR NZ,$+4: LD A,10
        CP 11: JR NC,ERRD_CALL

 LD B,A

;НАБИРАЕМ ЦИФРУ, В [B] КОЛ-ВО ИМПУЛЬСОВ

CALL_C 

;РАЗРЫВ ЛИНИИ НА 60ms (3/5)

DCAL_OFF LD A,0
         OUT (#FE),A

CDEL_0   LD A,0
DDEL_0   LD C,248
         DEC C: JP NZ,$-1
         DEC A: JP NZ,DDEL_0

;ЗАМЫКАНИЕ ЛИНИИ И ПАУЗА 40ms (2/5)

DCAL_ON LD A,0
        OUT (#FE),A

;ЗАДЕРЖКА НА [A] ms
CDEL_1  LD A,0
DDEL_1  LD C,248
        DEC C: JP NZ,$-1
        DEC A: JP NZ,DDEL_1

  DJNZ CALL_C

;МЕЖЦИФРОВАЯ ПАУЗА В 600ms

CDEL_COD LD B,0
 W_CDEL  NOP: NOP: LD DE,1457
        DEC DE: LD A,D
        OR E: JP NZ,$-3
        DJNZ W_CDEL

;ЕСЛИ НАЖАТ ПРОБЕЛ - ВЫХОД,ИНАЧЕ НАБИРАЕМ
;НОМЕР ДАЛЬШЕ
        LD A,#7F: IN A,(#FE)
        RRCA: JR NC,BRK_CALL
 JR ID_CALL

;ОПРАШИВАЕМ ЛИНИЮ 32 РАЗА

WAIT_CALL DI: PUSH BC
        LD B,32
        LD HL,0

CALL_DIAL LD DE,#0B59
         CALL SCAN_IN
         CALL DELAY_37
          LD E,A: LD D,0: ADD HL,DE
         DJNZ CALL_DIAL

  POP BC
;КОНТРОЛЬ ГУДКА, СРЕДН. АРИФМ.
 ;ЗНАЧЕНИЕ ЧАСТОТЫ ЗА 32 ОПРОСА
        SRA H: RR L : SRA H: RR L
        SRA H: RR L : SRA H: RR L
        SRA H: RR L
        LD A,L: SRA A

;В ИНТЕРВАЛЕ 150...250 - ЧАСТОТА ГУДКА
        CP 150: RET C
        CP 250: CCF
        RET

        XOR A: SCF: RET
      ENDIF

;ВЫЗЫВАЕТСЯ ПРИ ОБНАРУЖЕНИИ ЗВОНКА.
;СНИМАЕТСЯ ТРУБКА. + ОПРЕДЕЛЕНИЕ НОМЕРА
;(ЗДЕСЬ ОТСУТСТВУЕТ!)

;out: MOD_BUFF НОМЕР В ASCII, В КОНЦЕ 0

D_AON   CALL D_ON_LINE
        LD B,75: EI: HALT: DJNZ $-2: DI
;ПОСЛЕ СНЯТИЯ ТРУБКИ ПАУЗА В 1.5 СЕК.
;ЕСЛИ ЕСТЬ АОН, ТО ОН МОЖЕТ ОПРЕДЕЛИТЬ
;НОМЕР

;ПЕРЕБРАСЫВАЕМ В БУФЕР МОДЕМА СООБЩЕНИЕ
;О СНЯТИИ ТРУБКИ

MOD_BUFF3 EQU $+1: LD DE,#1111
         LD HL,AON_TXT
           LD BC,EAON_TXT-AON_TXT
         LDIR
         RET

AON_TXT 
DB 13,"Модем подключен к линии",13,0
EAON_TXT 

;ДВЕ НИЖЕСЛЕДУЮЩИЕ П/П ИСПОЛЬЗУЮТСЯ
;КАК "ЗАГЛУШКИ", Т.К. АЛГОРИТМ АВТОВЫБОРА
;СКОРОСТИ ЕЩЕ НЕ ОБДУМЫВАЛСЯ

;установить соединение, передача
;Т.Е. ВНАЧАЛЕ "ПЕРЕДАЕТ", ПОТОМ "СЛУШАЕТ"

SET_CON_A 

;установить соединение, прием
;Т.Е. ВНАЧАЛЕ "СЛУШАЕТ", ПОТОМ "ПЕРЕДАЕТ"

SET_CON_P 
MOD_BUFF4 EQU $+1: LD DE,0
      IF CALLING
        PUSH HL
         LD (HL),13: LD BC,1: XOR A
        CALL D_TRANSMIT
        POP HL
      ENDIF

;УСТАНОВКА СОЕДИНЕНИЯ
;В MOD_BUFF ВОЗВРАЩАЕТСЯ ТЕКСТОВОЕ СООБЩ.
 ;О СОЕДИНЕНИИ, В КОНЦЕ - КОД #00
;В [A] УСТАНОВЛЕНАЯ СКОРОСТЬ, ИЛИ #80
;ЕСЛИ ОНА НЕОПРЕДЕЛЕНА
         LD HL,CARR_TXT
         LD BC,ECARR_TXT-CARR_TXT
         LDIR
         LD A,#80 ;СКОРОСТЬ НЕОПРЕДЕЛЕНА
         RET

CARR_TXT 
DB 13,"Соедение установлено",13,0
ECARR_TXT 

;ИНСТАЛЯЦИЯ ПЕРЕД СКАНИРОВАНИЕМ ЛИНИИ
;В [A] - ГРОМКОСТЬ ВЫВОДА ЗВУКА ЛИНИИ
;ЧЕРЕЗ AY

D_WAIT_INS 
        LD HL,#4000: LD (LCOUNT_A),HL
        AND #0F: SET 6,A: LD (SOUND+1),A
        JR Z,D_WAIT_INS1
         LD BC,#FFFD: LD A,7: OUT (C),A
         LD B,#BF: LD A,#3F: OUT (C),A

GD_WAIT_INS1 
        XOR A: LD (LAST_DT+1),A
        LD (COUNT0+1),A
        LD (COUNT1+1),A
        LD (LAST0+1),A
        LD (OFFCOU+1),A
        RET

;СКАНИРОВАНИЕ ЛИНИИ
;out
;CY=1: НИЧЕГО
 ; [B] КОЛИЧЕСТВО ЦИКЛОВ ОПРОСА
; [C] СКОЛЬКО ВСЕГО ДОЛЖНО БЫТЬ ЦИКЛОВ
;CY=0, ;[A] - КОД:
;1 - ПРИНЯТ БЛОК, 2 - ЗАНЯТО, 3 - ВЫЗОВ

D_WAIT_LN 
        DI
        LD HL,0
        LD DE,16*256+12  ;11

 LD BC,#FFFD: LD A,8: OUT (C),A
        LD A,(SOUND+1)
        AND #0F: JR Z,$+4: LD B,#BF

;ОПРОС ЛИНИИ НА СИНХРОСИГНАЛ БЛОКА И
;КОНТРОЛЬ КОТОТКИХ ГУДКОВ, ВНАЧАЛЕ
;СЧИТАЕМ СРЕДН. АРИФМ. ЗНАЧЕНИЕ ЧАСТОТЫ
;ЗА 16 ОПРОСОВ

MDLOOP1 
        IN A,(#FE): AND #20

;АНАЛИЗ/НЕТ СИГНАЛА ВЫЗОВА
    IF CALLING
        JP Z,RING : ELSE: JP $+3
    ENDIF

 CALL IN_LINE_F
        CP 11: JP C,MDLOOP2
        CP 89: JP NC,MDLOOP2
        DEC E: JP Z,INPUT_BLOCK ;БЛОК?
MDLOOP2 ADD A,L: LD L,A
        JR NC,$+3: INC H
        DEC D: JP NZ,MDLOOP1

 SRA H: RR L : SRA H: RR L
        SRA H: RR L : SRA H: RR L
        LD A,L: SRA A

;В ИНТЕРВАЛЕ 150...250 - ЧАСТОТА ГУДКА
;ЕСЛИ ГУДОК, ТО А=1 ИНАЧЕ А=0
        CP 150: JR C,TST_OFFL
        CP 250: JR C,TST_ONL

TST_OFFL XOR A: JR $+4
TST_ONL  LD A,1

;ЕСЛИ СОСТ. СИГНАЛА НЕ ИЗМЕНИЛОСЬ, ТО
 ;ПРОСТО УВЕЛИЧИТЬ СЧЕТЧИК. ЕСЛИ
;ИЗМЕНИЛОСЬ, ТО ПЕРЕКЛЮЧИТЬ СЧЕТЧИК

LAST_DT  CP 0: LD (LAST_DT+1),A
         JR NZ,NEW_DTL

ADR_IDL  LD HL,0: INC (HL): LD A,(HL)
         CP 200: CALL NC,D_WAIT_INS1
         JR E_WAIT_LN

;ЧАСТОТА ИЗМЕНИЛАСЬ:

NEW_DTL DEC A: JR Z,NEW_DTL1

;СТАЛА "0": ПЕРЕКЛЮЧАЕМ СЧЕТЧИК
         LD HL,COUNT0+1 : LD (HL),0
        LD (ADR_IDL+1),HL

;ЕСЛИ БЫЛО >4 ЕДЕНИЦ И >4 НУЛЕЙ ПОДРЯД,
;ЗНАЧИТ ПОЙМАЛИ СИГНАЛ ОТБОЯ

COUNT1  LD A,0: CP 4: JP C,RES_OFF
LAST0   LD A,0: CP 4: JP C,RES_OFF

;ПОЙМАВ 3 ГУДКА ОТКЛЮЧИТСЯ

OFFCOU  LD A,0: INC A: LD (OFFCOU+1),A
        CP 3: JR Z,BUSY_FOUND

;ЧАСТОТА СТАЛА "1": ПЕРЕКЛЮЧАЕМ СЧЕТЧИК
NEW_DTL1 LD HL,COUNT1+1 : LD (HL),0
        LD (ADR_IDL+1),HL
COUNT0  LD A,0
JPE_WAIT_LN LD (LAST0+1),A
        JR E_WAIT_LN

RES_OFF XOR A
        LD (COUNT0+1),A
        LD (COUNT1+1),A
        JR JPE_WAIT_LN

BUSY_FOUND
        OR A: LD A,2 ;CY=0, A=2 "ЗАНЯТО"
        RET

;ПОЙМАЛИ ЗВОНОК, ПРОВЕРКА НА РЕАЛЬНОСТЬ
;ЕСЛИ СИГНАЛ ВЫЗОВА БУДЕТ ДЕРЖАТЬСЯ
;НЕКОТОРОЕ ВРЕМЯ - ЗНАЧИТ ВЫЗОВ В НАТУРЕ

GRINGLD C,2
RING1   LD B,30: NOP: DJNZ $-1
        IN A,(#FE): AND #20
        JP NZ,D_WAIT_LN
        DEC C: JR NZ,RING1

;ЗВОНОК ЕСТЬ, ОЖИДАЕМ ЕГО ОКОНЧАНИЯ

RING2   IN A,(#FE): AND #20: JR Z,RING2
         LD A,3   ;CY=0, A=3 "ЗВОНОК"
        RET

E_WAIT_LN LD BC,#0101
          SCF: RET  ;CY=1 - НИЧЕГО НЕТ

;ОПРОС ВХОДА: В [A] БУДЕТ ЧАСТОТА СИГНАЛА

IN_LINE_F PUSH HL: PUSH DE
          LD DE,(LCOUNT_A)
SOUND     LD L,0

LP_TIN_F INC E: JP Z,END_TIN_F
         INC E: JP Z,END_TIN_F
         IN A,(#FE)
          RLCA: RLCA: SBC A,A
          AND L: NOP: OUT (C),A
         AND #40: XOR D: JP Z,LP_TIN_F
        XOR D: LD (LCOUNT_B),A

RET_TIN_F LD A,E
        LD HL,LCOUNT_A
        SUB (HL): LD (HL),A
        LD A,E
        POP DE: POP HL
        RET

END_TIN_F DEC E: JR RET_TIN_F

;ПОЙМАЛИ СИНХРОСИГНАЛ, ПРИНИМАЕМ БЛОК

INPUT_BLOCK
        CALL IN_LINE
        CALL CONTR_SPEED
        CALL LOAD_DATA
        RET C

E_LOAD_DT LD A,(SPEED): LD D,A
BLOCK_LEN EQU $+1: LD BC,#0101
;CY=0   УСПЕШНО ПРИНЯЛИ БЛОК
          OR A: LD A,1
          RET

;ДОЛГОЕ ОЖИДАНИЕ БЛОКА И ПРИЕМ БЛОКА

;out: CY НЕТ БЛОКА
;[BC] ДЛИНА
;[D] СКОРОСТЬ (#80 НЕОПРЕДЕЛЕНА)

D_WAIT_BLC
        CALL WAIT_LINE: RET C
        CALL LOAD_DATA
        CALL LINE_FREE
        JR E_LOAD_DT

SCAN_IN CALL IN_LINE
        CP D : RET C
 CP E : CCF
        RET

IN_LINE_D;ЗАДЕРЖКА И ОПРОС ВХОДА
        PUSH BC : POP BC

;ОПРОС ВХОДА

IN_LINE PUSH HL : PUSH BC
        LD A,(LCOUNT_A) : LD C,A
        LD A,(LCOUNT_B) : LD B,A

LOOP_TIN INC C : JP Z,END_TIN
         IN A,(#FE) : AND #40
         XOR B : JP Z,LOOP_TIN

 XOR B : LD (LCOUNT_B),A
RET_TIN LD A,C
        LD HL,LCOUNT_A
        SUB (HL) : LD (HL),A
        LD A,C
        POP BC : POP HL
        RET

END_TIN DEC C: JR RET_TIN



;ОЖИДАНИЕ ОСВОБОЖДЕНИЯ ЛИНИИ, ВЕРТИМСЯ
;ЗДЕСЬ ДО ТЕХ ПОР, ПОКА ИЗ ЛИНИИ НЕ
;ИСЧЕЗНЕТ СИГНАЛ АБОНЕНТА

LINE_FREE
        PUSH AF : PUSH DE : PUSH BC
          XOR A : LD (LCOUNT_A),A
         LD A,#40 : LD (LCOUNT_B),A
        CALL IN_LINE
        LD DE,#0570;#0180
        NOP : NOP
LN_FREE1 NOP: NOP
LN_FREE2 LD B,4
         CALL DELAY_37
         CALL SCAN_IN
         NOP : JP  NC,LN_FREE1

LN_FREE3 DEC B : JP Z,LINE_FREE4
        CP #FF : JP NC,LINE_FREE4
        CALL DELAY_37
        CALL SCAN_IN
        JP C,LN_FREE3
        JP LN_FREE2

;ЛИНИЯ СВОБОДНА

LINE_FREE4
        POP BC : POP DE : POP AF
        RET



;СИНХРОНИЗАЦИЯ БЛОКА

SYNCD1_IN JP SYNC1_IN
SYNC1_IN  NOP : NOP
        CALL IN_LINE
        CP D : JP C,ED_SYNCD
        CP E : CCF: JP C,ED_SYNCD
        LD B,A
        LD A,(HL)
        OR A : JP Z,SYNC1_I1
        ADD A,B : LD (HL),A
SYNC1_I2 ADD A,0
         INC HL
         RET
SYNC1_I1 JP SYNC1_I2

SYNCD2_IN JP SYNC2_IN
SYNC2_IN  NOP : NOP
SYNC2_I6 CALL IN_LINE
        CP D: JP C,ED_SYNCD
        CP E: CCF: JP C,ED_SYNCD
        LD B,A
        LD A,(HL)
        SUB B
        JP P,SYNC2_I2
        XOR A : ADD A,0
SYNC2_I1 LD (HL),A
         INC HL
         RET
SYNC2_I2 JP SYNC2_I1

ED_SYNCD INC SP : INC SP
  ERR_SYNC POP DE : POP HL
         RET

;ЗАДЕРЖКИ НА СООТВ. ЧИСЛО ТАКТОВ
DELAY_57   JP DELAY_47
DELAY_47   JP DELAY_37
DELAY_37   CALL DELAY_27
DELAY_27   RET
DELAY_68   CALL DELAY_27
           CALL DELAY_27
           NOP
           RET

DELAY_C LD B,#FE
         CALL DELAY_47
         CALL DELAY_47
        DJNZ DELAY_C+2
        DEC C : JP NZ,DELAY_C
        RET

;ОЖИДАНИЕ СИГНАЛА АБОНЕНТА
;В ТЕЧЕНИИ 2...4 СЕКУНД

WAIT_LINE DI
          LD HL,#4000 : LD (LCOUNT_A),HL
          LD D,3
WT_LINE1 LD E,3
WT_LINE2 LD H,1
WT_LINE3 LD B,16
         LD A,H: LD (LCOUNT_C),A
LP_WLINE CALL IN_LINE
         CP MIN+1 : JP C,WAIT_CONTR1
         CP #2D : JP C,WAIT_SPEED
WAIT_CONTR
         ADD A,L : JP NC,$+4 : INC H
         ADD A,6 : LD L,A
         JP NC,$+4 : INC H
         LD A,(LCOUNT_C)
         CP H
         JP C,WT_LINE3
         JP Z,WAIT_CONTR2
           DEC E : JP NZ,WT_LINE2
           DEC D : JP NZ,WT_LINE1
         SCF: RET

WAIT_CONTR1 CP 5
        JP WAIT_CONTR

WAIT_CONTR2 LD B,16
        JP LP_WLINE

;КОНТРОЛЬ СКОРОСТИ ПРИ ОЖИДАНИИ

WAIT_SPEED
        CALL DELAY_47: NOP
        DEC B : JP NZ,LP_WLINE
        CALL IN_LINE

;КОНТРОЛЬ СКОРОСТИ. ПОДСЧЕТ ЧИСЛА ИМПУЛЬ-
;СОВ => СКОРОСТЬ

CONTR_SPEED
 LD BC,#0006
        CALL IN_LINE
        CALL IN_LINE_D
        CALL IN_LINE_D
        PUSH BC: POP BC
C_SPEED CALL IN_LINE
        ADD A,B: LD B,A
        DEC C: JR NZ,C_SPEED
        OR A
        RET

;ПРИЕМ БЛОКА.
;В [B] ЧИСЛО ИМПУЛЬСОВ (СКОРОСТЬ)

LOAD_DATA
MOD_BUFF1 EQU $+1: LD HL,0
        LD A,195 : CP B
         JP C,INP_600;?>195 = 600
        LD A,130 : CP B
        JP C,INP_1800   ;?>130 = 1800
        LD A,60 : CP B
        CCF : RET C     ;?>060 = 2400

INP_FAST LD A,2
         LD (SPEED),A ;СКОРОСТЬ 2400
        CALL SYNC_FAST: RET C
        CALL LOAD_BYTE_FAST : RET C

;ПРИНИМАЕМ ДЛИНУ БЛОКА: ЕСЛИ 0-Й БАЙТ
;РАВЕН #08, ТО ДЛИНА БЛОКА БОЛЬШЕ НА
;256 БАЙТ
        LD (ZERO_BYTE),A
        LD D,0
        CP 8: JR NZ,$+3: INC D
;ПРИНИМАЕМ МЛ. БАЙТ ДЛИНЫ
         CALL LOAD_BYTE_FAST: RET C
        LD E,A: OR A: JR NZ,$+3: INC D

 LD (BLOCK_LEN),DE

;ПРИНИМАЕМ САМ БЛОК, ДЛИНОЙ [DE]

GLD_BLOCK_FAST
        CALL LOAD_BYTE_FAST: RET C
        LD (HL),A
        INC HL: DEC DE
        LD A,D: OR E
        JP NZ,LD_BLOCK_FAST
        RET

;ПРИНИМАЕМ БАЙТ

LOAD_BYTE_FAST
        LD B,8   ;ЛОВИМ 8 БИТ
        CALL IN_LINE

;ОПРЕДЕЛИЛИ ЧАСТОТУ, ЕСЛИ ОНА ЛЕЖИТ
;В ДИАПАЗОНЕ ОТ MIN ДО MAX, ТО БИТ
;ПРИНЯТ, ИНАЧЕ - ОШИБКА
        CP MIN : JP C,ERR_LDFAST
        CP MAX : JP NC,ERR_LDFAST

;ЕСЛИ ЧАСТОТА БОЛЬШЕ ZERO - ПРИНЯЛИ
;ЕДИНИЦУ, МЕНЬШЕ - НУЛЬ
        CP ZERO
        RL C ;ПРИНЯЛИ ИНВЕРСНЫЙ БИТ
        CALL DELAY_47   ;27
        DEC B: JP Z,_LOAD_BYTE_FAST
        CALL IN_LINE
        JP LOAD_BYTE_FAST+2

_LOAD_BYTE_FAST
        LD A,C: CPL ;ИНВЕРТИРОВАЛИ БАЙТ
        PUSH AF
        CALL IN_LINE
        POP AF
          OR A: RET ;БАЙТ ПРИНЯТ

ERR_LDFAST        ;ОШИБКА ПРИЕМА
        POP BC
        SCF: RET

;СИНХРОНИЗАЦИЯ БЛОКА

SYNC_FAST PUSH HL
        LD DE,MIN*256+ZERO-3
        LD A,1
        LD (SYNC_TABL),A
        LD (SYNC_TABL+1),A
        CALL IN_LINE
        CALL DELAY_68
         CALL IN_LINE
S1_FAST CALL DELAY_57
        CALL IN_LINE
        CP D : JP C,ERR_SYNC
        CP E : JP C,S1_FAST

 LD E,MAX-1
        LD HL,SYNC_TABL
        CALL DELAY_47
        CALL IN_LINE
        CALL DELAY_68
        CALL DELAY_27
         CALL IN_LINE
         CALL DELAY_68
         CALL DELAY_27
        CALL IN_LINE
        CALL DELAY_47
        CALL DELAY_27
        CALL SYNCD1_IN
        CALL SYNCD1_IN
         LD HL,SYNC_TABL
         CALL SYNC2_IN
         CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        CALL SYNCD1_IN
         LD HL,SYNC_TABL
         CALL SYNC2_IN
         CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        LD C,A
        CALL SYNCD1_IN
        CP C : JP M,S2_FAST
         CALL IN_LINE
         CALL DELAY_68
         CALL DELAY_27

S2_FAST CALL IN_LINE
        CALL DELAY_68
        CALL IN_LINE
        POP HL
        OR A: RET



;!!! ДЛЯ СКОРОСТЕЙ 1800/600 ВСЕ ОЧЕНЬ
;ПОХОЖЕ, ПОЭТОМУ БЕЗ КОМЕНТАРИЕВ

INP_1800 LD A,1: LD (SPEED),A
        CALL IN_LINE
        CALL DELAY_27
        NOP
        LD DE,#0E19
        LD DE,#0E19
        CALL SYNC_1800: RET C
        LD D,0
         CALL LOAD_BYTE_1800: RET C
        LD (ZERO_BYTE),A
        CP 8: JR NZ,$+3: INC D
;ПРИНИМАЕМ ДЛИНУ
         CALL LOAD_BYTE_1800: RET C
        LD E,A: OR A: JR NZ,$+3: INC D

 LD (BLOCK_LEN),DE
GLD_BLOCK_1800
        CALL LOAD_BYTE_1800: RET C
        LD (HL),A
        INC HL: DEC DE
        LD A,D: OR E
        JP NZ,LD_BLOCK_1800
        RET

LOAD_BYTE_1800
         PUSH BC : LD B,8
        CALL IN_LINE
          CP #0F: JP C,ERR_LD1800
        CP #2D: JP NC,ERR_LD1800
        CP #1C: LD A,C: RLA: LD C,A
        CALL DELAY_27
          DEC B: JP NZ,NEXT_B1800
        LD A,C: CPL
        POP BC
        PUSH AF
        CALL IN_LINE
        POP AF
        OR A: RET

NEXT_B1800
        CALL DELAY_27
        NOP
        CALL IN_LINE
        CALL DELAY_57
        CALL DELAY_27
        NOP
        JP LOAD_BYTE_1800+3

ERR_LD1800
        POP BC
        SCF: RET

SYNC_1800 PUSH HL
        PUSH DE
        OR A : LD A,1
        LD (SYNC_TABL),A
        LD (SYNC_TABL+1),A
        CALL IN_LINE
        CALL DELAY_68
        CALL DELAY_27
        NOP
        CALL IN_LINE
        CALL DELAY_27
        NOP
S1_1800 CALL DELAY_68
        CALL IN_LINE
        NOP
        CP D: JP C,ERR_SYNC
        CP E: JP C,S1_1800
        LD DE,#0E2E
        LD HL,SYNC_TABL
        CALL DELAY_47
        CALL IN_LINE
        CALL DELAY_68
        CALL DELAY_27
        NOP
        CALL IN_LINE
        CALL DELAY_68
        CALL DELAY_27
        NOP
        CALL IN_LINE
        CALL DELAY_47
        CALL DELAY_27
        ADD A,0
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        LD HL,SYNC_TABL
        CALL SYNC2_IN
        CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        CALL SYNCD1_IN
        LD HL,SYNC_TABL
        CALL SYNC2_IN
        CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        LD C,A
        ADD A,0
        CALL SYNCD1_IN
        CP C: JP M,S2_1800
        CALL IN_LINE
        CALL DELAY_68
        CALL DELAY_27
        NOP
S2_1800 CALL IN_LINE
        CALL DELAY_68
CALL DELAY_27
        NOP
        CALL IN_LINE
        POP DE
        POP HL
        OR A: RET

INP_600 XOR A: LD (SPEED),A
        CALL IN_LINE
        NOP
        LD DE,#1728
        LD DE,#1728
        CALL SYNC_600: RET C
        LD D,0
         CALL LOAD_BYTE_600 : RET C
        LD (ZERO_BYTE),A
          CP 8: JR NZ,$+3 : INC D
;ПРИНИМАЕМ ДЛИНУ
         CALL LOAD_BYTE_600 : RET C
        LD E,A: OR A: JR NZ,$+3: INC D

 LD (BLOCK_LEN),DE
LD_BLOCK_600
        CALL LOAD_BYTE_600: RET C
        LD (HL),A
        INC HL: DEC DE
        LD A,D: OR E
        JP NZ,LD_BLOCK_600
        RET



GLOAD_BYTE_600
         PUSH DE: PUSH BC
         LD B,8
        CALL IN_LINE
        CALL IN_LINE
        CALL IN_LINE
        CP #17: JP C,ERR_LD600
          CP #59: JP NC,ERR_LD600
        CP #2D: LD A,E: RLA: LD E,A
        CALL IN_LINE
        DEC B
        JP NZ,LOAD_BYTE_600+4
        LD A,E: CPL: OR A
        POP BC
        POP DE
        RET

ERR_LD600 POP BC: POP DE
        SCF: RET

SYNC_600 PUSH HL: PUSH DE
        OR A
        LD A,1
        LD (SYNC_TABL),A
        LD (SYNC_TABL+1),A
        LD (SYNC_TABL+2),A
        LD (SYNC_TABL+3),A
        CALL IN_LINE
        CALL DELAY_68
        CALL DELAY_27
        NOP
        CALL IN_LINE
        CALL DELAY_27
        NOP
S1_600  CALL DELAY_68
        CALL IN_LINE
        NOP
        CP D: JP C,ERR_SYNC
        CP E: JP C,S1_600
        LD A,(SYNC_TABL+4)
        INC A
        LD (SYNC_TABL+4),A
        ADD A,0
        LD DE,#0E59
        LD HL,SYNC_TABL
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        LD HL,SYNC_TABL
        CALL SYNC2_IN
        CALL SYNCD2_IN
        CALL SYNCD2_IN
        CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        LD HL,SYNC_TABL
        CALL SYNC2_IN
        CALL SYNCD2_IN
        CALL SYNCD2_IN
        CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        LD HL,SYNC_TABL
        CALL SYNC2_IN
        CALL SYNCD2_IN
        CALL SYNCD2_IN
        CALL SYNCD2_IN
        LD HL,SYNC_TABL
        CALL SYNC1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        CALL SYNCD1_IN
        LD HL,SYNC_TABL
        CALL SYNC2_IN
        LD C,A
        ADD A,0
        CALL SYNC2_IN
        CP C : JP M,EXT_SYNC
        LD C,A
        CALL SYNC2_I6
        CP C : JP M,EXT_SYNC
        LD C,A
        CALL SYNC2_I6
        CP C : JP M,EXT_SYNC
        OR A : JP Z,ERR_SYNC
        NOP
        CALL IN_LINE
EXT_SYNC POP DE: POP HL
  OR A: RET



;ПЕРЕДАЧА БЛОКА ИЗ MOD_BUFF,
;BC - ДЛИНА, A - СКОРОСТЬ

D_TRANSMIT DI
        LD (SPEED),A
        PUSH AF  ;СОХРАНИЛИ СКОРОСТЬ
MOD_BUFF2 EQU $+1: LD HL,0
        DEC HL
        PUSH HL
        ADD HL,BC
        EX (SP),HL ;АДРЕС ПОСЛ. БАЙТА

 LD (HL),C  ;МЛ. БАЙТ ДЛИНЫ
        DEC HL: LD (HL),7
        LD A,B: OR A
        JR Z,$+3: INC (HL) ;ДЛИНА >256

 DEC HL
        LD (HL),#AA ;СИНХРО БАЙТ
        XOR A
        DEC HL: LD (HL),A
        DEC HL: LD (HL),A
        DEC HL

 POP DE  ;АДРЕС ПОСЛЕДНЕГО БАЙТА
         POP AF  ;СКОРОСТЬ ПЕРЕДАЧИ
          OR  A: JP Z,TRANSMIT_600
        DEC A: JP Z,TRANSMIT_1800

GTRANSMIT_FAST
        XOR  A: LD (HL),A ;СИНХРО
        DEC HL: LD (HL),A
        DEC HL: LD (HL),A
        DEC HL: LD (HL),A
        DEC HL: LD (HL),A

 CALL LINE_FREE
        PUSH BC
        LD C,1: CALL DELAY_C
        POP BC
        CALL OUTPUT_FAST
        PUSH HL
        PUSH DE
        LD BC,#020C
        LD A,0
        NOP: NOP: NOP: NOP
        JP OUT_BIT2600

;ПЕРЕДАЕМ БЛОК

OUTPUT_FAST
        LD A,(HL)         ;ПЕРЕДАЕМ БАЙТ
        CALL OU_BYTE_FAST
        NOP
        CALL COMP_HL_DE
        RET Z          ;БЛОК ПЕРЕДАН
        INC HL: JP OUTPUT_FAST

;ПЕРЕДАЧА БАЙТА

OU_BYTE_FAST
        PUSH HL: PUSH DE
        LD BC,#080C
OUT_BIT2600
        PUSH AF
        RLA : JP C,BIT1_FAST
          LD HL,D0_FAST : JP OB_FAST ;=0
.BIT1_FAST LD HL,D1_FAST : JP OB_FAST ;=1

;ПРИ ПЕРЕДАЧИ 1-ГО БИТА MIC OFF МЕНЬШЕ НА
;12 (168 ТАКТОВ),Т.К. 168 ТАКТОВ НУЖНЫ
;ДЛЯ ПОЛУЧЕНИЯ СЛЕД. БАЙТА,КОНТРОЛЯ,...

GOB_FAST RRA
        LD A,(HL)
          SUB C : LD D,A : INC HL
        LD E,(HL) : INC HL
        CALL OUT_DATA
        POP AF
        RLCA
        DEC B
        LD C,0 : LD C,0 : NOP
        JP NZ,OUT_BIT2600
        POP DE : POP HL
        RET

;ДЛЯ 1800/600 ПОХОЖЕ

GTRANSMIT_1800
        XOR  A : LD (HL),A
        DEC HL : LD (HL),A

 CALL LINE_FREE
        PUSH BC
        LD C,1 : CALL DELAY_C
        POP BC
        CALL OUTPUT_1800
        PUSH HL : PUSH DE
        LD BC,#020C
        LD A,0
        NOP : NOP : NOP : NOP
        JP OUT_BIT1800

OUTPUT_1800
        LD A,(HL)
        CALL OU_BYTE_1800
        NOP
        CALL COMP_HL_DE
        RET Z
        INC HL: JP OUTPUT_1800

OU_BYTE_1800
        PUSH HL: PUSH DE
        LD BC,#080C
OUT_BIT1800
        PUSH AF
        RLA: JP C,BIT1_1800
          LD HL,D0_1800: JP OB_1800 ;=0
-BIT1_1800 LD HL,D1_1800: JP OB_1800 ;=1

GOB_1800 RRA
        LD A,(HL)
        SUB C: LD D,A: INC HL
        LD E,(HL): INC HL
        CALL OUT_DATA
        POP AF
        RLCA
        DEC B
        LD C,0: LD C,0: NOP
        JP NZ,OUT_BIT1800
        POP DE: POP HL
        RET

TRANSMIT_600
        CALL LINE_FREE
        PUSH BC
        LD C,1: CALL DELAY_C
        POP BC
        CALL OUTPUT_600
        PUSH HL: PUSH DE
        LD BC,#020D
        LD A,0
        NOP: NOP: NOP: NOP
        JP OUT_BIT600

OUTPUT_600
        LD A,(HL)
        CALL OU_BYTE_600
        RLA: LD B,A
        CALL COMP_HL_DE
        LD A,B: RRA
        RET Z
        INC HL: JP OUTPUT_600

OU_BYTE_600
        PUSH HL: PUSH DE
        LD BC,#080D
        NOP

OUT_BIT600
        PUSH AF
        RLA: JP C,B71_600 ;B7=1
        RRA: JP C,B70_B01 ;B7=0,B0 =1
        LD HL,D00_600 ;B7 =0 B0 =0
        JP OB_600

B71_600 RRA: JP NC,B71_B01
        LD HL,D10_600   ;B7=1 B0=0
        JP OB_600

B71_B01 LD HL,D11_600   ;B7=1 B0=1
        JP OB_600

B70_B01 LD HL,D01_600   ;B7=0 B0=1
        JP OB_600

OB_600  NOP
        LD A,(HL)
        SUB C: LD D,A: INC HL
        LD  E,(HL): INC HL
        CALL OUT_DATA
        CALL OUT_DATA
        POP AF
        RLCA
        DEC B
        LD C,0: NOP : NOP
        JP NZ,OUT_BIT600
        POP DE:  POP HL
        RET

;СРАВНИТЬ HL И DE
COMP_HL_DE
        NOP
        LD A,H : CP D
        JP NZ,$+6: LD A,L: CP E: RET
        NOP: NOP: RET

;ПЕРЕДАЧА БИТА
OUT_DATA
        DEC D: JP NZ,$-1 ;ЗАДЕРЖКА D

BORDER_0 LD A,#00   ;MIC OFF
        JP $+3
        OUT (#FE),A
        DEC E: JP NZ,$-1 ;ЗАДЕРЖКА E

BORDER_1 LD A,#08   ;MIC ON
         JP $+3
         OUT (#FE),A
        LD D,(HL): INC HL
        LD E,(HL): INC HL
        NOP
        RET

;ТАБЛИЦЫ ДЛЯ ПЕРЕДАТЧИКА

;1800
D0_1800 DB 36,36+13 ;ЧАСТОТЫ ДЛЯ "0"
D1_1800 DB 67,67+13 ;ЧАСТОТЫ ДЛЯ "1"

D00_600 DB #36,#44,#40,#44 ;B7 =0 B0 =0
-D01_600 DB #57,#58,#49,#44 ;B7 =0 B0 =1
-D10_600 DB #57,#65,#61,#65 ;B7 =1 B0 =0
-D11_600 DB #36,#4D,#54,#65 ;B7 =1 B0 =1



D0_FAST DB 28,28+13  ;КОДА ПЕРЕДАЧИ "0"
D1_FAST DB 51,51+13  ;SPEED FAST"1"

MIN     EQU 11
MAX     EQU 37
GZEROEQU 23

;ЧИСЛО ТАКТОВ В ПЕРЕДАЧИ БИТА
;T=(2*D+13)*14+56  D - ЧИСЛО ИЗ ТАБЛИЦЫ
;D0_?? ДЛЯ ПЕРЕДАЧИ "0" И D1_?? ДЛЯ "1"

;СРЕДНЯЯ СКОРОСТЬ :
;SPEED=(SPD0+SPD1)/2
;SPD0=3500000/T0  SPD1=3500000/T1

;ПРИЕМНИК :
;ЕСЛИ С ЛИНИИ ПРИНЯТО ЧИСЛО < MIN -ОШИБКА
;ЕСЛИ > MAX : ОШИБКА
;ЕСЛИ MIN < ?? < ZERO : ПРИНЯЛИ "0"
;ЕСЛИ ZERO < ?? < MAX : ПРИНЯЛИ "1"

;ZERO=T0/46
;MAX=T1/46
;MIN=ZERO-11..13

;В ДАННОМ ДРАЙВЕРЕ П/П РАБОТЫ С ЧАСАМИ
;ОТСУТСТВУЮТ, И СТОЯТ "ЗАГЛУШКИ"

;УСТАНОВИТЬ ВРЕМЯ [A]-[B]-[C]

D_SET_TIME

;СЧИТАТЬ ВРЕМЯ [A]-[B]-[C]

D_RD_TIME

;ЕСЛИ ЧАСЫ ПОЛУАВТОНОМНЫ, ТО ЭТА П/П
  ;ПРОИЗВОДИТ ПОДСЧЕТ ВРЕМЕНИ

D_CAL_TIM

;УСТАНОВИТЬ ТАЙМЕР НА [BC] МИНУТ

D_SET_ALR

;ДОБАВИТЬ К ТАЙМЕРУ [BC] МИНУТ

D_ADD_ALR
 SCF: RET 

;ЕСЛИ ВРЕМЯ ИСТЕКЛО, CY=1 

D_RD_ALR XOR A: RET 

END

_______________________________



Другие статьи номера:

Сегодня в номере - содержание журнала.

Авторы - авторы журнала ZX-Format No.6

От авторов - свершилось давно ожидаемое событие...

Игрушки - Последний утюг (новелла по игре 48 утюгов).

Игрушки - Приключения Винни Пуха. Часть вторая.

Игрушки - описание игры The Crypt (Castle Master 2).

Игрушки - описание редактора Адевентюр - PAW (часть 1).

Игрушки - описание редактора Адевентюр - PAW (часть 2).

Игрушки - описание редактора Адевентюр - PAW (часть 3).

Игрушки - описание редактора Адевентюр - PAW (часть 4).

Игрушки - описание редактора Адевентюр - PAW (часть 5).

Программистам - Beta Basic: продолжение разговора о бейсике (часть 2).

Программистам - General Sound: Руководство по программированию.

Программистам - MMD - драйвер. Описание структуры драйвера модема для терминальной программы MMD.

Программистам - AI от В.Медноногова. Подробное описание "волнового алгоритма" трассировки (автоматического рассчета оптимального) пути, с примером реализации на Basic.

Программистам - Искуственный интеллект. Продолжение цикла статей об "AI". Общие основы нахождения пути к цели.

Программистам - Тr-Dos для программистов. Макс Петров завершает свой рассказ о нетрадиционых методах работы с диском.

Программистам - обмен опытом: "3-colour". Описание эффекта "8-цветов на точку", хелп к вьюверу и сколько слов о конвертации картинок в формат "3-colour".

Программистам - обмен опытом: "3-colour". Несколько слов о конвертации картинок в формат RGB.

Программистам - обмен опытом: программирование мультиколорных эффектов.

IS-DOS - пользователям: как выполнить индивидуальную настройку системы IS-DOS на конкретную модель ZX Spectrum-совместимого компьютера и на выполнение Ваших задач.

IS-DOS - пользователям: как скопировать системный диск IS-DOS и остаться при этом в живых.

IS-DOS - программистам: краткий курс - программирование в среде IS-DOS.

IS-DOS - news: новые программы IS-DOS.

Железо - Краткий рассказ о возможностях процессора Z-180.

Железо - Multiviewer. Описание доработочки, позволяющей мерять скорость программ по бордюру без влезания в коды - легким нажатием кнопки.

Железо - о новом проекте фирмы Peters - "Sprinter". Новый Spectrum-совместимый компьютер нового поколения Speccy.

Железо - Мнение пользователя о скорпионовском контроллере IDE HDD - SMUC.

Железо - SuperSpectrum: об одном проекте Spectrum-совместимой машины. Её особенностью является совместимость с PC.

Железо - X-Trade FAQ. Ответы на наиболее часто задаваемые вопросы по GS и XTR-модему.

Премьера - Flash tracker. Описание 4-х канального редактора цифровой музыки, работающего с SoundDrive, от самого автора SoundDrive - Flash Inc.

Премьера - Описание последней версии универсальной терминальной программы, используемой в SpbZxNet.

Премьера - Mortal Kombat: что ждёт Вас в полной версии игры и некоторые коментарии к demo версии.

Премьера - XReversy: презентация новой игрушки, из популярного семейства "реши задачку - посмотри картинку".

Интервью - Интервью с одним из известнейших спектрумистов - Андреем Ларченко.

Здесь был ты - Рассказ "Абсолютная власть".

Здесь был ты - Рассказ "Дорога".

Здесь был ты - Повелитель зубов: пародия на одну популярную трилогию...

Почта - Обратная связь: ответное письмо Alex'а из Нижнего Тагила, выставленного в прошлом номере в "Уголок ламера".

Почта - Письма читателей: Андрей Яковлев, Денис Токарчук, Алексей Гаркулим, Александр Гордеев, Евгений Шумилов, Ниточкин Вадим, Михаил Ларкин.

Почта - бесплатная реклама и обьявления.

Разное - Страшилка.: Nemo рассуждает о месте PC и Spectrum'а в современной России.

Разное - Рецензия Nemo на книжку по цифровой схемотехнике. Для всех, кто хоть когда-нибудь испытывал желание включить паяльник и...

Разное - анкета: Результаты нашего социологического опроса спектрумистов.

Разное - Конкурс. Краткий отчет о наших конкурсах.

Разное - Проблемы рынка ПО: когда загнется Спектрум. Во всем ли виноваты Хакеры?

Разное - Перспективы ПО. Краткий обзор готовящегося к выходу ПО: Fast Tracker, Pro Sound Creator, Чёрный Ворон.

Разное - Перспективы ПО. Адвентюра From Beyond или "Извне".

Разное - мемуары о Питерской модемной сети для ZX Spectrum - SPbZXNet.

Amiga Club - Между нами, пользователями: сравнение характеристик Amiga 1200 с IBM PC.

Amiga Club - сравниваем производительность Амиг и PC. Насколько Амига актуальна в современных играх?


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Преамбула - На днях получил письмо от VEL'а, который прислал три диска с софтом.
Реклама - Реклама и объявления ...
Реклама - Реклама от В. Богдановича
Обзор - O новых программах: Narc, The Hundred, Heavy Metal Mover, Quick Draw McGraw, Iice Climber (Альпинист), Super Cars, Lode Runner 3, Down Town, Страна Мифов, Gremlin 2, Sword of Bane, Turbo Skate Fighter, Assault Course, Mercs, Darkman. Десятка лучших игр.
Реклама - Реклама и объявления ...

В этот день...   24 апреля