Project

General

Profile

Statistics
| Revision:

root / lab4 / state_machine.c @ 78

History | View | Annotate | Download (5.63 KB)

1
#include <lcom/lcf.h>
2

    
3
#include "state_machine.h"
4
#include "mouse_macros.h"
5
#include "mouse.h"
6
#include "errors.h"
7

    
8
struct mouse_ev* mouse_get_event(struct packet *pp) {
9

    
10
    static struct mouse_ev event;
11
    static struct packet last; // compare consecutive events
12
    static int aux = 1; // first iteration
13

    
14
    if (pp == NULL)
15
        return &event;
16

    
17
    // current packet
18
    uint8_t lb_press = pp->bytes[0] & LEFT_BUTTON;
19
    uint8_t rb_press = pp->bytes[0] & RIGHT_BUTTON;
20
    uint8_t mb_press = pp->bytes[0] & MIDDLE_BUTTON;
21
    int16_t delta_x = sign_extend_byte(pp->bytes[0] & MSB_X_DELTA, pp->bytes[1]);
22
    int16_t delta_y = sign_extend_byte(pp->bytes[0] & MSB_Y_DELTA, pp->bytes[2]);
23

    
24
    if (aux) { // first event detected
25
        if (lb_press && (rb_press | mb_press) == 0 && delta_x == 0 && delta_y == 0)
26
            event.type = LB_PRESSED;
27
        else if (rb_press && (lb_press | mb_press) == 0 && delta_x == 0 && delta_y == 0)
28
            event.type = RB_PRESSED;
29
        else if ((delta_x || delta_y) && (lb_press | rb_press | mb_press) == 0) {
30
            event.type = MOUSE_MOV;
31
            event.delta_x = delta_x;
32
            event.delta_y = delta_y;
33
        } else
34
            event.type = BUTTON_EV;
35
        aux = 0;
36
    } else {
37
        // last packet
38
        uint8_t last_lb_press = last.bytes[0] & LEFT_BUTTON;
39
        uint8_t last_rb_press = last.bytes[0] & RIGHT_BUTTON;
40
        uint8_t last_mb_press = last.bytes[0] & MIDDLE_BUTTON;
41

    
42
        if (lb_press && (rb_press | mb_press) == 0 && delta_x == 0 && delta_y == 0 && last_lb_press == 0)
43
            event.type = LB_PRESSED;
44
        else if (rb_press && (lb_press | mb_press) == 0 && delta_x == 0 && delta_y == 0 && last_rb_press == 0)
45
            event.type = RB_PRESSED;
46
        else if ((lb_press | rb_press | mb_press) == 0 && delta_x == 0 && delta_y == 0 && last_lb_press)
47
            event.type = LB_RELEASED;
48
        else if ((lb_press | rb_press | mb_press) == 0 && delta_x == 0 && delta_y == 0 && last_rb_press)
49
            event.type = RB_RELEASED;
50
        else if ((delta_x || delta_y) && (lb_press | rb_press | mb_press) == (last_lb_press | last_rb_press | last_mb_press)) {
51
            event.type = MOUSE_MOV;
52
            event.delta_x = delta_x;
53
            event.delta_y = delta_y;
54
        } else
55
            event.type = BUTTON_EV;
56
    }
57

    
58
    // update last packet for comparison
59
    last = *pp;
60

    
61
    return &event;
62
}
63

    
64
int state_machine(struct mouse_ev* event, uint8_t x_len, uint8_t tolerance) {
65

    
66
    static enum states state = INITIAL;
67
    static int response = OTHER_ERROR;
68
    static int x_length = 0;
69
    static int y_length = 0;
70

    
71
    if (event == NULL)
72
        return response;
73

    
74
    switch (state) {
75
        case INITIAL:
76
            if (event->type == LB_PRESSED)
77
                state = DRAG_UP;
78
            break;
79
        case DRAG_UP:
80
            if (event->type == MOUSE_MOV) {
81
                if (abs(event->delta_x) > tolerance || abs(event->delta_y) > tolerance) {
82
                    state = INITIAL;
83
                    x_length = 0;
84
                    y_length = 0;
85
                    break;
86
                }
87

    
88
                x_length += event->delta_x;
89
                y_length += event->delta_y;
90
            } else if (event->type == LB_RELEASED) {
91
                if (x_length == 0 || y_length == 0) {
92
                    state = INITIAL;
93
                    break;
94
                }
95

    
96
                int slope = y_length / x_length;
97

    
98
                if (slope <= 1 || x_length < x_len) {
99
                    state = INITIAL;
100
                    x_length = 0;
101
                    y_length = 0;
102
                    break;
103
                }
104

    
105
                state = VERTEX;
106
                x_length = 0;
107
                y_length = 0;
108
            } else {
109
                state = INITIAL;
110
                x_length = 0;
111
                y_length = 0;
112
            }
113
            break;
114
        case VERTEX:
115
            if (event->type == MOUSE_MOV) {
116
                if (abs(event->delta_x) > tolerance || abs(event->delta_y) > tolerance)
117
                    state = INITIAL;
118
            } else if (event->type == RB_PRESSED) {
119
                state = DRAG_DOWN;
120
            } else if (event->type == LB_PRESSED) {
121
                state = DRAG_UP;
122
            } else
123
                state = INITIAL;
124
            break;
125
        case DRAG_DOWN:
126
            if (event->type == MOUSE_MOV) {
127
                if (abs(event->delta_x) > tolerance || abs(event->delta_y) > tolerance) {
128
                    state = INITIAL;
129
                    x_length = 0;
130
                    y_length = 0;
131
                    break;
132
                }
133

    
134
                x_length += event->delta_x;
135
                y_length += event->delta_y;
136
            } else if (event->type == RB_RELEASED) {
137
                if (x_length == 0 || y_length == 0) {
138
                    state = INITIAL;
139
                    break;
140
                }
141

    
142
                int slope = y_length / x_length;
143

    
144
                if (slope >= -1 || x_length < x_len) {
145
                    state = INITIAL;
146
                    x_length = 0;
147
                    y_length = 0;
148
                    break;
149
                }
150

    
151
                state = FINAL;
152
                x_length = 0;
153
                y_length = 0;
154
            } else {
155
                state = INITIAL;
156
                x_length = 0;
157
                y_length = 0;
158
            }
159
            break;
160
        case FINAL: // acception state
161
            response = SUCCESS;
162
        default: // invalid state / dead state
163
            response = INVALID_STATE;
164
    }
165
    return response;
166
}