Forum: PC-Programmierung Ubuntu: Piepston auf PC-Speaker ausgeben


von Third E. (third-eye)


Lesenswert?

Hallo,

ich habe auf einem Rechner LinuxCNC installiert, d.h. da läuft jetzt 
eine angepasste Ubuntu-Version.

Es soll außerdem ein von mir geschriebenes C-Programm geben, das als 
Modbus-Master fungiert und mit der angeschlossenen Hardware (mehrere 
µCs) kommuniziert.

Für Fehlermeldungen usw. würde ich gerne das ASCII-Zeichen dez. 7 (Beep) 
ausgeben. Leider funktioniert das nicht.
Der PC-Speaker an sich funktioniert aber (Piepston nach dem Einschalten 
des PCs).

Habe dann ergoogelt, dass man in der blacklist.conf
die Zeile

blacklist pcspkr

auskommentieren soll.
Das habe ich gemacht und neu gestartet.
Der Speaker ist aber immer noch stumm.

Was hat es denn mit der Zeile

blacklist snd_pcsp

auf sich?

Habe nicht recht verstanden, warum es diese zwei verschiedenen Parameter 
gibt?

Third-Eye

von Luxx (Gast)


Lesenswert?

Teste mal was beep macht.

apt-get install beep

von rere (Gast)


Lesenswert?

Third Eye schrieb:
> blacklist pcspkr
>
> blacklist snd_pcsp
Das sind Kernel-Module die nicht automatisch geladen werden. Nähere 
Inofs gibt es mit modinfo:
Was ergeben folgende Befehle:
1
modinfo snd_pcsp
1
modinfo pcspkr

Und was macht kommt bei:
1
modprobe pcspkr && echo -e "\a"

von Third E. (third-eye)


Lesenswert?

rere schrieb:
> Was ergeben folgende Befehle:
>
1
> modinfo snd_pcsp
2
>

modinfo snd_pcsp
filename: 
/lib/modules/2.6.32-122-rtai/kernel/sound/drivers/pcsp/snd-pcsp.ko
alias:          platform:pcspkr
license:        GPL
description:    PC-Speaker driver
author:         Stas Sergeev <stsp@users.sourceforge.net>
srcversion:     868DCB4E1C3C6D3CCAE01D1
depends:        snd-pcm,snd
vermagic:       2.6.32-122-rtai SMP mod_unload 586TSC
parm:           nforce_wa:Apply NForce chipset workaround (expect bad 
sound) (bool)
parm:           index:Index value for pcsp soundcard. (int)
parm:           id:ID string for pcsp soundcard. (charp)
parm:           enable:Enable PC-Speaker sound. (bool)


>
1
> modinfo pcspkr
2
>

modinfo pcspkr
filename: 
/lib/modules/2.6.32-122-rtai/kernel/drivers/input/misc/pcspkr.ko
alias:          platform:pcspkr
license:        GPL
description:    PC Speaker beeper driver
author:         Vojtech Pavlik <vojtech@ucw.cz>
srcversion:     2ED00EA2D81C3AF226399DB
depends:
vermagic:       2.6.32-122-rtai SMP mod_unload 586TSC

> Und was macht kommt bei:
>
1
> modprobe pcspkr && echo -e "\a"
2
>
Da passiert gar nichts, es kommt nur die Standardmeldung "WARNING: All 
config files need .conf: /etc/modprobe.d/emc2, it will be ignored in a 
future release."

Luxx schrieb:
> Teste mal was beep macht.
>
> apt-get install beep

Danke für den Tipp, beep funktioniert in der Kommandozeile. beep war 
vorher nicht installiert.

Leider kriege ich mit meinem C-Programm im CodeBlocks immer noch kein 
Piepsen hin. Weder mit printf("%c", "\a"); noch mit beep() aus ncurses.

von Luxx (Gast)


Lesenswert?

