Skip to content

Instantly share code, notes, and snippets.

@3Nigma
Last active December 16, 2015 05:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 3Nigma/5384236 to your computer and use it in GitHub Desktop.
Save 3Nigma/5384236 to your computer and use it in GitHub Desktop.
Antetul (.h) și codul suport (.c) al librăriei avrps2m responsabilă de comunicațiile între un dispozitiv AVR și un mouse PS/2.
/*
* Modul de comunicatii AVR-PS/2 Mouse
* Copyright (c) 2013, Victor ADASCALITEI, admin@tuscale.ro
*
* Eliberez aceste surse sub licenta CC de tip BY-NC-SA 3.0 . Pentru mai multe informatii, va invit sa accesati
* urmatoarea adresa : http://creativecommons.org/licenses/by-nc-sa/3.0/ro/ .
*/
#include <avr/interrupt.h>
#define F_CPU 9600000UL
#include <util/delay.h>
#include "ps2mouse.h"
/* regiune de variabile interne folosite de modul */
uint8_t ps2m_nr_bit_linie = 0;
uint8_t ps2m_rx_octet = 0;
ps2m_dir_comunicatii ps2m_tip_actiune = PS2M_COM_MOUSE_LA_GAZDA;
uint8_t ps2m_paritate_date = 0;
volatile uint8_t ps2m_tx_octet = 0;
uint8_t ps2m_rx_octet_valid = 0;
volatile uint8_t ps2m_rx_date_primite = 0;
uint8_t ps2m_rezolutie_curenta = 4;
/* regiunea functiilor interne folosite de catre modul */
void ps2m_trimite_la_mouse(uint8_t date) {
/* tragem linia de tact la '0' pentru cel putin 100us.
Preluam datele ce le dorim transmise catre mouse si pregatim rutina de intrerupere exterioara intre timp */
DDRB |= PS2M_PIN_TACT;
ps2m_tx_octet = date;
ps2m_tip_actiune = PS2M_COM_GAZDA_LA_MOUSE;
ps2m_nr_bit_linie = 0;
_delay_us(100);
/* apoi tragem linia de date la acelasi potential '0' */
DDRB |= PS2M_PIN_DATE;
/* eliberam linia ceasului (trece pe valoare '1') */
DDRB &= ~PS2M_PIN_TACT;
/* asteptam ca mouseul sa inceapa sesiunea de comunicatii pentru a-i trimite datele */
}
uint8_t ps2m_asteapta_date(void) {
while (ps2m_rx_date_primite == 0);
ps2m_rx_date_primite = 0;
return ps2m_rx_octet_valid;
}
extern ps2m_finalitate ps2m_citeste_configuratie(ps2m_st_stare *pdStare) {
ps2m_finalitate finalitateFct = PS2M_ESUAT;
ps2m_trimite_la_mouse(PS2M_COM_GAZDA_OBT_STARE);
if (ps2m_asteapta_date() == PS2M_COM_GAZDA_ACK) {
pdStare->bitiStare = ps2m_asteapta_date();
pdStare->rezolutie = ps2m_asteapta_date();
pdStare->rataEsantionare = ps2m_asteapta_date();
finalitateFct = PS2M_OK;
}
return finalitateFct;
}
extern ps2m_finalitate ps2m_citeste_deplasamente(ps2m_st_date *pdDate) {
ps2m_finalitate finalitateFct = PS2M_ESUAT;
ps2m_trimite_la_mouse(PS2M_COM_GAZDA_OBT_DEPLASAMENTE);
if (ps2m_asteapta_date() == PS2M_COM_GAZDA_ACK) {
pdDate->bitiStare = ps2m_asteapta_date();
pdDate->deplasareX = ps2m_asteapta_date();
pdDate->deplasareY = ps2m_asteapta_date();
finalitateFct = PS2M_OK;
}
return finalitateFct;
}
extern ps2m_finalitate ps2m_init(void) {
int8_t rezultatInitializare = PS2M_ESUAT;
/* introducem o mica intarziere pentru a lasa lucrurile sa se linisteasca (tensiuni si alte cele) */
_delay_ms(100);
/* configuram linia de tact pentru a declansa întreruperi externe.
Pornim de la premiza ca mouseul va transmite primul date (pe front descrescator de tact) */
MCUCR |= _BV(ISC01);
GIMSK |= _BV(INT0);
sei();
/* pornim de la nivele cunoscute de tensiuni pe pini */
PS2M_PIN_REGISTRU_SCRIERE &= ~(PS2M_PIN_DATE | PS2M_PIN_TACT);
/* verificam linia de comunicatii cu mouse-ul reinitializând-o */
ps2m_trimite_la_mouse(PS2M_COM_GAZDA_RESET);
if (ps2m_asteapta_date() == PS2M_COM_GAZDA_ACK &&
ps2m_asteapta_date() == PS2M_COM_GAZDA_BAT && ps2m_asteapta_date() == PS2M_COM_GAZDA_ID) {
/* totul în regula pâna aici. Activam modul de raportare a coordonatelor la cerere */
ps2m_trimite_la_mouse(PS2M_COM_GAZDA_LA_CERERE);
if (ps2m_asteapta_date() == PS2M_COM_GAZDA_ACK) {
/* modul a fost selectat cu succes, iar initializarea s-a încheiat cu succes */
rezultatInitializare = PS2M_OK;
}
}
return rezultatInitializare;
}
ISR(INT0_vect) {
/* avansam numarul de biti primiti/transmisi */
ps2m_nr_bit_linie ++;
if (ps2m_tip_actiune == PS2M_COM_MOUSE_LA_GAZDA) {
/* regiunea de comunicatie de tip mouse-la-gazda.
Datele sunt valide pe frontul descrescator a semnalului de tact */
if (ps2m_nr_bit_linie > 1 && ps2m_nr_bit_linie < 10) {
/* integram bitul valid de date în octetul curent.
Octetul este transmis cu bitul cel mai putin semnificativ (MSB) primul. */
ps2m_rx_octet = ps2m_rx_octet >> 1;
if ((PS2M_PIN_REGISTRU_CITIRE & PS2M_PIN_DATE) != 0) {
ps2m_rx_octet |= 0x80;
}
} else if (ps2m_nr_bit_linie == 11) {
/* ignoram bitul de paritate ('1' -> daca octetul primit continea un numar par de biti '1' si '0' daca el continea un numar impar de biti '1')
si preluam datele pe bitul de 'stop' */
ps2m_rx_octet_valid = ps2m_rx_octet;
ps2m_rx_date_primite = 1;
ps2m_nr_bit_linie = 0;
}
} else {
/* comunicatie de tip gazda-la-mouse
Se evalueaza pe frontul crescator a semnalului de tact */
if (ps2m_nr_bit_linie < 9) {
/* trimitem cei 8 biti doriti in maniera "celui mai putin semnificativ bit" primul (MSB) */
if ((ps2m_tx_octet & 0x01) == 0) {
PS2M_PIN_REGISTRU_DIRECTIE |= PS2M_PIN_DATE;
} else {
PS2M_PIN_REGISTRU_DIRECTIE &= ~PS2M_PIN_DATE;
ps2m_paritate_date ^= 1;
}
ps2m_tx_octet >>= 1;
} else if (ps2m_nr_bit_linie == 9){
/* transmitem bitul de paritate ('1' pentru numar par de '1' transmisi si '0' in caz contrar) */
if (ps2m_paritate_date == 0) {
PS2M_PIN_REGISTRU_DIRECTIE &= ~PS2M_PIN_DATE;
} else {
PS2M_PIN_REGISTRU_DIRECTIE |= PS2M_PIN_DATE;
}
} else if (ps2m_nr_bit_linie == 10){
/* eliberam linia de date */
PS2M_PIN_REGISTRU_DIRECTIE &= ~PS2M_PIN_DATE;
} else {
/* secventa de transmitere s-a incheiat, aducem sistemul intr-o stare de asteptare a raspunsului de la mouse */
ps2m_tip_actiune = PS2M_COM_MOUSE_LA_GAZDA;
ps2m_nr_bit_linie = 0;
}
}
}
/*
* Modul de comunicatii AVR-PS/2 Mouse
* Copyright (c) 2013, Victor ADASCALITEI, admin@tuscale.ro
*
* Eliberez aceste surse sub licenta CC de tip BY-NC-SA 3.0 . Pentru mai multe informatii, va invit sa accesati
* urmatoarea adresa : http://creativecommons.org/licenses/by-nc-sa/3.0/ro/ .
*/
#ifndef _PS2MOUSE_H_
#define _PS2MOUSE_H_
#include <avr/io.h>
/* definitii de elemente fizice (pini/registrii) folosite de catre modul */
#define PS2M_PIN_DATE _BV(PB4)
#define PS2M_PIN_TACT _BV(PB1)
#define PS2M_PIN_REGISTRU_DIRECTIE DDRB
#define PS2M_PIN_REGISTRU_SCRIERE PORTB
#define PS2M_PIN_REGISTRU_CITIRE PINB
/* pachete de date (octeti) cu interpretare speciala in sistem */
#define PS2M_COM_GAZDA_RESET 0xFF
#define PS2M_COM_GAZDA_OBT_DEPLASAMENTE 0xEB
#define PS2M_COM_GAZDA_ACK 0xFA
#define PS2M_COM_GAZDA_BAT 0xAA
#define PS2M_COM_GAZDA_ID 0x00
#define PS2M_COM_GAZDA_LA_CERERE 0xF0
#define PS2M_COM_GAZDA_OBT_STARE 0xE9
/* regiune de masti pentru bitii de stare ('bitiStare') din structura 'ps2m_st_stare' */
#define PS2M_ST_MOD_MSC 0x40
#define PS2M_ST_SCALARE_MSC 0x20
#define PS2M_ST_BT_STANGA_MSC 0x04
#define PS2M_ST_BT_MIJLOC_MSC 0x02
#define PS2M_ST_BT_DREAPTA_MSC 0x01
/* regiune de masti pentru bitii de stare ('bitiStare') din structura 'ps2m_st_date' */
#define PS2M_DT_DEPASIRE_Y_MSK 0x80
#define PS2M_DT_DEPASIRE_X_MSK 0x40
#define PS2M_DT_SEMN_Y_MSK 0x20 /* '1' pentru deplasare in jos si '0' pentru miscare in sus */
#define PS2M_DT_SEMN_X_MSK 0x10 /* '1' -> deplasare la stanga, iar '0' -> deplasare la dreapta */
#define PS2M_DT_BT_STANGA_MSC 0x01
#define PS2M_DT_BT_MIJLOC_MSC 0x04
#define PS2M_DT_BT_DREAPTA_MSC 0x02
/* regiunea enumerarilor folosite in modul */
typedef enum {PS2M_OK, PS2M_ESUAT} ps2m_finalitate;
typedef enum {PS2M_COM_GAZDA_LA_MOUSE, PS2M_COM_MOUSE_LA_GAZDA} ps2m_dir_comunicatii;
typedef enum {PS2M_DT_DX_STANGA, PS2M_DT_DX_DREAPTA} ps2m_dir_depl_x;
typedef enum {PS2M_DT_DY_SUS, PS2M_DT_DY_JOS} ps2m_dir_depl_y;
/* structurile de date relevante pentru modul */
typedef struct {
uint8_t bitiStare;
uint8_t deplasareX;
uint8_t deplasareY;
} ps2m_st_date;
typedef struct {
uint8_t bitiStare;
uint8_t rezolutie;
uint8_t rataEsantionare;
} ps2m_st_stare;
/* variabile folosite in functiile substituibile (inline) de mai jos */
extern uint8_t ps2m_rezolutie_curenta;
/* functiile disponibile din modul */
extern ps2m_finalitate ps2m_init(void);
extern ps2m_finalitate ps2m_citeste_configuratie(ps2m_st_stare *pdStare);
extern ps2m_finalitate ps2m_citeste_deplasamente(ps2m_st_date *pdDate);
inline uint8_t ps2m_este_buton_stanga_apasat(ps2m_st_date *pdDate) {
return (pdDate->bitiStare & PS2M_DT_BT_STANGA_MSC) != 0;
}
inline uint8_t ps2m_este_buton_mijloc_apasat(ps2m_st_date *pdDate) {
return (pdDate->bitiStare & PS2M_DT_BT_MIJLOC_MSC) != 0;
}
inline uint8_t ps2m_este_buton_dreapta_apasat(ps2m_st_date *pdDate) {
return (pdDate->bitiStare & PS2M_DT_BT_DREAPTA_MSC) != 0;
}
inline uint8_t ps2m_obtine_val_deplasament_brut_x(ps2m_st_date *pdDate) {
return pdDate->deplasareX;
}
inline double ps2m_obtine_val_deplasament_mm_x(ps2m_st_date *pdDate) {
return ((double)ps2m_obtine_val_deplasament_brut_x(pdDate))/ps2m_rezolutie_curenta;
}
inline ps2m_dir_depl_x ps2m_obtine_dir_deplasament_x(ps2m_st_date *pdDate) {
if ((pdDate->bitiStare & PS2M_DT_SEMN_X_MSK) != 0) {
return PS2M_DT_DX_STANGA;
}
return PS2M_DT_DX_DREAPTA;
}
inline uint8_t ps2m_obtine_val_deplasament_brut_y(ps2m_st_date *pdDate) {
return pdDate->deplasareY;
}
inline double ps2m_obtine_val_deplasament_mm_y(ps2m_st_date *pdDate) {
return ((double)ps2m_obtine_val_deplasament_brut_y(pdDate))/ps2m_rezolutie_curenta;;
}
inline ps2m_dir_depl_y ps2m_obtine_dir_deplasament_y(ps2m_st_date *pdDate) {
if ((pdDate->bitiStare & PS2M_DT_SEMN_Y_MSK) != 0) {
return PS2M_DT_DY_JOS;
}
return PS2M_DT_DY_SUS;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment