Gå til innhold

Daemon for å lytte på tilkoblet utstyr på paralellport


shoop!

Anbefalte innlegg

Skal programmere opp noe mot en LPT-port (et "minitastatur" med noen få knapper), og trenger da en deamon av noe slag for å konstant lytte til LPT-porten, og se om den har noen statusforandringer. Noen som har noen interessante programmer/tips til meg? Forenklet sett blir det å trykke på en knapp for å kjøre en shell-kommando.

 

Og god jul, forresten :xmas:

Lenke til kommentar
Videoannonse
Annonse

"Unless your external hardware uses the one interrupt-capable input (ACK, if I recall correctly), you have no alternative but to poll the input port."

https://www.linuxquestions.org/questions/pr...12/#post2807334

 

Og siden paralellporten sikkert er representert av en fil i /dev (lp0 feks) så bør ikke polling fra bash være veldig problematisk.

 

Selv hadde jeg kanskje tittet litt etter noe USB-hardware med lignende funksjonalitet, ihvertfall hvis du ser for deg å bruke enheten litt fremover også. Da er det gode muligheter for at du kan bruke X-events e.l. Mye mer kos :p

Lenke til kommentar

NorthWave: Takker for info. Hadde håpet på en eller annen daemon som lå og sjekket etter forandringer på /dev/lp0 konstant, og gjorde noe om en verdi der skiftet.

 

Hvor mye jobb er det å gå via USB-grensesnittet? Med parallellporten var det så greit når man bygget opp kretskortet dette kobles til fra bunnen av.

Lenke til kommentar

Åja, dette er noe du har laget fra bunnen av ja? Fortell litt mer om oppsettet, så er det ofte greier å komme med gode råd. ;) Det er godt mulig at parallellport var det beste valget dersom du bare har noen enkle brytere koplet innpå. Skal du over på seriell/USB der så må man nesten inn med mikrokontroller eller noe spesielt for slike oppgaver, og det er nok betydelig verre enn å implementere en liten parallelldemon!

For daemoner trenger ikke være veldig magiske saker, det kan man hacke sammen i bash for enkle oppgaver. Hvis du bare finner ut hva som skjer på /dev/lp0 (alternativt /dev/port) når knapper blir/er trykket inn så skal nok jeg/andre kunne hjelpe deg med et script som ordner resten. :)

Jeg har nemlig ikke paralellporter selv, ihvertfall ikke sånn umiddelbart.

Lenke til kommentar

NorthWave: Sier mer enn gjerne ja til litt hjelp med å bygge opp dette. Skal beskrive prosjektet mitt under :)

 

Prosjektet: Planlegger å bygge en musikkpc inn i en gammel CD-spiller. Denne har bl.a. knapper i fronten, og et VFD-display. I første omgang vil jeg gjerne koble syv av knappene til forskjellige funksjoner, der noen vil styre MPD.

- på/av-bryter som går rett til hovedkortet.

- reset-bryter som går rett til hovedkortet.

- Eject En bryter til å åpne det optiske drevet, loddes rett til selve drevet.

- Play kobles til parallellporten, som til slutt skal kjøre mpc play.

- Pause skal kjøre mpc pause

- Prev skal kjøre mpc prev

- Next skal kjøre mpc next

 

LPT-porten har 8 data-porter, så å kjøre 1:1 på verdier og funksjoner til knappene er ganske greit.

 

Har funnet et program (pin) som kan lese fra LPT-porten (og returnerer 0-255).

 

[shoop@asdf - 22:39:17 - ~/lpt/parashell/bin/Linux]> time sudo ./pin 0x379
127

real	0m0.003s
user	0m0.000s
sys	0m0.007s

 

Den bruker tilnærmet ingen tid til å sjekke status på LPT, så om denne kjøres X antall ganger i sekundet vil jeg tro det fortsatt går greit. Er redd det vil bli et problem, for om ./pin 0x379 kjøres 30 ganger på et sekund, og knappen Next holdes inne i 1/10-del av et sekund, så vil MPD hoppe tre sanger frem. Hvordan løse dette?

 

