Skip to content
Snippets Groups Projects
Select Git revision
  • 3bcfb8ccce9d1e07c1e3426a52cbf85e14dae936
  • master default protected
  • update
  • v3.0
  • v2.0
5 results

PowerSensor.cc

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    PowerSensor.cc 5.77 KiB
    //  Copyright (C) 2016
    //  ASTRON (Netherlands Institute for Radio Astronomy) / John W. Romein
    //  P.O. Box 2, 7990 AA  Dwingeloo, the Netherlands
    
    //  This file is part of PowerSensor.
    
    //  PowerSensor is free software: you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License as published by
    //  the Free Software Foundation, either version 3 of the License, or
    //  (at your option) any later version.
    
    //  PowerSensor is distributed in the hope that it will be useful,
    //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    //  GNU General Public License for more details.
    
    //  You should have received a copy of the GNU General Public License
    //  along with PowerSensor.  If not, see <http://www.gnu.org/licenses/>.
    
    
    #include "PowerSensor.h"
    
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    
    #include <errno.h>
    #include <fcntl.h>
    #include <omp.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <termios.h>
    #include <unistd.h>
    
    
    
    PowerSensor::PowerSensor(const char *device, const char *dumpFileName)
    :
      dumpFile(dumpFileName == 0 ? 0 : new std::ofstream(dumpFileName)),
      stop(false)
    {
      lastState.microSeconds = 0;
    
      if ((fd = open(device, O_RDWR)) < 0) {
        perror("open device");
        exit(1);
      }
    
    
      //Configure port for 8N1 transmission
      struct termios options;
    
      tcgetattr(fd, &options);		//Gets the current options for the port
      cfsetispeed(&options, B2000000);	//Sets the Input Baud Rate
      cfsetospeed(&options, B2000000);	//Sets the Output Baud Rate
    
      options.c_cflag = (options.c_cflag & ~CSIZE) | CS8;
      options.c_iflag = IGNBRK;
      options.c_lflag = 0;
      options.c_oflag = 0;
      options.c_cflag |= CLOCAL | CREAD;
      options.c_cc[VMIN] = sizeof(State::MC_State);
      options.c_cc[VTIME] = 0;
      options.c_iflag &= ~(IXON | IXOFF | IXANY);
      options.c_cflag &= ~(PARENB | PARODD);
    
      /* commit the options */
      tcsetattr(fd, TCSANOW, &options);
    
      /* Wait for the Arduino to reset */
      sleep(2);
      /* Flush anything already in the serial buffer */
      tcflush(fd, TCIFLUSH);
    
      if ((errno = pthread_mutex_init(&mutex, 0)) != 0) {
        perror("pthread_mutex_init");
        exit(1);
      }
    
      doMeasurement(); // initialise
    
      if ((errno = pthread_create(&thread, 0, &PowerSensor::IOthread, this)) != 0) {
        perror("pthread_create");
        exit(1);
      }
    }
    
    
    PowerSensor::~PowerSensor()
    {
      stop = true;
    
      if ((errno = pthread_join(thread, 0)) != 0)
        perror("pthread_join");
    
      if ((errno = pthread_mutex_destroy(&mutex)) != 0)
        perror("pthread_mutex_destroy");
    
      if (close(fd))
        perror("close device");
    
      if (dumpFile != 0)
        delete dumpFile;
    }
    
    
    void PowerSensor::lock()
    {
      if ((errno = pthread_mutex_lock(&mutex)) != 0) {
        perror("pthread_mutex_lock");
        exit(1);
      }
    }
    
    
    void PowerSensor::unlock()
    {
      if ((errno = pthread_mutex_unlock(&mutex)) != 0) {
        perror("pthread_mutex_unlock");
        exit(1);
      }
    }
    
    
    void *PowerSensor::IOthread(void *arg)
    {
      return static_cast<PowerSensor *>(arg)->IOthread();
    }
    
    
    void *PowerSensor::IOthread()
    {
      while (!stop)
        doMeasurement();
    
      return 0;
    }
    
    
    void PowerSensor::doMeasurement()
    {
      State::MC_State currentState;
    
      ssize_t retval, bytesRead = 0;
    
      if (write(fd, "s", 1) != 1) {
        perror("write device");
        exit(1);
      }
    
      do {
        if ((retval = ::read(fd, (char *) &currentState.consumedEnergy + bytesRead, sizeof(State::MC_State) - bytesRead)) < 0) {
          perror("read device");
          exit(1);
        }
      } while ((bytesRead += retval) < sizeof(State::MC_State));
    
      lock();
    
      if (lastState.microSeconds != currentState.microSeconds) {
        previousState = lastState;
        lastState = currentState;
    
        if (dumpFile != 0)
          *dumpFile << "S " << currentState.microSeconds / 1e6 << ' ' << (currentState.consumedEnergy - previousState.consumedEnergy) * (65536.0 / 512) / (currentState.microSeconds - previousState.microSeconds) << std::endl;
      }
    
    #if 0
      static double lastTime;
      static unsigned count;
      ++ count;
    
      if (lastTime + 1 < omp_get_wtime()) {
    #pragma omp critical (cout)
        std::cout << "nr times read = " << count << std::endl;
        lastTime = omp_get_wtime();
        count = 0;
      }
    #endif
    
      unlock();
    }
    
    
    void PowerSensor::mark(const State &state, const char *name, unsigned tag)
    {
      if (dumpFile != 0) {
        lock();
        *dumpFile << "M " << state.lastState.microSeconds * 1e-6 << ' ' << tag << " \"" << (name == 0 ? "" : name) << '"' << std::endl;
        unlock();
      }
    }
    
    
    void PowerSensor::mark(const State &startState, const State &stopState, const char *name, unsigned tag)
    {
      if (dumpFile != 0) {
        lock();
        *dumpFile << "M " << startState.lastState.microSeconds * 1e-6 << ' ' << stopState.lastState.microSeconds * 1e-6 << ' ' << tag << " \"" << (name == 0 ? "" : name) << '"' << std::endl;
        unlock();
      }
    }
    
    
    PowerSensor::State PowerSensor::read()
    {
      State state;
    
      lock();
      state.previousState = previousState;
      state.lastState = lastState;
      state.timeAtRead = omp_get_wtime();
      unlock();
    
      return state;
    }
    
    
    double PowerSensor::Joules(const State &firstState, const State &secondState)
    {
      return Watt(firstState, secondState) * seconds(firstState, secondState);
    }
    
    
    double PowerSensor::seconds(const State &firstState, const State &secondState)
    {
      return secondState.timeAtRead - firstState.timeAtRead;
    }
    
    
    double PowerSensor::Watt(const State &firstState, const State &secondState)
    {
      uint32_t microSeconds = secondState.lastState.microSeconds - firstState.lastState.microSeconds;
    
      if (microSeconds != 0)
        return (secondState.lastState.consumedEnergy - firstState.lastState.consumedEnergy) * (65536.0 / 512) / microSeconds;
      else // very short time
        return (secondState.lastState.consumedEnergy - secondState.previousState.consumedEnergy) * (65536.0 / 512) / (secondState.lastState.microSeconds - secondState.previousState.microSeconds);
    }