Programeer opdrachtenOpdracht : opdr4_marvin.txt

Terug naar de inzendingen
Opdracht 4,Marvin Raaijmakers
17-Maart-2005
 
 Zo klaar:
 http://www.linux-box.nl/~marvin/src/mouse.tar.gz
 
 [B]Waarschuwing:[/B] [I]Het is verstandig om het programma niet onder X te
 runnen, omdat deze dan wel eens zou kunnen freezen.[/I]
 
 Mijn progsel geeft zowel de X-richting als de Y-richting aan. Hierdoor krijgt
 de gebruiker meer informatie over de beweging. Oh ik bedenk mij nu net dat de
 meldingen in het Engels worden gegeven, maar dit vraagt slechts een paar
 kleine aanpassingen in mouse.h om het in het Nederlands om te zetten.
 Het programma is zo gemaakt dat het verschillende soorten muizen om kan gaan.
 In de versie die ik heb gemaakt worden de ms-serial en de PS/2 muis
 ondersteund, maar het is zeer eenvoudig om voor een andere interface (USB
 bijv) een "driver" te maken.
 
 1 
***** Makefile *****
  
 2TARGET = mouse
 3SOURCES = \
 4        mouse.c \
 5        intf_ms_serial.c \
 6        intf_ps2.c
 7
 8CFLAGS=-I. -O2 -Wall
 9LINKFLAGS=-lm
 10CC=gcc
 11
 12OBJECTS=$(SOURCES:.c=.o)
 13
 14all: $(TARGET)
 15
 16cc:
 17        $(MAKE) CC=cc \
 18                all
 19
 20$(TARGET): $(OBJECTS)
 21        $(CC) $(LINKFLAGS) -o  $@ $(OBJECTS)
 22
 23clean:
 24        $(RM) $(TARGET) $(OBJECTS)
 25
 1 
***** mouse.h*****
  
 2/*-------------------------------------------------------------------------------
 3Name               : mouse.h
 4Author             : Marvin Raaijmakers
 5Description        : Main header file of mouse
 6Date of last change: 17-March-2005
 7
 8    Copyright (C) 2005 Marvin Raaijmakers
 9
 10    This program is free software; you can redistribute it and/or modify
 11    it under the terms of the GNU General Public License as published by
 12    the Free Software Foundation; either version 2 of the License, or
 13    any later version.
 14
 15    This program is distributed in the hope that it will be useful,
 16    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18    GNU General Public License for more details.
 19
 20    You should have received a copy of the GNU General Public License
 21    along with this program; if not, write to the Free Software
 22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23
 24    You can contact me at: marvin_raaijmakers(at)linux-box(dot)nl
 25    (replace (at) by @ and (dot) by .)
 26---------------------------------------------------------------------------------*/
 27#define MAX_SPEED (180)
 28/* = INT sqrt(max_x_speed^2 * max_y_speed^2) 
 29 * = INT sqrt(127^2 * 127^2)
 30 * = INT sqrt(2) * 127
 31 */
 32#define SLOW   (MAX_SPEED/4)
 33#define MAX_MSG_SIZE  (100)
 34#define NUM_INTERFACES  (2)
 35#define MAX_DEVICE_NAME  (100)
 36#define INTERFACE_NAME_SIZE (100)
 37#define NUM_ARGS  (2)
 38#define ARG_INTERFACE  (1)
 39#define ARG_DEVICE  (2)
 40
 41#define ACCESS_DENIED (-1)
 42
 43#define MSG_UP  "up"
 44#define MSG_DOWN "down"
 45#define MSG_LEFT "left"
 46#define MSG_RIGHT "right"
 47#define MSG_LBUTTON "lbutton"
 48#define MSG_RBUTTON "rbutton"
 49
 50typedef int Boolean;
 51#define TRUE (1)
 52#define FALSE (0)
 53
 54#define EQUAL (0)
 55
 56#define calc_speed(_dX, _dY)  ((int) sqrt( _dY*_dY + _dX*_dX) )
 57#define direction_changed(_ev1, _ev2) (memcmp(&((_ev1)->direction), &((_ev2)->direction), sizeof(DIRECTION)) != EQUAL)
 58
 59
 60typedef enum {
 61 LBUTTON,
 62 RBUTTON
 63} BUTTON_TYPE;
 64
 65typedef enum {
 66 XNULL,
 67 LEFT,
 68 RIGHT
 69} XDIRECTION;
 70
 71typedef enum {
 72 YNULL,
 73 UP,
 74 DOWN
 75} YDIRECTION;
 76
 77typedef enum {
 78 PRESSED,
 79 RELEASED
 80} BUTTON_STATE;
 81
 82typedef struct {
 83 BUTTON_STATE right,
 84   left;
 85} BUTTONS;
 86
 87typedef struct {
 88 XDIRECTION x;
 89 YDIRECTION y;
 90} DIRECTION;
 91
 92typedef struct {
 93 DIRECTION direction;
 94 BUTTONS  button;
 95 int  speed;
 96} EVENT;
 97
 98typedef struct {
 99 char name[INTERFACE_NAME_SIZE+1];
 100 void (*init_mouse) (int mouse);
 101 void (*read_event) (int mouse, EVENT *event);
 102} INTERFACE;
 103
 104
 105extern void ms_serial_init (int mouse);
 106extern void ms_serial_event (int mouse, EVENT *event);
 107extern void ps2_init (int mouse);
 108extern void ps2_event (int mouse, EVENT *event);
 109
 1 
