summaryrefslogtreecommitdiff
path: root/rs422lib/rsbus.c
blob: e0a18ec2a69961e1968d2aeff79cc88609b24f92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * rsbus.c
 *
 *  Created on: 2014-4-26
 *      Author: Tuowen
 */
#include "rsbus.h"
#include "sysctl.h"

#define SYSRET (0xF0)
#define INSREP (0x0F)

// Maximum size of receive buffer
#define RSMAX (20)

#define CODE_LEN (6)

unsigned char rs_rxbuf[RSMAX];
unsigned char len;
unsigned char pch;
rshdlr rxhdlr;
enum rs_stat{REST,ST,ADDR,READ,DISCARD,ED,DED};
enum rs_stat rs_st=REST;

unsigned char rs_tx[CODE_LEN+RS_MAX]={STBIT1,0,RSADDR,MACTYPE};
volatile unsigned char tx_len;
volatile unsigned char tx_pos=255;

volatile unsigned char mac_stat[4]={0,0,0,0};

// UART transmit routine
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
   if (tx_pos == tx_len) // TX over?
   {
      UC0IE &= ~UCA0TXIE; // Disable USCI_A0 TX interrupt
   	  RSOUT &= ~(RSPIN);
   	  tx_pos = 255;
   }
   else
   	   UCA0TXBUF = rs_tx[tx_pos++]; // TX next character
}

// Inline send for ISR
#pragma FUNC_ALWAYS_INLINE(rsbus_w_irq)
static __inline void rsbus_w_irq(unsigned char* buf,unsigned int len)
{
	unsigned int i;
	if (tx_pos < tx_len)	// This shouldn't happen
		return;				// Race condition
	RSOUT |= RSPIN;
	tx_len=len+7;
	unsigned int parity=MACTYPE^RSADDR;
	rs_tx[1]=0; // Useless addr spec
	for (i=0;i<len;++i)
		parity^=(rs_tx[4+i]=buf[i]);
	rs_tx[4+len]=parity;
	rs_tx[5+len]=EDBIT0;
	rs_tx[6+len]=EDBIT1;
	tx_pos=0;
	UCA0TXBUF=(STBIT0 & 0xff);
	UC0IE |= UCA0TXIE;
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void rsbus_rx(void)
{
	//IFG2&=(~UCA0RXIFG);
	unsigned char dat;
	dat=UCA0RXBUF;
	/************ Simple State Machine *************/
	switch (rs_st)
	{
	case REST:
		rs_st=(dat==STBIT0)?ST:REST;
		break;
	case ST:
		rs_st=(dat==STBIT1)?ADDR:REST;
		break;
	case ADDR:
		if (dat==RSADDR)
		{
			rs_st=READ;
			len=0;
			pch=RSADDR;
		}
		else
			rs_st=DISCARD;
		break;
	case READ:
		rs_rxbuf[len++]=dat;
		pch^=dat;
		if (dat==EDBIT0)
			rs_st=ED;
		if (len>=RSMAX)
			rs_st=REST;
		break;
	case DISCARD:
		if (dat==EDBIT0)
			rs_st=DED;
		break;
	case DED:
		if (dat==EDBIT1)
			rs_st=REST;
		else
			rs_st=DISCARD;
		break;
	case ED:
		if (dat==EDBIT1)
		{
			rs_st=REST;
			--len;
			pch^=EDBIT0;
			if (pch==0) // Parity check passed
			{
				if (len<2)
					rsbus_w_irq((unsigned char*)mac_stat,4); // RETURN CURRENT STATUS
				else
					SYSCALL_IRQ(RSSYSBIT); // SYSCTL call happened here!!!
			}
			else	// Parity check failed
			{
				dat = SYSRET ^ INSREP;		// RETURN REP
				rsbus_w_irq(&dat,1);
			}
		}
		else
		{
			rs_rxbuf[len++]=dat;
			pch^=dat;
			rs_st=READ;
			if (len>=RSMAX)
				rs_st=REST;
		}
		break;
	}
}

void rsbus_w(int addr,unsigned char* buf,unsigned int len)
{
	while (tx_pos < tx_len)		// This shouldn't happen
		__delay_cycles(100);	// Race condition -> wait
	unsigned int i;
	if (len>RS_MAX)
		return;
	RSOUT |= RSPIN;
	tx_len=len+7;
	unsigned int parity=addr^MACTYPE^RSADDR;
	rs_tx[1]=addr; // Useless addr spec
	for (i=0;i<len;++i)
		parity^=(rs_tx[4+i]=buf[i]);
	rs_tx[4+len]=parity;
	rs_tx[5+len]=EDBIT0;
	rs_tx[6+len]=EDBIT1;
	tx_pos=0;
	UCA0TXBUF=(STBIT0 & 0xff);
	UC0IE |= UCA0TXIE;
}

void rsbus_syscall()
{
	rxhdlr(rs_rxbuf,len-1);
}

void rsbus_init(rshdlr hdlr) // If need to change this part consult user guide pg908
{
	P1SEL |= BIT1 + BIT2 ;                    // P1.1 = RXD, P1.2=TXD
	P1SEL2 |= BIT1 + BIT2 ;                   // P1.1 = RXD, P1.2=TXD
	UCA0CTL1 |= UCSSEL_2;                     // UartCLK: SMCLK=4MHz
	UCA0BR0 = 0xA0;                            // BaudRate: 19200
	UCA0BR1 = 1;                              // BaudRate: 19200
	UCA0MCTL = UCBRS1+UCBRS2;// + UCBRS1;               // Modulation UCBRSx = 3
	UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
	IE2 |= UCA0RXIE;                          // Enable USCI_A0 RX interrupt
	/******************* CTL for output buffer ***********************/
	RSDIR |= RSPIN;
	RSOUT &= ~(RSPIN); //HIGH for ENABLE -> Low as DEFAULT
	/******************* SYSCTL INIT *************************/
	rxhdlr=hdlr;
	sysctl_reghdlr(RSSYSBIT,&rsbus_syscall);
}