TopList Яндекс цитирования
Русский переплет
Портал | Содержание | О нас | Авторам | Новости | Первая десятка | Дискуссионный клуб | Научный форум
-->
Первая десятка "Русского переплета"
Темы дня:

Ещё многих дураков радует бравое слово: революция!

| Обращение к Дмитрию Олеговичу Рогозину по теме "космические угрозы": как сделать систему предупреждения? | Кому давать гранты или сколько в России молодых ученых?
Rambler's Top100

Низкоуровневое программирование параллельных портов под *nix

На языке с запрограммировать lpt порт можно например так(примеры более или менее продвинутых программ внизу текста по ссылкам):

#include <stdio.h>
#include <unistd.h>
#include <asm/io.h>

#define base 0x278
#define time 100000

int main(){
  int x = 0x32;
  printf("идет импульс в парралельный порт !\n");
  if (ioperm(base,3,1))
  printf("Couldn't get port at %x\n", base), exit(1);
  if (ioperm(base, 3, 1)) {perror("ioperm"); exit(1);}
  while(1){
    outb(x, base);
    usleep(time);
    outb(0, base);
    usleep(time);
  }
}
exit(0);

Использованы две функции, ioperm и outb. Первая устанавливает права на работу с портами ввода/вывода. Вторая пишет в порт, в основном она предназначена для использования в ядре. Функция inb соответственно читает из порта.

читая man ioperm:
Libc5 рассматривает ioperm как системный вызов, и поэтому в unistd.h есть ее прототип. В Glibc1 этого прототипа нет. В Glibc2, в sys/io.h и в sys/perm.h этот прототип есть. Второй вариант существует только в i386.

lpt порт - это несколько регистров, в которые можно писать командой скажем outb(). 278 порт это порт данных, если писать 0x5(двоичное 00000101 то 2,5 вольта будут, в соответствии с единицами в двоичном числе, на 2-м и 4-м контактах). Если же писать через /dev/lp, то получается аналогично, но придется выставлять внешний сигнал busy. Этот сигнал нужно выставлять или джампером на материнской плате, или в BIOS, в зависимости от марки платы. когда включается порт на материнской плате, то она устанавивает регистры на правильные порты и прерывания, затем, если сделать insmod linux, то драйвер прикрепляется на на соответствующие устройства и отвечает за обмен по принтерному протоколу, т.е. правильно выставляет сигналы strobe init.
(from некто john www.linux.org.ru)

Чтобы программировать порты на, скажем python, можно воспользоваться Simplified Wrapper and Interface Generator - SWIG.

Например программа пишущая в порт:

#include <asm/io.h>
int main(){
   iopl(3);
   outb(1, 0x378);
}
Компилируем cc -O2 io.c, помним, что использование только под суперюзером. Что нужно сделать, чтобы написать то-же самое на Python? Воспользоваться SWIG, чтобы сделать возможным доступ из Python к outb(), inb() и iopl(). Ниже пример io.c для SWIG:
#include <asm/io.h> 

int py_iopl(int level){
  return iopl(level);
}
void py_outb(unsigned char val, int port){
  outb(val, port);
}                                                
unsigned char py_inb(int port)
{
  return inb(port);
}                                
Запускаем SWIG и генерируем io.so. Пример работы:
>>>import io
>>>io.py_iopl(3)
>>>io.py_outb(10, 0x378)
>>>io.py_inb(0x378)
10
>>>

Для того, чтобы включить код на языке с в модуль perl, читаем man perlxstut или

http://www.perldoc.com/perl5.6.1/pod/perlxstut.html#EXAMPLE-1

именно первый пример!!!

создаем файл .xs с таким кодом(т.е. оно его конечно само создаст, но то что оно создало, надо вытереть):

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <stdio.h>
#include <unistd.h>
#include <asm/io.h>

#define base 0x278
#define time 100000

MODULE = port           PACKAGE = port          

int
main()
CODE:
  int x = 0x32;
  printf("Пошел импульс в паралельный порт !\n");
  if (ioperm(base,3,1))
    printf("Couldn't get port at %x\n", base), exit(1);
  if (ioperm(base, 3, 1)) {perror("ioperm"); exit(1);}
  while(1){
    outb(x, base); /*посылаем 00110010 в порт*/
    usleep(time);
    outb(0, base);
    usleep(time);
  }
