⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flag1.c

📁 TDK 6521 SOC 芯片 DEMO程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************************************************
 * This code and information is provided "as is" without warranty of any   *
 * kind, either expressed or implied, including but not limited to the     *
 * implied warranties of merchantability and/or fitness for a particular   *
 * purpose.                                                                *
 *                                                                         *
 * Copyright (C) 2005 Teridian Semiconductor Corp. All Rights Reserved.    *
 ***************************************************************************/
//**************************************************************************
//    
//  DESCRIPTION: 71M652x POWER METER - FLAG protocol. 
//  This code is a state machine that sends and receives messages.
//  The messages are interpreted and constructed using "templates."
//  The code was written once, tested, then ported to the other port
//  by copying the code, and including the other port's serial driver.
//  The message templates are byte-arrays stored in flag.c.
//  The input interrupt flag_in() steps through the message template.
//  The output interrupt flag_out() uses the message template to construct
//  the next character to send.
//  Whenever an input or output message is complete, the interrupt
//  calls the overall state machine, flag_state().
// 
//  AUTHOR:  RGV
//
//  HISTORY: See end of file
//
//**************************************************************************
//               
// File: flag.c
//               
//**************************************************************************
// This file is the shared logic of all the flag interfaces on a meter.
// This flag protocol is a simplified subset, with fixed baud rates, 
// a fixed password and only a few commands.
// To use this file, include it after including a serial hardware abstraction
// layer.  See flag0.c and ser0.h for an example.


#include "options.h"
#if FLAG && FLAG1
#include "calibration.h"
#include "irq.h"
#include "ce.h"
#include "flag.h" // shared parts, mostly message templates
#include "library.h"
#include "meter.h"
#include "sfrs.h"  // access to SFRs
#include "stm.h"

#define PORT 1

#if PORT==0
#include "ser0.h"
#include "flag0.h"
#endif

#if PORT==1
#include "ser1.h"
#include "flag1.h"
#endif

#define LOGGING 0

// Variables are not differentiated by direction of data motion
// because the protocol is "strictly half duplex"- it's not needed
static uint8x_t state; // the protocol state
static bool authorized; // got a valid password
static bool out; // 1 = transmitting is OK, 0 = receving is ok
static uint8x_t cur_char; // the current character
static uint8d_t t;  // temporary data (has to be "data" to read SFRs)
static uint8x_t bcc; // the checksum (longitudinal parity)
static uint8x_t error; // the current error status
static uint8x_t error_last_rcv; // the error of the last receved message
static uint8r_t *msg_ptr; // the current message
static uint8x_t msg_fld_index; // where it is in the current message
static uint8x_t msg_fld, msg_fld_next; // the data that should be at this place
static uint8x_t cmd, cmd_subtype; // the last command and subtype
static uint8x_t cmd_main;  // set in interrupt, cleared in main loop
static uint16x_t address;  // xdata memory address
static uint8x_t data_bit_index;  // where to put the next hex digit, usually
static uint8x_t hex_byte;  // the value of a byte
static uint8x_t char_cnt;  // req. characters...
static uint8x_t data_cnt;  // req. bytes...
static uint8x_t data_index;  // where to put the next data byte, usually
static uint8x_t data_buffer[MAX_DATA_INDEX + 1]; // Buffers data for writing
static STM      char_timer; // measures time between characters
static uint16x_t *session_timer; // time till flag signs off


#if LOGGING != 1
#define log(_v_)
#else
uint8x_t log_data[16];
uint8d_t log_index;

// insert to the log
#pragma save
#pragma NOAREGS
void log (uint8_t val) small reentrant
{
   log_index = 0x0f & (++log_index);
   log_data[log_index] = val;
}
#pragma restore
#endif

// This starts the shared routines of the flag state machine

/* starts the character receive timeout */
#pragma save
#pragma NOAREGS
static void fail_char_timer (void) small reentrant
{
    error = CharTimeout;
    log(0x80);
    log(error);
    char_timer = NULL;
}
static void reset_char_timer (void) small reentrant
{
#if TIMERS
    if (char_timer != NULL)
    {
        *char_timer = CHAR_TIMEOUT;
    }
    else
    {
        char_timer = stm_start (CHAR_TIMEOUT, FALSE, fail_char_timer);
    }
#endif
}
#pragma restore