**** intf_ps2.c *****
  
 2/*-------------------------------------------------------------------------------
 3Name               : intf_ps2.c
 4Author             : Marvin Raaijmakers
 5Description        : Interface for PS/2 mouse
 6Date of last change: 17-March-2005
 7
 8    Copyright (C) 2005 Marvin Raaijmakers
 9
 10    This program is free software; you can redistribute it and/or modify
 11    it under the terms of the GNU General Public License as published by
 12    the Free Software Foundation; either version 2 of the License, or
 13    any later version.
 14
 15    This program is distributed in the hope that it will be useful,
 16    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18    GNU General Public License for more details.
 19
 20    You should have received a copy of the GNU General Public License
 21    along with this program; if not, write to the Free Software
 22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23
 24    You can contact me at: marvin_raaijmakers(at)linux-box(dot)nl
 25    (replace (at) by @ and (dot) by .)
 26---------------------------------------------------------------------------------*/
 27#include 
 28#include 
 29
 30#include 
 31
 32#define DATA_SIZE (3)
 33
 34#define LEFT_BUTTON 0x01
 35#define RIGHT_BUTTON 0x02
 36#define MOVED_RIGHT 0x10
 37#define MOVED_UP 0x20
 38
 39
 40void
 41ps2_init (int mouse)
 42{
 43
 44
 45
 46void
 47ps2_event ( int mouse,
 48  EVENT *event  )
 49/*
 50Input:
 51 mouse - The file descriptor to the device
 52Output:
 53 event - The information about the readen event
 54Returns:
 55 -
 56Desciption:
 57 This function reads an event from mouse, which is a file descriptor to a PS/2
 58 mouse. This function is written by using the following information about the data
 59 packages sent by the mouse:
 60 
 61    | D7  D6  D5  D4  D3  D2  D1  D0
 62 ---+---------------------------------
 63 1. | XV  XV  YS  XS  1   0   R   L
 64 2. | X7  X6  X5  X4  X3  X2  X1  X0
 65 3. | Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
 66 
 67 L       Left button state (1 = pressed down)
 68 R       Right button state (1 = pressed down)
 69 X0-X7   Movement in X direction
 70 Y0-Y7   Movement in Y direction
 71 XS,YS   Movement data sign bits (1 = negative)
 72 XV,YV   Movement data overflow bits (1 = overflow has occured)
 73*/
 74{
 75 char output[DATA_SIZE];
 76 signed char dX, dY;
 77 
 78 read (mouse, output, DATA_SIZE);
 79 dX = output[1];
 80 dY = output[2];
 81 
 82 /* If the left button is pressed */
 83 if (output[0] & LEFT_BUTTON)
 84 {
 85  event->button.left = PRESSED;
 86 }
 87 else
 88 {
 89  event->button.left = RELEASED;
 90 }
 91 /* If the right button is pressed */
 92 if (output[0] & RIGHT_BUTTON)
 93 {
 94  event->button.right = PRESSED;
 95 }
 96 else
 97 {
 98  event->button.right = RELEASED;
 99 }
 100 /* Get the x-direction: */
 101 if (output[0] & MOVED_RIGHT)
 102 {
 103  event->direction.x = RIGHT;
 104 }
 105 else if (dX)
 106 {
 107  event->direction.x = LEFT;
 108 }
 109 else
 110 {
 111  event->direction.x = XNULL;
 112 }
 113 /* Get the y-direction: */
 114 if (output[0] & MOVED_UP)
 115 {
 116  event->direction.y = UP;
 117 }
 118 else if (dY)
 119 {
 120  event->direction.y = DOWN;
 121 }
 122 else
 123 {
 124  event->direction.y = YNULL;
 125 }
 126 
 127 event->speed = calc_speed (dX, dY);
 128}
 1 
***** intd_ms_serial.c *****
  
 2/*-------------------------------------------------------------------------------
 3Name               : intf_ms_serial.c
 4Author             : Marvin Raaijmakers
 5Description        : Interface for ms serial mouse
 6Date of last change: 17-March-2005
 7
 8    Copyright (C) 2005 Marvin Raaijmakers
 9
 10    This program is free software; you can redistribute it and/or modify
 11    it under the terms of the GNU General Public License as published by
 12    the Free Software Foundation; either version 2 of the License, or
 13    any later version.
 14
 15    This program is distributed in the hope that it will be useful,
 16    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18    GNU General Public License for more details.
 19
 20    You should have received a copy of the GNU General Public License
 21    along with this program; if not, write to the Free Software
 22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23
 24    You can contact me at: marvin_raaijmakers(at)linux-box(dot)nl
 25    (replace (at) by @ and (dot) by .)
 26---------------------------------------------------------------------------------*/
 27#include 
 28#include 
 29
 30#include 
 31
 32#define START_BIT 0x40
 33#define LEFT_BUTTON 0x20
 34#define RIGHT_BUTTON 0x10
 35
 36#define DTR ('M')
 37
 38
 39void
 40ms_serial_init (int mouse)
 41{
 42 char output;
 43 
 44 read (mouse,&output, 1);
 45 if (output == DTR)
 46 {
 47  /*printf ("DTR line is toggled\n");*/
 48 }
 49
 50
 51
 52void
 53ms_serial_event ( int mouse,
 54   EVENT *event  )
 55/*
 56Input:
 57 mouse - The file descriptor to the device
 58Output:
 59 event - The information about the readen event
 60Returns:
 61 -
 62Desciption:
 63 This function reads an event from mouse, which is a file descriptor to a ms
 64 serial mouse. This function is written by using the following information about
 65 the data packages sent by the mouse:
 66 
 67 Data packet is 3 byte packet. It is send to the computer every time mouse
 68 state changes (mouse moves or keys are pressed/released).
 69 
 70    | D7   D6   D5   D4   D3   D2   D1   D0
 71 ---+----------------------------------------
 72 1. |  X    1   LB   RB   Y7   Y6   X7   X6
 73 2. |  X    0   X5   X4   X3   X2   X1   X0      
 74 3. |  X    0   Y5   Y4   Y3   Y2   Y1   Y0
 75 
 76 Note: The bit marked with X is 0 if the mouse received with 7 databits
 77 and 2 stop bits format. It is also possible to use 8 databits and 1 stop
 78 bit format for receiving. In this case X gets value 1.
 79 
 80 The byte marked with 1. is send first, then the others. The bit D6 in
 81 the first byte is used for syncronizing the software to mouse packets
 82 if it goes out of sync.
 83 
 84 LB is the state of the left button (1 means pressed down)
 85 RB is the state of the right button (1 means pressed down)
 86 X7-X0 movement in X direction since last packet (signed byte)
 87 Y7-Y0 movement in Y direction since last packet (signed byte)
 88*/
 89{
 90 char output;
 91 signed char dX, dY;
 92 
 93 /* Read bytes and stop after we read a byte containing the START_BIT*/
 94 do {
 95  read (mouse, &output, 1);
 96 } while (!(output & START_BIT));
 97 
 98 /* If the left button is pressed */
 99 if (output & LEFT_BUTTON)
 100 {
 101  event->button.left = PRESSED;
 102 }
 103 else
 104 {
 105  event->button.left = RELEASED;
 106 }
 107 /* If the right button is pressed */
 108 if (output & RIGHT_BUTTON)
 109 {
 110  event->button.right = PRESSED;
 111 }
 112 else
 113 {
 114  event->button.right = RELEASED;
 115 }
 116 
 117 /* Read the 8th and 7th bit of dX */
 118 dX = 0xC0 & (output << 6);
 119 /* Read the 8th and 7th bit of dY */
 120 dY = 0xC0 & (output << 4);
 121 
 122 read (mouse, &output, 1);
 123 /* Read the remaining bits of dX */
 124 dX |= output;
 125 read (mouse, &output, 1);
 126 /* Read the remaining bits of dY */
 127 dY |= output;
 128 if (dX > 0)
 129 {
 130  event->direction.x = RIGHT;
 131 }
 132 else if (dX < 0)
 133 {
 134  event->direction.x = LEFT;
 135 }
 136 else
 137 {
 138  event->direction.x = XNULL;
 139 }
 140 
 141 if (dY > 0)
 142 {
 143  event->direction.y = DOWN;
 144 }
 145 else if (dY < 0)
 146 {
 147  event->direction.y = UP;
 148 }
 149 else
 150 {
 151  event->direction.y = YNULL;
 152 }
 153 
 154 event->speed = calc_speed (dX, dY);
 155}
 1 
***** mouse.c *****
  
 2/*-------------------------------------------------------------------------------
 3Name               : mouse.c
 4Author             : Marvin Raaijmakers
 5Description        : Program which prints information about mouse actions
 6Date of last change: 17-March-2005
 7
 8    Copyright (C) 2005 Marvin Raaijmakers
 9
 10    This program is free software; you can redistribute it and/or modify
 11    it under the terms of the GNU General Public License as published by
 12    the Free Software Foundation; either version 2 of the License, or
 13    any later version.
 14
 15    This program is distributed in the hope that it will be useful,
 16    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18    GNU General Public License for more details.
 19
 20    You should have received a copy of the GNU General Public License
 21    along with this program; if not, write to the Free Software
 22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23
 24    You can contact me at: marvin_raaijmakers(at)linux-box(dot)nl
 25    (replace (at) by @ and (dot) by .)
 26---------------------------------------------------------------------------------*/
 27#include 
 28#include 
 29#include 
 30#include 
 31#include 
 32#include 
 33
 34#include 
 35
 36
 37static const INTERFACE interfaces[NUM_INTERFACES] = {
 38 /* NAME  INIT FUNCTION READ EVENT FUNCTION */
 39 {  "ms-serial", ms_serial_init, ms_serial_event  },
 40 {  "PS/2", ps2_init, ps2_event  }
 41};
 42
 43
 44static Boolean proccess_parameters (int argc, char *argv[], INTERFACE **interface, char *device);
 45static void strconvchars (char *string, char (*convert)(char));
 46static Boolean handle_button (BUTTON_STATE current_state, BUTTON_STATE previous_state, BUTTON_TYPE button_type);
 47static Boolean handle_movement (EVENT *ev_current, EVENT *ev_previous);
 48static void init_event (EVENT *event);
 49
 50
 51void
 52strconvchars ( char *string,
 53  char (*convert)(char) )
 54/*
 55Input:
 56 convert - The function to convert the characters in the string with
 57Ouput:
 58 string - The string converted using convert
 59Returns:
 60 -
 61Description:
 62 This function coverts the characters of string using convert. convert should be
 63 a function which takes a character as an input variable and returns the converted
 64 value. string should be a terminated by the '\0' character.
 65*/
 66{
 67 while (*string != '\0')
 68 {
 69  *string = (*convert)(*string);
 70  string++;
 71 }
 72}
 73
 74
 75Boolean
 76handle_button ( BUTTON_STATE current_state,
 77  BUTTON_STATE previous_state,
 78  BUTTON_TYPE button_type    )
 79/*
 80Input:
 81 current_state - The current state of the button
 82 previous_state - The previous state of the button
 83 button_type - Indicates the button
 84Ouput:
 85 -
 86Returns:
 87 TRUE if the button is pressed for the first time, otherwise FALSE.
 88Desciption:
 89 This function writes a message to the stdout if the button is currently pressed while
 90 previously it was not.
 91*/
 92{
 93 char *msg;
 94 
 95 if (current_state == PRESSED && current_state != previous_state)
 96 {
 97  switch (button_type)
 98  {
 99   case LBUTTON:
 100    msg = MSG_LBUTTON;
 101    break;
 102   case RBUTTON:
 103    msg = MSG_RBUTTON;
 104    break;
 105   default:
 106    msg = "";
 107    break;
 108  }
 109  printf ("%s ", msg);
 110  return (TRUE);
 111 }
 112 return (FALSE);
 113}
 114
 115
 116Boolean
 117handle_movement ( EVENT *ev_current,
 118   EVENT *ev_previous    )
 119/*
 120Input:
 121 ev_current - The current mouse event
 122 ev_previous - The previous mouse event
 123Output:
 124 -
 125Returns:
 126 TRUE if the direction of the movement changed, or if the speed changed from slow
 127 to fast or visa versa. Otherwise FALSE.
 128Description:
 129 This function compares ev_current with ev_previous. If the direction of the
 130 movement changed, or if the speed changed from slow to fast or visa versa,
 131 the following information about the movement will be printed to the stdout:
 132  
 133 If there was no movement in one of the directions, that direction will not
 134 be printed. If the speed of the movement is slow (which means <= SLOW) the
 135 direction will be printed with lowercase letters and otherwise (which means the
 136 speed > SLOW) with uppercase letters.
 137*/
 138{
 139 char msg[MAX_MSG_SIZE] = "";
 140 
 141 
 142 /* If the direction or the speed changed */
 143 if (direction_changed(ev_current, ev_previous) ||
 144     (ev_current->speed > SLOW && ev_previous->speed <= SLOW) ||
 145     (ev_current->speed <= SLOW && ev_previous->speed > SLOW)    )
 146 {
 147  switch (ev_current->direction.x)
 148  {
 149   case LEFT:
 150    strncat (msg, MSG_LEFT " ", MAX_MSG_SIZE);
 151    break;
 152   case RIGHT:
 153    strncat (msg, MSG_RIGHT " ", MAX_MSG_SIZE);
 154   default:
 155    break;
 156  }
 157  switch (ev_current->direction.y)
 158  {
 159   case UP:
 160    strncat (msg, MSG_UP " ", MAX_MSG_SIZE);
 161    break;
 162   case DOWN:
 163    strncat (msg, MSG_DOWN " ", MAX_MSG_SIZE);
 164   default:
 165    break;
 166  }
 167  if (ev_current->speed > SLOW)
 168  {
 169   strconvchars (msg, toupper);
 170  }
 171  else
 172  {
 173   strconvchars (msg, tolower);
 174  }
 175  printf (msg);
 176  return (TRUE);
 177 }
 178 return (FALSE);
 179}
 180
 181
 182void
 183init_event (EVENT *event)
 184/*
 185Input:
 186 -
 187Output:
 188 event - initialized to be "empty"
 189Returns:
 190 -
 191Description:
 192 This function initializes event.
 193*/
 194{
 195 event->direction.x = XNULL;
 196 event->direction.y = YNULL;
 197 event->button.left  = RELEASED;
 198 event->button.right = RELEASED;
 199 event->speed = 0;
 200}
 201
 202
 203Boolean
 204proccess_parameters ( int  argc,
 205   char  *argv[],
 206   INTERFACE **interface,
 207   char  *device       )
 208{
 209 int count;
 210 
 211 if (argc != NUM_ARGS+1)
 212 {
 213  printf ("%s: invalid number of arguments\n", argv[0]);
 214  return (FALSE);
 215 }
 216 
 217 *interface = NULL;
 218 for (count = 0; count < NUM_INTERFACES; count++)
 219 {
 220  if ( strcmp(interfaces[count].name, argv[ARG_INTERFACE]) == EQUAL )
 221  {
 222   *interface = &(interfaces[count]);
 223   break;
 224  }
 225 }
 226 /* If no existing interface was found */
 227 if (*interface == NULL)
 228 {
 229  printf ("%s: '%s' is an invalid interface\n", argv[0], argv[ARG_INTERFACE]);
 230  return (FALSE);
 231 }
 232 
 233 strncpy (device, argv[ARG_DEVICE], MAX_DEVICE_NAME);
 234 device[MAX_DEVICE_NAME] = '\0';
 235 
 236 return (TRUE);
 237}
 238
 239
 240int
 241main (int argc, char *argv[])
 242{
 243 INTERFACE *interface;
 244 char device[MAX_DEVICE_NAME+1];
 245 int mouse;
 246 int count;
 247 EVENT ev_current, ev_previous;
 248 
 249 /* If the parameters are wrong */
 250 if ( proccess_parameters(argc, argv, &interface, device) == FALSE )
 251 {
 252  printf ("Usage: %s INTERFACE DEVICE\n"
 253   "The following interfaces are available:\n", argv[0]);
 254  for (count = 0; count < NUM_INTERFACES; count++)
 255  {
 256   printf ("  %s\n", interfaces[count].name);
 257  }
 258  exit (1);
 259 }
 260 
 261 mouse = open(device, O_RDONLY);
 262 if (mouse == -1)
 263 {
 264  printf ("ERROR: Couldn't open '%s'.", device);
 265  if ( access(device, R_OK) == ACCESS_DENIED )
 266  {
 267   printf (" Access denied!");
 268  }
 269  putchar ('\n');
 270  exit(1);
 271 }
 272 
 273 /* Initialize the mouse */
 274 (*interface->init_mouse) (mouse);
 275 init_event (&ev_current);
 276 init_event (&ev_previous);
 277 
 278 while (1)
 279 {
 280  ev_previous = ev_current;
 281  (*interface->read_event) (mouse, &ev_current);
 282  if ( handle_movement (&ev_current, &ev_previous) |
 283   handle_button (ev_current.button.left, ev_previous.button.left, LBUTTON) |
 284   handle_button (ev_current.button.right, ev_previous.button.right, RBUTTON) )
 285  {
 286   putchar ('\n');
 287  }
 288 }
 289}
 
 
Mijn commentaar
 
 Zoals we inmiddels van jou gewend zijn heb je weer een mooi stukje werk
 geleverd Marvin.
 Je hebt heel slim gebruik gemaakt van het princype dat er per paketje maar een
 zekere verplaatsing gemeld kan worden om zodoende de snelheid te bepalen.
 (ik zat zelf al te denken aan timer constructies maar da's dus niet nodig)
 Ook je vooruitziende blik andere muistypen te ondersteunen kan ik erg
 waarderen.
 Op je code kan ik niet veel aanmerken, behoudens een aantal persoonlijke
 voorkeuren.
 (zo probeer ik zelf zo lang mogelijk het gebruik van [B]extern[/B] te
 voorkomen en vind ik dat je het allemaal wel heel erg mooi hebt gemaakt)
 
 Je opmerking over het bevriezen van X is terecht en geen tekortkoming van je
 programma.
 n.l. op het moment dat je dit gaat uitvoeren neem je ook de bijhorende
 devicenode over.
 dat leid oom bij gpm nog al eens tot problemen.
 
 Al met al wederom een indrukwekkend resultaat !