[Perl + seriele poort] ioctl's gebruiken in perl script

Pagina: 1
Acties:

  • VROEM!
  • Registratie: Februari 2000
  • Laatst online: 18-05-2025

VROEM!

broembroem!

Topicstarter
Ik heb op dit moment een mp3 bakje draaien dat ik aanstuur met de seriele poort.
De programmatuur die daarbij zit heb ik deels bij elkaar gescharreld en deels zelf geklust. Op dit moment is er een perl script voor een LCD display aan de parallelle poort, een bash script voor playlists etc managen, nog wat kleine scripts voor mini ondingen en een C - programma om de poort uit te lezen.

Dit is allemaal wat chaotisch, dus ik dacht ik integreer alles in 1 programma. Daarbij is mijn keuze gevallen op perl.

Het schema dat ik gebruik is van de winamp poort control uit de CME faq.
Afbeeldingslocatie: http://www.tweakers.net/ext/f/26147/full.gif

Wat ik nu in het perl script wil is iets vergelijkbaars als gebeurt in dit C-programma:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>


int main(int argc, char **argv)
{
    int fd;
    int status, button;
    unsigned int serial;

    fd = open(argc == 2 ? argv[1] : "/dev/ttyS0", O_RDONLY|O_NONBLOCK|O_NOCTTY);
    if (fd < 0) {
        perror("Cannot open serial device");
        exit(1);
    }

    while (1) {
        ioctl(fd, TIOCMIWAIT, TIOCM_RNG|TIOCM_CTS|TIOCM_DSR|TIOCM_CD);
        status = ioctl (fd, TIOCMGET, &serial);
        if (status != 0) {
            perror ("TIOCMGET failed");
            continue;
        }
        button = 0;
        if (serial & TIOCM_CD) {
            button |= 1;
        }
        if (serial & TIOCM_DSR) {
            button |= 2;
        }
        if (serial & TIOCM_CTS) {
            button |= 4;
        }
        if (serial & TIOCM_RI) {
            button |= 8;
        }
        if (button) {
            printf("Button %d pressed\n", button);
        }
        else {
            printf("Button released\n");
        }
    }
    return 0;
}

Nu probeer ik uit te vissen hoe je die ioctl's direct aan kan roepen in perl. Ik heb wel modules en zo gevonden, maar die kunnen niet omgaan met de tiocmiwait ioctl.
Ook is bij het gebruik van een module de complexiteit weer ietsje groter, ik wil graag iets maken dat werkt als stand alone pakket en zo min mogelijk afhankelijk is van modules/software van derden.
Bovendien wil ik tiocmiwait gebruiken om te wachten op een knop event, terwijl de voorbeelden die op internet rondgaan allemaal gebruik maken van een loop die keihard eens in de zoveel tijd afgelopen wordt.

Na veel klooien heb ik het volgende script in elkaar geklust:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
printf "Gebruik Variabelen \n";

use Fcntl;
use POSIX qw(:termios_h);
use IO::Handle;
require 'sys/ioctl.ph'; # Using this for TIOCM* stuff
use Getopt::Std;

printf "Maak variabelen\n";
    my ($tty_dev_name_in);
    my ($button);
    my ($status);
    my ($flags);
    my ($CD);
    my ($DSR);
    my ($CTS);
    my ($RI);

printf "Vul variabelen in\n";
    $tty_dev_name_in = "/dev/ttyS0";
    $CD = 0;
    $DSR = 0;
    $CTS = 0;
    $RI = 0;
printf "Poort openen \n";
    sysopen(TTY_IN, $tty_dev_name_in, O_RDWR) || 
    die ("Can't open tty_in '$tty_dev_name_in' - error : $!");
    $status = ioctl (FILE, &TIOCMSET, &TIOCM_DTR);
