[comp.unix.questions] Let the Sun-3 beep! How???

wagner@iaoobelix.UUCP (04/16/87)

Subject: Bell on SUN-3 Workstation

Apparently, it is impossible to let the Sun console beep without using
`window_bell'. Does anybody out there know of a possiblity other than this
function (e.g. by accessing the keyboard bell) to generate a beep?

Juergen Wagner,		     (USENET) ...seismo!unido!iaoobel!wagner
("Gandalf")			 Fraunhofer Institute IAO, Stuttgart

guy%gorodish@Sun.COM (Guy Harris) (04/21/87)

> Apparently, it is impossible to let the Sun console beep without using
> `window_bell'. Does anybody out there know of a possiblity other than this
> function (e.g. by accessing the keyboard bell) to generate a beep?

As the saying goes, "seek and ye shall find".  Seek in the
documentation first, and you stand a good chance of finding without
having to ask.  Quoting from our documentation (KB(4S) in the 3.2
UNIX Interface Reference, although it's in the 3.0 documentation as
well):

     Keyboard Commands
	The call KIOCCMD sends a command to the keyboard:

	     /*
	      * Commands to the Sun-2 keyboard.
	      */
	     #define KBD_CMD_RESET   0x01 /* Reset keyboard as if power-up */
	     #define KBD_CMD_BELL    0x02 /* Turn on the bell */
	     #define KBD_CMD_NOBELL  0x03 /* Turn off the bell */

	     /*
	      * Commands to the Sun-3 keyboard.  KBD_CMD_BELL & KBD_CMD_NOBELL
	      * work as well.
	      */
	     #define KBD_CMD_CLICK   0x0A /* Turn on the click annunciator */
	     #define KBD_CMD_NOCLICK 0x0B /* Turn off the click annunciator */

	     int x;
	     err = ioctl(fd, KIOCCMD, &x);

	Inappropriate commands for particular keyboard types are ignored.
	Since there is no reliable way to get the state of the bell or click
	(because we can't query the keyboard, and also because a process could
	do writes to the appropriate serial driver -- thus going around this
	'ioctl') we don't provide an equivalent "ioctl" to query its state.

The "ioctl"s are defined in <sys/kbio.h> and the commands are defined
in <sys/kbd.h>.  This "ioctl" should be issued on "/dev/kbd" or
whatever keyboard you're running from.  All "win_bell" does to
generate an audible bell is to:

	open the keyboard for the current screen
	do a KIOCCMD with a pointer to a variable containing
	    KBD_CMD_BELL
	sleep for the specified interval of time
	do a KIOCCMD with a pointer to a variable containing
	    KBD_CMD_NOBELL
	close the keyboard

(The KBD_CMD_CLICK/KBD_CMD_NOCLICK stuff is for turning keyclick mode
on and off.)

No muss, no fuss, and *especially* no need for "/dev/bell" (which is
not a supported item, so there's no guarantee that it will work on
future keyboards).

jpn@teddy.UUCP (04/23/87)

