/* posix headers */

#include <stdio.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <bsd/libc.h>
#include <bsd/sys/ttydev.h>
#include <errno.h>


    extern void event_left_button_changed(int mouse_id,int pressed);
    extern void event_middle_button_changed(int mouse_id,int pressed);
    extern void event_right_button_changed(int mouse_id,int pressed);
    extern void event_mouse_moved(int mouse_id,int dx,int dy);


    typedef struct {
        int     id;
        struct {
            char    left:1,middle:1,right:1;
        }       old_buttons;
        struct {
            char    left:1,middle:1,right:1;
        }       new_buttons;
        char    dx;
        char    dy;
        char    packet_length;
        char    packet[4];
    }       mouse_t;


    

    void mouse_initialize(mouse_t* that,int id)
        /*
            DOES:    Initialize a mouse. The id will be passed to the event
                     routines and serves to identify the mouse device.
        */
    {
        that->id=id;
        that->old_buttons.left=0;
        that->old_buttons.middle=0;
        that->old_buttons.right=0;
        that->new_buttons.left=0;
        that->new_buttons.middle=0;
        that->new_buttons.right=0;
        that->dx=0;
        that->dy=0;
        that->packet_length=0;
        that->packet[0]=0;
        that->packet[1]=0;
        that->packet[2]=0;
        that->packet[3]=0;
    }/*mouse_initialize*/


    void mouse_decode_packet(mouse_t* that)
        /*
            PRIVATE
        */
    {
        /*
            bit:   | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
            -------|---|---|---|---|---|---|---|
            Word 1 | 1 | LB| RB| V7| V6| H7| H6|
            Word 2 | 0 | H5| H4| H3| H2| H1| H0|
            Word 3 | 0 | V5| V4| V3| V2| V1| V0|
            Word 4 | 0 | MB|  0|  0|  0|  0|  0| (optional)
            
        */
        
        if(that->packet_length<3){
            return;
        }
        that->new_buttons.middle=that->old_buttons.middle;
        that->new_buttons.left=((that->packet[0]&0x20)==0)?0:1;
        that->new_buttons.right=((that->packet[0]&0x10)==0)?0:1;
        if(that->packet_length>3){
            that->new_buttons.middle=((that->packet[3]&0x20)==0)?0:1;
        }
        that->dy=((that->packet[0]&0x0c)<<4)|(that->packet[2]&0x3f);
        that->dx=((that->packet[0]&0x03)<<6)|(that->packet[1]&0x3f);
    }/*mouse_decode_packet*/
    
 
    void mouse_send_event(mouse_t* that)
        /*
            PRIVATE
        */
    {
        if(that->packet_length==4){
            /* only middle button event */
            if(that->old_buttons.middle!=that->new_buttons.middle){
                that->old_buttons.middle=that->new_buttons.middle;
                event_middle_button_changed(that->id,that->new_buttons.middle);
            }
        }else{
            /* other events */
            if(that->old_buttons.left!=that->new_buttons.left){
                that->old_buttons.left=that->new_buttons.left;
                event_left_button_changed(that->id,that->new_buttons.left);
            }
            if(that->old_buttons.right!=that->new_buttons.right){
                that->old_buttons.right=that->new_buttons.right;
                event_right_button_changed(that->id,that->new_buttons.right);
            }
            if((that->dy!=0)||(that->dx!=0)){
                event_mouse_moved(that->id,that->dx,that->dy);
            }
        }
    }/*mouse_send_event*/


    void mouse_sent_byte(mouse_t* that,char byte)
        /*
            NOTE:    Entry point to the mouse. Just send it the bytes
                     received from the serial line one by one.
        */
    {
        if(byte&0x40){
            /* start of packet */
            that->packet[0]=0x7f&byte;
            that->packet_length=1;
        }else if(that->packet_length<4){
            that->packet[(int)that->packet_length++]=0x7f&byte;
            if(3<=that->packet_length){
                mouse_decode_packet(that);
                mouse_send_event(that);
            }
        }/* else too long packet, let's ignore it.*/
    }/*mouse_sent_byte*/


    void event_left_button_changed(int mouse_id,int pressed)
    {
        printf("                 Left   %s\n",pressed?"ON":"off");
    }/*event_left_button_changed*/


    void event_middle_button_changed(int mouse_id,int pressed)
    {
        printf("                 Middle %s\n",pressed?"ON":"off");
    }/*event_middle_button_changed*/


    void event_right_button_changed(int mouse_id,int pressed)
    {
        printf("                 Right  %s\n",pressed?"ON":"off");
    }/*event_right_button_changed*/


    void event_mouse_moved(int mouse_id,int dx,int dy)
    {
        printf("Moved  %3d,%3d\n",dx,dy);
    }/*event_mouse_moved*/




    int serial_mouse_open(const char* path)
        /*
            DOES:    open the serial device at path (should be /dev/tty[ab]),
                     and initialize it to be used with a serial mouse.
            RETURN:  the opened file descriptor.
        */
    {
        int fd=open(path,O_RDWR|O_EXCL,0);
        if(fd<0){
            return(fd);
        }else{
            struct sgttyb s;
            s.sg_ispeed=B1200;
            s.sg_ospeed=B1200;
            s.sg_erase=0;
            s.sg_kill=0;
            s.sg_flags=RAW;
            ioctl(fd,TIOCSETP,s);
        }
        {
            unsigned char byte=0xff;
            write(fd,&byte,1);
        }
        return(fd);
    }/*serial_mouse_open*/


    int main(int argc,char** argv)
    {
        mouse_t       mouse;
        unsigned char byte;
        int           serial_fd;
        const char*   serial_path="/dev/ttyb";
        if(argv[1]!=0){
            serial_path=argv[1];
        }
        mouse_initialize(&mouse,0);
        /* kmouse_initialize(); */
        serial_fd=serial_mouse_open(serial_path);
        if(serial_fd>=0){
            fprintf(stderr,"mouse driver started on port '%s'.\n",serial_path);
            do{
                int res=read(serial_fd,&byte,1);
                fprintf(stderr,"%4d  %02x.\n",res,byte);
                if(res<0){
                    switch(errno){
                    case EINTR:
                    case EAGAIN:
                        break;
                    default:
                        perror("read serial port");
                        break;
                    }
                }else if(res==1){
                    mouse_sent_byte(&mouse,byte);
                }
            }while(1);
        }else{
            perror("open serial port");
            return(1);
        }
    }/*main*/




/*** mouse.c                          -- 2003-11-24 08:26:25 -- pascal   ***/