printf "Wachten op knop event\n";
while (1){
    $status = ioctl (FILE, &TIOCMIWAIT, TIOCM_RI|&TIOCM_CTS|&TIOCM_DSR|&TIOCM_CD);
    if ($status != 0) {
    printf  "TIOCMGET failed\n";
            }
            $button = 0;
        $CD = 0;
        $DSR = 0;
        $CTS = 0;
        $RI = 0;

        
            if (FILE, &TIOCMGET, &TIOCM_CD) {
                $CD = 1;
            }
            if (FILE, &TIOCMGET, &TIOCM_DSR) {
                $DSR = 2;
            }
            if (FILE, &TIOCMGET, &TIOCM_CTS) {
            $CTS = 4;
            }
        if (FILE, &TIOCMGET, &TIOCM_RI) {
            $RI = 8;
            }
            if ($button) {
            printf("Button %d pressed\n", $button);
            }
        else {
            printf("Button released\n");
            }
        printf "$CD\n";
        printf "$DSR\n";
        printf "$CTS\n";
        printf "$RI\n";
        $button = $CD + $DSR + $CTS + $RI;
        printf "$button pressed \n";
        };

Dit script blijft echter niet hangen op de regel met tiocmiwait, bovendien geeft hij direct aan dat alle lijnen hoog zijn, terwijl dat niet het geval is.
Ik heb veel geprobeerd te zoeken, maar ik heb nergens kunnen vinden wat ik precies aan het doen ben en al helemaal niet wat er fout gaat.
Het grootste gat in mijn kennis is hoe ik met ioctl's direct in perl de seriele poort aan kan roepen. De documentatie is hierover niet erg duidelijk en ik heb er ook weinig voorbeelden van kunnen vinden.

[ Voor 5% gewijzigd door VROEM! op 07-11-2004 15:20 ]

ieeeepppppp :P


  • Eric Oud Ammerveld
  • Registratie: December 2000
  • Laatst online: 05-07-2024

Eric Oud Ammerveld

Arduino developing... :)

Misschien een gekke vraag, maar je hebt wel support voor ttyS (seriele poort) meegebakken in je kernel?
(Standaard zit dit er in, maar ik heb het er bijvoorbeeld uitgelaten)
Wat geeft een :
code:
1
cat /dev/ttyS0
als uitvoer wanneer je op de knopjes drukt? (ik neem aan een hoop onzin)

Die loop afbreken lijkt me ook niet de meest nette optie, daarnaast kan het natuurlijk voor cpu overhead zorgen; da's niet netjes programmeren. :/

Het probleem is dus als ik het goed begrijp het verkrijgen van een interrupt
van de COM poort zodat perl een procedure kan starten?

[ Voor 42% gewijzigd door Eric Oud Ammerveld op 07-11-2004 22:59 ]

-=@@D=- Macbook Pro 16"


  • VROEM!
  • Registratie: Februari 2000
  • Laatst online: 18-05-2025

VROEM!

broembroem!

Topicstarter
De kernel heeft seriele poort support, ik heb vannacht inmiddels net een werkend script gekregen :)
Hier is de betreffende sub:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sub get_line_status ()
{
    my $flags;
    my $lines="";
    $flags = pack("L",0);
    printf "Tiocmiwait\n";
    ioctl(TTY_IN, &TIOCMIWAIT, $flags);
#   printf "Tiocmget\n";
    unless(ioctl(TTY_IN, &TIOCMGET, $flags)){
    die sprintf "$0: ioctl TIOCMGET on tty_in failed: $!\n";
    }
    $flags = unpack("L",$flags);
    # printf "Raw flags are 0%04o\n", $flags;
    # Can't read this in ftdi driver but here anyway
    $lines .= "DTR " if ($flags & &TIOCM_DTR);
    $lines .= "RTS " if ($flags & &TIOCM_RTS);
    # These should be readable
    $lines .= "CD " if ($flags & &TIOCM_CD);
    $lines .= "DSR " if ($flags & &TIOCM_DSR);
    $lines .= "CTS " if ($flags & &TIOCM_CTS);
    $lines .= "RI " if ($flags & &TIOCM_RI);
    #   return $lines;
# Button number generation
    my $CD  .= "1" if ($flags & &TIOCM_CD);
    my $DSR .= "2" if ($flags & &TIOCM_DSR);
    my $CTS .= "4" if ($flags & &TIOCM_CTS);
    my $RI  .= "8" if ($flags & &TIOCM_RI);
    my $number = $CD + $DSR + $CTS + $RI;
    return $number;
}

Ik post nog even niet het hele script, dat is te groot.
Zes weken aan het zoeken geweest en dan binnen een uur na m'n topic post de oplossing vinden, grrrr

ieeeepppppp :P