📄 emeter-communication.c
字号:
//--------------------------------------------------------------------------
//
// Software for MSP430 based e-meters.
//
// You may not use the Program in non-TI devices.
//
// File: emeter-communications.c
//
// Steve Underwood <steve-underwood@ti.com>
// Texas Instruments Hong Kong Ltd.
//
// $Id: emeter-communication.c,v 1.7 2005/11/17 09:25:23 a0754793 Exp $
//
/*! \file emeter-structs.h */
//
//--------------------------------------------------------------------------
//
#include <stdint.h>
#if !defined(__MSP430__)
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#endif
#if defined(__GNUC__)
#include <signal.h>
#endif
#if defined(__MSP430__)
#include <io.h>
#endif
#include <emeter-toolkit.h>
#include "emeter.h"
#include "emeter-structs.h"
#if !defined(NULL)
#define NULL (void *) 0
#endif
enum host_commands_e
{
HOST_CMD_GET_METER_CONFIGURATION = 0x56,
HOST_CMD_SET_METER_CONSUMPTION = 0x57,
HOST_CMD_SET_RTC = 0x58,
HOST_CMD_GET_RTC = 0x59,
HOST_CMD_SET_PASSWORD = 0x60,
HOST_CMD_GET_READINGS_PHASE_1 = 0x61,
HOST_CMD_GET_READINGS_PHASE_2 = 0x62,
HOST_CMD_GET_READINGS_PHASE_3 = 0x63,
HOST_CMD_GET_READINGS_NEUTRAL = 0x64,
HOST_CMD_ERASE_FLASH_SEGMENT = 0x70,
HOST_CMD_SET_FLASH_POINTER = 0x71,
HOST_CMD_FLASH_DOWNLOAD = 0x72,
HOST_CMD_FLASH_UPLOAD = 0x73,
HOST_CMD_ZAP_MEMORY_AREA = 0x74,
HOST_CMD_SUMCHECK_MEMORY = 0x75,
HOST_CMD_GET_RAW_POWER_PHASE_1 = 0x91,
HOST_CMD_GET_RAW_POWER_PHASE_2 = 0x92,
HOST_CMD_GET_RAW_POWER_PHASE_3 = 0x93,
HOST_CMD_GET_RAW_REACTIVE_POWER_PHASE_1 = 0x95,
HOST_CMD_GET_RAW_REACTIVE_POWER_PHASE_2 = 0x96,
HOST_CMD_GET_RAW_REACTIVE_POWER_PHASE_3 = 0x97,
HOST_CMD_GET_RAW_POWER_NEUTRAL = 0x99,
HOST_CMD_GET_RAW_REACTIVE_POWER_NEUTRAL = 0x9D,
HOST_CMD_CHECK_RTC_ERROR = 0xA0,
HOST_CMD_RTC_CORRECTION = 0xA1,
HOST_CMD_MULTIRATE_SET_PARAMETERS = 0xC0,
HOST_CMD_MULTIRATE_GET_PARAMETERS = 0xC1,
HOST_CMD_MULTIRATE_CLEAR_USAGE = 0xC2,
HOST_CMD_MULTIRATE_GET_USAGE = 0xC3,
};
#if defined(__MSP430__) && (defined(IEC1107_SUPPORT) || defined(SERIAL_CALIBRATION_SUPPORT))
#define MAX_IEC1107_MSG_BODY 66
typedef union
{
#if 0
uint8_t uint8[4 + 12 + 256];
uint16_t uint16[(4 + 12 + 256)/2];
#else
uint8_t uint8[4 + 12 + MAX_IEC1107_MSG_BODY];
uint16_t uint16[(4 + 12 + MAX_IEC1107_MSG_BODY)/2];
#endif
} serial_msg_t;
#define IEC1107_MSG_RX_START_BODY 10
#define IEC1107_MSG_RX_START_BODY_W 5
#define IEC1107_MSG_TX_START_BODY 14
#define IEC1107_MSG_TX_START_BODY_W 7
/* Incoming serial message buffer */
serial_msg_t rx_msg;
uint8_t rx_msg_len;
uint8_t char_timeout_1107;
static uint8_t rx_msg_ptr;
/* Outgoing serial message buffer */
serial_msg_t tx_msg;
uint8_t tx_msg_len;
static uint8_t tx_msg_ptr;
uint16_t *next_flash_loc;
#endif
int is_calibration_enabled(void)
{
return TRUE;
}
#if IEC1107_D_SUPPORT
int iec1107d_status;
void send_1107d_report(void)
{
int i;
uint8_t x;
uint8_t bcd[5];
const uint8_t *s;
static const uint8_t id[] = "/SJJ5eHZSJJ V1.01\r\n";
static const uint8_t serial_number_tag[] = "1-0:0.0.9*255(";
static const uint8_t property_number_tag[] = "1-0:0.0.0*255(";
static const uint8_t energy_tag[] = "1-0:1.8.0*255(";
static const uint8_t status_tag[] = "1-0:96.5.5*255(";
static const uint8_t factory_number_tag[] = "0-0:96.1.255*255(";
static const uint8_t even_parity[128] =
{
0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x06, 0x87,
0x88, 0x09, 0x0A, 0x8B, 0x0C, 0x8D, 0x8E, 0x0F,
0x90, 0x11, 0x12, 0x93, 0x14, 0x95, 0x96, 0x17,
0x18, 0x99, 0x9A, 0x1B, 0x9C, 0x1D, 0x1E, 0x9F,
0xA0, 0x21, 0x22, 0xA3, 0x24, 0xA5, 0xA6, 0x27,
0x28, 0xA9, 0xAA, 0x2B, 0xAC, 0x2D, 0x2E, 0xAF,
0x30, 0xB1, 0xB2, 0x33, 0xB4, 0x35, 0x36, 0xB7,
0xB8, 0x39, 0x3A, 0xBB, 0x3C, 0xBD, 0xBE, 0x3F,
0xC0, 0x41, 0x42, 0xC3, 0x44, 0xC5, 0xC6, 0x47,
0x48, 0xC9, 0xCA, 0x4B, 0xCC, 0x4D, 0x4E, 0xCF,
0x50, 0xD1, 0xD2, 0x53, 0xD4, 0x55, 0x56, 0xD7,
0xD8, 0x59, 0x5A, 0xDB, 0x5C, 0xDD, 0xDE, 0x5F,
0x60, 0xE1, 0xE2, 0x63, 0xE4, 0x65, 0x66, 0xE7,
0xE8, 0x69, 0x6A, 0xEB, 0x6C, 0xED, 0xEE, 0x6F,
0xF0, 0x71, 0x72, 0xF3, 0x74, 0xF5, 0xF6, 0x77,
0x78, 0xF9, 0xFA, 0x7B, 0xFC, 0x7D, 0x7E, 0xFF,
};
/* IEC1107 specifies 7 bit + even parity data. We want to use 8 bit data for calibration, so we
use software generation for the parity bit. */
/* If the password is set we are in calibration mode, and the IEC1107D messages should not be sent.
After calibration is complete, the password may or may not have been cleared. If it is still set
a reset of the MCU will restore normal operation. */
if ((meter_status & PASSWORD_OK))
return;
iec1107d_status = 0;
if (total_power > 0)
iec1107d_status |= 0x80;
#if SELF_TEST_SUPPORT
if (nv_parms.s.meter_failures != 0xFFFF)
iec1107d_status |= 0x01;
#endif
i = 0;
s = id;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
if (nv_parms.s.property_number[0])
{
s = property_number_tag;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
s = nv_parms.s.property_number;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
tx_msg.uint8[i++] = even_parity[')'];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
}
if (nv_parms.s.serial_number[0])
{
s = serial_number_tag;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
s = nv_parms.s.serial_number;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
tx_msg.uint8[i++] = even_parity[')'];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
}
s = energy_tag;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
last_reported_total_consumed_kwh = total_consumed_kwh;
last_reported_total_consumed_100mwh = total_consumed_100mwh;
bin2bcd32(bcd, last_reported_total_consumed_kwh);
tx_msg.uint8[i++] = even_parity['0' + ((bcd[2] >> 4) & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + (bcd[2] & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + ((bcd[3] >> 4) & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + (bcd[3] & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + ((bcd[4] >> 4) & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + (bcd[4] & 0xF)];
tx_msg.uint8[i++] = even_parity['.'];
bin2bcd16(bcd, last_reported_total_consumed_100mwh);
tx_msg.uint8[i++] = even_parity['0' + ((bcd[1] >> 4) & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + (bcd[1] & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + ((bcd[2] >> 4) & 0xF)];
tx_msg.uint8[i++] = even_parity['0' + (bcd[2] & 0xF)];
tx_msg.uint8[i++] = even_parity[')'];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
s = status_tag;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
x = '0' + ((iec1107d_status >> 4) & 0xF);
if (x > '9')
x += 7;
tx_msg.uint8[i++] = even_parity[x];
x = '0' + (iec1107d_status & 0xF);
if (x > '9')
x += 7;
tx_msg.uint8[i++] = even_parity[x];
tx_msg.uint8[i++] = even_parity[')'];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
if (nv_parms.s.factory_number[0])
{
s = factory_number_tag;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
s = nv_parms.s.factory_number;
while (*s)
tx_msg.uint8[i++] = even_parity[*s++];
tx_msg.uint8[i++] = even_parity[')'];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
}
tx_msg.uint8[i++] = even_parity['!'];
tx_msg.uint8[i++] = even_parity['\r'];
tx_msg.uint8[i++] = even_parity['\n'];
tx_msg_ptr = 0;
tx_msg_len = i;
#if defined(USART1TX_VECTOR)
IE2 |= UTXIE1;
#else
U0IE |= UTXIE0;
#endif
}
#endif
#if defined(__MSP430__) && (defined(IEC1107_SUPPORT) || defined(SERIAL_CALIBRATION_SUPPORT))
int send_msg(int len)
{
if (len > 4 + 12 + MAX_IEC1107_MSG_BODY)
return FALSE;
tx_msg_ptr = 0;
tx_msg_len = len;
#if defined(USART1TX_VECTOR)
IE2 |= UTXIE1;
#else
U0IE |= UTXIE0;
#endif
return TRUE;
}
int prepare_tx_message(int len)
{
int i;
tx_msg.uint8[0] = 0xFE;
tx_msg.uint8[1] = 0xFE;
tx_msg.uint8[2] = 0xFE;
tx_msg.uint8[3] = 0xFE;
tx_msg.uint8[4] = 0x68;
tx_msg.uint8[5] = 0x99;
tx_msg.uint8[6] = 0x99;
tx_msg.uint8[7] = 0x99;
tx_msg.uint8[8] = 0x99;
tx_msg.uint8[9] = 0x99;
tx_msg.uint8[10] = 0x99;
tx_msg.uint8[11] = 0x68;
tx_msg.uint8[12] = 0x23;
tx_msg.uint8[13] = len;
tx_msg.uint8[IEC1107_MSG_TX_START_BODY + len] = 0;
tx_msg.uint8[IEC1107_MSG_TX_START_BODY + len + 1] = 0x16;
for (i = 4; i < IEC1107_MSG_TX_START_BODY + len; i++)
tx_msg.uint8[IEC1107_MSG_TX_START_BODY + len] += tx_msg.uint8[i];
return send_msg(IEC1107_MSG_TX_START_BODY + len + 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -