ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

         
     
    Ще раз про прямий доступ до апаратури
         

     

    Інформатика, програмування

    Ще раз про прямий доступ до апаратури

    Сивцов Павло

    Преамбула

    Одного разу мій знайомий попросив написати йому просту програму - «сторожовий пес». Все, що потрібно робити - це відловити момент розмикання або замикання зовнішнього контакту і при настанні такої події запустити іншу програму. Працювати програма повинна під Windows XP. Завдання виглядала елементарної. Єдине, що не хотілося робити - апаратну частину. Тобто найкраще було б знайти таке рішення, при якому майже нічого не потрібно було б паяти.

    Досить швидко з'ясувалося, що простіше за все для такої мети використовувати опитування станів LPT-або COM-портів. Тут і починається найцікавіше.

    LPT

    Для реалізації «сторожового пса» на LPT-порту можна використовувати періодичний опитування стану деяких його контактів. Можна просто виявляти стану ліній SELECTED (контакт 13), BUSY (контакт 11) і PAPER EMPTY (контакт 12). Досить замикати/розмикати вибраний контакт з «Землею» (контакти 18-25). Я вибрав використання BUSY - замикав контакти 11 і 23. Отже, апаратна частина виходила елементарної, тепер треба було якось достукатися до вибраного контакту з програмної сторони. Тут-то і зустрілася перша складність - легальних способів прямого доступу до портів в лінійці Windows NT немає. Використовувати примочки типу gwio.sys, що дозволяють прямий доступ до апаратури, дуже не хотілося. Робота з портом як з файлом у даному випадку не підходить, тому що потрібно не дані читати, а опитувати стану. Тим не менше, після тривалого вивчення MSDN, легальний доступ до деяких лініях порту було виявлено! Спосіб цей - доступ до порту через функцію DeviceIoControl (..., IOCTL_PAR_QUERY_INFORMATION, ...). Тут виявилася друга складність - відсутність потрібних заголовків файлів для Delphi. Довелося самостійно портувати ntddpar.h з DDK. Портована файл отримав назву JwaNtDdPar.pas і був люб'язно доданий Marcel van Brakel в JEDI Windows API Library.

    Невеликий приклад демонструє загальний код. Delphi 7.

    Приклад коду        

    uses   

    SysUtils, JwaWinType, JwaWinNT,   JwaWinBase, JwaNtDdPar;      

    ($ WARN SYMBOL_PLATFORM OFF)      

    function GetLptStatus: Boolean;   

    var   

    eFileHandle: THandle;   

    eInfo: TParQueryInformation;   

    eBytesReturned: DWORD;   

    begin   

    // відкриємо порт   

    eFileHandle: =   CreateFile ( 'LPT1', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);   

    Win32Check (eFileHandle <>   INVALID_HANDLE_VALUE);   

    try   

    // дізнаємося стан   

    Win32Check (DeviceIoControl (eFileHandle,   IOCTL_PAR_QUERY_INFORMATION, nil, 0,   

    @ eInfo, SizeOf (eInfo),   @ eBytesReturned, nil ));   

    Result: = (Byte (eInfo.Status)   and PARALLEL_BUSY) = 0;   

    finally   

    // не забудьте закрити хендл по завершенню   роботи   

    Win32Check (CloseHandle (eFileHandle ));   

    end;   

    end;     

    Короткий і елегантний код, чи не так? Для вирішення поставленого завдання досить опитувати стан порту раз-два в секунду. В принципі, звичайно ж, краще відразу відкрити порт при старті, а закрити по завершення.        

    ПОПЕРЕДЖЕННЯ   

    На жаль, не вдасться відкрити порт в   режимі FILE_FLAG_OVERLAPPED, щоб потім використовувати переваги   асинхронної роботи. Точніше, порт відкрити вдасться, не вдасться отримати подія   при зміні статусу ліній порту.   

    Зате цей код успішно відпрацював з-під   гостьовий облікового запису під Windows XP.     

    Останній нюанс - брязкіт контактів. «Брязкіт контактів - це явище багаторазового неконтрольованого замикання та розмикання контактів в моменти їхнього зіткнення і розбіжності ». Тривають такі перехідні процеси в кнопках близько 10-15 мілісекунд. Тобто з великою ймовірністю ми будемо отримувати помилкові спрацьовування нашого коду, якщо інтервал між перевірками буде коротшим.

    Сподіваюся, цей приклад роботи з LPT-портом послужить хорошою демонстрацією того, як у багатьох випадках легко отримати легальний доступ до апаратури без написання драйверів або обходу Hardware Abstraction Layer. Не для того цей HAL придумували, щоб його обходити.

    Доводилося читати про випадки захоплення порту спулера друку, але на практиці таку ситуацію зустріти не вдалося. Якщо хто-небудь зможе прояснити це питання, я буду радий.        

    ПРИМІТКА   

    До речі, в середині сторінки http://cooler.irk.ru/cl190902.html   викладено досить цікавий лист, в якому описується робота з портом   в режимі IEEE_COMPATIBILITY. Такий режим дозволяє з мінімумом рухів тіла   забезпечити повноцінний висновок даних на саморобний LPT-пристрій.     

    COM

    При використанні COM-порту завдання виявлення зовнішнього події може бути вирішена ще простіше. Досить замикати/розмикати контакти 7 (RTS) та 8 (CTS) у девятіконтактного роз'єму (знову нічого не доведеться паяти) і перевіряти наявність сигналу CTS. Причому опитування можна робити через стандартний CommApi.

    Приклад коду        

    function GetComStatus: Boolean;   

    var   

    eFileHandle: THandle;   

    eStatus: DWORD;   

    begin   

    // відкриємо порт   

    eFileHandle: =   CreateFile ( 'COM1', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);   

    Win32Check (eFileHandle <>   INVALID_HANDLE_VALUE);   

    try   

    // дізнаємося стан   

    Win32Check (GetCommModemStatus (eFileHandle,   eStatus ));   

    Result: = (eStatus and   MS_CTS_ON)> 0;   

    finally   

    // не забудьте закрити хендл по завершенню   роботи   

    Win32Check (CloseHandle (eFileHandle ));   

    end;   

    end;     

    Втім, цей приклад елегантним вже не назвеш, тому що використання COM-порту дає можливість позбутися від періодичного опитування, використовуючи асинхронну роботу через WaitCommEvent і WaitForMultipleObjects.

    Нижче наведений код прикладу. Для пояснення суті того, що відбувається код рясно прокоментований. Але все-таки зверну увагу на деякі нюанси:

    WaitForMultipleObjects чекає нескінченно. Ніяких періодичних опитувань - значить і ніякого споживання ресурсів. Все реалізовано на подіях.

    Немає необхідності в TerminateThread для примусового припинення виконання потоку. Виконання може бути «Культурно» закінчено в будь-який момент. Для цього використовується окрема подія.

    Проста реалізація неблокірующей затримки для придушення брязкоту. Оскільки періодичний опитування ми не застосовуємо, то, щоб позбутися від помилкових спрацьовувань програмним шляхом, потрібно почекати кілька десятків мілісекунд, і якщо стан за цей час не змінилося, то замикання/розмикання ланцюга відбулося. Як таймера використовується WaitableTimer. Зверніть увагу на його теоретичну точність.

    Ключовий метод        

    procedure   TComWatchdogThread.Execute;   

    var   

    // структура, що використовується для Win32   зберігання внутрішньої інформації при   

    // асинхронної роботі. Нічого крім поля   hEvent нам від неї не потрібно   

    eOverlapped: TOverlapped;      

    // запит очікування асинхронного події   зміни стану порту   

    //............................................. ..............................   

    procedure InitWaitCommEvent;   

    var   

    eEventMask: DWORD;   

    begin   

    // помилки ERROR_IO_PENDING потрібно просто   ігнорувати - їх наявність означає   

    // тільки те, що остання операція з   портом ще не завершена.   

    // Що цікаво, не можна двічі поспіль   викликати WaitCommEvent, тобто   

    // запросив подія - значить, дочекайся його.   

    if not WaitCommEvent (FComHandle, eEventMask,   @ eOverlapped)   

    and (GetLastError <>   ERROR_IO_PENDING) then   

    RaiseLastOSError;   

    end;      

    var   

    // TWOHandleArray - це просто готовий масив з 64 Хендли для   

    // функції WaitForMultipleObjects. Ми використовуємо тільки 3 Хендли,   

    // але для простоти скористаємося готовим   масивом на 64, щоб   

    // не зв'язуватися з ручним розподілом   пам'яті.   

    eHandles: TWOHandleArray;   

    eTime: Int64;   

    eStatus: DWORD;   

    eStubInstalled: Boolean;   

    begin   

    // заповнимо структури для асинхронної роботи   

    FillChar (eOverlapped, SizeOf (eOverlapped),   0);   

    eOverlapped.hEvent: =   FChangeEvent;   

    eHandles [0]: =   eOverlapped.hEvent;   

    eHandles [1]: = FTerminateEvent;   

    eHandles [2]: = FFlutterTimer;   

    // 0.5 секунди для SetWaitableTimer   

    eTime: = -5000000;   

    // Нічого собі точність, чи не так?      

    // попередньо зведений прапор очікування   події, щоб цикл заробив   

    InitWaitCommEvent;      

    while not Terminated do   

    case WaitForMultipleObjects (3,   @ eHandles, False, INFINITE) of   

    // при зміні стану порту   

    WAIT_OBJECT_0:   

    begin   

    // знову зведений прапор очікування події   

    InitWaitCommEvent;   

    // для придушення брязкоту зробимо невелику   затримку. Якщо стан   

    // порту зміниться швидше, ніж закінчиться   час затримки (брязкіт), то   

    // таймер просто буде переведений "на   пізніше ".   

    Win32Check (SetWaitableTimer (FFlutterTimer,   eTime, 0, nil, nil,   

    False ));   

    end;      

    // при запиті примусового завершення   потоку   

    WAIT_OBJECT_0 + 1:   

    // негайний вихід - завершення   виконання потоку   

    Exit;      

    // після затримки для придушення брязкоту   

    WAIT_OBJECT_0 + 2:   

    begin   

    // дізнаємося стан   

    Win32Check (GetCommModemStatus (FComHandle,   eStatus ));   

    eStubInstalled: = (eStatus and   MS_CTS_ON)> 0;      

    // викличемо обробник події   

    if eStubInstalled then   

    DoOnChange;   

    end;      

    // при наглої помилку   

    WAIT_FAILED:   

    // сталося страшне ...   

    RaiseLastOSError;   

    end;   

    end;     

    Повний код прикладу наведено у доданому до статті архіві.

    Список літератури

    JEDI Windows API Library http://members.chello.nl/m.vanbrakel2/win32api.zip

    Parallel Port Central http://www.lvr.com/parport.htm

    Serial Port Central http://www.lvr.com/serport.htm

    Лист в журнал «Cooler» про прямий доступ до LPT http://cooler.irk.ru/cl190902.html

    Для підготовки даної роботи були використані матеріали з сайту http://www.rsdn.ru/

         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status