-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
CFLAGS = -o3 -Wall -lm | ||
|
||
metric-provider-binary: source.c | ||
gcc $< $(CFLAGS) -o $@ | ||
sudo chown root $@ | ||
sudo chmod u+s $@ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Information | ||
|
||
TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#ifndef __MCP_COM_H | ||
#define __MCP_COM_H | ||
|
||
enum mcp_types { f501, f511 }; | ||
|
||
int f511_init(const char *port); | ||
/* Power in 10mW for channel 1 and 2 */ | ||
int f511_get_power(int *ch1, int *ch2, int fd); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import os | ||
|
||
#pylint: disable=import-error, invalid-name | ||
from metric_providers.base import BaseMetricProvider | ||
|
||
class PsuEnergyAcMcpMachineProvider(BaseMetricProvider): | ||
def __init__(self, resolution): | ||
super().__init__( | ||
metric_name='psu_energy_ac_mcp_machine', | ||
metrics={'time': int, 'value': int}, | ||
resolution=resolution, | ||
unit="mJ", | ||
current_dir=os.path.dirname(os.path.abspath(__file__)), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <stdio.h> | ||
#include <stdint.h> | ||
#include <string.h> | ||
#include <termios.h> | ||
#include <unistd.h> | ||
#include <stdlib.h> | ||
#include <sys/time.h> | ||
|
||
#include "mcp_com.h" | ||
|
||
/* | ||
This file is mostly copied from https://github.com/osmhpi/pinpoint/blob/master/src/data_sources/mcp_com.c | ||
Credits to Sven Köhler and the OSM group from the HPI | ||
In case the file is not original work: Possible prior origins of the file are unknown. However it is an implementation | ||
of the protocol defined here: | ||
- https://www.microchip.com/en-us/development-tool/ADM00706 | ||
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005473B.pdf | ||
*/ | ||
|
||
// Set address pointer to 0xa (active power), read 32 bits | ||
const unsigned char f501_read_active_power[] = { 0x41, 0x0, 0xa, 0x44 }; | ||
const unsigned char f501_read_apparent_power_divisor[] = | ||
{ 0x41, 0x00, 0x40, 0x52 }; | ||
const unsigned char f501_set_apparent_power_divisor[] = | ||
{ 0x41, 0x00, 0x40, 0x57, 0x00, 0x03 }; | ||
const unsigned char f501_set_accumulation_interval[] = | ||
{ 0x41, 0x00, 0x5A, 0x57, 0x00, 0x00 }; | ||
const unsigned char f501_read_range[] = { 0x41, 0x00, 0x48, 0x44 }; | ||
|
||
const unsigned char f511_read_active_power[] = { 0x41, 0x0, 0x16, 0x4E, 8 }; | ||
const unsigned char f511_read_active_power1[] = { 0x41, 0x0, 0x16, 0x4E, 4 }; | ||
const unsigned char f511_read_active_power2[] = { 0x41, 0x0, 0x1a, 0x4E, 4 }; | ||
const unsigned char f511_set_accumulation_interval[] = | ||
{ 0x41, 0x00, 0xA8, 0x4D, 2, 0x00, 0x00 }; | ||
|
||
static unsigned int msleep_time=1000; | ||
|
||
enum mcp_states { init, wait_ack, get_len, get_data, validate_checksum }; | ||
|
||
enum mcp_states mcp_state = wait_ack; | ||
|
||
int fd; | ||
|
||
int init_serial(const char *port, int baud) | ||
{ | ||
struct termios tty; | ||
|
||
fd = open(port, O_RDWR | O_NOCTTY | O_SYNC); | ||
if (fd < 0) { | ||
return -1; | ||
} | ||
|
||
if (tcgetattr(fd, &tty) < 0) { | ||
return -1; | ||
} | ||
|
||
cfsetospeed(&tty, (speed_t) baud); | ||
cfsetispeed(&tty, (speed_t) baud); | ||
|
||
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ | ||
tty.c_cflag &= ~CSIZE; | ||
tty.c_cflag |= CS8; /* 8-bit characters */ | ||
tty.c_cflag &= ~PARENB; /* no parity bit */ | ||
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ | ||
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ | ||
|
||
/* setup for non-canonical mode */ | ||
tty.c_iflag &= | ||
~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); | ||
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); | ||
tty.c_oflag &= ~OPOST; | ||
|
||
/* fetch bytes as they become available */ | ||
tty.c_cc[VMIN] = 1; | ||
tty.c_cc[VTIME] = 1; | ||
|
||
if (tcsetattr(fd, TCSANOW, &tty) != 0) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
int mcp_cmd(unsigned char *cmd, unsigned int cmd_length, unsigned char *reply, int fd) | ||
{ | ||
unsigned char buf[80]; | ||
unsigned char command_packet[80]; | ||
int rdlen; | ||
uint8_t len; | ||
uint8_t i; | ||
uint8_t checksum = 0; | ||
uint8_t datap = 0; | ||
|
||
command_packet[0] = 0xa5; | ||
command_packet[1] = cmd_length + 3; | ||
memcpy(command_packet + 2, cmd, cmd_length); | ||
for (i = 0; i < cmd_length + 2; i++) { | ||
checksum += command_packet[i]; | ||
} | ||
command_packet[i] = checksum; | ||
tcflush(fd, TCIOFLUSH); | ||
len = write(fd, command_packet, cmd_length + 3); | ||
if (len != cmd_length + 3) { | ||
return -1; | ||
} | ||
tcdrain(fd); | ||
while (1) { | ||
rdlen = read(fd, buf, 1); | ||
if (rdlen == 0) { | ||
return -1; | ||
} | ||
switch (mcp_state) { | ||
case wait_ack: | ||
if (buf[0] == 0x06) { | ||
/* Only read commands will return more than an ACK */ | ||
if ((command_packet[5] == 0x44) | ||
|| (command_packet[5] == 0x52) | ||
|| (command_packet[5] == 0x4e)) { | ||
mcp_state = get_len; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
break; | ||
case get_len: | ||
len = buf[0]; | ||
/* Workaround for sporadically broken packets, fix me! */ | ||
if(len != 11){ | ||
mcp_state = wait_ack; | ||
return -1; | ||
} | ||
mcp_state = get_data; | ||
break; | ||
case get_data: | ||
reply[datap++] = buf[0]; | ||
if ((datap + 2) == (len - 1)) { | ||
mcp_state = validate_checksum; | ||
} | ||
break; | ||
case validate_checksum: | ||
mcp_state = wait_ack; | ||
checksum = 0x06 + len; | ||
for (i = 0; i < (len - 3); i++) { | ||
checksum += reply[i]; | ||
} | ||
if (checksum == buf[0]) { | ||
return len - 3; | ||
} else { | ||
return -1; | ||
} | ||
break; | ||
default: | ||
mcp_state = wait_ack; | ||
} | ||
|
||
} | ||
} | ||
|
||
|
||
|
||
int f511_get_power(int *ch1, int *ch2, int fd) | ||
{ | ||
int res; | ||
unsigned char reply[40]; | ||
res = | ||
mcp_cmd((unsigned char *)&f511_read_active_power, | ||
sizeof(f511_read_active_power), (unsigned char *)&reply, fd); | ||
if (res > 0) { | ||
*ch1 = (reply[3] << 24) + (reply[2] << 16) | ||
+ (reply[1] << 8) + reply[0]; | ||
*ch2 = (reply[7] << 24) + (reply[6] << 16) | ||
+ (reply[5] << 8) + reply[4]; | ||
return 0; | ||
} else { | ||
return -1; | ||
} | ||
} | ||
|
||
int f511_init(const char *port) | ||
{ | ||
unsigned char reply[80]; | ||
int res; | ||
|
||
if (init_serial(port, B115200) < 0) { | ||
return -1; | ||
} | ||
res = | ||
mcp_cmd((unsigned char *)f511_set_accumulation_interval, | ||
sizeof(f511_set_accumulation_interval), | ||
(unsigned char *)&reply, fd); | ||
if(res < 0) return res; | ||
return fd; | ||
} | ||
|
||
|
||
|
||
int main(int argc, char **argv) { | ||
|
||
int c; | ||
struct timeval now; | ||
|
||
while ((c = getopt (argc, argv, "hi:d")) != -1) { | ||
switch (c) { | ||
case 'h': | ||
printf("Usage: %s [-h] [-m]\n\n",argv[0]); | ||
printf("\t-h : displays this help\n"); | ||
printf("\t-i : specifies the milliseconds sleep time that will be slept between measurements\n\n"); | ||
exit(0); | ||
case 'i': | ||
msleep_time = atoi(optarg); | ||
break; | ||
default: | ||
fprintf(stderr,"Unknown option %c\n",c); | ||
exit(-1); | ||
} | ||
} | ||
|
||
setvbuf(stdout, NULL, _IONBF, 0); | ||
|
||
long fd = f511_init("/dev/ttyACM0"); | ||
int data[2]; // The MCP has two outlets where you can measure. | ||
|
||
while (1) { | ||
int result = f511_get_power(&data[0], &data[1], fd); | ||
if(result != 0) { | ||
printf("Error. Result was not 0\n"); | ||
break; | ||
} | ||
// The MCP returns the current power consumption in 10mW steps. | ||
gettimeofday(&now, NULL); | ||
printf("%ld%06ld %ld\n", now.tv_sec, now.tv_usec, (long)(data[0]*10*((double)msleep_time/1000)) ); | ||
usleep(msleep_time*1000); | ||
} | ||
close(fd); | ||
|
||
return 0; | ||
} |