Hier ist der Quellcode von ubuntu beep, vielleicht findest du was 
brauchbares darin.
http://packages.ubuntu.com/lucid/beep
1
/*  beep - just what it sounds like, makes the console beep - but with
2
 * precision control.  See the man page for details.
3
 *
4
 * Try beep -h for command line args
5
 *
6
 * This code is copyright (C) Johnathan Nightingale, 2000.
7
 *
8
 * This code may distributed only under the terms of the GNU Public License 
9
 * which can be found at http://www.gnu.org/copyleft or in the file COPYING 
10
 * supplied with this code.
11
 *
12
 * This code is not distributed with warranties of any kind, including implied
13
 * warranties of merchantability or fitness for a particular use or ability to 
14
 * breed pandas in captivity, it just can't be done.
15
 *
16
 * Bug me, I like it:  http://johnath.com/  or johnath@johnath.com
17
 */
18
19
#include <fcntl.h>
20
#include <getopt.h>
21
#include <signal.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
#include <sys/ioctl.h>
27
#include <sys/types.h>
28
#include <linux/kd.h>
29
30
/* I don't know where this number comes from, I admit that freely.  A 
31
   wonderful human named Raine M. Ekman used it in a program that played
32
   a tune at the console, and apparently, it's how the kernel likes its
33
   sound requests to be phrased.  If you see Raine, thank him for me.  
34
   
35
   June 28, email from Peter Tirsek (peter at tirsek dot com):
36
   
37
   This number represents the fixed frequency of the original PC XT's
38
   timer chip (the 8254 AFAIR), which is approximately 1.193 MHz. This
39
   number is divided with the desired frequency to obtain a counter value,
40
   that is subsequently fed into the timer chip, tied to the PC speaker.
41
   The chip decreases this counter at every tick (1.193 MHz) and when it
42
   reaches zero, it toggles the state of the speaker (on/off, or in/out),
43
   resets the counter to the original value, and starts over. The end
44
   result of this is a tone at approximately the desired frequency. :)
45
*/
46
#ifndef CLOCK_TICK_RATE
47
#define CLOCK_TICK_RATE 1193180
48
#endif
49
50
#define VERSION_STRING "beep-1.2.2"
51
char *copyright = 
52
"Copyright (C) Johnathan Nightingale, 2002.  "
53
"Use and Distribution subject to GPL.  "
54
"For information: http://www.gnu.org/copyleft/.";
55
56
/* Meaningful Defaults */
57
#define DEFAULT_FREQ       440.0 /* Middle A */
58
#define DEFAULT_LENGTH     200   /* milliseconds */
59
#define DEFAULT_REPS       1
60
#define DEFAULT_DELAY      100   /* milliseconds */
61
#define DEFAULT_END_DELAY  NO_END_DELAY
62
#define DEFAULT_STDIN_BEEP NO_STDIN_BEEP
63
64
/* Other Constants */
65
#define NO_END_DELAY    0
66
#define YES_END_DELAY   1
67
68
#define NO_STDIN_BEEP   0
69
#define LINE_STDIN_BEEP 1
70
#define CHAR_STDIN_BEEP 2
71
72
typedef struct beep_parms_t {
73
  float freq;     /* tone frequency (Hz)      */
74
  int length;     /* tone length    (ms)      */
75
  int reps;       /* # of repetitions         */
76
  int delay;      /* delay between reps  (ms) */
77
  int end_delay;  /* do we delay after last rep? */
78
  int stdin_beep; /* are we using stdin triggers?  We have three options:
79
         - just beep and terminate (default)
80
         - beep after a line of input
81
         - beep after a character of input
82
         In the latter two cases, pass the text back out again,
83
         so that beep can be tucked appropriately into a text-
84
         processing pipe.
85
      */
86
  struct beep_parms_t *next;  /* in case -n/--new is used. */
87
} beep_parms_t;
88
89
/* Momma taught me never to use globals, but we need something the signal 
90
   handlers can get at.*/
91
int console_fd = -1;
92
93
/* If we get interrupted, it would be nice to not leave the speaker beeping in
94
   perpetuity. */
