From e62be3b12d3c94d709a77d89f52c31f7c4ac475d Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 4 Dec 2021 22:22:47 -0800 Subject: Initial commit. --- arduino/Counter.cc | 98 ++++++++++++++++++++++ arduino/Counter.h | 45 +++++++++++ arduino/Makefile | 4 + arduino/config.cc | 61 ++++++++++++++ arduino/config.h | 12 +++ arduino/rpmcount.ino | 147 +++++++++++++++++++++++++++++++++ desktop/main.cc | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ desktop/rpmcount.pro | 15 ++++ desktop/serial_utils.h | 33 ++++++++ desktop/term.cc | 28 +++++++ desktop/term.h | 3 + desktop/types.h | 27 +++++++ 12 files changed, 688 insertions(+) create mode 100755 arduino/Counter.cc create mode 100755 arduino/Counter.h create mode 100755 arduino/Makefile create mode 100755 arduino/config.cc create mode 100755 arduino/config.h create mode 100755 arduino/rpmcount.ino create mode 100755 desktop/main.cc create mode 100755 desktop/rpmcount.pro create mode 100755 desktop/serial_utils.h create mode 100755 desktop/term.cc create mode 100755 desktop/term.h create mode 100755 desktop/types.h diff --git a/arduino/Counter.cc b/arduino/Counter.cc new file mode 100755 index 0000000..abf7c27 --- /dev/null +++ b/arduino/Counter.cc @@ -0,0 +1,98 @@ +#include "Counter.h" + +#include + +void Counter::init (unsigned long startDelay, unsigned long rpmCount, unsigned long signalsPerRPM) +{ + this->startDelay = startDelay; + this->rpmCount = rpmCount; + this->signalsPerRPM = signalsPerRPM; + reset(); +} + +void Counter::setStartDelay (unsigned long val) +{ + startDelay = val; +} + +void Counter::setRPMCount (unsigned long val) +{ + rpmCount = val; +} + +void Counter::setSignalsPerRPM (unsigned long val) +{ + signalsPerRPM = val; +} + +void Counter::start (unsigned long startTime) +{ + if (state == READY) + { + this->startTime = startTime; + state = WAITING_FOR_TIMEOUT; + } +} + +void Counter::reset () +{ + state = READY; +} + +void Counter::update (unsigned long t, int rpmSignal) +{ + switch (state) + { + case WAITING_FOR_TIMEOUT: + { + if (t - startTime >= startDelay) + { + startTime = t; // Update start time for counting state + signals = 0; + state = COUNTING; + } + break; + } + case COUNTING: + { + // Count signals in 1 second intervals + if (lastRpmSignal != rpmSignal && rpmSignal == HIGH) + { + signals++; + } + // 1 second interval reached + if (t - startTime >= 1000) + { + float rpm = ((float) signals / (float) signalsPerRPM) * 60.0f; + if (rpm <= rpmCount) + { + startTime = t; // Update start time for signaling state + state = SIGNALING; + } + else + { + // RPM threshold not reached. + // Count signals per second from scratch. + //Serial.print("rpm: \r\n"); Serial.print(rpm); Serial.print("\r\n"); + startTime = t; + signals = 0; + } + } + break; + } + case SIGNALING: + { + if (t - startTime >= 3000) + { + state = READY; + } + } + default: break; + } + lastRpmSignal = rpmSignal; +} + +Counter::State Counter::getState () const +{ + return state; +} diff --git a/arduino/Counter.h b/arduino/Counter.h new file mode 100755 index 0000000..f832023 --- /dev/null +++ b/arduino/Counter.h @@ -0,0 +1,45 @@ +#pragma once + +class Counter +{ +public: + + enum State + { + READY, + WAITING_FOR_TIMEOUT, + COUNTING, + SIGNALING + }; + +public: + + void init (unsigned long startDelay, unsigned long rpmCount, unsigned long signalsPerRPM); + + void setStartDelay (unsigned long); + + void setRPMCount (unsigned long); + + void setSignalsPerRPM (unsigned long); + + void start (unsigned long startTime); + + void reset (); + + void update (unsigned long time, int rpmSignal); + + State getState () const; + +private: + + State state; + + unsigned long startDelay; + unsigned long rpmCount; + unsigned long signalsPerRPM; + unsigned long startTime; + + unsigned long signals; + + bool lastRpmSignal; +}; diff --git a/arduino/Makefile b/arduino/Makefile new file mode 100755 index 0000000..54884fa --- /dev/null +++ b/arduino/Makefile @@ -0,0 +1,4 @@ +#ARDUINO_LIBS = +BOARD_TAG = uno +MONITOR_PORT = /dev/ttyACM0 +include /usr/share/arduino/Arduino.mk diff --git a/arduino/config.cc b/arduino/config.cc new file mode 100755 index 0000000..a46c663 --- /dev/null +++ b/arduino/config.cc @@ -0,0 +1,61 @@ +#include "config.h" + +#include +#include + +#define ROM_INITIALISED 17 + +#define DEFAULT_SIGNALS_PER_RPM 133 +#define DEFAULT_START_DELAY_MILLIS 1000 +#define DEFAULT_RPM_COUNT 5000 + +static Config config; + +int writeLong (int address, unsigned long val) +{ + const char* p = (char*) &val; + int i = 0; + for (; i < sizeof(val); ++i, ++p) + { + EEPROM.write(address + i, *p); + } + return address + i; +} + +int readLong (int address, unsigned long& val) +{ + char* p = (char*) &val; + int i = 0; + for (; i < sizeof(val); ++i, ++p) + { + *p = EEPROM.read(address + i); + } + return address + i; +} + +const Config& readConfig () +{ + byte initialised = EEPROM.read(0); + if (initialised != ROM_INITIALISED) + { + int addr = 1; + addr = writeLong(addr, DEFAULT_START_DELAY_MILLIS); + addr = writeLong(addr, DEFAULT_RPM_COUNT); + addr = writeLong(addr, DEFAULT_SIGNALS_PER_RPM); + EEPROM.write(0, ROM_INITIALISED); + } + int addr = 1; + addr = readLong(addr, config.startDelay); + addr = readLong(addr, config.rpmCount); + addr = readLong(addr, config.signalsPerRPM); + return config; +} + +void writeConfig (const Config& config) +{ + int addr = 1; + addr = writeLong(addr, config.startDelay); + addr = writeLong(addr, config.rpmCount); + addr = writeLong(addr, config.signalsPerRPM); + EEPROM.write(0, ROM_INITIALISED); +} diff --git a/arduino/config.h b/arduino/config.h new file mode 100755 index 0000000..cb3bf93 --- /dev/null +++ b/arduino/config.h @@ -0,0 +1,12 @@ +#pragma once + +struct Config +{ + unsigned long startDelay; // Start delay in milliseconds + unsigned long rpmCount; // Number of RPM ticks to count + unsigned long signalsPerRPM; // Number of signal ticks per RPM tick +}; + +const Config& readConfig (); + +void writeConfig (const Config&); diff --git a/arduino/rpmcount.ino b/arduino/rpmcount.ino new file mode 100755 index 0000000..51e6bfe --- /dev/null +++ b/arduino/rpmcount.ino @@ -0,0 +1,147 @@ +#include "config.h" +#include "Counter.h" + +#define RPM_INPUT 2 +#define START_BUTTON 3 +#define COUNTING_LED 4 +#define TIMEOUT_LED 5 +#define READY_LED 6 +#define SIGNAL_PIN 7 + +enum ErrorCode +{ + Ok, + Error +}; + +enum MessageHeader +{ + ReadConfig, + UpdateStartDelay, + UpdateRPMCount, + UpdateSignalsPerRPM +}; + +Config config; +Counter counter; + +void setup () +{ + Serial.begin(9600); + + pinMode(RPM_INPUT, INPUT); + pinMode(START_BUTTON, INPUT); + pinMode(COUNTING_LED, OUTPUT); + pinMode(TIMEOUT_LED, OUTPUT); + pinMode(READY_LED, OUTPUT); + pinMode(SIGNAL_PIN, OUTPUT); + config = readConfig(); + counter.init(config.startDelay, config.rpmCount, config.signalsPerRPM); + digitalWrite(READY_LED, HIGH); +} + +void updateSerial () +{ + unsigned long val = -1; + bool sendACK = false; + byte code; + + while (Serial.available() > 0) + { + MessageHeader header = (MessageHeader) Serial.read(); + switch (header) + { + case ReadConfig: + code = Ok; + Serial.write(code); + Serial.write((const uint8_t*) &config.startDelay, sizeof(config.startDelay)); + Serial.write((const uint8_t*) &config.rpmCount, sizeof(config.rpmCount)); + Serial.write((const uint8_t*) &config.signalsPerRPM, sizeof(config.signalsPerRPM)); + Serial.flush(); + break; + + case UpdateStartDelay: + Serial.readBytes((char*)&val, sizeof(val)); + config.startDelay = val; + writeConfig(config); + sendACK = true; + break; + + case UpdateRPMCount: + Serial.readBytes((char*)&val, sizeof(val)); + config.rpmCount = val; + writeConfig(config); + sendACK = true; + break; + + case UpdateSignalsPerRPM: + Serial.readBytes((char*)&val, sizeof(val)); + config.signalsPerRPM = val; + writeConfig(config); + sendACK = true; + break; + + default: + code = Error; + Serial.write(code); + Serial.flush(); + break; + } + } + + if (sendACK) + { + code = Ok; + Serial.write(code); + Serial.write((const uint8_t*) &val, sizeof(val)); + Serial.flush(); + } +} + +void loop () +{ + Counter::State state = counter.getState(); + if (state == Counter::READY) + { + if (digitalRead(START_BUTTON) == HIGH) + { + unsigned long t = millis(); + counter.start(t); + digitalWrite(READY_LED, LOW); + digitalWrite(TIMEOUT_LED, HIGH); + } + else updateSerial(); + } + else if (state == Counter::WAITING_FOR_TIMEOUT) + { + unsigned long t = millis(); + int rpmSignal = digitalRead(RPM_INPUT); + counter.update(t, rpmSignal); + if (counter.getState() == Counter::COUNTING) + { + digitalWrite(TIMEOUT_LED, LOW); + digitalWrite(COUNTING_LED, HIGH); + } + } + else if (state == Counter::COUNTING) + { + unsigned long t = millis(); + int rpmSignal = digitalRead(RPM_INPUT); + counter.update(t, rpmSignal); + if (counter.getState() == Counter::SIGNALING) + { + digitalWrite(COUNTING_LED, LOW); + digitalWrite(SIGNAL_PIN, HIGH); + } + } + else if (state == Counter::SIGNALING) + { + unsigned long t = millis(); + counter.update(t, LOW); + if (counter.getState() == Counter::READY) + { + digitalWrite(SIGNAL_PIN, LOW); + digitalWrite(READY_LED, HIGH); + } + } +} diff --git a/desktop/main.cc b/desktop/main.cc new file mode 100755 index 0000000..ba77e4b --- /dev/null +++ b/desktop/main.cc @@ -0,0 +1,215 @@ +#include "serial_utils.h" +#include "term.h" +#include "types.h" + +#include +#include +#include +#include + +using namespace std; +using namespace LibSerial; + +enum ErrorCode +{ + Ok, + Error +}; + +enum MessageHeader +{ + ReadConfig, + UpdateStartDelay, + UpdateRPMCount, + UpdateSignalsPerRPM +}; + +struct Config +{ + U32 startDelay; // Start delay in milliseconds + U32 rpmCount; // Number of RPM ticks to count + U32 signalsPerRPM; // Number of signal ticks per RPM tick +}; + +template +bool writeSafe (SerialStream& serial, MessageHeader header, const T& val) +{ + write(serial, (U8)header); + write(serial, val); + + U8 errorCode = read(serial); + T x = read(serial); + + fprintf(stderr, "error code: %d\n", errorCode); + fprintf(stderr, "val: %d\n", x); + + return errorCode == Ok && x == val; +} + +bool configureStartDelay (SerialStream& serial, Config& config) +{ + printf("Tiempo de retardo (milisegundos)\n"); + printf("--------------------------------\n"); + printf("\n"); + printf("Valor actual : %d\n", config.startDelay); + printf("\n"); + printf("Nuevo valor : "); + + U32 x; + cin >> x; + + bool result = writeSafe(serial, UpdateStartDelay, x); + if (result) + { + config.startDelay = x; + } + return result; +} + +bool configureRPMCount (SerialStream& serial, Config& config) +{ + printf("RPM maximo\n"); + printf("----------\n"); + printf("\n"); + printf("Valor actual : %d\n", config.rpmCount); + printf("\n"); + printf("Nuevo valor : "); + + U32 x; + cin >> x; + + bool result = writeSafe(serial, UpdateRPMCount, x); + if (result) + { + config.rpmCount = x; + } + return result; +} + +bool configureSignalsPerRPM (SerialStream& serial, Config& config) +{ + printf("Impulsos/RPM\n"); + printf("------------\n"); + printf("\n"); + printf("Valor actual : %d\n", config.signalsPerRPM); + printf("\n"); + printf("Nuevo valor : "); + + U32 x; + cin >> x; + + bool result = writeSafe(serial, UpdateSignalsPerRPM, x); + if (result) + { + config.signalsPerRPM = x; + } + return result; +} + +void loop (SerialStream& serial, Config& config) +{ + int option = -1; + + while (option != 0) + { + system("clear"); + printf("Configuracion\n"); + printf("-------------\n"); + printf("Tiempo de retardo : %d\n", config.startDelay); + printf("RPM maximo : %d\n", config.rpmCount); + printf("Impulsos/rpm : %d\n", config.signalsPerRPM); + printf("\n"); + printf("Menu\n"); + printf("----\n"); + printf("[0] Salir\n"); + printf("[1] Configurar tiempo de retardo\n"); + printf("[2] Configurar RPM maximo\n"); + printf("[3] Configurar impulsos/RPM\n"); + printf("\n"); + printf("> "); + + option = getch() - '0'; + system("clear"); + + bool error = false; + + switch (option) + { + case 1: error = !configureStartDelay(serial, config); break; + case 2: error = !configureRPMCount(serial, config); break; + case 3: error = !configureSignalsPerRPM(serial, config); break; + default: break; + } + + if (error) + { + fprintf(stderr, "Error al escribir valor\n"); + return; + } + } +} + +void readConfig (SerialStream& serial, Config& config) +{ + write(serial, (U8)ReadConfig); + + U8 errorCode = read(serial); + if (errorCode == Ok) + { + config.startDelay = read(serial); + config.rpmCount = read(serial); + config.signalsPerRPM = read(serial); + } +} + +void openArduino (const char* serialDevice, SerialStream& serial) +{ + if (serial.IsOpen()) serial.Close(); + serial.Open(serialDevice); + serial.SetBaudRate(SerialStreamBuf::BAUD_9600); + serial.SetCharSize(SerialStreamBuf::CHAR_SIZE_8); + serial.SetNumOfStopBits(1); + serial.SetParity(SerialStreamBuf::PARITY_DEFAULT); + serial.SetFlowControl(SerialStreamBuf::FLOW_CONTROL_DEFAULT); +} + +void usage (const char* argv0) +{ + fprintf(stderr, "Uso:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "%s \n", argv0); + fprintf(stderr, "\n"); + fprintf(stderr, "Args:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "dispositivo - Nombre de dispositivo serie\n"); +} + +int main (int argc, char** argv) +{ + if (argc != 2) + { + usage(argv[0]); + exit(0); + } + + const char* serialDevice = argv[1]; + + SerialStream serial; + printf("Conectando con %s...\n", serialDevice); + openArduino(serialDevice, serial); + if (serial.IsOpen()) + { + sleep(2); // Wait for arduino to wake up + printf("Leyendo configuracion...\n"); + Config config; + readConfig(serial, config); + loop(serial, config); + } + else + { + printf("Error al conectar con %s\n", serialDevice); + cin.get(); + } + + return 0; +} diff --git a/desktop/rpmcount.pro b/desktop/rpmcount.pro new file mode 100755 index 0000000..794ae42 --- /dev/null +++ b/desktop/rpmcount.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +LIBS += -lserial + +SOURCES += \ + main.cc \ + term.cc + +HEADERS += \ + types.h \ + serial_utils.h \ + term.h diff --git a/desktop/serial_utils.h b/desktop/serial_utils.h new file mode 100755 index 0000000..8c351e4 --- /dev/null +++ b/desktop/serial_utils.h @@ -0,0 +1,33 @@ +#pragma once + +#include "types.h" + +#include + +template +T read (LibSerial::SerialStream& serial) +{ + T x; + serial.read((char*) &x, sizeof(T)); + return x; +} + +template <> +U32 read (LibSerial::SerialStream& serial) +{ + U32 x = 0; + for (int i = 0; i < 4; ++i) + { + U8 b; + serial.read((char*)&b, 1); + x = x >> 8; + x |= (b << 24); + } + return x; +} + +template +void write (LibSerial::SerialStream& serial, const T& val) +{ + serial.write((const char*) &val, sizeof(T)); +} diff --git a/desktop/term.cc b/desktop/term.cc new file mode 100755 index 0000000..a72f1e9 --- /dev/null +++ b/desktop/term.cc @@ -0,0 +1,28 @@ +#include "term.h" + +#include +#include //_getch*/ +#include //_getch*/ + +char getch () +{ + char buf=0; + struct termios old={0}; + fflush(stdout); + if(tcgetattr(0, &old)<0) + perror("tcsetattr()"); + old.c_lflag&=~ICANON; + old.c_lflag&=~ECHO; + old.c_cc[VMIN]=1; + old.c_cc[VTIME]=0; + if(tcsetattr(0, TCSANOW, &old)<0) + perror("tcsetattr ICANON"); + if(read(0,&buf,1)<0) + perror("read()"); + old.c_lflag|=ICANON; + old.c_lflag|=ECHO; + if(tcsetattr(0, TCSADRAIN, &old)<0) + perror ("tcsetattr ~ICANON"); + printf("%c\n",buf); + return buf; + } diff --git a/desktop/term.h b/desktop/term.h new file mode 100755 index 0000000..356992f --- /dev/null +++ b/desktop/term.h @@ -0,0 +1,3 @@ +#pragma once + +char getch (); diff --git a/desktop/types.h b/desktop/types.h new file mode 100755 index 0000000..da462d4 --- /dev/null +++ b/desktop/types.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +/* +File: Types +*/ + +#if defined(__GNUC__) || defined(__GNUG__) //Compiling with GNU C/C++ compiler + typedef __INT8_TYPE__ I8; + typedef __INT16_TYPE__ I16; + typedef __INT32_TYPE__ I32; + typedef __INT64_TYPE__ I64; + typedef __UINT8_TYPE__ U8; + typedef __UINT16_TYPE__ U16; + typedef __UINT32_TYPE__ U32; + typedef __UINT64_TYPE__ U64; +#else //Visual Studio + typedef __int8 I8; + typedef __int16 I16; + typedef __int32 I32; + typedef __int64 I64; + typedef unsigned __int8 U8; + typedef unsigned __int16 U16; + typedef unsigned __int32 U32; + typedef unsigned __int64 U64; +#endif -- cgit v1.2.3