Setter veldig pris på alle som skriver noe i forhold til dette :)

Lenke til kommentar

Flott at du har funnet et program som gir verdien til, det løser første utfordring. Link gjerne til kildekoden/dokumentasjon. Jeg ber forøvrig Cyclo/mod om å splitte postene våre ut i en egen tråd, så slipper vi å forstyrre alle de andre i kafèen :p Men det er bare å fortsette her i mellomtiden tenker jeg.

 

Krav til en daemon er at:

- den er "frakoplet" (std in,ut,error) fra den kjørende terminal

- prosessen skal være barnet til prosessen init

- svarer på signalene TERM, QUIT og HUP

- har et kontrollscript i init mappen som svarer på argumentene start, stop og restart

 

Basert på hva jeg er komfortabel med selv så vil jeg anbefale Python, selv om man kunne hacket sammen noe i bash ganske kjapt også. En daemon kan da lages slik feks:

http://www.enterpriseitplanet.com/networki...11315_3786386_1

http://www.jejik.com/articles/2007/02/a_si...emon_in_python/

 

Problemet med at knappen ligger inne ordnes ved "software debouncing". I sin enkleste form er det slik at for å kjøre kommandoen så krever man bryteren er aktivert OG at forrige gang man "pollet" så var den deaktivert. Det betyr at bryteren akkurat har blitt slått på.

Man bør også kreve at bryteren har vært aktiv feks 5 ganger etterhverandre, det minker sjansen for feil pga støy fra bryteren. Fungerer ikke det bra nok må man bruke mer kompliserte algoritmer, men det er stort sett ikke nødvendig. Kan gjøre noen modifikasjoner på hardwaresiden også, hvis ønskelig.

Endret av NorthWave
Lenke til kommentar

Det var en god ide å skille ut dette fra tråden, da det kan bli litt komplekst og uinteressant for mange :p

 

Binærfila pin kommer fra Parashell, og den er veldig enkelt laget:

/*
* pout  -- By: Brett Carroll
* Read data from the Parallel Port
*/

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

int main(int argc, char **argv)
{					
int in_data;
int PORT;

if (argc!=2) 
  printf("USAGE: pin [PORT]\n ie., pin 0x378\n"), exit(1); 

sscanf(argv[1],"%i",&PORT); // Get PORT value (ie. 0x378, 0x379, 0x37a)

if (ioperm(PORT,1,1))
	fprintf(stderr, "ERROR: Can't gain access to port %x\n", PORT), exit(1);

in_data = inb(PORT);
printf("%d\n",in_data);

return(in_data);
}

(GPL V.2+)

 

Kontrollskriptet skal jeg nok klare å lage selv, basert på alle de andre init-scriptene. Kjører Arch, så har BSD-stil på init-filene. Python har jeg dog aldri skrevet selv.

 

Så det som må skrives er et python-skript som bruker pin til å sjekke portene, og bruker "software debouncing".

 

Hva mener du egentlig med "Man bør også kreve at bryteren har vært aktiv feks 5 ganger etter hverandre, det minker sjansen for feil pga støy fra bryteren."? Bryterne er 100% mekaniske, så det vil vel ikke oppstå støy fra de? Og det vil jo også kreve at bryteren blir holdt inne X antall millisekunder, noe som kan gjøre at de ikke responderer om det blir et veldig raskt trykk.

 

Takker så mye for at du tar deg tid til dette, NorthWave :)

 

Her er forresten et bilde av en modell med likt utseende som min:

post-166907-1230248619_thumb.jpg

Lenke til kommentar

Da er tråden splittet ut :D

 