95
void handle_signal(int signum) {
96
  switch(signum) {
97
  case SIGINT:
98
    if(console_fd >= 0) {
99
      /* Kill the sound, quit gracefully */
100
      ioctl(console_fd, KIOCSOUND, 0);
101
      close(console_fd);
102
      exit(signum);
103
    } else {
104
      /* Just quit gracefully */
105
      exit(signum);
106
    }
107
  }
108
}
109
110
/* print usage and exit */
111
void usage_bail(const char *executable_name) {
112
  printf("Usage:\n%s [-f freq] [-l length] [-r reps] [-d delay] "
113
   "[-D delay] [-s] [-c]\n",
114
   executable_name);
115
  printf("%s [Options...] [-n] [--new] [Options...] ... \n", executable_name);
116
  printf("%s [-h] [--help]\n", executable_name);
117
  printf("%s [-v] [-V] [--version]\n", executable_name);
118
  exit(1);
119
}
120
121
122
/* Parse the command line.  argv should be untampered, as passed to main.
123
 * Beep parameters returned in result, subsequent parameters in argv will over-
124
 * ride previous ones.
125
 * 
126
 * Currently valid parameters:
127
 *  "-f <frequency in Hz>"
128
 *  "-l <tone length in ms>"
129
 *  "-r <repetitions>"
130
 *  "-d <delay in ms>"
131
 *  "-D <delay in ms>" (similar to -d, but delay after last repetition as well)
132
 *  "-s" (beep after each line of input from stdin, echo line to stdout)
133
 *  "-c" (beep after each char of input from stdin, echo char to stdout)
134
 *  "-h/--help"
135
 *  "-v/-V/--version"
136
 *  "-n/--new"
137
 *
138
 * March 29, 2002 - Daniel Eisenbud points out that c should be int, not char,
139
 * for correctness on platforms with unsigned chars.
140
 */