/* stops the character receive timeout */
#if TIMERS
#pragma save
#pragma NOAREGS
static void stop_char_timer (void) small reentrant
{
    if (char_timer != NULL) {
        stm_stop ( char_timer );
    }
    char_timer = NULL;
}
#pragma restore
#endif

/* starts the session timeout */
#if TIMERS
#pragma save
#pragma NOAREGS
static void fail_session_timer (void) small reentrant
{
    error = SessionTimeout;
    log(0x81);
    log(error);
    session_timer = NULL;
}
static void reset_session_timer (void) small reentrant
{
    if ( session_timer != NULL ) {
        *session_timer = SESSION_TIMEOUT;
    } else {
        session_timer = stm_start (SESSION_TIMEOUT, FALSE, fail_session_timer);
    }
}
#pragma restore
#endif

/* transmit- starts transmission a message */
#pragma save
#pragma NOAREGS
static void xmit(void) small reentrant
{
#if TIMERS
    stop_char_timer ();
#endif
    ser_disable_rcv_rdy(); // disable receive interrupt
    data_index = 0;  // where to put the next data byte, usually
    out = 1;
    log(0xFF);
    ser_xmit_on(); // power up or switch-in transmitter; xmit is not free
    ser_enable_xmit_rdy(); // enable transmit interrupt
}
#pragma restore

/* receive- starts receiving a message */
#pragma save
#pragma NOAREGS
static void recv(void) small reentrant
{
    #if TIMERS
    stop_char_timer ();
    reset_session_timer (); // start the session timer
    #endif
    
    ser_xmit_off(); // power off or switch-out transmitter; xmit is not free
    ser_disable_xmit_rdy(); // disable transmit interrupt
    out = 0;
    data_index = 0;  // where to put the next data byte, usually
    log(0xFE);
    ser_enable_rcv_rdy(); // enable receive interrupt
}
#pragma restore

// start transmitting an error
#pragma save
#pragma NOAREGS
static void xmit_error (void) small reentrant
{
    state = STATE_XMIT_ERR;
    msg_ptr = msg_err;
    xmit(); /* start transmitting a message */
}
#pragma restore

// request that the message be repeated
#pragma save
#pragma NOAREGS
static void xmit_nak (void) small reentrant
{
    state = STATE_XMIT_NAK;
    msg_ptr = msg_nak;
    xmit(); /* start transmitting a message */
}
#pragma restore

// start a new message
#pragma save
#pragma NOAREGS
static void new_msg (void) small reentrant
{
    msg_fld_index = 0;
    cmd = 0;
    cmd_subtype = 0; // the last command and subtype
    address = 0;  // default
    data_bit_index = 0;  // where to put the next hex digit, usually
    hex_byte = 0;  // the value of a byte
    char_cnt = 0;  // up to characters...
    data_cnt = 0;  // up to bytes...
    error = NoError;
    log(0x82);
    log(error);
}
#pragma restore

//  starting state; permits signing on
#pragma save
#pragma NOAREGS
static void sign_on (void) small reentrant
{
    ser_xmit_free ();  // free the transmit LED for pulsing 
    new_msg ();  // initialize the message variables
    authorized = FALSE;
    REG_LOCKED = FALSE;
    state = STATE_RCV_SIGN_ON;
    msg_ptr = msg_sign_on;
    recv(); /* start receiving a message */
    #if TIMERS
    if (session_timer != NULL) {
       stm_stop (session_timer);
    }
    session_timer = NULL;
    stop_char_timer ();
    #endif
}
#pragma restore

// acknowledge the previous message, so it is not retransmitted
#pragma save
#pragma NOAREGS
static void xmit_ack (void) small reentrant
{
    state = STATE_XMIT_ACK;
    msg_ptr = msg_ack;
    xmit(); /* start transmitting a message */
}
#pragma restore

/* the flag state machine- the one that selects which
 * messages to send and receive 
 * This machine runs when a message is complete, to 
 * determine the next message to send or receive.
 * The flag protocol is strictly half-duplex...
 * */

#pragma save
#pragma NOAREGS
// this copes with the received sign-on message
static void send_id (void) small reentrant
{
    if (error != NoError) {
       sign_on (); // enables receive, turns off timeouts
    } else {
       state = STATE_XMIT_ID;
       msg_ptr = msg_id;
       xmit(); // transmit a message, char timeout stops, restart msg timeout
    }
}
#pragma restore