>Apparently, it is impossible to let the Sun console beep without using
>`window_bell'. Does anybody out there know of a possiblity other than this
>function (e.g. by accessing the keyboard bell) to generate a beep?

For your beeping pleasure:  beep.c
------------------
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sundev/kbd.h>
#include <sundev/kbio.h>

#define BELL		0x07	/* Control-G */
#define NULL		0

main(argc, argv)
int argc;
char **argv;
    {
    int	bell;
    int cmd;
    int iterations = 1;
    static struct  timeval  ring_time  =  {0, 100000};
    static struct  timeval  pause_time  =  {0, 50000};

    if ( argc > 1 && isdigit(argv[1][0]))
	{
	iterations = atoi(argv[1]);
	}

    if ( (bell = open("/dev/kbd",2)) < 0 )
	{
	/* no /dev/kbd.  Fail gracefully */
	char out;

	out = BELL;
	write(1, &out, 1);
	exit(0);
	}

    do
	{
	cmd = KBD_CMD_BELL;
	ioctl(bell, KIOCCMD, &cmd);

	select(0, NULL, NULL, NULL, &ring_time);

	cmd = KBD_CMD_NOBELL;
	ioctl(bell, KIOCCMD, &cmd);

	if (iterations > 1)
	    select(0, NULL, NULL, NULL, &pause_time);

	} while (--iterations > 0);

    exit(0);
    }

watson@ames.UUCP (04/30/87)

Here is a morse code program for Sun workstations.
I wrote this after reading the discusion of Sun's bell in
in the news group comp.unix.questions.

Have fun.


#
#--------------- cut here ------------------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by kirin!watson on Wed Apr 29 17:21:44 PDT 1987
# Contents:  morse.c
 
echo x - morse.c
sed 's/^@//' > "morse.c" <<'@//E*O*F morse.c//'
/*
 *  Morse Code Program for Suns    Version 1.0
 *
 *  Here is a little program I wrote that converts standard input
 *  to morse code.  The Sun's bell is used to beep the code.
 *  The speed of the generated beeps vary, depending on the model of Sun.
 *  Speed can be changed with the optional first argument on the command
 *  line: 
 *      
 *           % morse 2     # is twice as fast 
 *           % morse 4     # is 3 times a fast
 *           % morse -2    # is  twice as slow 
 *           % morse -3    # is  3 times a slow 
 *
 *  It can be used across a network with remote shell:
 *
 *           % rsh remote_host morse
 * 
 *  Or with pipes: 
 *
 *           % fortune | morse 
 * 
 *  I have not include all the character set. ( ?, !, -, etc. )
 *  New characters can be easily added to the big case statement in main.
 *   
 *  I don't have time to work with this anymore so don't send the bugs to me.
 *  Send me better versions though :^)
 *
 *  Oh yeah, this works on Suns version 3.2 of the UNIX4.3bsd operating system.
 *  compile with: 
 *                    % cc morse.c -o morse -O
 *  
 *
 *   Have fun!
 *   John S. Watson  4/29/87
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sundev/kbd.h>
#include <sundev/kbio.h>
 
int keyboard;
int scale = 3000;
int factor = 1;

unit_pause( number)
   int number;
{
   int i;
  
   for ( i = 0; i < number* (int) scale; i++);
}

dit()
{
   int on = KBD_CMD_BELL;
   int off = KBD_CMD_NOBELL;
   int i;

   ioctl(keyboard, KIOCCMD, &on);
   unit_pause(1);
   ioctl(keyboard, KIOCCMD, &off);
   unit_pause(1);
}

 
da()
{
   int on = KBD_CMD_BELL;
   int off = KBD_CMD_NOBELL;
   int i;

   ioctl(keyboard, KIOCCMD, &on);
   unit_pause( 3);
   ioctl(keyboard, KIOCCMD, &off);
   unit_pause( 1);
}


read_line( buffer)
  char buffer[];
{
  char character;
  int i = 0;
  
  do 
    {
    character = getchar();
    if (  feof(stdin) ) exit(0);
    buffer[i] = character;
    ++i;
    }
  while( character != '\n' );
  
  buffer[ i - 1 ] = '\0';
}



init_keyboard()
{
  keyboard = open("/dev/kbd", O_RDWR, 0666);
  if (keyboard < 0) {
     perror("/dev/kbd");
     exit(1);
     }   
  return( keyboard);
}

main(argc, argv)
 int argc;
 char **argv;
{
  int i;
  char line[81];
  
  if ( argc == 2 )
     {

     factor = atoi( argv[1]);
     if ( factor > 0) 
        scale /= factor;
      else
        scale *= -factor;

     if ( (int) scale == 0) {
        fprintf(stderr, "can't go that fast\n");
        exit(0);
        }
     }

  init_keyboard();


  while ( 1) {
      read_line( line);
      for ( i = 0; i < strlen( line) ; i++) {
      unit_pause( 2);
      switch( line[i] )
            {
             case 'A' : 
             case 'a' :  dit(); da();
                         break;
             case 'B' : 
             case 'b' :  da(); dit(); dit();
                         break;
             case 'C' :
             case 'c' :  da(); dit(); da(); dit();
                         break;
             case 'D' :
             case 'd' :  da(); dit(); dit();
                         break;
             case 'E' :
             case 'e' :  dit();
                         break;
             case 'F' :
             case 'f' :  dit(); dit(); da(); dit();
                         break;
             case 'G' :
             case 'g' :  da(); da(); dit();
                         break;
             case 'H' :
             case 'h' :  dit(); dit(); dit(); dit();
                         break;
             case 'I' :
             case 'i' :  dit(); dit();
                         break;
             case 'J' :
             case 'j' :  dit(); da(); da(); da();
                         break;
             case 'K' :
             case 'k' :  da(); dit(); da();
                         break;
             case 'L' :
             case 'l' :  dit(); da(); dit(); dit();
                         break;
             case 'M' :
             case 'm' :  da(); da();
                         break;
             case 'N' :
             case 'n' :  da(); dit();
                         break;
             case 'O' :
             case 'o' :  da(); da(); da();
                         break;
             case 'P' :
             case 'p' :  dit(); da(); da(); dit();
                         break;
             case 'Q' :
             case 'q' :  da(); da(); dit(); da();
                         break;
             case 'R' :
             case 'r' :  dit(); da(); dit();
                         break;
             case 'S' :
             case 's' :  dit(); dit(); dit();
                         break;
             case 'T' :
             case 't' :  da();
                         break;
             case 'U' :
             case 'u' :  dit(); dit(); da();
                         break;
             case 'V' :
             case 'v' :  dit(); dit(); dit(); da();
                         break;
             case 'W' :
             case 'w' :  dit(); da(); da();
                         break;
             case 'X' :
             case 'x' :  da(); dit(); dit(); da();
                         break;
             case 'Y' :
             case 'y' :  da(); dit(); da(); da();  
                         break;
             case 'Z' :
             case 'z' :  da(); da(); dit(); dit();
                         break;

             case '0' :  da(); da(); da(); da(); da();
                         break;
 
             case '1' :  dit(); da(); da(); da(); da();
                         break;
 
             case '2' :  dit(); dit(); da(); da(); da();
                         break;
 
             case '3' :  dit(); dit(); dit(); da(); da();
                         break;
 
             case '4' :  dit(); dit(); dit(); dit(); da();
                         break;
 
             case '5' :  dit(); dit(); dit(); dit(); dit();
                         break;
 
             case '6' :  da(); dit(); dit(); dit(); dit();
                         break;
 
             case '7' :  da(); da(); dit(); dit(); dit();
                         break;
 
             case '8' :  da(); da(); da(); dit(); dit();
                         break;
 
             case '9' :  da(); da(); da(); da(); dit();
                         break;
 
             case ',' :  da(); da(); dit(); dit(); da(); da();
                         break;
 
             case '.' :  dit(); da(); dit(); da(); dit(); da();
                         break;

             /*
              * add new characters here!
              */
 
             case ' ' : 
             default  :  unit_pause(5);
                         break;
             }
     }
  }
}
@//E*O*F morse.c//
chmod u=rw,g=r,o=r morse.c
 
exit 0

-- 
  John S. Watson 
  NASA Ames Research Center
  ARPA:  watson@ames.arpa
  UUCP:  ...!ames!watson

chris@mimsy.UUCP (04/30/87)

In article <1415@ames.UUCP> watson@ames.UUCP (John S. Watson) writes:
>Here is a morse code program for Sun workstations.

John's program works, but, being a fan of data structures, I had
to rewrite it.  Also, his tends to use inordinate amounts of CPU
time, to run at different speeds on different kinds of Suns, and
to sound somewhat lopsided if you had something in the background.
Moreover, if you interrupted it, it might leave the bell on, which
is decidedly annoying.

This version's output is essentially identical.  The single optional
argument specifies the number of milliseconds for the basic time
unit (default 30).  The Sun timer resolution is somewhat low, and
values between 21 and 30 all act the same, and 20 runs 50% faster
than these; this is an annoyance, but it does keep the CPU time
down.

/*
 * Morse Code Program for Suns
 *
 * Inspired by version by:
 *	John S. Watson  4/29/87
 *	NASA Ames Research Center
 *	ARPA:  watson@ames.arpa
 *	UUCP:  ...!ames!watson
 *
 * This version by:
 *	Chris Torek  4/29/87
 *	University of Maryland
 *	Department of Computer Science
 *	(chris@mimsy.umd.edu)
 */

#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sundev/kbd.h>
#include <sundev/kbio.h>

/*
 * Morsetab[] contains the `visual form' rendition of each known
 * character.  All other characters act as word separators, hence
 * there is no need for an entry for space.
 *
 * The encode() function puts a pointer to the valid codes in the
 * table codetab[]; the invalid ones remain NULL.  The code translation
 * table is 256 entries, and the initialisation of the array is
 * portable to EBCDIC (among others).
 *
 * N.B.: all of the code values in morsetab[] must be valid input
 * character codes.
 */
