?? flag0.c
字號:
/***************************************************************************
* 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 && FLAG0
#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 0
#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 + -