| 1 | #include <termios.h> |
|---|
| 2 | #include <iostream> |
|---|
| 3 | #include <string> |
|---|
| 4 | #include <sstream> |
|---|
| 5 | #include <fcntl.h> |
|---|
| 6 | #include <sys/select.h> |
|---|
| 7 | #include <pthread.h> |
|---|
| 8 | #include "gainer.h" |
|---|
| 9 | #include <iomanip> |
|---|
| 10 | |
|---|
| 11 | #define ABORT_UNLESS(stmt) \ |
|---|
| 12 | if (!((stmt))) { \ |
|---|
| 13 | std::stringstream msg(""); \ |
|---|
| 14 | msg << "failed in L" << __LINE__ << ": "; \ |
|---|
| 15 | perror(msg.str().c_str()); \ |
|---|
| 16 | abort(); \ |
|---|
| 17 | } |
|---|
| 18 | |
|---|
| 19 | #ifdef DEBUG |
|---|
| 20 | #define DEBUG_PRINT(msg) std::cerr << msg << std::endl; |
|---|
| 21 | #else |
|---|
| 22 | #define DEBUG_PRINT(msg) ; |
|---|
| 23 | #endif // DEBUG |
|---|
| 24 | |
|---|
| 25 | void *Gainer::receiver(void *arg) { |
|---|
| 26 | Gainer *self(reinterpret_cast<Gainer *>(arg)); |
|---|
| 27 | |
|---|
| 28 | struct timeval timeout; |
|---|
| 29 | timeout.tv_sec = 1; |
|---|
| 30 | timeout.tv_usec = 0; |
|---|
| 31 | |
|---|
| 32 | while (not self->end_) { |
|---|
| 33 | //DEBUG_PRINT("next_event..."); |
|---|
| 34 | |
|---|
| 35 | fd_set fds; |
|---|
| 36 | FD_ZERO(&fds); |
|---|
| 37 | FD_SET(self->io_, &fds); |
|---|
| 38 | |
|---|
| 39 | int ret(select(self->io_+1, &fds, NULL, NULL, &timeout)); |
|---|
| 40 | if (0 != ret) { |
|---|
| 41 | //DEBUG_PRINT("receiver: selected"); |
|---|
| 42 | const size_t SIZE(80); |
|---|
| 43 | char buf[SIZE]; |
|---|
| 44 | char ch(' '); |
|---|
| 45 | size_t i(0); |
|---|
| 46 | while ('*' != ch and i<SIZE) { |
|---|
| 47 | read(self->io_, &ch, 1); |
|---|
| 48 | buf[i++] = ch; |
|---|
| 49 | } |
|---|
| 50 | //read(self->io_, buf, SIZE); |
|---|
| 51 | //DEBUG_PRINT(buf); |
|---|
| 52 | std::string s(buf); |
|---|
| 53 | |
|---|
| 54 | self->process_event(s); |
|---|
| 55 | } |
|---|
| 56 | } |
|---|
| 57 | return NULL; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | namespace Gainer { |
|---|
| 61 | Gainer::Gainer(const std::string &path, int config) : |
|---|
| 62 | led_(false) |
|---|
| 63 | , config_(config) |
|---|
| 64 | , end_(false) |
|---|
| 65 | , on_pressed(NULL) |
|---|
| 66 | , on_released(NULL) |
|---|
| 67 | { |
|---|
| 68 | ABORT_UNLESS(-1 != (io_ = open(path.c_str(), O_RDWR))); |
|---|
| 69 | ABORT_UNLESS(-1 != fsync(io_)); |
|---|
| 70 | setup_port(); |
|---|
| 71 | pthread_create(&thread_, NULL, receiver, this); |
|---|
| 72 | reboot(); |
|---|
| 73 | set_configuration(config_); |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | Gainer::~Gainer() { |
|---|
| 77 | reboot(); |
|---|
| 78 | end_ = true; |
|---|
| 79 | pthread_join(thread_, NULL); |
|---|
| 80 | close(io_); |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | void Gainer::setup_port() { |
|---|
| 84 | struct termios term; |
|---|
| 85 | ABORT_UNLESS(0 == tcgetattr(io_, &term)); |
|---|
| 86 | ABORT_UNLESS(0 == cfsetispeed(&term, B38400)); |
|---|
| 87 | ABORT_UNLESS(0 == cfsetospeed(&term, B38400)); |
|---|
| 88 | term.c_cflag |= CS8; |
|---|
| 89 | ABORT_UNLESS(0 == tcsetattr(io_, TCSANOW, &term)); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | void Gainer::set_configuration(int number) { |
|---|
| 93 | if (1 > number or number > 7) |
|---|
| 94 | throw GainerInternal::Exception(); |
|---|
| 95 | |
|---|
| 96 | config_ = number; |
|---|
| 97 | std::stringstream ss(""); |
|---|
| 98 | ss << "KONFIGURATION_" << number; |
|---|
| 99 | command(ss.str(), 1); |
|---|
| 100 | |
|---|
| 101 | for (int i(0); i<CONFIG[config_][AIN]; i++) // create analog inputs |
|---|
| 102 | analog_inputs.push_back(0); |
|---|
| 103 | |
|---|
| 104 | for (int i(0); i<CONFIG[config_][DIN]; i++) // create digital inputs |
|---|
| 105 | digital_inputs.push_back(false); |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | // void Gainer::set_matrix(ary) // TODO |
|---|
| 109 | |
|---|
| 110 | void Gainer::set_led(bool flag) { command(flag ? "h" : "l"); } |
|---|
| 111 | void Gainer::reboot() { command("Q", 2); } |
|---|
| 112 | void Gainer::peek_digital_inputs() { command("R"); } |
|---|
| 113 | void Gainer::peek_analog_inputs() { command("I"); } |
|---|
| 114 | void Gainer::continuous_digital_inputs() { command("r"); } |
|---|
| 115 | void Gainer::continuous_analog_inputs() { command("i"); } |
|---|
| 116 | void Gainer::exit_continuos() { command("E"); } |
|---|
| 117 | |
|---|
| 118 | void Gainer::set_digital_output(int n) { |
|---|
| 119 | std::stringstream ss("D"); |
|---|
| 120 | for (int i(0); i< CONFIG[config_][DOUT]-1; i++) |
|---|
| 121 | ss << ' '; |
|---|
| 122 | ss << n; |
|---|
| 123 | command(ss.str()); |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | void Gainer::command(const std::string &cmd, int wait) { |
|---|
| 127 | command_send(cmd + '*'); |
|---|
| 128 | sleep(wait); |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | void Gainer::command_send(const std::string &cmd) { |
|---|
| 132 | write(io_, cmd.c_str(), cmd.size()); |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | void Gainer::process_event(std::string &event) { |
|---|
| 136 | //DEBUG_PRINT("event: " << event); |
|---|
| 137 | switch(event[0]) { |
|---|
| 138 | case '!': // something wrong |
|---|
| 139 | throw GainerInternal::Exception(); |
|---|
| 140 | case 'h': // led on |
|---|
| 141 | led_ = true; |
|---|
| 142 | break; |
|---|
| 143 | case 'l': // led off |
|---|
| 144 | led_ = false; |
|---|
| 145 | break; |
|---|
| 146 | case 'N': // button pressed |
|---|
| 147 | on_pressed(); |
|---|
| 148 | break; |
|---|
| 149 | case 'F': // button released |
|---|
| 150 | on_released(); |
|---|
| 151 | break; |
|---|
| 152 | case 'i': |
|---|
| 153 | case 'I': { // analog_input |
|---|
| 154 | std::string::size_type ast(event.find('*')); |
|---|
| 155 | std::string s(event.substr(1, ast-1)); |
|---|
| 156 | sscanf(s.c_str(), "%02X%02X%02X%02X*", |
|---|
| 157 | &analog_inputs[0], &analog_inputs[1], |
|---|
| 158 | &analog_inputs[2], &analog_inputs[3]); |
|---|
| 159 | break; |
|---|
| 160 | } |
|---|
| 161 | case 'r': |
|---|
| 162 | case 'R': { // digital input |
|---|
| 163 | std::string::size_type ast(event.find('*')); |
|---|
| 164 | std::stringstream ss(event.substr(1, ast-1)); |
|---|
| 165 | int num; |
|---|
| 166 | ss >> std::hex >> num; |
|---|
| 167 | for (size_t i(0); i<digital_inputs.size(); i++) |
|---|
| 168 | digital_inputs[i] = num & (1<<i); |
|---|
| 169 | break; |
|---|
| 170 | } |
|---|
| 171 | default: |
|---|
| 172 | break; |
|---|
| 173 | } |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | const int Gainer::CONFIG[][4] = { |
|---|
| 177 | // N_AIN, N_DIN, N_AOUT, N_DOUT |
|---|
| 178 | {0,}, // dummy |
|---|
| 179 | {4, 4, 4, 4}, // 1 |
|---|
| 180 | {8, 0, 4, 4}, // 2 |
|---|
| 181 | {4, 4, 8, 0}, // 3 |
|---|
| 182 | {8, 0, 8, 0}, // 4 |
|---|
| 183 | {0,16, 0, 0}, // 5 |
|---|
| 184 | {0, 0, 0,16}, // 6 |
|---|
| 185 | {0,} // 7 for matrix LED |
|---|
| 186 | }; |
|---|
| 187 | |
|---|
| 188 | } // Gainer |
|---|