struct morse {
	int	m_code;		/* the input character (lowercase) */
	char	*m_rend;	/* and its rendition */
} morsetab[] = {
	'a',	".-",
	'b',	"-..",
	'c',	"-.-.",
	'd',	"-..",
	'e',	".",
	'f',	"..-.",
	'g',	"--.",
	'h',	"....",
	'i',	"..",
	'j',	".---",
	'k',	"-.-",
	'l',	".-..",
	'm',	"--",
	'n',	"-.",
	'o',	"---",
	'p',	".--.",
	'q',	"--.-",
	'r',	".-.",
	's',	"...",
	't',	"-",
	'u',	"..-",
	'v',	"...-",
	'w',	".--",
	'x',	"-..-",
	'y',	"-.--",
	'z',	"--..",
	'0',	"-----",
	'1',	".----",
	'2',	"..---",
	'3',	"...--",
	'4',	"....-",
	'5',	".....",
	'6',	"-....",
	'7',	"--...",
	'8',	"---..",
	'9',	"----.",
	',',	"--..--",
	'.',	".-.-.-",
	-1,	NULL		/* end marker */
};

char	*codetab[256];

/* convert X to milliseconds (in scale factors) */
#define	MS(x)	((x) * 1000)

char	*progname;
long	scale = MS(30);