141
void parse_command_line(int argc, char **argv, beep_parms_t *result) {
142
  int c;
143
144
  struct option opt_list[4] = {{"help", 0, NULL, 'h'},
145
             {"version", 0, NULL, 'V'},
146
             {"new", 0, NULL, 'n'},
147
             {0,0,0,0}};
148
  while((c = getopt_long(argc, argv, "f:l:r:d:D:schvVn", opt_list, NULL))
149
  != EOF) {
150
    int argval = -1;    /* handle parsed numbers for various arguments */
151
    float argfreq = -1; 
152
    switch(c) {      
153
    case 'f':  /* freq */
154
      if(!sscanf(optarg, "%f", &argfreq) || (argfreq >= 20000 /* ack! */) || 
155
   (argfreq <= 0))
156
  usage_bail(argv[0]);
157
      else
158
  result->freq = argfreq;    
159
      break;
160
    case 'l' : /* length */
161
      if(!sscanf(optarg, "%d", &argval) || (argval < 0))
162
  usage_bail(argv[0]);
163
      else
164
  result->length = argval;
165
      break;
166
    case 'r' : /* repetitions */
167
      if(!sscanf(optarg, "%d", &argval) || (argval < 0))
168
  usage_bail(argv[0]);
169
      else
170
  result->reps = argval;
171
      break;
172
    case 'd' : /* delay between reps - WITHOUT delay after last beep*/
173
      if(!sscanf(optarg, "%d", &argval) || (argval < 0))
174
  usage_bail(argv[0]);
175
      else {
176
  result->delay = argval;
177
  result->end_delay = NO_END_DELAY;
178
      }
179
      break;
180
    case 'D' : /* delay between reps - WITH delay after last beep */
181
      if(!sscanf(optarg, "%d", &argval) || (argval < 0))
182
  usage_bail(argv[0]);
183
      else {
184
  result->delay = argval;
185
  result->end_delay = YES_END_DELAY;
186
      }
187
      break;
188
    case 's' :
189
      result->stdin_beep = LINE_STDIN_BEEP;
190
      break;
191
    case 'c' :
192
      result->stdin_beep = CHAR_STDIN_BEEP;
193
      break;
194
    case 'v' :
195
    case 'V' : /* also --version */
196
      printf("%s\n",VERSION_STRING);
197
      exit(0);
198
      break;
199
    case 'n' : /* also --new - create another beep */
200
      result->next = (beep_parms_t *)malloc(sizeof(beep_parms_t));
201
      result->next->freq       = DEFAULT_FREQ;
202
      result->next->length     = DEFAULT_LENGTH;
203
      result->next->reps       = DEFAULT_REPS;
204
      result->next->delay      = DEFAULT_DELAY;
205
      result->next->end_delay  = DEFAULT_END_DELAY;
206
      result->next->stdin_beep = DEFAULT_STDIN_BEEP;
207
      result->next->next       = NULL;
208
      result = result->next; /* yes, I meant to do that. */
209
      break;
210
    case 'h' : /* notice that this is also --help */
211
    default :
212
      usage_bail(argv[0]);
213
    }
214
  }
215
}  
216
217
void play_beep(beep_parms_t parms) {
218
  int i; /* loop counter */
219
220
  /* try to snag the console */
221
  if((console_fd = open("/dev/console", O_WRONLY)) == -1) {
222
    fprintf(stderr, "Could not open /dev/console for writing.\n");
223
    printf("\a");  /* Output the only beep we can, in an effort to fall back on usefulness */
224
    perror("open");
225
    exit(1);
226
  }
227
  
228
  /* Beep */
229
  for (i = 0; i < parms.reps; i++) {                    /* start beep */
230
    if(ioctl(console_fd, KIOCSOUND, (int)(CLOCK_TICK_RATE/parms.freq)) < 0) {
231
      printf("\a");  /* Output the only beep we can, in an effort to fall back on usefulness */
232
      perror("ioctl");
233
    }
234
    /* Look ma, I'm not ansi C compatible! */
235
    usleep(1000*parms.length);                          /* wait...    */
236
    ioctl(console_fd, KIOCSOUND, 0);                    /* stop beep  */
237
    if(parms.end_delay || (i+1 < parms.reps))
238
       usleep(1000*parms.delay);                        /* wait...    */
239
  }                                                     /* repeat.    */
240
241
  close(console_fd);
242
}
243
244
245
246
int main(int argc, char **argv) {
247
  char sin[4096], *ptr;
248
  
249
  beep_parms_t *parms = (beep_parms_t *)malloc(sizeof(beep_parms_t));
250
  parms->freq       = DEFAULT_FREQ;
251
  parms->length     = DEFAULT_LENGTH;
252
  parms->reps       = DEFAULT_REPS;
253
  parms->delay      = DEFAULT_DELAY;
254
  parms->end_delay  = DEFAULT_END_DELAY;
255
  parms->stdin_beep = DEFAULT_STDIN_BEEP;
256
  parms->next       = NULL;
257
258
  signal(SIGINT, handle_signal);
259
  parse_command_line(argc, argv, parms);
260
261
  /* this outermost while loop handles the possibility that -n/--new has been
262
     used, i.e. that we have multiple beeps specified. Each iteration will
263
     play, then free() one parms instance. */
264
  while(parms) {
265
    beep_parms_t *next = parms->next;
266
267
    if(parms->stdin_beep) {
268
      /* in this case, beep is probably part of a pipe, in which case POSIX 
269
   says stdin and out should be fuly buffered.  This however means very 
270
   laggy performance with beep just twiddling it's thumbs until a buffer
271
   fills. Thus, kill the buffering.  In some situations, this too won't 
272
   be enough, namely if we're in the middle of a long pipe, and the 
273
   processes feeding us stdin are buffered, we'll have to wait for them,
274
   not much to  be done about that. */
275
      setvbuf(stdin, NULL, _IONBF, 0);
276
      setvbuf(stdout, NULL, _IONBF, 0);
277
      while(fgets(sin, 4096, stdin)) {
278
  if(parms->stdin_beep==CHAR_STDIN_BEEP) {
279
    for(ptr=sin;*ptr;ptr++) {
280
      putchar(*ptr);
281
      fflush(stdout);
282
      play_beep(*parms);
283
    }
284
  } else {
285
    fputs(sin, stdout);
286
    play_beep(*parms);
287
  }
288
      }
289
    } else {
290
      play_beep(*parms);
291
    }
292
293
    /* Junk each parms struct after playing it */
294
    free(parms);
295
    parms = next;
296
  }
297
298
  return EXIT_SUCCESS;
299
}

von Third E. (third-eye)


Lesenswert?

Offenbar wird da die Funktion ioctl verwendet:
http://man7.org/linux/man-pages/man2/ioctl.2.html

Leider hilft mir das nicht viel weiter.

