14e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*    Copyright 2014-2015 ARM Limited
24e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov *
34e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * Licensed under the Apache License, Version 2.0 (the "License");
44e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * you may not use this file except in compliance with the License.
54e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * You may obtain a copy of the License at
64e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov *
74e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov *     http://www.apache.org/licenses/LICENSE-2.0
84e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov *
94e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * Unless required by applicable law or agreed to in writing, software
104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * distributed under the License is distributed on an "AS IS" BASIS,
114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * See the License for the specific language governing permissions and
134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * limitations under the License.
144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov*/
154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*
184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * readenergy.c
194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov *
204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov * Reads APB energy registers in Juno and outputs the measurements (converted to appropriate units).
214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov *
224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov*/
234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <errno.h>
244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <fcntl.h>
254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <stdint.h>
264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <stdio.h>
274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <stdlib.h>
284e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <string.h>
294e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <signal.h>
304e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <sys/mman.h>
314e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <sys/stat.h>
324e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <sys/types.h>
334e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <time.h>
344e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#include <unistd.h>
354e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
364e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// The following values obtained from Juno TRM 2014/03/04 section 4.5
374e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
384e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Location of APB registers in memory
394e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define APB_BASE_MEMORY 0x1C010000
404e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// APB energy counters start at offset 0xD0 from the base APB address.
414e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define BASE_INDEX 0xD0 / 4
424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// the one-past last APB counter
434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define APB_SIZE 0x120
444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Masks specifying the bits that contain the actual counter values
464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define CMASK 0xFFF
474e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define VMASK 0xFFF
484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define PMASK 0xFFFFFF
494e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
504e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Sclaing factor (divisor) or getting measured values from counters
514e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH0_PM1_SYS_SCALE 761
524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH1_PM2_A57_SCALE 381
534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH2_PM3_A53_SCALE 761
544e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH3_PM4_GPU_SCALE 381
554e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH4_VSYS_SCALE 1622
564e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH5_VA57_SCALE 1622
574e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH6_VA53_SCALE 1622
584e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ADC_CH7_VGPU_SCALE 1622
594e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH04_SYS_SCALE (SYS_ADC_CH0_PM1_SYS_SCALE * SYS_ADC_CH4_VSYS_SCALE)
604e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH15_A57_SCALE (SYS_ADC_CH1_PM2_A57_SCALE * SYS_ADC_CH5_VA57_SCALE)
614e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH26_A53_SCALE (SYS_ADC_CH2_PM3_A53_SCALE * SYS_ADC_CH6_VA53_SCALE)
624e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_POW_CH37_GPU_SCALE (SYS_ADC_CH3_PM4_GPU_SCALE * SYS_ADC_CH7_VGPU_SCALE)
634e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH0_SYS_SCALE 12348030000
644e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH1_A57_SCALE 6174020000
654e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH0_A53_SCALE 12348030000
664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define SYS_ENM_CH0_GPU_SCALE 6174020000
674e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
684e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Original values prior to re-callibrations.
694e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH0_PM1_SYS_SCALE 819.2*/
704e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH1_PM2_A57_SCALE 409.6*/
714e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH2_PM3_A53_SCALE 819.2*/
724e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH3_PM4_GPU_SCALE 409.6*/
734e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH4_VSYS_SCALE 1638.4*/
744e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH5_VA57_SCALE 1638.4*/
754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH6_VA53_SCALE 1638.4*/
764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ADC_CH7_VGPU_SCALE 1638.4*/
774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH04_SYS_SCALE (SYS_ADC_CH0_PM1_SYS_SCALE * SYS_ADC_CH4_VSYS_SCALE)*/
784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH15_A57_SCALE (SYS_ADC_CH1_PM2_A57_SCALE * SYS_ADC_CH5_VA57_SCALE)*/
794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH26_A53_SCALE (SYS_ADC_CH2_PM3_A53_SCALE * SYS_ADC_CH6_VA53_SCALE)*/
804e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_POW_CH37_GPU_SCALE (SYS_ADC_CH3_PM4_GPU_SCALE * SYS_ADC_CH7_VGPU_SCALE)*/
814e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH0_SYS_SCALE 13421772800.0*/
824e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH1_A57_SCALE 6710886400.0*/
834e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH0_A53_SCALE 13421772800.0*/
844e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov/*#define SYS_ENM_CH0_GPU_SCALE 6710886400.0*/
854e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
864e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Ignore individual errors but if see too many, abort.
874e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define ERROR_THRESHOLD 10
884e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
894e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// Default counter poll period (in milliseconds).
904e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov#define DEFAULT_PERIOD 100
914e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
92dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse// Default duration for the instrument execution (in seconds); 0 means 'forever'
93dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse#define DEFAULT_DURATION 0
94dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse
954e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// A single reading from the energy meter. The values are the proper readings converted
964e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// to appropriate units (e.g. Watts for power); they are *not* raw counter values.
974e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovstruct reading
984e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
994e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch0_pm1_sys;
1004e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch1_pm2_a57;
1014e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch2_pm3_a53;
1024e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch3_pm4_gpu;
1034e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch4_vsys;
1044e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch5_va57;
1054e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch6_va53;
1064e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_adc_ch7_vgpu;
1074e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_pow_ch04_sys;
1084e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_pow_ch15_a57;
1094e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_pow_ch26_a53;
1104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_pow_ch37_gpu;
1114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_enm_ch0_sys;
1124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_enm_ch1_a57;
1134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_enm_ch0_a53;
1144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	double sys_enm_ch0_gpu;
1154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov};
1164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovinline uint64_t join_64bit_register(uint32_t *buffer, int index)
1184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
1194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	uint64_t result = 0;
1204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	result |= buffer[index];
1214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	result |= (uint64_t)(buffer[index+1]) << 32;
1224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	return result;
1234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
1244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovint nsleep(const struct timespec *req, struct timespec *rem)
1264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
1274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	struct timespec temp_rem;
1284e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	if (nanosleep(req, rem) == -1)
1294e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
1304e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		if (errno == EINTR)
1314e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		{
1324e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			nsleep(rem, &temp_rem);
1334e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		}
1344e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		else
1354e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		{
1364e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			return errno;
1374e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		}
1384e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
1394e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	else
1404e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
1414e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		return 0;
1424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
1434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
1444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid print_help()
1464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
14709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	fprintf(stderr, "Usage: readenergy [-t PERIOD] [-o OUTFILE]\n\n"
1484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			"Read Juno energy counters every PERIOD milliseconds, writing them\n"
149dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse			"to OUTFILE in CSV format either until SIGTERM is received OR\n"
150dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse			"till the specified duration elapsed.\n"
15109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath			"If OUTFILE is not specified, stdout will be used.\n\n"
1524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			"Parameters:\n"
1534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			"	PERIOD is the counter poll period in milliseconds.\n"
1544e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			"	       (Defaults to 100 milliseconds.)\n"
155dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse			"	DURATION is the duration before execution terminates.\n"
156dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse			"		(Defaults to 0 seconds, meaning run till user\n"
157dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse			"		terminates execution.\n"
1584e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			"	OUTFILE is the output file path\n");
1594e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
1604e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1614e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// debugging only...
1624e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovinline void dprint(char *msg)
1634e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
1644e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	fprintf(stderr, "%s\n", msg);
1654e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	sync();
1664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
1674e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1684e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- config ----------------------------------------------------
1694e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1704e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovstruct config
1714e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
1724e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	struct timespec period;
1734e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	char *output_file;
174dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	long duration_in_sec;
1754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov};
1764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid config_init_period_from_millis(struct config *this, long millis)
1784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
1794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	this->period.tv_sec = (time_t)(millis / 1000);
1804e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	this->period.tv_nsec = (millis % 1000) * 1000000;
1814e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
1824e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1834e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid config_init(struct config *this, int argc, char *argv[])
1844e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
1854e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	this->output_file = NULL;
1864e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	config_init_period_from_millis(this, DEFAULT_PERIOD);
187dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	this->duration_in_sec = DEFAULT_DURATION;
1884e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
1894e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	int opt;
190dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	while ((opt = getopt(argc, argv, "ht:o:d:")) != -1)
1914e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
1924e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		switch(opt)
1934e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		{
1944e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			case 't':
1954e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				config_init_period_from_millis(this, atol(optarg));
1964e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				break;
1974e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			case 'o':
1984e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				this->output_file = optarg;
1994e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				break;
200dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse			case 'd':
201dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse				this->duration_in_sec = atol(optarg);
202dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse				break;
2034e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			case 'h':
2044e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				print_help();
2054e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				exit(EXIT_SUCCESS);
2064e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				break;
2074e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			default:
2084e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				fprintf(stderr, "ERROR: Unexpected option %s\n\n", opt);
2094e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				print_help();
2104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov				exit(EXIT_FAILURE);
2114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		}
2124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
2134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
2144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- /config ---------------------------------------------------
2164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- emeter ----------------------------------------------------
2184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovstruct emeter
2204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
2214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	int fd;
2224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	FILE *out;
2234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	void *mmap_base;
2244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov};
2254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_init(struct emeter *this, char *outfile)
2274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
22809915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	if(outfile)
2294e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
23009915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		this->out = fopen(outfile, "w");
23109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		if (this->out == NULL)
23209915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		{
23309915101d849cdc285726f6366f4b1a168a7f74aChris Redpath			fprintf(stderr, "ERROR: Could not open output file %s; got %s\n", outfile, strerror(errno));
23409915101d849cdc285726f6366f4b1a168a7f74aChris Redpath			exit(EXIT_FAILURE);
23509915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		}
23609915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	} else {
23709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		this->out = stdout;
2384e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
2394e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov        this->fd = open("/dev/mem", O_RDONLY);
2404e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov        if(this->fd < 0)
2414e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov        {
2424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov                fprintf(stderr, "ERROR: Can't open /dev/mem; got %s\n", strerror(errno));
2434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		fclose(this->out);
2444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		exit(EXIT_FAILURE);
2454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov        }
2464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2474e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	this->mmap_base = mmap(NULL, APB_SIZE, PROT_READ, MAP_SHARED, this->fd, APB_BASE_MEMORY);
2484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	if (this->mmap_base == MAP_FAILED)
2494e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
2504e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		fprintf(stderr, "ERROR: mmap failed; got %s\n", strerror(errno));
2514e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		close(this->fd);
2524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		fclose(this->out);
2534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		exit(EXIT_FAILURE);
2544e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
2554e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
25609915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	if(this->out) {
25709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		fprintf(this->out, "sys_curr,a57_curr,a53_curr,gpu_curr,"
25809915101d849cdc285726f6366f4b1a168a7f74aChris Redpath				   "sys_volt,a57_volt,a53_volt,gpu_volt,"
25909915101d849cdc285726f6366f4b1a168a7f74aChris Redpath				   "sys_pow,a57_pow,a53_pow,gpu_pow,"
26009915101d849cdc285726f6366f4b1a168a7f74aChris Redpath				   "sys_cenr,a57_cenr,a53_cenr,gpu_cenr\n");
26109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	}
2624e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
2634e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2644e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_read_measurements(struct emeter *this, struct reading *reading)
2654e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
2664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	uint32_t *buffer = (uint32_t *)this->mmap_base;
2674e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch0_pm1_sys = (double)(CMASK & buffer[BASE_INDEX+0]) / SYS_ADC_CH0_PM1_SYS_SCALE;
2684e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch1_pm2_a57 = (double)(CMASK & buffer[BASE_INDEX+1]) / SYS_ADC_CH1_PM2_A57_SCALE;
2694e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch2_pm3_a53 = (double)(CMASK & buffer[BASE_INDEX+2]) / SYS_ADC_CH2_PM3_A53_SCALE;
2704e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch3_pm4_gpu = (double)(CMASK & buffer[BASE_INDEX+3]) / SYS_ADC_CH3_PM4_GPU_SCALE;
2714e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch4_vsys = (double)(VMASK & buffer[BASE_INDEX+4]) / SYS_ADC_CH4_VSYS_SCALE;
2724e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch5_va57 = (double)(VMASK & buffer[BASE_INDEX+5]) / SYS_ADC_CH5_VA57_SCALE;
2734e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch6_va53 = (double)(VMASK & buffer[BASE_INDEX+6]) / SYS_ADC_CH6_VA53_SCALE;
2744e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_adc_ch7_vgpu = (double)(VMASK & buffer[BASE_INDEX+7]) / SYS_ADC_CH7_VGPU_SCALE;
2754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_pow_ch04_sys = (double)(PMASK & buffer[BASE_INDEX+8]) / SYS_POW_CH04_SYS_SCALE;
2764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_pow_ch15_a57 = (double)(PMASK & buffer[BASE_INDEX+9]) / SYS_POW_CH15_A57_SCALE;
2774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_pow_ch26_a53 = (double)(PMASK & buffer[BASE_INDEX+10]) / SYS_POW_CH26_A53_SCALE;
2784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_pow_ch37_gpu = (double)(PMASK & buffer[BASE_INDEX+11]) / SYS_POW_CH37_GPU_SCALE;
2794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_enm_ch0_sys = (double)join_64bit_register(buffer, BASE_INDEX+12) / SYS_ENM_CH0_SYS_SCALE;
2804e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_enm_ch1_a57 = (double)join_64bit_register(buffer, BASE_INDEX+14) / SYS_ENM_CH1_A57_SCALE;
2814e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_enm_ch0_a53 = (double)join_64bit_register(buffer, BASE_INDEX+16) / SYS_ENM_CH0_A53_SCALE;
2824e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	reading->sys_enm_ch0_gpu = (double)join_64bit_register(buffer, BASE_INDEX+18) / SYS_ENM_CH0_GPU_SCALE;
2834e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
2844e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
2854e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_take_reading(struct emeter *this)
2864e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
2874e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	static struct reading reading;
2884e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	int error_count = 0;
2894e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	emeter_read_measurements(this, &reading);
2904e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	int ret = fprintf(this->out, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n",
2914e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch0_pm1_sys,
2924e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch1_pm2_a57,
2934e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch2_pm3_a53,
2944e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch3_pm4_gpu,
2954e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch4_vsys,
2964e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch5_va57,
2974e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch6_va53,
2984e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_adc_ch7_vgpu,
2994e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_pow_ch04_sys,
3004e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_pow_ch15_a57,
3014e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_pow_ch26_a53,
3024e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_pow_ch37_gpu,
3034e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_enm_ch0_sys,
3044e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_enm_ch1_a57,
3054e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_enm_ch0_a53,
3064e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			reading.sys_enm_ch0_gpu);
3074e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	if (ret < 0)
3084e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
3094e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		fprintf(stderr, "ERROR: while writing a meter reading: %s\n", strerror(errno));
3104e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		if (++error_count > ERROR_THRESHOLD)
3114e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov			exit(EXIT_FAILURE);
3124e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
3134e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
3144e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
3154e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid emeter_finalize(struct emeter *this)
3164e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
3174e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	if (munmap(this->mmap_base, APB_SIZE) == -1)
3184e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
3194e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		// Report the error but don't bother doing anything else, as we're not gonna do
3204e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		// anything with emeter after this point anyway.
3214e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		fprintf(stderr, "ERROR: munmap failed; got %s\n", strerror(errno));
3224e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
3234e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	close(this->fd);
3244e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	fclose(this->out);
3254e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
3264e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
3274e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov// -------------------------------------- /emeter ----------------------------------------------------
3284e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
329dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljusevolatile int done = 0;
3304e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
3314e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovvoid term_handler(int signum)
3324e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
3334e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	done = 1;
3344e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
3354e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
336dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljusevoid sigalrm_handler(int signum)
337dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse{
338dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	done = 1;
339dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse}
340dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse
341dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse
3424e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimovint main(int argc, char *argv[])
3434e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov{
3444e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	struct sigaction action;
3454e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	memset(&action, 0, sizeof(struct sigaction));
3464e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	action.sa_handler = term_handler;
3474e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	sigaction(SIGTERM, &action, NULL);
3484e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
3494e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	struct config config;
3504e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	struct emeter emeter;
3514e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	config_init(&config, argc, argv);
3524e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	emeter_init(&emeter, config.output_file);
3534e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
354dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	if (0 != config.duration_in_sec)
355dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	{
356dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse		/*Set the alarm with the duration from use only if a non-zero value is specified
357dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse		  else it will run forever until SIGTERM signal received from user*/
358dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse		/*Set the signal handler first*/
359dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse		signal(SIGALRM, sigalrm_handler);
360dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse		/*Now set the alarm for the duration specified by the user*/
361dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse		alarm(config.duration_in_sec);
362dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse
363dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse	}
364dfc63a1cc09d0d701e0faa9af6b5509c95bd86deBasil Eljuse
36509915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	if(config.output_file)
3664e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	{
36709915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		struct timespec remaining;
36809915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		while (!done)
36909915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		{
37009915101d849cdc285726f6366f4b1a168a7f74aChris Redpath			emeter_take_reading(&emeter);
37109915101d849cdc285726f6366f4b1a168a7f74aChris Redpath			nsleep(&config.period, &remaining);
37209915101d849cdc285726f6366f4b1a168a7f74aChris Redpath		}
37309915101d849cdc285726f6366f4b1a168a7f74aChris Redpath	} else 	{
3744e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov		emeter_take_reading(&emeter);
3754e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	}
3764e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov
3774e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	emeter_finalize(&emeter);
3784e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov	return EXIT_SUCCESS;
3794e6afe960b0540a0e9781bdfbd82352ff157d24Sergei Trofimov}
380