#pragma save
#pragma NOAREGS
// STATE_XMIT_ID, next step of sign on
static void rcv_id_ack(void) small reentrant
{
   if (error != NoError) {
       sign_on (); // enables receive, turns off timeouts
   } else {
       new_msg(); // clear old message data
       state = STATE_RCV_ID_ACK;
       msg_ptr = msg_ack_id;
       recv(); // enables receive, and character time out 
   }
}
#pragma restore

#pragma save
#pragma NOAREGS
// STATE_RCV_ID_ACK, receive the ack of the ID
static void send_password (void) small reentrant
{

    error_last_rcv = error;

    error = NoError;
    log(0x83);
    log(error);

    switch (error_last_rcv)
    {
    case NoError:
        state = STATE_XMIT_PASSWORD_OPERAND;
        msg_ptr = msg_P0;
        xmit(); // transmit msg, char timeout stops, restart msg timeout
        break;
    case AuthorizationBad: // is Y = 1?
    default: // any data or message errors?
        state = STATE_XMIT_EMPTY_READOUT;
        msg_ptr = msg_nak_ack_id;
        xmit(); // transmit msg, char timeout stops, restart msg timeout
        break;
    case ParityBad:
    case ChecksumBad:
        sign_on ();
        break;
    }
}
#pragma restore

#pragma save
#pragma NOAREGS
// prepare to receive a command
static void get_cmd (void) small reentrant // after data is xmitted
{
    new_msg ();
    state = STATE_RCV_COMMAND;
    msg_ptr = msg_cmd;
    recv(); /* start receiving a message */
}
#pragma restore

#pragma save
#pragma NOAREGS
static void do_cmd_after_ack (void) small reentrant // STATE_XMIT_ACK
{
    // perform commands that have to finish after acknowledge
    // This is where a change of baud rate should occur
    while (cmd == 'Z') {
        EA = 0; // disable interrupts, force watchdog reset
    }

    get_cmd ();
}
#pragma restore

#pragma save
#pragma NOAREGS
// STATE_RCV_COMMAND, after a command is received, act on it
static void do_cmd (void) small reentrant
{
    // the error status is from a received message
    error_last_rcv = error; // save it
    error = NoError;
    log(0x84);
    log(error);
    // errors override commands
    // See the no-error case for the commands
    switch (error_last_rcv)
    {
    default:
    case AuthorizationBad: // checked when the C field is received
    case CommandBad: // checked when the D field is received
    case DataBad: // checked by the data and address field
    case MessageBad: // unexpected format checked by default
        xmit_error (); // transmit error, char timeout off, msg timeout st.
        break;
    case ParityBad: // checked by the serial driver
    case ChecksumBad: // checked by BCC field
    case CharTimeout: // checked by a timer
    case SessionTimeout: // checked by a timer
        xmit_nak (); // transmit nak, char timeout off, msg timeout st.
        break;
    case NoError:
    case PasswordBad: // checked by default
        switch (cmd) // interpret a command
        {
        default: // unknown command
            error_last_rcv = CommandBad;
            xmit_error (); // char timeout off, msg timeout restarts
            break;
        case 'U': // update command (nonstandard)
            if (REG_SOURCE_OK)
            {
                cmd_main = cmd; // ask the main loop routine to do this
                xmit_ack (); // char timeout off, msg timeout restarts
            } else {
                xmit_nak (); // char timeout off, msg timeout restarts
            }
            break;
        #if CAL_SAVE
        case 'C': // save calibration (nonstandard)
            cmd_main = cmd; // ask the main loop routine to do this
            xmit_ack (); // char timeout off, msg timeout restarts
            break;
        #endif
        case 'Z': // reset (nonstandard)
            xmit_ack (); // have to send the ack before resetting
            break;
        case 'B': // break, i.e. cease communicating
            sign_on (); // enable receive, all timeouts off
            break;
        case 'P': // password validation
            if (error_last_rcv == PasswordBad) {
                authorized = FALSE;
                state = STATE_XMIT_BREAK;
                msg_ptr = msg_B0;
                xmit(); // transmit msg, char timeout off, msg timeout st.
                break;
            }
            authorized = TRUE;
            REG_LOCKED = TRUE; // stop background updates
            xmit_ack (); // char timeout off, msg timeout restarts

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -