This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F425: Calibrating the e-meter

Other Parts Discussed in Thread: MSP430F425, MSP430AFE253

Tool/software: TI C/C++ Compiler

HI,

I have to work on MSP430F425. My code in the TI TIDC299 software.

I tried to calibrate the meter but the texas instruments 430 calibrated mass

  Turn on red. So there is a communication error. I used a simple terminal to test communication uart which is configured in tidc449 I find that the communication is established correctly and there are messages that I received. I did not understand where the problem is. I think there is a communication between the graphical interface of TI GUI and the code tidc499 which allows to test the communication because there is no problem on the hardware side. I need help to know the instruction in the communication part which is dided to test the communication. Always the graphical interface turning red.

emeter-communication.c
//--------------------------------------------------------------------------
//
//  Software for MSP430 based e-meters.
//
//  THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
//  REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
//  INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
//  FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
//  COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
//  TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
//  POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
//  INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
//  YOUR USE OF THE PROGRAM.
//
//  IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
//  CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
//  THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
//  OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
//  OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
//  EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
//  REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
//  OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
//  USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
//  AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
//  YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
//  (U.S.$500).
//
//  Unless otherwise stated, the Program written and copyrighted
//  by Texas Instruments is distributed as "freeware".  You may,
//  only under TI's copyright in the Program, use and modify the
//  Program without any charge or restriction.  You may
//  distribute to third parties, provided that you transfer a
//  copy of this license to the third party and the third party
//  agrees to these terms by its first use of the Program. You
//  must reproduce the copyright notice and any other legend of
//  ownership on each copy or partial copy, of the Program.
//
//  You acknowledge and agree that the Program contains
//  copyrighted material, trade secrets and other TI proprietary
//  information and is protected by copyright laws,
//  international copyright treaties, and trade secret laws, as
//  well as other intellectual property laws.  To protect TI's
//  rights in the Program, you agree not to decompile, reverse
//  engineer, disassemble or otherwise translate any object code
//  versions of the Program to a human-readable form.  You agree
//  that in no event will you alter, remove or destroy any
//  copyright notice included in the Program.  TI reserves all
//  rights not specifically granted under this license. Except
//  as specifically provided herein, nothing in this agreement
//  shall be construed as conferring by implication, estoppel,
//  or otherwise, upon you, any license or other right under any
//  TI patents, copyrights or trade secrets.
//
//  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.8 2007/08/07 05:55:38 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

#define MEASURES_ACTIVE_POWER                   0x01
#define MEASURES_TRIGONOMETRIC_REACTIVE_POWER   0x02
#define MEASURES_VA_POWER                       0x04
#define MEASURES_VRMS                           0x08
#define MEASURES_IRMS                           0x10
#define MEASURES_POWER_FACTOR                   0x20
#define MEASURES_MAINS_FREQUENCY                0x40
#define MEASURES_QUADRATURE_REACTIVE_POWER      0x80

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) // changer
        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);
}