Angående selve prosjektet ville jeg valgt C om du har mulighet. Programmering mot paralellporten er egentlig rimelig trivielt i C, og da har man også mulighet for low level access på en rimelig grei måte (Slike ting som dette er det alltid en fordel å gjøre på low level). Sist, men ikke minst, er det en fordel å skrive daemons i C i stedet for Perl eller Python for å spare ressurser.

 

Selv skrev jeg en gang i tiden et C-program som var akkurat det motsatte av dette, altså en daemon som styrer eksterne enheter via paralellporten. Så det er mulig jeg kan komme med litt hjelp når du har konkrete spørsmål.

 

Til sist et lite tips om planlegging. Om du har tenkt å kanskje utvide systemet etterhvert med et bra display, er det noe du bør tenke på nå, før du legger for mye arbeid i dette. Jeg kjøpte for en stund siden et Matrox Orbital 4x80 tegns LCD display i forbindelse med et lite prosjekt jeg jobbet på. Jeg oppdaget at denne hadde en haug digitale inputs og outputs, som styres via samme serielltilkobling som brukes for å putte tegn på displayet. Dette gjør tilkobling av brytere mm. til en lek. Så om du har vurdert å ha et LCD display på saken du bygger, er det kanskje en ide å undersøke det nærmere, før du lager din daemon.

Lenke til kommentar
Da er tråden splittet ut :D

 

Angående selve prosjektet ville jeg valgt C om du har mulighet. Programmering mot paralellporten er egentlig rimelig trivielt i C, og da har man også mulighet for low level access på en rimelig grei måte (Slike ting som dette er det alltid en fordel å gjøre på low level). Sist, men ikke minst, er det en fordel å skrive daemons i C i stedet for Perl eller Python for å spare ressurser.

 

Selv skrev jeg en gang i tiden et C-program som var akkurat det motsatte av dette, altså en daemon som styrer eksterne enheter via paralellporten. Så det er mulig jeg kan komme med litt hjelp når du har konkrete spørsmål.

 

Til sist et lite tips om planlegging. Om du har tenkt å kanskje utvide systemet etterhvert med et bra display, er det noe du bør tenke på nå, før du legger for mye arbeid i dette. Jeg kjøpte for en stund siden et Matrox Orbital 4x80 tegns LCD display i forbindelse med et lite prosjekt jeg jobbet på. Jeg oppdaget at denne hadde en haug digitale inputs og outputs, som styres via samme serielltilkobling som brukes for å putte tegn på displayet. Dette gjør tilkobling av brytere mm. til en lek. Så om du har vurdert å ha et LCD display på saken du bygger, er det kanskje en ide å undersøke det nærmere, før du lager din daemon.

Takker for "splitten", cyclo :)

 

Har aldri skrevet C, så det blir noe nytt for meg. Skriver dog PHP, uten at det kan sammenlignes.

 

Har lyst til å utvide prosjektet til å bruke en VFD-skjerm til informasjon, så tipset om produsenten "Matrix Orbital" var absolutt ikke dumt. Du kunne ikke tenke deg til å fortelle litt om hvordan du bruker din skjerm? Og prøvde du noen gang å koble til brytere til disse digitale inngangene? Andre erfaringer angående de skjermene?

 

Etter litt googling ser det ut som om det ikke er noe mer komplisert å programmere mot seriellporten enn parallellporten. Her er litt om programmering mot diverse porter (litt utdatert, muligens?), og her er wikipedia sin artikkel om RS232. TLDP har også masse informasjon, så dette kan bli veldig tungt å sette seg inn i..

 

tingo: Vet ikke helt om det kommer til nytte nå, men tusen takk for linken :)

Lenke til kommentar

Takk for at du splittet tråden Cyclo! Jeg er dog helt uenig i at man bør bruke C til dette (selv om det utvilsomt også er velegnet), da det er meget lite ytelseskritisk og det er mye greiere å slippe så mye low level skit som mulig (imo). For en som kjenner PHP vil det også sannsynligvis være enklere å forholde seg til.

 