exit(0);
далее по инструкциям мана, затем
[root@mobile100 port]# perl Makefile.PL; make; make test
Writing Makefile for port
gcc -c  -fno-strict-aliasing -I/usr/local/include -O2 -march=i386 -mcpu=i686
-DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" -fPIC
-I/usr/lib/perl5/5.6.0/i386-linux/CORE  port.c
Running Mkbootstrap for port ()
chmod 644 port.bs
LD_RUN_PATH="" gcc -o blib/arch/auto/port/port.so  -shared -L/usr/local/lib
port.o     
chmod 755 blib/arch/auto/port/port.so
cp port.bs blib/arch/auto/port/port.bs
chmod 644 blib/arch/auto/port/port.bs
Manifying blib/man3/port.3pm
PERL_DL_NONLAZY=1 /usr/bin/perl -Iblib/arch -Iblib/lib
-I/usr/lib/perl5/5.6.0/i386-linux -I/usr/lib/perl5/5.6.0 test.pl
1..1
ok 1
[root@mobile100 port]# 

и пишется скрипт:

#!/usr/bin/perl
use ExtUtils::testlib;
use Mytest;
Mytest::main();

File u.pl not changed so no update needed.
[root@mobile100 port]# ./u.pl
Пошел импульс в паралельный порт !

[root@mobile100 port]#
период задается #define time 100000 - т.е. по программе выходит 5 герц частота, а так 1/10 секунды = 100000. Соответственно от вида байта со 2-го по 9-й пин(каждый пин это один бит, допустим 0x32 это 00110010, т.е. 2-й пин ноль, третий единица, четвертый и пятый нули, 6,7 - 1 и 8 и 9 нули) возникает разность потенциалов в 2,5 вольт, как показал осциллограф С1-74. Нуумерация пинов есть прямо на принтерном порту.

Cобственно почему такой суррогат и не выложил готовый модуль*.tar.gz, не разобрался с межпроцессорным взаимодействием между сишными и перловыми программами(имхо, только через IPC это сделать грамотно и можно, но это долго). Потому представляю вам, если более знакомы с межпроцессорным взаимодействием через pipe или семафоры самим написать данный код, перловая же часть более менее понятна.

По крайней мере на перле заняться низкоуровневым программированием паралельных портов вполне себе даже можно.

Конфигурация машины(хотя это врядли важно, сишные библиотеки стандартные):

p266, ASUS.

[root@mobile100 perl]# uname --all 
Linux mobile100 2.2.19-3.asp #1 Fri Apr 6 14:49:33 MSD 2001 i686
unknown
[root@mobile100 perl]# 
Иксы соответственно стоят, воркстейшн. ASPLinux7.1 девелоперский. Еще, важно, нужно ОБЯЗАТЕЛЬНО заземлить корпуса осциллографа и компьютера(правда я не заземлял, но оно в темноте малость искрило). Иначе может сгореть компьютер. И не подключать к этим контактам маленькие лампочки на 3,5 вольта, т.к. у неё вроде потребляемая мощность чего-то около полуватта, и не факт что lpt порт выдержит такую мощность. Вобщем сигнал использовать только как сигнальный(на базу транзистора или на вход иного усилителя). Ну вобщем кому надо тот поймет. Иначе можно запросто пожечь материнскую плату или принтерный порт.

где про это все прочитать можно:

  1. http://www.opennet.ru/docs/RUS/Lpg/lpg.txt.html про пайпы и семафоры и пр. что как-раз не вышло.
  2. http://www.linux.org.ru/books/HOWTO/Printing-HOWTO-3.html#ss3.1 там есть одна вещь, в биос компьютера должен быть включен parallel port *78/IRQ7, ну, вобщем чтобы не было там disabled, иначе тогда когда говоришь modprobe lp то в /proc/devices не добавляется lp, т.е. без драйвера обратиться к параллельному порту не получится.
  3. http://www.thailinux.com/2001/01/21/topic4.html - немного программок, из латинского текста все ясно
  4. http://www.opennet.ru/docs/HOWTO-RU/mini/IO-Port-Programming.html ну детальнейшее описание просто(про perl ни слова)...

В принципе можно обойтись без написания драйвера, оторвав от терминала и запустив скрипт демоном.


Rambler's Top100