void process_rx_message(serial_msg_t *rx_msg, int rx_len)
{
    int i;
    int32_t z;
    int32_t z1;
  
    uint16_t *last_flash_loc;

    /* Messages with type 0x23 are custom messages we
      use for calibration, password protection, etc.
      All other message types go to a custom message
      handler (if available). */
    if (rx_msg->uint8[8] != 0x23)
    {
#if CUSTOM_SERIAL_MESSAGE_SUPPORT
        custom_serial_message_handler(&rx_msg, rx_msg_len);
#endif
        return;
    }
    if ((rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] & 0x80))
    {
        /* This looks like one of our own messages, which has echoed back
           to us */
        return;
    }

    /* Only process messages if the password has been given correctly
       (except for the password test message, of course). */
    if (!(meter_status & PASSWORD_OK)  &&  rx_msg->uint8[IEC1107_MSG_RX_START_BODY] != 0x60)
        return;

    switch (rx_msg->uint8[IEC1107_MSG_RX_START_BODY])
    {
    case HOST_CMD_GET_METER_CONFIGURATION:
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 2] = NUM_PHASES;
    #if defined(NEUTRAL_MONITOR_SUPPORT)
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 3] = 1;
    #else
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 3] = 0;
    #endif
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 4] = 0
    #if defined(LIMP_MODE_SUPPORT)
                                                    | 0x01
    #endif
    #if defined(PHASE_CORRECTION_SUPPORT)
                                                    | 0x02
    #endif
    #if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
                                                    | 0x04
    #endif
    #if defined(RTC_SUPPORT)
                                                    | 0x08
    #endif
    #if defined(CORRECTED_RTC_SUPPORT)
                                                    | 0x10
    #endif
    #if defined(TEMPERATURE_SUPPORT)
                                                    | 0x20
    #endif
    #if SELF_TEST_SUPPORT
                                                    | 0x40
    #endif
    #if MULTI_RATE_SUPPORT
                                                    | 0x80
    #endif
                                                    ;

        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 5] = MEASURES_ACTIVE_POWER
    #if defined(REACTIVE_POWER_SUPPORT)  &&  !defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT)
                                                    | MEASURES_TRIGONOMETRIC_REACTIVE_POWER
    #endif
    #if defined(VA_POWER_SUPPORT)
                                                    | MEASURES_VA_POWER
    #endif
    #if defined(VRMS_SUPPORT)
                                                    | MEASURES_VRMS
    #endif
    #if defined(IRMS_SUPPORT)
                                                    | MEASURES_IRMS
    #endif
    #if defined(POWER_FACTOR_SUPPORT)
                                                    | MEASURES_POWER_FACTOR
    #endif
    #if defined(MAINS_FREQUENCY_SUPPORT)
                                                    | MEASURES_MAINS_FREQUENCY
    #endif
    #if defined(REACTIVE_POWER_SUPPORT)  &&  defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT)
                                                    | MEASURES_QUADRATURE_REACTIVE_POWER
    #endif
                                                    ;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 6] = 0x00
    #if GAIN_STAGES > 1
                                                    | 0x01
    #endif
                                                    ;
        prepare_tx_message(7);
        break;
    case HOST_CMD_SET_METER_CONSUMPTION:
        z = rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
        z |= (int32_t) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 2] << 16;
        z1 = rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 3];
        z1 |= (int32_t) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 4] << 16;
        custom_set_consumption(z, z1);
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        prepare_tx_message(2);
    case HOST_CMD_SET_RTC:
    #if defined(RTC_SUPPORT)
        rtc.year = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 2];
        rtc.month = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 3];
        rtc.day = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 4];
        rtc.hour = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 5];
        rtc.minute = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 6];
        rtc.second = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 7];
        set_rtc_sumcheck();
    #endif
    #if defined(CUSTOM_RTC_SUPPORT)
        custom_rtc_set(rx_msg->uint8);
    #endif
    #if defined(MULTI_RATE_SUPPORT)
        multirate_align_with_rtc();
    #endif
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        prepare_tx_message(2);
        break;
    case HOST_CMD_GET_RTC:
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
    #if defined(RTC_SUPPORT)
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 2] = rtc.year;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 3] = rtc.month;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 4] = rtc.day;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 5] = rtc.hour;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 6] = rtc.minute;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 7] = rtc.second;
    #endif
    #if defined(CUSTOM_RTC_SUPPORT)
        custom_rtc_retrieve(tx_msg.uint8);
    #endif
    #if defined(TEMPERATURE_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = temperature;
    #endif
        prepare_tx_message(10);
        break;
    case HOST_CMD_SET_PASSWORD:
        /* Check the calibration password */
        if (rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1] == SERIAL_CALIBRATION_PASSWORD_1
           &&
           rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 2] == SERIAL_CALIBRATION_PASSWORD_2
           &&
           rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 3] == SERIAL_CALIBRATION_PASSWORD_3
           &&
           rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 4] == SERIAL_CALIBRATION_PASSWORD_4)
        {
            meter_status |= PASSWORD_OK;
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
            prepare_tx_message(2);
        }
        else
        {
            /* Only respond to a bad password, if the password was good before. That lets
               us know we have unset the password OK, but doesn't give any information to
               people trying to attack the meter. */
            if ((meter_status & PASSWORD_OK))
            {
                tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
                tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
                prepare_tx_message(2);
            }
            meter_status &= ~PASSWORD_OK;
        }
        break;
    case HOST_CMD_GET_READINGS_PHASE_1:
    #if !defined(SINGLE_PHASE)
    case HOST_CMD_GET_READINGS_PHASE_2:
    case HOST_CMD_GET_READINGS_PHASE_3:
        /* Exchange voltage, current and power readings (neutral).
           frequency, power factor and reactive power readings. */
        phase = &chan[rx_msg->uint8[IEC1107_MSG_RX_START_BODY] - 0x61];
    #endif
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
    #if defined(VRMS_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = phase->V_rms;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = 0;
    #endif
    #if defined(IRMS_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = phase->current.I_rms;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = 0;
    #endif
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = phase->current.power;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = phase->current.power >> 16;
    #if defined(REACTIVE_POWER_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = phase->reactive_power;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = phase->reactive_power >> 16;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = 0;
    #endif
    #if defined(VA_POWER_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = phase->VA_power;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 8] = phase->VA_power >> 16;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 8] = 0;
    #endif

    #if defined(POWER_FACTOR_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 9] = phase->power_factor;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 9] = 0;
    #endif
    #if defined(MAINS_FREQUENCY_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 10] = phase->frequency;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 10] = 0;
    #endif
    #if defined(LIMP_MODE_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 11] = phase->V_dc_estimate[0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 12] = phase->V_dc_estimate[0] >> 16;
    #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 11] = phase->V_dc_estimate;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 12] = phase->V_dc_estimate >> 16;
    #endif
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 13] = phase->current.I_dc_estimate[0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 14] = phase->current.I_dc_estimate[0] >> 16;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 30] = 0;
        prepare_tx_message(31);
        break;
    #if defined(NEUTRAL_MONITOR_SUPPORT)
    case HOST_CMD_GET_READINGS_NEUTRAL:
        /* Exchange voltage, current and power readings (neutral).
           frequency, power factor and reactive power readings. */
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        #if defined(SINGLE_PHASE)
            #if defined(VRMS_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = phase->V_rms;
            #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = 0;
            #endif
            #if defined(IRMS_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = phase->neutral.I_rms;
            #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = 0;
            #endif
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = phase->neutral.power;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = phase->neutral.power >> 16;
            #if REACTIVE_POWER_SUPPORT
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = phase->reactive_power;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = phase->reactive_power >> 16;
            #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = 0;
            #endif
            #if VA_POWER_SUPPORT
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = phase->VA_power;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 8] = phase->VA_power >> 16;
            #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 8] = 0;
            #endif
            #if defined(POWER_FACTOR_SUPPORT)
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 9] = phase->power_factor;
            #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 9] = 0;
            #endif
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 10] = phase->frequency;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 11] = phase->V_dc_estimate;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 12] = phase->V_dc_estimate >> 16;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 13] = phase->neutral.I_dc_estimate[0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 14] = phase->neutral.I_dc_estimate[0] >> 16;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 30] = 0;
        #else
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = neutral.I_rms;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 8] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 9] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 10] = phase->frequency;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 11] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 12] = 0;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 13] = phase->current.I_dc_estimate;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 14] = phase->current.I_dc_estimate >> 16;
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 30] = 0;
        #endif
        prepare_tx_message(31);
        break;
    #endif
    case HOST_CMD_ERASE_FLASH_SEGMENT:
        /* Initialise flash data download, by erasing the area to be used, and setting the
           write pointer. */
        /* There is no checking here to ensure we do not erase inappropriate places. */
        next_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
        flash_clr((int16_t *) next_flash_loc);
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        prepare_tx_message(2);
        break;
    case HOST_CMD_SET_FLASH_POINTER:
        next_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        prepare_tx_message(2);
        break;
    case HOST_CMD_FLASH_DOWNLOAD:
        if (is_calibration_enabled())
        {
            next_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
            for (i = 2;  i < (rx_len - 12) >> 1;  i++)
                flash_write_int16((int16_t *) next_flash_loc++, rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + i]);
            flash_secure();
            /* Return the next address to the host, so it can check for missed messages */
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
            tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = (uint16_t) next_flash_loc;
            prepare_tx_message(4);
        }
        break;
    case HOST_CMD_FLASH_UPLOAD:
        if (is_calibration_enabled())
        {
            next_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
            for (i = 1;  i < MAX_IEC1107_MSG_BODY/2;  i++)
                tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + i] = *next_flash_loc++;
            prepare_tx_message(MAX_IEC1107_MSG_BODY);
        }
        break;
    case HOST_CMD_ZAP_MEMORY_AREA:
        /* Zap memory area (usually this will be flash) */
        if (is_calibration_enabled())
        {
            next_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
            last_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 2];
            while (next_flash_loc < last_flash_loc)
                flash_write_int16((int16_t *) next_flash_loc++, rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 3]);
            flash_secure();
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
            tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = (uint16_t) next_flash_loc;
            prepare_tx_message(4);
        }
        break;
    case HOST_CMD_SUMCHECK_MEMORY:
        /* Sumcheck a specified memory area, and return the sumcheck */
        if (is_calibration_enabled())
        {
            next_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 1];
            last_flash_loc = (uint16_t *) rx_msg->uint16[IEC1107_MSG_RX_START_BODY_W + 2];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
            tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
            tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = 0;
            while (next_flash_loc < last_flash_loc)
                tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] += *next_flash_loc++;
            flash_secure();
            prepare_tx_message(4);
        }
        break;
    case HOST_CMD_GET_RAW_POWER_PHASE_1:
    #if !defined(SINGLE_PHASE)
    case HOST_CMD_GET_RAW_POWER_PHASE_2:
    case HOST_CMD_GET_RAW_POWER_PHASE_3:
        phase = &chan[rx_msg->uint8[IEC1107_MSG_RX_START_BODY] - 0x91];
    #endif
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = phase->sample_count_logged;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = phase->current.P_accum_logged[0][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = phase->current.P_accum_logged[0][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = phase->current.P_accum_logged[0][2];
#if GAIN_STAGES > 1
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = phase->current.P_accum_logged[1][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = phase->current.P_accum_logged[1][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = phase->current.P_accum_logged[1][2];
        prepare_tx_message(16);
#else
        prepare_tx_message(10);
#endif
        break;
    #if defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT)
    case HOST_CMD_GET_RAW_REACTIVE_POWER_PHASE_1:
        #if !defined(SINGLE_PHASE)
    case HOST_CMD_GET_RAW_REACTIVE_POWER_PHASE_2:
    case HOST_CMD_GET_RAW_REACTIVE_POWER_PHASE_3:
        phase = &chan[rx_msg->uint8[IEC1107_MSG_RX_START_BODY] - 0x95];
        #endif
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = phase->sample_count_logged;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = phase->current.P_reactive_accum_logged[0][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = phase->current.P_reactive_accum_logged[0][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = phase->current.P_reactive_accum_logged[0][2];
#if GAIN_STAGES > 1
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = phase->current.P_reactive_accum_logged[1][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = phase->current.P_reactive_accum_logged[1][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = phase->current.P_reactive_accum_logged[1][2];
        prepare_tx_message(16);
#else
        prepare_tx_message(10);
#endif
        break;
    #endif
    #if defined(SINGLE_PHASE)  &&  defined(NEUTRAL_MONITOR_SUPPORT)
    case HOST_CMD_GET_RAW_POWER_NEUTRAL:
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = phase->sample_count_logged;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = phase->neutral.P_accum_logged[0][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = phase->neutral.P_accum_logged[0][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = phase->neutral.P_accum_logged[0][2];
#if GAIN_STAGES > 1
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = phase->neutral.P_accum_logged[1][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = phase->neutral.P_accum_logged[1][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = phase->neutral.P_accum_logged[1][2];
        prepare_tx_message(16);
#else
        prepare_tx_message(10);
#endif
        break;
        #if defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT)
    case HOST_CMD_GET_RAW_REACTIVE_POWER_NEUTRAL:
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = phase->sample_count_logged;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = phase->neutral.P_reactive_accum_logged[0][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 3] = phase->neutral.P_reactive_accum_logged[0][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 4] = phase->neutral.P_reactive_accum_logged[0][2];
#if GAIN_STAGES > 1
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 5] = phase->neutral.P_reactive_accum_logged[0][0];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 6] = phase->neutral.P_reactive_accum_logged[0][1];
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 7] = phase->neutral.P_reactive_accum_logged[0][2];
        prepare_tx_message(16);
#else
        prepare_tx_message(10);
#endif
        break;
        #endif
    #endif
    case HOST_CMD_CHECK_RTC_ERROR:
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
    #if defined(__MSP430_HAS_TA3__)
        z = assess_rtc_speed();
    #endif
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = z;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = z >> 16;
        prepare_tx_message(6);
        break;
    #if defined(CORRECTED_RTC_SUPPORT)
    case HOST_CMD_RTC_CORRECTION:
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = rtc_correction;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 2] = rtc_correction >> 16;
        prepare_tx_message(6);
        break;
    #endif
    #if defined(MULTI_RATE_SUPPORT)
    case HOST_CMD_MULTIRATE_SET_PARAMETERS:
        i = multirate_put(&rx_msg->uint8[IEC1107_MSG_RX_START_BODY]);
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = i;
        prepare_tx_message(4);
        break;
    case HOST_CMD_MULTIRATE_GET_PARAMETERS:
        i = multirate_get(&rx_msg->uint8[IEC1107_MSG_RX_START_BODY], &tx_msg.uint8[IEC1107_MSG_TX_START_BODY]);
        prepare_tx_message(i);
        break;
    case HOST_CMD_MULTIRATE_CLEAR_USAGE:
        i = multirate_clear_usage(&rx_msg->uint8[IEC1107_MSG_RX_START_BODY]);
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY + 1] | 0x80;
        tx_msg.uint16[IEC1107_MSG_TX_START_BODY_W + 1] = i;
        prepare_tx_message(4);
        break;
    case HOST_CMD_MULTIRATE_GET_USAGE:
        i = multirate_get_usage(&rx_msg->uint8[IEC1107_MSG_RX_START_BODY], &tx_msg.uint8[IEC1107_MSG_TX_START_BODY]);
        prepare_tx_message(i);
        break;
    #endif
    default:
        /* For all other message types reply with type 0xFF - bad message type */
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY] = rx_msg->uint8[IEC1107_MSG_RX_START_BODY];
        tx_msg.uint8[IEC1107_MSG_TX_START_BODY + 1] = 0xFF;
        prepare_tx_message(2);
        break;
    }
}
#endif

#if defined(__MSP430__)  &&  (defined(IEC1107_SUPPORT)  ||  defined(SERIAL_CALIBRATION_SUPPORT))  &&  (defined(USART0RX_VECTOR)  ||  defined(USART0RX_ISR))
/* Interrupt to accept IEC1107 messages. */
ISR(USART0RX, serial_rx_interrupt0)
{
    uint8_t ch;
    int i;
    int sum;

    ch = RXBUF0;
    if (char_timeout_1107 == 0)
        rx_msg_ptr = 0;
    char_timeout_1107 = SAMPLES_PER_10_SECONDS/200;
    if (rx_msg_ptr == 0)
    {
        if (ch == 0x68)
        {
            rx_msg.uint8[rx_msg_ptr++] = ch;
            rx_msg_len = 12 + MAX_IEC1107_MSG_BODY;
        }
    }
    else
    {
        if (rx_msg_ptr == 9)
        {
            if (ch <= MAX_IEC1107_MSG_BODY)
                rx_msg_len = 12 + ch;
            else
                rx_msg_ptr = 0;
        }
        rx_msg.uint8[rx_msg_ptr++] = ch;
        if (rx_msg_ptr == rx_msg_len)
        {
            /* End of message */
            sum = rx_msg.uint8[0];
            for (i = 1;  i < rx_msg_len - 2;  i++)
                sum += rx_msg.uint8[i];
            if (rx_msg.uint8[rx_msg_len - 2] == (sum & 0xFF)
                &&
                rx_msg.uint8[rx_msg_len - 1] == 0x16)
            {
                /* Good message received */
                process_rx_message(&rx_msg, rx_msg_len);
            }
            rx_msg_ptr = 0;
        }
  
    
    }
    
     IFG2 &= ~URXIFG0;
}
#endif

#if defined(__MSP430__)  &&  (defined(IEC1107_SUPPORT)  ||  defined(SERIAL_CALIBRATION_SUPPORT))  &&  (defined(USART1RX_VECTOR)  ||  defined(USART1RX_ISR))
/* Interrupt to accept IEC1107 messages. */
ISR(USART1RX, serial_rx_interrupt1)
{
    uint8_t ch;
    int i;
    int sum;

    ch = RXBUF1;
    if (char_timeout_1107 == 0)
        rx_msg_ptr = 0;
    char_timeout_1107 = SAMPLES_PER_10_SECONDS/200;
    if (rx_msg_ptr == 0)
    {
        if (ch == 0x68)
        {
            rx_msg.uint8[rx_msg_ptr++] = ch;
            rx_msg_len = 12 + MAX_IEC1107_MSG_BODY;
        }
    }
    else
    {
        if (rx_msg_ptr == 9)
        {
            if (ch <= MAX_IEC1107_MSG_BODY)
                rx_msg_len = 12 + ch;
            else
                rx_msg_ptr = 0;
        }
        rx_msg.uint8[rx_msg_ptr++] = ch;
        if (rx_msg_ptr == rx_msg_len)
        {
            /* End of message */
            sum = rx_msg.uint8[0];
            for (i = 1;  i < rx_msg_len - 2;  i++)
                sum += rx_msg.uint8[i];
            if (rx_msg.uint8[rx_msg_len - 2] == (sum & 0xFF)
                &&
                rx_msg.uint8[rx_msg_len - 1] == 0x16)
            {
                /* Good message received */
                process_rx_message(&rx_msg, rx_msg_len);
            }
            rx_msg_ptr = 0;
        }
    }
}
#endif

/* Interrupt to send IEC1107 messages. */
#if defined(__MSP430__)  &&  (defined(IEC1107_SUPPORT)  ||  defined(SERIAL_CALIBRATION_SUPPORT))  &&  (defined(USART0TX_VECTOR)  ||  defined(USART0TX_ISR))
ISR(USART0TX, serial_tx_interrupt0)
{
    TXBUF0 = tx_msg.uint8[tx_msg_ptr++];
    if (tx_msg_ptr >= tx_msg_len)
    {
        /* Stop transmission */
        U0IE &= ~UTXIE0;
        tx_msg_ptr = 0;
        tx_msg_len = 0;
    }
}
#endif

#if defined(__MSP430__)  &&  (defined(IEC1107_SUPPORT)  ||  defined(SERIAL_CALIBRATION_SUPPORT))  &&  (defined(USART1TX_VECTOR)  ||  defined(USART1TX_ISR))
ISR(USART1TX, serial_tx_interrupt1)
{
    TXBUF1 = tx_msg.uint8[tx_msg_ptr++];
    if (tx_msg_ptr >= tx_msg_len)
    {
        /* Stop transmission */
        IE2 &= ~UTXIE1;
        tx_msg_ptr = 0;
        tx_msg_len = 0;
    }
}
#endif

  • I think the problem in the function
    Int prepare_tx_message (int len)
    Is that this function ensures the communication test between the interface and the counter !!
      Help me please .
  • Arfaoui,

    Are you configuring the COM port on your PC properly? You have to check Device Manager in Windows to find out which COM port the RS232-to-USB adapter is using. Then, you have to update the COM port number in the 'calibration-config.xml' file in "tidc299.zip" -> "emeter-software" -> "emeter-software" -> "GUI" folder. Also, I'm assuming that you're using one of our EVMs or a custom hardware that has the UART interface implemented properly.

    Regards,

    James

    MSP Customer Applications

  • thank you James for reply,
    Yes i have configure com 6 and also i change the port in the xml file of GUI and i am sure the hardware communication is well established. Because I have tested its functionality by a simple terminal I think the problem software side for this I am looking for it is the responsible function has established the beginning of communication.

  • If you are using a simple terminal program, you'll need to send commands to the i20xx device using the dlt645 protocol. I've found that the Serial Port Utility terminal software allows multi-byte packets required for this protocol to be generated. The GUI uses this protocol with the default communication code to pass data back and forth. Since you're using a simple terminal program, you're probably sending data byte-by-byte, which may not work correctly with the state machine in the code for the various commands. Perhaps you could use a logic analyzer to monitor what's being send over the UART interface as well.

    Although you are sure that your hardware is working, it may be good to try the original code on our EVM as a comparison. If you're already using an EVM, then this wouldn't apply.

    Regards,

    James

    MSP Customer Applications

  • Hi JAMES,

    I think I can do an interface using MATLAB which allows to read and write data on the counter to calibrate the values ​​to avoid the standard screen format for the old interface is possible !!! I change my configuration uart for a simple communication of sending and receiving the problem is what possible to interfere MATLAB with MSP430F425 !! Is what a good idea !! Because I think the TIDC299 code uses an IEC1107 communication protole and the interface uses dlt645.

  • Hello,

    You can use MATLAB to read and write data from/to the device, but you'll have to either change the existing protocol in the code according to the protocol that you've chosen or match the existing protocol. For the first option, this would require a substantial amount of work for you, but if the latter option won't work (e.g. commands don't do what you need them to do), it can be done.

    I'm sorry if I've misunderstood your question.

    Regards,

    James

    MSP Customer Applications
  • James is what you can explain how to change protocol with MATLAB !! If you have any documents or a link that can help me !!!
    thank you very much
  • Hello,

    Unfortunately, I don't have much experience with using MATLAB to interface with hardware, but I found some links that may be helpful (see below). Also, if you interested in keeping the DLT645 protocol as-is on the MSP430F425 and just want to use MATLAB to read the results, calibrate the device, etc., I would encourage you to post a question about how to do this in MATLAB's Community and Support website.

    If you would like to change the DLT645 protocol, this can be done but would involve extensive work. I don't have any specific references on how to do this, but if you have a specific UART-based protocol that you're required to use, you can modify the code to create the appropriate data packet (frame start notification, address, control bits, data, checksum, etc.) according to the specifications for that protocol. For example, you can read about the structure of the DLT645 protocol in Appendix A in the MSP430AFE253 Test Report for China State Grid Specification app note.

    Hopefully this helps.

    Regards,

    James

    MSP Customer Applications

  • thank you james,
    i Have a problem when i transfer the data by uart the data receive in MATLAB interface is not the same i don't unserstund where is the problem ( baudrate of uart is not good configuration or the data in rs232 change the format)

    //UART CONFIGURATION
    UCTL0 = SWRST;
    P2DIR |= (BIT4);
    P2OUT &= ~(BIT4);

    P2SEL |= BIT4 + BIT5; // P2.5 UCA0RXD inputBIT4 +
    ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
    UCTL0 = CHAR;
    UTCTL0 |= SSEL1; // UCLK = ACLK = 32.768kHz
    UBR00 = 0x69;
    UBR10 = 0x3;
    UMCTL0 = 0x03;
    UCTL0 &= ~SWRST; // Initialize USART state machine
    IE2 |= URXIE0 + UTXIE0; // Enable USART0 RX/TX interrupt



    // interruption de reception et de transmition
    #if defined(__MSP430__)
    /* Interrupt to accept IEC1107 messages. */
    ISR(USART0RX, serial_rx_interrupt0)
    {
    uint8_t ch;
    int i;
    int sum;

    ch = RXBUF0;


    IFG2 &= ~URXIFG0;

    }
    #endif


    /* Interrupt to send IEC1107 messages. */
    #if defined(__MSP430__)
    ISR(USART0TX, serial_tx_interrupt0)
    {


    TXBUF0 = rx_msg;



    IFG2 &= ~UTXIFG0;
    }
    #endif
  • The UART of MSP430 work in ASCII!!! beacuse when i send a value i receive an other value!!!

**Attention** This is a public forum