Dette er kjapp kode, men jeg tror nok at det er mer elegant enn man få til i C. :)

Den kjører programmet som får portstatus (bytt ut echo 128 med programmets navn, må ligge i path), dekoder outputen og kjører kommandoer avhengig av hvilke knapper som trykkes inn (konfigureres i den øverste dicten).

 

 

#!/usr/bin/python
import time
import sys
from subprocess import Popen,PIPE

cmds = { #button number and corresponding action
0: 'mpc play', 
1: 'mpc prev', 
2: 'mpc next', 
3: 'mpc pause', 
4: 'echo amixer set Master 5%+',
5: 'echo amixer set Master 5%-', 
6: 'echo amixer set Master toggle', 
7: 'echo shutdwn'
}
old_state = 0

while True:
p = Popen("echo 128",shell=True,stdout=PIPE)
for l in p.stdout:
	state = int(l)
events = (state ^ old_state) & ~old_state #buttons activated
for button_no, cmd in cmds.iteritems(): #execute cmd for each activated button
	if events & 2**button_no:			
		Popen(cmd,shell=True)
old_state = state
time.sleep(1/5000.0)

 

 

 

Mye mas med jul altså, først familieselskap og så fest...

EDIT: spoiler og fila :)

Endret av NorthWave
Lenke til kommentar

Alt for lenge siden jeg jobbet med hobbyhardware mot paralellporten, og jeg brukte ikke linux engang på den tida, men :

 

Kan du ikke koble knappene slik at de i tillegg til å endre dataportene aktiverer ACK-pinnen på paralellporten, og fanget det med noe interrupt-greier?

 

I stedet for denne ustabile poolingen, altså?

Endret av Kagee
Lenke til kommentar
Takk for at du splittet tråden Cyclo! Jeg er dog helt uenig i at man bør bruke C til dette (selv om det utvilsomt også er velegnet), da det er meget lite ytelseskritisk og det er mye greiere å slippe så mye low level skit som mulig (imo). For en som kjenner PHP vil det også sannsynligvis være enklere å forholde seg til.

 

Dette er kjapp kode, men jeg tror nok at det er mer elegant enn man få til i C. :)

Den kjører programmet som får portstatus (bytt ut echo 128 med programmets navn, må ligge i path), dekoder outputen og kjører kommandoer avhengig av hvilke knapper som trykkes inn (konfigureres i den øverste dicten).

Ikke for å være sur og grinete og slikt, men elegant? For det første må du jo uansett her gå lowlevel, du bare lar et eksternt program gjøre det (du sier forøvrig ikke noe om hvilket program du har tenkt at han skulle bruke). Dette eksterne programmet trenger bare å være på noen ytterst få kodelinjer, og da kan man like gjerne slenge på et par linjer ekstra for å få resten av funksjonaliteten.

Å kalle et program som går i løkke og åpner pipes for elegant får meg til å sette kaffen i halsen, det er voldtekt av systemressurser (hehe - litt overdramatisering her muligens) ;)

 

Om du først vil gjøre dette med python og gjøre det på en elegant måte er oppskriften slik:

 

Bruk/skriv et lowlevel program som kjører som daemon og kaller pythonscriptet når status har endret seg, og la pythonscriptet avgjøre hva som skal gjøres videre. Dermed slipper man å gå over bekken etter vann.

 

Et kjapt eksempel ved bruk av parapin modulen kunne se ut noe slikt som dette:

int main()
{
 if(pin_init_user(LPT1))
exit(EXIT_FAILURE);
 while (1){
if	(pin_is_set(LP_PIN11))
// do something here f. eks. kalle et python script som tar seg av hva som skal gjøres, eller gjøre det direkte her.
sleep(1);
 }
}

Dette er da selvsagt polling, og for å gjøre det på den mest riktige måten bør man bruke ACK-pinnen og interrupts slik Kagee foreslår. Programmet overfor har eliminert alle ressursproblemene til python scriptet og er i mine øyne også langt mer elegant ;)

