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
183
|
/*
* 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};
#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;
}
}
// Send something to the rs422 bus
// Length must not exceeds RS_MAX
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 = 208; // BaudRate: 19200
UCA0BR1 = 0; // BaudRate: 19200
UCA0MCTL = UCBRS0 + 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);
}
|