Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

#include <avr/io.h>
#include <avr/interrupt.h>

#include <util/delay.h>

#include "mytypes.h"
#include "main.h"
#include "ps2.h"
#include "zx.h"
#include "pins.h"
#include "spi.h"
#include "rs232.h"

//if want Log than comment next string
#undef LOGENABLE

UBYTE ps2_decode(UBYTE count, UWORD shifter)
{
        UBYTE t,byte;

        if( count!=0 ) return 0x00; // have nothing received

        // check packet:
        //shifter.hi - stp.par.7.6.5.4.3.2
        //shifter.lo - 1.0.strt.x.x.x.x.x

        if( !( shifter&0x8000 ) ) return 0x00; // stopbit must be 1
        if( shifter&0x0020 ) return 0x00; // startbit must be 0


        byte = (UBYTE) ( 0x00FF & (shifter>>6) );

        t = byte ^ (byte>>4);
        t = t ^ (t>>2);
        t = t ^ (t>>1); // parity

        t = t ^ (UBYTE) ( shifter>>14 ); // compare parities

        if( !(t&1) ) return 0x00; // must be different

        return byte;
}

UWORD ps2_encode(UBYTE byte)
{
        UWORD t;
        t = byte ^ (byte>>4);
        t = t ^ (t>>2);
        t = ~(1 & (t ^ (t>>1))); // parity

        t = (((t<<8) + byte)<<1) + 0x0400;

        // prepare to shifter:
        //shifter.hi - x.x.x.x.x.stp.par.7
        //shifter.lo - 6.5.4.3.2.1.0.strt
        return t;
}

volatile UWORD ps2keyboard_shifter;
volatile UBYTE ps2keyboard_count;
volatile UBYTE ps2keyboard_timeout;
volatile UBYTE ps2keyboard_cmd_count;
volatile UBYTE ps2keyboard_cmd;

static void ps2keyboard_release_clk(void)
{
        ps2keyboard_count = 12; //counter reinit
        if( flags_register & FLAG_PS2KEYBOARD_DIRECTION )
        {
                PS2KBDAT_DDR &= ~(1<<PS2KBDAT); //ps2 keyboard data pin to input mode
                flags_register &= ~(FLAG_PS2KEYBOARD_DIRECTION); //set to receive mode
        }

        //release ps2 receiver (disabled by now)
        EIFR = (1<<INTF4); // clr any spurious int which can happen when we pulldown clock pin
        PS2KBCLK_DDR  &= ~(1<<PS2KBCLK); //ps2 keyboard clk pin to input mode
        PS2KBCLK_PORT |= (1<<PS2KBCLK);  //release clk pin
}