Lenke til kommentar
Har lyst til å utvide prosjektet til å bruke en VFD-skjerm til informasjon, så tipset om produsenten "Matrix Orbital" var absolutt ikke dumt. Du kunne ikke tenke deg til å fortelle litt om hvordan du bruker din skjerm? Og prøvde du noen gang å koble til brytere til disse digitale inngangene? Andre erfaringer angående de skjermene?

Vell. Bryterfunksjonaliteten er ganske enkel. (husker ikke hvor mange brytere man kan koble til, men det er en god del. Varianten jeg bruker er USB varianten. Denne kobles til og brukes som en seriellport. For å teste åpner man en terminal mot porten, skal man deretter lage et program er det fort gjort i python, perl e.l.

 

Uansett. Det finnes egentlig haugevis av instillinger og funksjoner på skjermen. Men for å ta den grunnleggende. Ganske enkelt er det slik at alt man skriver til porten blir skrevet til skjerm. Det er faktisk så banalt at echo 'hei' > /dev/ttyUSB0 vil skrive hei på skjermen.

Input tilkoblingene er rett og slett en haug pinner på baksiden av kortet. Ved å kortslutte en av pinnene mot en av de andre pinnen, utfører man en input. Så en bryter kan f. eks. kobles til to av pinnene, og trykkes på. Det som skjer er at hver pinnepar har en egen "bokstav" (egentlig et heksadesimalt tall) som skrives til porten.

Så for å få til dette her ville du skrive et lite script som åpner porten, og hver gang du vil at noe skal skrive på skjerm skriver du til porten, samtidig som du leser fra porten hele tiden for å se om en bryter er trykket.

 

(Tror denne beskrivelsen min ble rimelig dårlig, men det er egentlig svært enkelt, og du får med en god bruksanvisning også)

Endret av cyclo
Lenke til kommentar
Hva mener du egentlig med "Man bør også kreve at bryteren har vært aktiv feks 5 ganger etter hverandre, det minker sjansen for feil pga støy fra bryteren."? Bryterne er 100% mekaniske, så det vil vel ikke oppstå støy fra de? Og det vil jo også kreve at bryteren blir holdt inne X antall millisekunder, noe som kan gjøre at de ikke responderer om det blir et veldig raskt trykk.

Det er nettopp den mekaniske naturen som skaper støy i fra bryteren. Problemet er langt mindre når man ikke bruker edge-triggering (men poller istedet), men fortsatt potensielt problematisk. Google har mye informasjon om emnet hvis ønskelig, ellers er det beskrevet litt her feks: http://www.bioinspired.com/users/ajg112/el.../debounce.shtml

 

Ikke for å være sur og grinete og slikt, men elegant? For det første må du jo uansett her gå lowlevel, du bare lar et eksternt program gjøre det (du sier forøvrig ikke noe om hvilket program du har tenkt at han skulle bruke). Dette eksterne programmet trenger bare å være på noen ytterst få kodelinjer, og da kan man like gjerne slenge på et par linjer ekstra for å få resten av funksjonaliteten.

Å kalle et program som går i løkke og åpner pipes for elegant får meg til å sette kaffen i halsen, det er voldtekt av systemressurser (hehe - litt overdramatisering her muligens) ;)

Sur og grinete oppfatter jeg deg ikke som, og jeg håper og antar at du ikke gjør det om meg heller. :) Hvilket program som var tenkt brukt sa han selv:

Så det som må skrives er et python-skript som bruker pin til å sjekke portene, og bruker "software debouncing".

I ettertid ser jeg at min kommentar om "eleganse" og "low-level" nok vil tolkes helt anderledes enn jeg egentlig mente det. Jeg mente at Python som språk lar en løse slike ting uten å måtte drive med kalling av eksterne programmer (fork, exec, wait o.l) og variabler/løkker osv på "low-level". Dette spesielt med tanke på at trådstarter ikke har minimalt med kjennskap til C og er vant med scriptspråk fra før.

