Select Git revision
PowerSensor.cc
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 *) ¤tState.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);
}