summaryrefslogtreecommitdiff
path: root/rotaryencoder.cpp
blob: 62ca33da7abd4ef9bf800d1fe9efb2132fbe2f80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "rotaryencoder.h"

#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <vector>

#include <QDebug>
#include <QElapsedTimer>

#include <wiringPi.h>

// got from https://gist.github.com/ast/a19813fce9d34c7240091db11b8190dd
// https://gist.github.com/ast
// Inspired by Paul Stoffregen's excellent Arduino library Encoder:
// https://github.com/PaulStoffregen/Encoder

constexpr int gpioA = 17;
constexpr int gpioB = 27;
// constexpr int gpioA = 0;
// constexpr int gpioB = 2;
// constexpr int gpioA = 11;
// constexpr int gpioB = 13;

const std::vector<int> encoderTable = {
    0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0
};

volatile int32_t positionSteps;
volatile uint8_t state;

void pin_isr(void) {
    uint8_t p1val = digitalRead(gpioA);
    uint8_t p2val = digitalRead(gpioB);
    uint8_t s = state & 3;

    if (p1val) s |= 4;
    if (p2val) s |= 8;

    state = (s >> 2);

    switch (s) {
    case 1: case 7: case 8: case 14:
        positionSteps = positionSteps + 1;
        return;
    case 2: case 4: case 11: case 13:
        positionSteps = positionSteps - 1;
        return;
    case 3: case 12:
        positionSteps = positionSteps + 2;
        return;
    case 6: case 9:
        positionSteps = positionSteps - 2;
        return;
    }
}

RotaryEncoder::RotaryEncoder()
{
    if (!m_self) {
        m_self = this;
    } else {
        qWarning() << "normally there should be only one instance of RotaryEncoder";
    }

    QElapsedTimer t;
    t.start();

    if (wiringPiSetupGpio()) {
        perror("wiringPiSetupGpio");
        exit(EXIT_FAILURE);
    }

    qDebug() << "msecs to setup wiringPi:" << t.elapsed();

    if ( wiringPiISR (gpioA, INT_EDGE_BOTH, &pin_isr) < 0 ) {
        perror("wiringPiISR");
        exit(EXIT_FAILURE);
    }

    qDebug() << "msecs to register interruption A:" << t.elapsed();

    if ( wiringPiISR (gpioB, INT_EDGE_BOTH, &pin_isr) < 0 ) {
        perror("wiringPiISR");
        exit(EXIT_FAILURE);
    }

    qDebug() << "msecs to register interruption B:" << t.elapsed();

    // pinMode (gpioA,  INPUT) ;
    // pinMode (gpioB,  INPUT) ;
    // pullUpDnControl(gpioA, PUD_UP);
    // pullUpDnControl(gpioB, PUD_UP);

    qDebug() << "encoder is ok";

    // // Show position every second
    // while ( 1 ) {
    //     constexpr double stepsPerMm = 200;
    //     const double positionMm = ::positionSteps / stepsPerMm;
    //     qDebug() << ::positionSteps
    //              << '-'
    //              << QString::number(positionMm, 'f', 3)
    //              << "(mm)";
    //     // printf( "%ld\n", ::position);
    //     usleep( 100 * 1000 ); // wait 1 second
    // }
}

RotaryEncoder::~RotaryEncoder()
{
    if (m_self == this) {
        m_self = nullptr;
    }
}

RotaryEncoder *RotaryEncoder::instance()
{
    return m_self;
}

int32_t RotaryEncoder::position() const
{
    return ::positionSteps;
}