At min løsningsmetode ikke er spesielt elegant er jeg fullt klar over. Den kan nok best karakteriseres som en "quick hack", hvor fokuset er lagt nesten utelukkende på utviklingstid. Jeg er ikke uenig i at det vil være mer "korrekt" å bruke en "bottom-up" tilnærming på problemet slik du foreslår, men det har jo minimalt med valg av språk å gjøre igrunnen (med unntak av at det muligens er få gode biblioteker for tilgang til parallellporten i Python? *sjekke*)

 

Koden du har vedlagt er jo vel og fin, men den gjør jo ikke halvparten av det som kreves for en fullstedig og fungerende løsning, og er jo sånn sett lite sammenlignbar med min kode som er komplett (med forbehold om at jeg ikke har mulighet til å testet det, og at den ikke akkurat er veldig robust).

 

EDIT: hadde glemt å fullføre første paragraf

Endret av NorthWave
Lenke til kommentar
Sur og grinete oppfatter jeg deg ikke som, og jeg håper og antar at du ikke gjør det om meg heller. :)

Hehe. Måtte bare ta mine forbehold. Etter en 12-13 års programeringserfaring har jeg merket meg at folk har en tendens til å oppfatte meg som akkurat det når det gjelder programering. :D

Hvilket program som var tenkt brukt sa han selv:
Så det som må skrives er et python-skript som bruker pin til å sjekke portene, og bruker "software debouncing".

Thnx. Det hadde jeg faktisk klart å overse.

I ettertid ser jeg at min kommentar om "eleganse" og "low-level" nok vil tolkes helt anderledes enn jeg egentlig mente det. Jeg mente at Python som språk lar en løse slike ting uten å måtte drive med kalling av eksterne programmer (fork, exec, wait o.l) og variabler/løkker osv på "low-level". Dette spesielt med tanke på at trådstarter ikke har minimalt med kjennskap til C og er vant med scriptspråk fra før.

Nja. Både og. Grunnen til at jeg anbefalte C, sånn bortsett fra at det er absolutt den beste løsningen med tanke på systemressurser, er at han sa han har erfaring med PHP. Har man PHP erfaring, bør man egentlig klare å sette seg inn i enkel C programmering superkjapt (ser man bort fra pekere og minnehåndtering). Alle systemkall i PHP er jo i utgangspunktet bare wrappere til C funksjoner. Om det man skal gjøre er så pass enkelt at man slipper å tenke på pekere og minnehåndtering, bør det jo ikke være så fjernt vil jeg tro. Sånn sett så mener jeg personlig at PHP er mye likere C enn det er Python.

Koden du har vedlagt er jo vel og fin, men den gjør jo ikke halvparten av det som kreves for en fullstedig og fungerende løsning, og er jo sånn sett lite sammenlignbar med min kode som er komplett (med forbehold om at jeg ikke har mulighet til å testet det, og at den ikke akkurat er veldig robust).

Derfor jeg foreslo å bruke et C program slik som det som daemon, og la den kalle et Python/Perl/PHP/bash/etc. script som faktisk utfører det som skal gjøres. Da får man en snill daemon som ikke sluker svære mengder unødvendige systemressurser, samtidig som man får enkeltheten til et scriptspråk når man skal gjøre kall på andre programmer og lignende. (Om man orker er jo selvsagt det beste å gjøre alt i C - men her taper man jo ikke så fryktelig mye på å være lat)

 

Forøvrig er siste forslaget til Kagee det absolutt beste, men også det mest krevende.

Lenke til kommentar

Må nesten legge prosjektet på is et par måneder, da både penger og tid for å realisere dette er en mangelvare. Kommer tilbake til tråden med en gang jeg starter opp igjen. Tusen takk til dere tre som har bidratt såpass mye som dere har. Et virkelig godt og hjelpsomt community her på diskusjon.no.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...