summaryrefslogtreecommitdiff
path: root/rs422lib/rsbus.c
blob: 705736f56a5844f3100e528b133d236d5daa734a (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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
 * rsbus.c
 *
 *  Created on: 2014-4-26
 *      Author: Tuowen
 */
#include "rsbus.h"
#include "sysctl.h"

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

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

unsigned char rs_tx[12]={STBIT1,0,RSADDR,MACTYPE,0,0,0,0,0,0,0,0};
unsigned char tx_len;
unsigned char tx_pos;

#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);
   }
   else
   	   UCA0TXBUF = rs_tx[tx_pos++]; // TX next character
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void rsbus_rx(void)
{
	//IFG2&=(~UCA0RXIFG);
	int 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)
				{
					ret=(SYSRET ^ MACTYPE);
					SYSCALL_IRQ(RSSYSRET); // RETURN machine type
				}
				else
					SYSCALL_IRQ(RSSYSBIT); // SYSCTL call happened here!!!
			}
			else
			{
				ret=(SYSRET ^ INSREP);
				SYSCALL_IRQ(RSSYSRET); // RETURN machine type
			}
		}
		else
		{
			rs_rxbuf[len++]=dat;
			pch^=dat;
			rs_st=READ;
			if (len>=RSMAX)
				rs_st=REST;
		}
		break;
	}
	/*//This is a repeater
	if (IFG2&UCA0TXIFG)
		UCA0TXBUF=dat;*/
}

void rsbus_w(int addr,unsigned char* buf,unsigned int len)
{
	unsigned int i;
	if (len>4)
		return;
	RSOUT |= RSPIN;
	tx_len=len+7;
	unsigned int parity=addr^MACTYPE^RSADDR;
	rs_tx[1]=addr;
	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_w(int addr,char* buf,int len)
{
	// Acquire output
	RSOUT |= RSPIN;
	delay_ms(2);
	unsigned int i=0;
	unsigned int parity=addr^RSADDR;
	// Start bits
	while ((IFG2&UCA0TXIFG) == 0);
	UCA0TXBUF=(STBIT0 & 0xff);
	while ((IFG2&UCA0TXIFG) == 0);
	UCA0TXBUF=(STBIT1 & 0xff);
	// Addr
	while ((IFG2&UCA0TXIFG) == 0);
	UCA0TXBUF=(addr & 0xff);
	// RSADDR
	while ((IFG2&UCA0TXIFG) == 0);
	UCA0TXBUF=(RSADDR & 0xff);
	// Data
	while (i<len)
	{
		parity^=buf[i];
		while ((IFG2&UCA0TXIFG) == 0);
		UCA0TXBUF=buf[i++];
	}
	// Parity bit
	while ((IFG2&UCA0TXIFG) == 0);
	UCA0TXBUF=(parity & 0xff);
	// End bits
	while ((IFG2&UCA0TXIFG) == 0);
		UCA0TXBUF=(EDBIT0 & 0xff);
	while ((IFG2&UCA0TXIFG) == 0);
		UCA0TXBUF=(EDBIT1 & 0xff);
	while ((IFG2&UCA0TXIFG) == 0);
	// Release output
	RSOUT &= ~(RSPIN);
}*/

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

void rsbus_ret()
{
	rsbus_w(0,(unsigned char*)&ret,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);
	sysctl_reghdlr(RSSYSRET,&rsbus_ret);
}