int	keyboard;
int	bell_on = KBD_CMD_BELL;
int	bell_off = KBD_CMD_NOBELL;
#define	FEEP()		(void) ioctl(keyboard, KIOCCMD, (char *) &bell_on)
#define	UNFEEP()	(void) ioctl(keyboard, KIOCCMD, (char *) &bell_off)

/*
 * Pause for number counts.  Number must not be `large'.
 */
unit_pause(number)
	int number;
{
	struct timeval tv;
#define USEC 1000000		/* microseconds per second */

	/* this value may be >= 1e6 */
	tv.tv_usec = number * scale;
	tv.tv_sec = tv.tv_usec / USEC;
	tv.tv_usec -= tv.tv_sec * USEC;
	(void) select(0, (int *)0, (int *)0, (int *)0, &tv);
}

/*
 * Do a dit (if it) or dah (if not).
 */
d(it)
	int it;
{

	FEEP();
	unit_pause(it ? 1 : 3);
	UNFEEP();
	unit_pause(1);
}

/*
 * Build the input character translation table.
 */
encode()
{
	register struct morse *p;
	register int i;

	for (p = morsetab; p->m_rend != NULL; p++) {
		i = p->m_code;
		if (codetab[i] != NULL)
			goto bug;
		codetab[i] = p->m_rend;
		if (islower(i)) {
			i = toupper(i);
			if (codetab[i] != NULL) {
bug:
				(void) fprintf(stderr,
					"%s: panic: codetab[%d] != NULL\n",
					progname, i);
				exit(1);
			}
			codetab[i] = p->m_rend;
		}
	}
}

init_keyboard()
{

	keyboard = open("/dev/kbd", O_RDWR, 0666);
	if (keyboard < 0) {
		(void) fprintf(stderr, "%s: cannot open ", progname);
		perror("/dev/kbd");
		exit(1);
	}
}

/*
 * `Print' the contents of file f in morse code.
 */
morse(f)
	register FILE *f;
{
	register int c;
	register char *mp;
	int inword = 0;

	while ((c = getc(f)) != EOF) {
		if ((mp = codetab[c]) == NULL) {
			if (inword) {
				unit_pause(5);
				inword = 0;
			}
			continue;
		}
		inword = 1;
		while ((c = *mp++) != 0)
			d(c == '.');
		unit_pause(2);
	}
}