void ps2keyboard_send(UBYTE data)
{
#ifdef LOGENABLE
{
        char log_ps2kb_parse[] = "KB>..\r\n";
        UBYTE b = data;
        log_ps2kb_parse[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
        log_ps2kb_parse[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
        to_log(log_ps2kb_parse);
}
#endif
        ps2keyboard_shifter = ps2_encode(data); //prepare data
        flags_register |= FLAG_PS2KEYBOARD_DIRECTION; //set send mode
        PS2KBCLK_PORT &= ~(1<<PS2KBCLK); //bring ps2 keyboard clk pin -
    PS2KBCLK_DDR  |= (1<<PS2KBCLK);  //generate interruption
}

void ps2keyboard_task(void)
{
        UBYTE b;

        if ( ( ps2keyboard_count == 12 ) &&
                 ( ps2keyboard_cmd != 0) &&
                 ( ps2keyboard_cmd_count != 0 ) )
        {
                //delay need for pause between release and hold clk pin
                _delay_us(100);

                //if need send command on current stage
                if ( ((ps2keyboard_cmd_count == 4)&&(ps2keyboard_cmd == PS2KEYBOARD_CMD_SETLED)) ||
                     ((ps2keyboard_cmd_count == 3)&&(ps2keyboard_cmd == PS2KEYBOARD_CMD_RESET)) )
                {
                        ps2keyboard_send(ps2keyboard_cmd);
                        ps2keyboard_cmd_count--;
                }
                else
                //if need send led data on current stage
                if ( ((ps2keyboard_cmd_count == 2)&&(ps2keyboard_cmd == PS2KEYBOARD_CMD_SETLED)) )
                {
                        b = PS2KEYBOARD_LED_SCROLLOCK&modes_register;
                        ps2keyboard_send(b);
                        ps2keyboard_cmd_count--;
                }
        }

        if ( ( ps2keyboard_count<12 ) &&
                 ( ps2keyboard_timeout==0 ) )
        {
                //error due send/receive
                ps2keyboard_release_clk();
#ifdef LOGENABLE
                to_log("KBerr\r\n");
#endif
                //TODO: ÷åòà äåëàòü

                //reset command
                ps2keyboard_cmd_count = 0;
                ps2keyboard_cmd = 0;

                //reset buffer
                zx_clr_kb();
        }

        if ( ps2keyboard_count!=0 ) return; // not received anything

        if ( !(flags_register&FLAG_PS2KEYBOARD_DIRECTION) )
        {
                //receive complete
                b = ps2_decode(ps2keyboard_count, ps2keyboard_shifter);
#ifdef LOGENABLE
{
        char log_ps2kb_parse[] = "KB<..\r\n";
        log_ps2kb_parse[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
        log_ps2kb_parse[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
        to_log(log_ps2kb_parse);
}
#endif
                if ( ps2keyboard_cmd )
                {
                        //wait for 0xFA on current stage
                        if ( ((ps2keyboard_cmd == PS2KEYBOARD_CMD_SETLED)&&(ps2keyboard_cmd_count == 3 || ps2keyboard_cmd_count == 1)) ||
                             ((ps2keyboard_cmd == PS2KEYBOARD_CMD_RESET)&&(ps2keyboard_cmd_count == 2)) )
                        {
                                if( b != 0xFA )
                                {
                                        ps2keyboard_cmd_count = 0;
                                        //if non FA - may be scan code received
                                        if ( b ) ps2keyboard_parse(b);
                                }
                                else ps2keyboard_cmd_count--;

                                if ( ps2keyboard_cmd_count == 0 ) ps2keyboard_cmd = 0;
                        }
                        else
                        //wait for 0xAA on current stage
                        if ( ((ps2keyboard_cmd == PS2KEYBOARD_CMD_RESET)&&(ps2keyboard_cmd_count == 1)) )
                        {
                                if ( b != 0xAA )
                                {
                                        //if non AA - may be scan code received
                                        if ( b ) ps2keyboard_parse(b);
                                }
                                ps2keyboard_cmd_count = 0;
                                ps2keyboard_cmd = 0;
                        }
                }
                else
                if ( b ) // there is no zero byte in scancode tables so we can ignore and use it as 'nothing received'
                {
                        ps2keyboard_parse(b);
                }
        }

        ps2keyboard_release_clk();
}

void ps2keyboard_send_cmd(UBYTE cmd)
{
        if ( ps2keyboard_cmd == 0 )
        {
                ps2keyboard_cmd = cmd;
                switch ( cmd )
                {
                case PS2KEYBOARD_CMD_RESET:
                        ps2keyboard_cmd_count = 3;
                        break;
                case PS2KEYBOARD_CMD_SETLED:
                        ps2keyboard_cmd_count = 4;
                        break;
                default:
                        ps2keyboard_cmd = 0;
                }
        }
}

void ps2keyboard_parse(UBYTE recbyte)
{
        static UBYTE was_release = 0;
        static UBYTE was_E0 = 0;

        static UBYTE last_scancode = 0;
        static UBYTE last_scancode_E0 = 1;

        static UBYTE skipshit = 0;

#ifdef LOGENABLE
        char log_ps2keyboard_parse[] = "KB..\r\n";
        if ( skipshit ) log_ps2keyboard_parse[1] = skipshit + '0';
        log_ps2keyboard_parse[2] = ((recbyte >> 4) <= 9 )?'0'+(recbyte >> 4):'A'+(recbyte >> 4)-10;
        log_ps2keyboard_parse[3] = ((recbyte & 0x0F) <= 9 )?'0'+(recbyte & 0x0F):'A'+(recbyte & 0x0F)-10;
        to_log(log_ps2keyboard_parse);
#endif


        if( skipshit )
        {
                skipshit--;
                return;
        }


        if( recbyte==0xFA ) return;
        if( recbyte==0xFE ) return;
        if( recbyte==0xEE ) return;
        if( recbyte==0xAA ) return;


        if( recbyte==0xE0 )
        {
                was_E0 = 1;
                return;
        }


        if( recbyte==0xF0 )
        {
                was_release = 1;
                return;
        }

        if( recbyte==0xE1 ) // pause pressed
        {
                skipshit=7;
                return; // skip next 7 bytes
        }


        if( (recbyte==last_scancode) && (was_E0==last_scancode_E0) )
        {
                if( was_release )
                {
                        last_scancode = 0x00;
                        last_scancode_E0 = 1; // impossible scancode: E0 00
                }
                else // was depress
                {
                        return;
                }
        }

        if( !was_release )
        {
                last_scancode = recbyte;
                last_scancode_E0 = was_E0;
        }

        if( (recbyte==0x12) && was_E0 ) // skip E0 12
        {
                was_E0 = 0;
                was_release = 0;
                return;
        }


        to_zx( recbyte, was_E0, was_release ); // send valid scancode to zx decoding stage

        was_E0 = 0;
        was_release = 0;

        return;
}

volatile UWORD ps2mouse_shifter;
volatile UBYTE ps2mouse_count;
volatile UBYTE ps2mouse_timeout;
volatile UBYTE ps2mouse_initstep;
volatile UBYTE ps2mouse_resp_count;

UBYTE ps2mouse_init_sequence[] =
        "\xFF"      //
        "\xFF"      // reset
        "\xFF"      //
        "\xF3\xC8"  // set sample rate 200  | switch to
        "\xF3\x64"  // set sample rate 100  |     scroll
        "\xF3\x50"  // set sample rate 80   |         mode
        "\xF2"      // get device type
        "\xF3\x0A"  // set sample rate 10
        "\xF2"      // get device type
        "\xE8\x02"  // set resolution
        "\xE6"      // set scaling 1:1
        "\xF3\x64"  // set sample rate 100
        "\xF4"      // enable
        ;

static void ps2mouse_release_clk(void)
{
        ps2mouse_count = 12; //counter reinit
        if( flags_register & FLAG_PS2MOUSE_DIRECTION )
        {
                PS2MSDAT_DDR &= ~(1<<PS2MSDAT); //ps2 mouse data pin to input mode
                flags_register &= ~(FLAG_PS2MOUSE_DIRECTION); //set to receive mode
        }

        //release ps2 receiver (disabled by now)
        EIFR = (1<<INTF5); // clr any spurious int which can happen when we pulldown clock pin
        PS2MSCLK_DDR  &= ~(1<<PS2MSCLK); //ps2 mouse clk pin to input mode
        PS2MSCLK_PORT |= (1<<PS2MSCLK);  //release clk pin
}

void ps2mouse_send(UBYTE data)
{
        ps2mouse_shifter = ps2_encode(data); //prepare data
        flags_register |= FLAG_PS2MOUSE_DIRECTION; //set send mode
        PS2MSCLK_PORT &= ~(1<<PS2MSCLK); //bring ps2 mouse clk pin -
    PS2MSCLK_DDR  |= (1<<PS2MSCLK);  //generate interruption
}

void ps2mouse_task(void)
{
        UBYTE b;

        if ( ( ps2mouse_count == 12 ) &&
                 ( ps2mouse_resp_count == 0) &&
                 ( ps2mouse_init_sequence[ps2mouse_initstep] != 0 ) )
        {
                //delay need for pause between release and hold clk pin
                _delay_us(200);

                //initialization not complete
                //send next command to mouse
                ps2mouse_send(ps2mouse_init_sequence[ps2mouse_initstep]);
                ps2mouse_resp_count++;
        }

        if ( ( ps2mouse_count<12 ) &&
                 ( ps2mouse_timeout==0 ) )
        {
#ifdef LOGENABLE
                char log_ps2mouse_err[] = "MS.err.\r\n";
                if( flags_register&FLAG_PS2MOUSE_DIRECTION ) log_ps2mouse_err[2]='S';   else log_ps2mouse_err[2]='R';
                if( ps2mouse_count<10 ) log_ps2mouse_err[6]='0'+ps2mouse_count;  else log_ps2mouse_err[6]='A'+ps2mouse_count-10;
                to_log(log_ps2mouse_err);
#endif
                //error due exchange data with PS/2 mouse

                //get direction
                b = flags_register&FLAG_PS2MOUSE_DIRECTION;

                //reset pins and states
                ps2mouse_release_clk();

                //analizing error
                if( b && (ps2mouse_initstep==0) )
                {
                        //error due send first init byte - mouse not connected to PS/2

                        //disable mouse
                        zx_mouse_reset(0);
                }
                else
                {
                        //error due receive or send non first byte - mouse connected to PS/2

                        //re-init mouse
                        ps2mouse_initstep = 0;
                }
        }

        if ( ps2mouse_count!=0 ) return; // not received anything

        if ( !(flags_register&FLAG_PS2MOUSE_DIRECTION) )
        {
                //receive complete
                b = ps2_decode(ps2mouse_count, ps2mouse_shifter);

#ifdef LOGENABLE
{
        char log_ps2mouse_parse[] = "MS<..\r\n";
        log_ps2mouse_parse[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
        log_ps2mouse_parse[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
        to_log(log_ps2mouse_parse);
}
#endif

                switch( ps2mouse_init_sequence[ps2mouse_initstep] )
                {
                        //initialization complete - working mode
                        case 0:
                                //TODO: send to ZX here
                                ps2mouse_resp_count++;
                                switch( ps2mouse_resp_count )
                                {
                                case 1:
                                        //byte 1: Y overflow | X overflow | Y sign bit | X sign bit | 1 | Middle Btn | Right Btn | Left Btn
                                        zx_mouse_button = (zx_mouse_button&0xF0) + ((b^0x07)&0x0F);
                                        break;
                                case 2:
                                        //byte 2: X movement
                                        zx_mouse_x += b;
                                        break;
                                case 3:
                                        //byte 3: Y movement
                                        zx_mouse_y += b;
                                        if ( !(flags_register&FLAG_PS2MOUSE_TYPE) )
                                        {
                                                //classical mouse
                                                ps2mouse_resp_count = 0;
                                                flags_register |= FLAG_PS2MOUSE_ZX_READY;
                                        }
                                        break;
                                case 4:
                                        //byte 4: wheel movement
                                        zx_mouse_button += ((b<<4)&0xF0);
                                        flags_register |= FLAG_PS2MOUSE_ZX_READY;
                                        ps2mouse_resp_count = 0;
                                }
                                break;

                        //reset command
                        case 0xFF:
                                if ( ps2mouse_resp_count==1 )
                                {
                                        //must be acknowledge
                                        if ( b != 0xFA )
                                        {
                                                //reset initialization
                                                ps2mouse_initstep = 0;
                                                ps2mouse_resp_count = 0;
                                                break;
                                        }
                                }
                                ps2mouse_resp_count++;
                                if ( ps2mouse_resp_count >= 4 )
                                {
                                        ps2mouse_resp_count = 0;
                                        ps2mouse_initstep++;
                                }
                                break;

                        //get device type
                        case 0xF2:
                                if ( ps2mouse_resp_count==1 )
                                {
                                        ps2mouse_resp_count++;
                                        //must be acknowledge
                                        if ( b != 0xFA )
                                        {
                                                //reset initialization
                                                ps2mouse_initstep = 0;
                                                ps2mouse_resp_count = 0;
                                        }
                                        break;
                                }
                                else
                                {
                                        ps2mouse_resp_count = 0;
                                        ps2mouse_initstep++;

                                        if ( b > 0 )
                                        {
                                                flags_register |= FLAG_PS2MOUSE_TYPE;
                                        }
                                        else
                                        {
                                                flags_register &= ~(FLAG_PS2MOUSE_TYPE);
                                        }
                                }
                                break;

                        //other commands
                        default:
                                if ( ps2mouse_resp_count==1 )
                                {
                                        //must be acknowledge
                                        if ( b != 0xFA )
                                        {
                                                //reset initialization
                                                ps2mouse_initstep = 0;
                                                ps2mouse_resp_count = 0;
                                                break;
                                        }
                                }
                                ps2mouse_resp_count = 0;
                                ps2mouse_initstep++;
                                break;
                }
        }
//#ifdef LOGENABLE
//      else
//      {
//              //send complete
//              char log_ps2mouse_parse[] = "MS>..\r\n";
//              b = ps2mouse_init_sequence[ps2mouse_initstep];
//              log_ps2mouse_parse[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//              log_ps2mouse_parse[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//              to_log(log_ps2mouse_parse);
//      }
//#endif

        ps2mouse_release_clk();
}