Структура драйвера модема для программы 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 _______________________________