catch()
{

	UNFEEP();
	exit(1);
}

set(sig, disp)
	int sig, (*disp)();
{

#if defined(sun) && defined(lint)
	/* Sun 3.0 lint library is wrong */
	if (signal(sig, (void (*)()) SIG_IGN) != SIG_IGN)
		(void) signal(sig, (void (*)()) disp);
#else
	if (signal(sig, SIG_IGN) != SIG_IGN)
		(void) signal(sig, disp);
#endif
}

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

	progname = argv[0];
	set(SIGHUP, catch);
	set(SIGQUIT, catch);
	set(SIGINT, catch);
	set(SIGTERM, catch);

	if (argc >= 2) {
		scale = MS(atoi(argv[1]));
		if (scale < MS(1)) {
			(void) fprintf(stderr,
				"%s: can't go that fast\n", progname);
			exit(1);
		}
	}
	init_keyboard();
	encode();
	morse(stdin);
	exit(0);
}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

hp@beta.UUCP (Akkana) (04/30/87)

I'm new to this newsgroup, so I may have missed a posting, but ...

I know about KBD_CMD_BELL and all that -- found it in the manual
and wrote a quickie beep routine for the Sun console -- but am I
the only one in the world bothered by the fact that ^G doesn't beep
a Sun console the way it does (practically) ever other terminal
ever made?  I've complained to Sun numerous times about how my
3/160 console doesn't beep when I print a ^G -- which means that
programs like talk and vi can't notify me, because THEY don't do
the kbd ioctl, and also that I won't be notified if I'm rlogged in
from another Sun, because if I try to do the ioctl it will come
out on the wrong screen.  Finally, it means that in all my programs
I have to do something like
#ifdef sun
#include <sundev/kbd.h>
#include <sundev/kbio.h>
#endif
.
.
#ifdev KBD_CMD_BELL	/* if we're on a Sun3, or at least 3.x */
if (on_console)		/* Need to check at beginning of program
			 * to make sure we're on the console so
			 * we don't beep it if someone else is on it
			 */
	ioctl( ...etc )
else
#else
	putchar('\07');
#endif

I mean, it wasn't that hard to figure out, but it's a little
inelegant to have to put that into every single program,
and Sun didn't do it when they wrote talk and vi.

After six months of hearing me talk about it, the local Sun reps
finally told me that there was an ECO which would fix the problem,
and came out to install a new CPU board (note that I had to be on
hardware maintenance to get this fixed).  A week and two CPU
boards later (the first one they sent out didn't work, and it
took several hours to get the second one working, for some reason)
I finally had a machine which supposedly beeped -- and guess what?
It's still barely audible -- too short and too quiet to be heard
when I'm standing across the room (i.e. talk still can't notify
me when someone's trying to talk to me).  And echoing several ^G's
is even less audible than echoing just one.

The Sun2/170 (2.2) I used to use had a wonderful ^G -- it was nice
and loud without being too obnoxious, and if I wanted something
really obnoxious I could always say "echo ^G^G^G^G^G^G^G^G^G^G^G^G^G^G"
and get a long, continuous bell which I couldn't fail to hear.
I'd like to be able to do that on my Sun3 without having to write
a C program (and compile it into all the system programs and PD
programs off the net and so forth) to do it.  Isn't anyone else
bothered by it?  I'm sure it's an easy fix -- I've asked Sun several
times why it isn't possible simply to take the source for the console
driver, find the part where it interprets a ^G, lengthen the time
before the KBD_CMD_NOBELL ioctl, and recompile; Sun is convinced
that it's a hardware problem and changing software won't help it.
Has anybody with source tried it?  (We're in the process of trying
to get source, but it hasn't happened yet.)  Is there something
wrong with my reasoning?  Is it really a hardware problem?  Do
other 3.x Sun3's beep loudly, and mine just happens to have a
strange problem?

..
	...Akkana         Center for Nonlinear Studies, LANL
	akkana%cnls@lanl.arpa   hp@lanl.arpa   ihnp4!lanl!hp

"I think I'll take a walk.  Hmm, wonder where this wire goes?"
			-- Max Headroom