Nofalls rufe ich halt aus meinem Programm die beep()-Funktion auf. Das 
ist zwar nicht besonders elegant, würde aber wohl erst mal 
funktionieren.
Zumal die Funktion ja sehr flexibel ist: Man kann Frequenz, Zeitdauer 
usw. parametrieren.

von Gerd E. (robberknight)


Lesenswert?

Wie wird denn Dein C-Programm gestartet? Loggst Du Dich da an 
Monitor&Tastatur direkt, ohne grafische Benutzeroberfläche, ein und 
startest es auf der Shell? Oder von der Ferne per SSH? Oder startest Du 
es aus dem X raus?

Dein Programm gibt das Bell-Sonderzeichen auf seinem Stdout aus. Das 
Terminal oder getty oder wer auch sonst das Stdout zur Darstellung 
weiterbearbeitet, muss das dann interpretieren. Und dort hapert es wohl.

Innerhalb von X wird das meist an die zugehörige Sound-Schnittstelle 
(also z.B. pulseaudio oder gstreamer) weitergegeben und von dort dann 
über die Soundkarte abgespielt.

von Klaus W. (mfgkw)


Lesenswert?

Third Eye schrieb:
> Weder mit printf("%c", "\a");

kein Wunder.

Wenn schon, dann entweder printf( "%s", "\a\n" ) oder printf( "%c", '\a' 
).
Also entweder einen String mit %s oder ein Zeichen mit %c...

von Rolf Magnus (Gast)


Lesenswert?

Third Eye schrieb:
> Offenbar wird da die Funktion ioctl verwendet:
> http://man7.org/linux/man-pages/man2/ioctl.2.html
>
> Leider hilft mir das nicht viel weiter.

Warum nicht?

Klaus Wachtler schrieb:
> Third Eye schrieb:
>> Weder mit printf("%c", "\a");
>
> kein Wunder.
>
> Wenn schon, dann entweder
> printf( "%s", "\a\n" ) oder printf( "%c", '\a').
> Also entweder einen String mit %s oder ein Zeichen mit %c...

Oder einfach
1
printf("\a\n");
Das Newline würde ich reinmachen, damit das \a nicht im Zeilenpuffer 
hängen bleibt. Alternativ kann man auch nach den printf ein 
fflush(stdout) machen, falls das Newline bei irgendwelchen Ausgaben 
stört.

von rere (Gast)


Lesenswert?

Gerd E. schrieb:
> Wie wird denn Dein C-Programm gestartet? Loggst Du Dich da an
> Monitor&Tastatur direkt, ohne grafische Benutzeroberfläche, ein und
> startest es auf der Shell? Oder von der Ferne per SSH? Oder startest Du
> es aus dem X raus?
Da könnte er dann auch folgendes machen:
1
echo -e "\a" > /dev/tty0
1
echo -e "\a" > /dev/console
Dürfte nur als root gehen.

Third Eye schrieb:
> Offenbar wird da die Funktion ioctl verwendet:
> http://man7.org/linux/man-pages/man2/ioctl.2.html
>
> Leider hilft mir das nicht viel weiter.
Warum nicht, oben (siehe 
Beitrag "Re: Ubuntu: Piepston auf PC-Speaker ausgeben") ist doch der 
Quelltext der dir alles aufzeigt?

von Klaus W. (mfgkw)


Lesenswert?

Rolf Magnus schrieb:
> Oder einfachprintf("\a\n");

naja, wenn es schon einfacher sein soll, ist die Frage ob printf 
angemessen ist, um 1 oder 2 Zeichen auszugeben.
putchar oder puts sind doch etwas schlanker - und man kann bei ihnen 
nicht so leicht Zeichen und Strings verwechseln :-)

von Rolf Magnus (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> naja, wenn es schon einfacher sein soll, ist die Frage ob printf
> angemessen ist, um 1 oder 2 Zeichen auszugeben.
> putchar oder puts sind doch etwas schlanker

Daß das auf dem Zielsystem signifikant ist, halte ich für 
unwahrscheinlich, abgesehen davon, daß der GCC das eh schon entsprechend 
optimiert.

> - und man kann bei ihnen nicht so leicht Zeichen und Strings verwechseln
> :-)

Das kriegt man da genauso hin.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.