Subversion Repositories HomeAutomation

Rev

Rev 339 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 339 Rev 342
1
/*********************************************************************
1
/*********************************************************************
2
 *
2
 *
3
 *                  CAN module
3
 *                  CAN module
4
 *
4
 *
5
 *********************************************************************
5
 *********************************************************************
6
 * FileName:        $HeadURL: https://svn.auml.se/svn/HomeAutomation/trunk/EmbeddedSoftware/PIC/canBase/Source/CAN.c $
6
 * FileName:        $HeadURL: https://svn.auml.se/svn/HomeAutomation/trunk/EmbeddedSoftware/PIC/canBase/Source/CAN.c $
7
 * Last changed:    $LastChangedDate: 2007-02-25 20:51:08 +0100 (Sun, 25 Feb 2007) $
7
 * Last changed:    $LastChangedDate: 2007-02-26 21:38:37 +0100 (Mon, 26 Feb 2007) $
8
 * By:              $LastChangedBy: johboh $
8
 * By:              $LastChangedBy: johboh $
9
 * Revision:        $Revision: 339 $
9
 * Revision:        $Revision: 342 $
10
 ********************************************************************/
10
 ********************************************************************/
11
 
11
 
12
#include <CANdefs.h>
12
#include <CANdefs.h>
13
#include <stackTasks.h>
13
#include <stackTasks.h>
14
#include <CAN.h>
14
#include <CAN.h>
15
#include <EEaccess.h>
15
#include <EEaccess.h>
16
#include <funcdefs.h>
16
#include <funcdefs.h>
17
#include <Tick.h>
17
#include <Tick.h>
18
 
18
 
19
TICK heartbeat;
19
TICK heartbeat;
20
static int MY_ID = DEFAULT_ID;
20
static int MY_ID = DEFAULT_ID;
21
static CAN_PACKET outCp;
21
static CAN_PACKET outCp;
22
 
22
 
23
static void canGetPacket(void);
23
static void canGetPacket(void);
24
 
24
 
25
 
25
 
26
/*
26
/*
27
*   Function: canInit
27
*   Function: canInit
28
*
28
*
29
*   Input:  none
29
*   Input:  none
30
*   Output: none
30
*   Output: none
31
*   Pre-conditions: none
31
*   Pre-conditions: none
32
*   Affects: Changes can registers.
32
*   Affects: Changes can registers.
33
*   Depends: none.
33
*   Depends: none.
34
*/
34
*/
35
void canInit()
35
void canInit()
36
{
36
{
37
    CANCON = 0x80; //request config mode
37
    CANCON = 0x80; //request config mode
38
    while ((CANSTAT & 0xE0) != 0x80 ); //wait for config mode request
38
    while ((CANSTAT & 0xE0) != 0x80 ); //wait for config mode request
39
 
39
 
40
    // BAUD AND TQS
40
    // BAUD AND TQS
41
 
41
 
42
    // 500Khz@40Mhz (new by the book)
42
    // 500Khz@40Mhz (new by the book)
43
    BRGCON1 = 0x04;
43
    BRGCON1 = 0x04;
44
    BRGCON2 = 0xD1;
44
    BRGCON2 = 0xD1;
45
    BRGCON3 = 0x81;
45
    BRGCON3 = 0x81;
46
 
46
 
47
    //BRGCON1=0;
47
    //BRGCON1=0;
48
   
48
   
49
    // Sync_Seq = 2 x TQ = 1
49
    // Sync_Seq = 2 x TQ = 1
50
    //BRGCON1bits.SJW1=0;
50
    //BRGCON1bits.SJW1=0;
51
    //BRGCON1bits.SJW0=1;
51
    //BRGCON1bits.SJW0=1;
52
   
52
   
53
    // Setting BRP.
53
    // Setting BRP.
54
    //BRGCON1=BRGCON1|CAN_BRP;
54
    //BRGCON1=BRGCON1|CAN_BRP;
55
   
55
   
56
    // Maximum PHEG1
56
    // Maximum PHEG1
57
    //BRGCON2bits.SEG2PHTS = 1;
57
    //BRGCON2bits.SEG2PHTS = 1;
58
   
58
   
59
    // Phase_Seg1 = 2 x TQ = 1
59
    // Phase_Seg1 = 2 x TQ = 1
60
    //BRGCON2bits.SEG1PH2 = 0;
60
    //BRGCON2bits.SEG1PH2 = 0;
61
    //BRGCON2bits.SEG1PH1 = 0;
61
    //BRGCON2bits.SEG1PH1 = 0;
62
    //BRGCON2bits.SEG1PH0 = 1;
62
    //BRGCON2bits.SEG1PH0 = 1;
63
   
63
   
64
    // Prop_Seq = 2 x TQ = 1
64
    // Prop_Seq = 2 x TQ = 1
65
    //BRGCON2bits.PRSEG2 = 0;
65
    //BRGCON2bits.PRSEG2 = 0;
66
    //BRGCON2bits.PRSEG1 = 0;
66
    //BRGCON2bits.PRSEG1 = 0;
67
    //BRGCON2bits.PRSEG0 = 1;
67
    //BRGCON2bits.PRSEG0 = 1;
68
   
68
   
69
    //  Enableing bus wake-up
69
    //  Enableing bus wake-up
70
    //BRGCON3bits.WAKDIS = 0;
70
    //BRGCON3bits.WAKDIS = 0;
71
   
71
   
72
    // Dont use filter when wakeup
72
    // Dont use filter when wakeup
73
    //BRGCON3bits.WAKFIL = 0;
73
    //BRGCON3bits.WAKFIL = 0;
74
   
74
   
75
    // Phase_Seg2 = 2 x TQ = 1
75
    // Phase_Seg2 = 2 x TQ = 1
76
    //BRGCON3bits.SEG2PH2 = 0;
76
    //BRGCON3bits.SEG2PH2 = 0;
77
    //BRGCON3bits.SEG2PH1 = 0;
77
    //BRGCON3bits.SEG2PH1 = 0;
78
    //BRGCON3bits.SEG2PH0 = 1;
78
    //BRGCON3bits.SEG2PH0 = 1;
79
 
79
 
80
    ECANCON=0;
80
    ECANCON=0;
81
    ECANCONbits.MDSEL1 = 1; // 0  For mode 1 
81
    ECANCONbits.MDSEL1 = 1; // 0  For mode 1 
82
    ECANCONbits.MDSEL0 = 0; // 1  For mode 1 
82
    ECANCONbits.MDSEL0 = 0; // 1  For mode 1 
83
 
83
 
84
 
84
 
85
    // FILTERS AND MASKS
85
    // FILTERS AND MASKS
86
    RXB0CONbits.RXM1=1;
86
    RXB0CONbits.RXM1=1;
87
    RXB0CONbits.RXM0=0;
87
    RXB0CONbits.RXM0=0;
88
 
88
 
89
 
89
 
90
    // INTERRUPTS
90
    // INTERRUPTS
91
   
91
   
92
    // Diable transmit interrupt
92
    // Diable transmit interrupt
93
    TXBIE = 0;
93
    TXBIE = 0;
94
 
94
 
95
    //rx any interrupt
95
    //rx any interrupt
96
    PIR3 = 0;
96
    PIR3 = 0;
97
    PIE3 = 0b00000011;
97
    PIE3 = 0b00000011;
98
 
98
 
99
    // High interrupt
99
    // High interrupt
100
    IPR3 =0b00000011;
100
    IPR3 =0b00000011;
101
 
101
 
102
    // Programmable buffers interrupt
102
    // Programmable buffers interrupt
103
    BIE0  = 0xFF;  
103
    BIE0  = 0xFF;  
104
 
104
 
105
 
105
 
106
    //loopback mode or not
106
    //loopback mode or not
107
    #ifdef CAN_LOOPBACK_MODE
107
    #ifdef CAN_LOOPBACK_MODE
108
        CANCON = 0x40;//request loopback mode
108
        CANCON = 0x40;//request loopback mode
109
        while ((CANSTAT & 0xE0) != 0x40 );//wait for loopback mode
109
        while ((CANSTAT & 0xE0) != 0x40 );//wait for loopback mode
110
    #else
110
    #else
111
        CANCON = 0x00;//request normal mode
111
        CANCON = 0x00;//request normal mode
112
        while ((CANSTAT & 0xE0) != 0x00 );//wait for normal mode
112
        while ((CANSTAT & 0xE0) != 0x00 );//wait for normal mode
113
    #endif
113
    #endif
114
 
114
 
115
 
115
 
116
    // Init ticker service
116
    // Init ticker service
117
    tickInit();
117
    tickInit();
118
 
118
 
119
 
119
 
120
    // Read ID and NID if exist.
120
    // Read ID and NID if exist.
121
    if (EERead(NODE_ID_EE)==NODE_HAS_ID)
121
    if (EERead(NODE_ID_EE)==NODE_HAS_ID)
122
    {
122
    {
123
        MY_ID=+EERead(NODE_ID_EE + 1);
123
        MY_ID=+EERead(NODE_ID_EE + 1);
124
    }
124
    }
125
 
125
 
126
    // Send user program startup heatbeat
126
    // Send user program startup heatbeat
127
    outCp.type=ptPGM;
127
    outCp.type=ptPGM;
128
    outCp.pgm.class=pcCTRL;
128
    outCp.pgm.class=pcCTRL;
129
    outCp.pgm.id=pctAPPBOOT;
129
    outCp.pgm.id=pctAPPBOOT;
130
    outCp.length=0;
130
    outCp.length=2;
-
 
131
    outCp.data[1]=(BYTE)((APP_VERSION & 0xFF00)>>8);
-
 
132
    outCp.data[0]=(BYTE)(APP_VERSION & 0xFF);
131
    while(!canSendMessage(outCp,PRIO_HIGH));
133
    while(!canSendMessage(outCp,PRIO_HIGH));
132
}
134
}
133
 
135
 
134
 
136
 
135
/*
137
/*
136
*   Function: canISR
138
*   Function: canISR
137
*
139
*
138
*   Input:  none
140
*   Input:  none
139
*   Output: none
141
*   Output: none
140
*   Pre-conditions: a call to canInit()
142
*   Pre-conditions: a call to canInit()
141
*   Affects: interrupt registers and receive data buffers
143
*   Affects: interrupt registers and receive data buffers
142
*   Depends: ..
144
*   Depends: ..
143
*/
145
*/
144
void canISR()
146
void canISR()
145
{
147
{
146
    ClrWdt();
148
    ClrWdt();
147
 
149
 
148
    if (PIR3bits.RXBnIF || PIR3bits.RXB1IF || PIR3bits.RXB0IF)
150
    if (PIR3bits.RXBnIF || PIR3bits.RXB1IF || PIR3bits.RXB0IF)
149
    {
151
    {
150
        ECANCON=(ECANCON&0b00000)|(0b10000|(CANCON&0x0F));
152
        ECANCON=(ECANCON&0b00000)|(0b10000|(CANCON&0x0F));
151
        if (RXB0CONbits.RXFUL) canGetPacket();
153
        if (RXB0CONbits.RXFUL) canGetPacket();
152
   
154
   
153
        if (PIR3bits.RXBnIF) {PIR3bits.RXBnIF = 0; return;}
155
        if (PIR3bits.RXBnIF) {PIR3bits.RXBnIF = 0; return;}
154
        if (PIR3bits.RXB1IF) {PIR3bits.RXB1IF = 0; return;}
156
        if (PIR3bits.RXB1IF) {PIR3bits.RXB1IF = 0; return;}
155
        if (PIR3bits.RXB0IF) {PIR3bits.RXB0IF = 0; return;}
157
        if (PIR3bits.RXB0IF) {PIR3bits.RXB0IF = 0; return;}
156
    }
158
    }
157
 
159
 
158
    tickUpdate();
160
    tickUpdate();
159
 
161
 
160
    if ((tickGet()-heartbeat)>TICK_SECOND*5)
162
    if ((tickGet()-heartbeat)>TICK_SECOND*5)
161
    {
163
    {
162
        // Send alive heartbeat
164
        // Send alive heartbeat
163
        outCp.type=ptPGM;
165
        outCp.type=ptPGM;
164
        outCp.pgm.class=pcCTRL;
166
        outCp.pgm.class=pcCTRL;
165
        outCp.pgm.id=pctHEARTBEAT;
167
        outCp.pgm.id=pctHEARTBEAT;
166
        outCp.length=0;
168
        outCp.length=0;
167
        canSendMessage(outCp,PRIO_HIGH);
169
        canSendMessage(outCp,PRIO_HIGH);
168
           
170
           
169
        heartbeat = tickGet();
171
        heartbeat = tickGet();
170
    }
172
    }
171
 
173
 
172
   
174
   
173
}
175
}
174
 
176
 
175
 
177
 
176
/*
178
/*
177
*   Function: canGetPacket
179
*   Function: canGetPacket
178
*
180
*
179
*   Input:  none
181
*   Input:  none
180
*   Output: none
182
*   Output: none
181
*   Pre-conditions: a call to canISR and an packet is available and banked to RXB0
183
*   Pre-conditions: a call to canISR and an packet is available and banked to RXB0
182
*   Affects: Calls canParse() function in main for parsing received packet.
184
*   Affects: Calls canParse() function in main for parsing received packet.
183
*   Depends: none.
185
*   Depends: none.
184
*/
186
*/
185
void canGetPacket()
187
void canGetPacket()
186
{
188
{
187
        CAN_PACKET cp;
189
        CAN_PACKET cp;
188
 
190
 
189
        //RXB0SIDH 28 27 26 25 24 23 22 21
191
        //RXB0SIDH 28 27 26 25 24 23 22 21
190
        //RXB0SIDL 20 19 18 xx xx xx 17 16
192
        //RXB0SIDL 20 19 18 xx xx xx 17 16
191
        //RXB0EIDH 15 14 13 12 11 10 09 08
193
        //RXB0EIDH 15 14 13 12 11 10 09 08
192
        //RXB0EIDL 07 06 05 04 03 02 01 00
194
        //RXB0EIDL 07 06 05 04 03 02 01 00
193
 
195
 
194
 
196
 
195
        cp.type = ((RXB0SIDH&0xC)>>6);
197
        cp.type = (BYTE)((RXB0SIDH&0xC0)>>6);
196
 
198
 
197
 
199
 
198
        if (cp.type==ptBOOT)
200
        if (cp.type==ptBOOT)
199
        {
201
        {
200
            cp.boot.type  = ((RXB0SIDH&0x38)>>3);
202
            cp.boot.type  = ((RXB0SIDH&0x38)>>3);
201
            cp.boot.offset= ((RXB0SIDH&0x7)<<5)+((RXB0SIDL&0xE0)>>3)+(RXB0SIDL&0x3);
203
            cp.boot.offset= ((RXB0SIDH&0x7)<<5)+((RXB0SIDL&0xE0)>>3)+(RXB0SIDL&0x3);
202
            cp.boot.rid   = RXB0EIDH;
204
            cp.boot.rid   = RXB0EIDH;
203
        }
205
        }
204
        else
206
        else
205
        {
207
        {
206
            cp.pgm.class= ((RXB0SIDH&0x3C)>>2);
208
            cp.pgm.class= ((RXB0SIDH&0x3C)>>2);
207
            cp.pgm.id   = (((WORD)RXB0SIDH&0x3)<<13)+(((WORD)RXB0SIDL&0xE0)<<5)+((RXB0SIDL&0x3)<<8)+RXB0EIDH;
209
            cp.pgm.id   = (((WORD)RXB0SIDH&0x3)<<13)+(((WORD)RXB0SIDL&0xE0)<<5)+(((WORD)RXB0SIDL&0x3)<<8)+(WORD)RXB0EIDH;
208
        }
210
        }
209
        cp.sid   = RXB0EIDL;
211
        cp.sid   = RXB0EIDL;
210
 
212
 
211
 
213
 
212
        // Data length
214
        // Data length
213
        cp.length=(RXB0DLCbits.DLC3<<3)+(RXB0DLCbits.DLC2<<2)+(RXB0DLCbits.DLC1<<1)+RXB0DLCbits.DLC0;
215
        cp.length=(RXB0DLCbits.DLC3<<3)+(RXB0DLCbits.DLC2<<2)+(RXB0DLCbits.DLC1<<1)+RXB0DLCbits.DLC0;
214
 
216
 
215
        // Data one bye one, for speed
217
        // Data one bye one, for speed
216
        cp.data[0]=RXB0D0;  cp.data[1]=RXB0D1;
218
        cp.data[0]=RXB0D0;  cp.data[1]=RXB0D1;
217
        cp.data[2]=RXB0D2;  cp.data[3]=RXB0D3;
219
        cp.data[2]=RXB0D2;  cp.data[3]=RXB0D3;
218
        cp.data[4]=RXB0D4;  cp.data[5]=RXB0D5;
220
        cp.data[4]=RXB0D4;  cp.data[5]=RXB0D5;
219
        cp.data[6]=RXB0D6;  cp.data[7]=RXB0D7;
221
        cp.data[6]=RXB0D6;  cp.data[7]=RXB0D7;
220
 
222
 
221
        // Clear ful status
223
        // Clear ful status
222
        RXB0CONbits.RXFUL=0;
224
        RXB0CONbits.RXFUL=0;
223
 
225
 
224
 
226
 
225
 
227
 
226
        // Check if bootloader request specific.
228
        // Check if bootloader request specific.
227
        // reset and id change
229
        // reset and id change
228
        if (cp.type==ptBOOT)
230
        if (cp.type==ptBOOT)
229
        {
231
        {
230
            if (cp.boot.rid==MY_ID)
232
            if (cp.boot.rid==MY_ID)
231
            {
233
            {
232
                if (cp.boot.type==btADDR) Reset(); // Reset me.
234
                if (cp.boot.type==btADDR) Reset(); // Reset me.
233
                if (cp.boot.type==btCHANGEID)
235
                if (cp.boot.type==btCHANGEID)
234
                {
236
                {
235
                        // Change my ID and NID
237
                        // Change my ID and NID
236
                        MY_ID=cp.data[0];
238
                        MY_ID=cp.data[0];
237
                        EEWrite(NODE_ID_EE+1,cp.data[0]);
239
                        EEWrite(NODE_ID_EE+1,cp.data[0]);
238
                        EEWrite(NODE_ID_EE,NODE_HAS_ID);
240
                        EEWrite(NODE_ID_EE,NODE_HAS_ID);
239
                        // Send ack with new id.
241
                        // Send ack with new id.
240
                        outCp.type=ptBOOT;
242
                        outCp.type=ptBOOT;
241
                        outCp.boot.type=btACK;
243
                        outCp.boot.type=btACK;
242
                        outCp.length=0;
244
                        outCp.length=0;
243
                        while(!canSendMessage(outCp,PRIO_HIGH));
245
                        while(!canSendMessage(outCp,PRIO_HIGH));
244
                }
246
                }
245
            }
247
            }
246
        }
248
        }
247
 
249
 
248
 
250
 
249
        //Call main parser
251
        //Call main parser
250
        if (cp.type==ptPGM) canParse(cp);
252
        if (cp.type==ptPGM) canParse(cp);
251
}
253
}
252
 
254
 
253
 
255
 
254
/*
256
/*
255
*   Function: canSendMessage
257
*   Function: canSendMessage
256
*
258
*
257
*   Input:  CAN_MESSAGE to send
259
*   Input:  CAN_MESSAGE to send
258
*   Output: True if packet scheduled sucess, false otherwise.
260
*   Output: True if packet scheduled sucess, false otherwise.
259
*   Pre-conditions: canInit
261
*   Pre-conditions: canInit
260
*   Affects: ..
262
*   Affects: ..
261
*   Depends: ..
263
*   Depends: ..
262
*/
264
*/
263
BOOL canSendMessage(CAN_PACKET cp, CAN_PRIORITY prio)
265
BOOL canSendMessage(CAN_PACKET cp, CAN_PRIORITY prio)
264
{
266
{
265
   
267
   
266
    if ( TXB0CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00011; }
268
    if ( TXB0CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00011; }
267
    if ( TXB1CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00100; }
269
    if ( TXB1CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00100; }
268
    if ( TXB2CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00101; }
270
    if ( TXB2CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00101; }
269
    // None of the transmit buffers were empty. 
271
    // None of the transmit buffers were empty. 
270
    else { return FALSE;}
272
    else { return FALSE;}
271
 
273
 
272
    if (prio<0 || prio>3) prio = 0;
274
    if (prio<0 || prio>3) prio = 0;
273
 
275
 
274
 
276
 
275
    //RXB0SIDH 28 27 26 25 24 23 22 21
277
    //RXB0SIDH 28 27 26 25 24 23 22 21
276
    //RXB0SIDL 20 19 18 xx xx xx 17 16
278
    //RXB0SIDL 20 19 18 xx xx xx 17 16
277
    //RXB0EIDH 15 14 13 12 11 10 09 08
279
    //RXB0EIDH 15 14 13 12 11 10 09 08
278
    //RXB0EIDL 07 06 05 04 03 02 01 00
280
    //RXB0EIDL 07 06 05 04 03 02 01 00
279
 
281
 
280
 
282
 
281
    if (cp.type==ptBOOT)
283
    if (cp.type==ptBOOT)
282
    {
284
    {
283
        RXB0SIDH = ((cp.type&0x3)<<6)+((cp.boot.type&0x7)<<3)+((cp.boot.offset&0xE0)>>5);
285
        RXB0SIDH = ((cp.type&0x3)<<6)+((cp.boot.type&0x7)<<3)+((cp.boot.offset&0xE0)>>5);
284
        RXB0SIDL = ((cp.boot.offset&0x1C)<<3)+(cp.boot.offset&0x3);
286
        RXB0SIDL = ((cp.boot.offset&0x1C)<<3)+(cp.boot.offset&0x3);
285
        RXB0EIDH = cp.boot.rid;
287
        RXB0EIDH = cp.boot.rid;
286
    }
288
    }
287
    else
289
    else
288
    {
290
    {
289
        RXB0SIDH = ((cp.type&0x3)<<6)+((cp.pgm.class&0xF)<<2)+((cp.pgm.id&0x6000)>>13);
291
        RXB0SIDH = ((cp.type&0x3)<<6)+((cp.pgm.class&0xF)<<2)+((cp.pgm.id&0x6000)>>13);
290
        RXB0SIDL = ((cp.pgm.id&0x1C00)>>5)+((cp.pgm.id&0x300)>>8);
292
        RXB0SIDL = ((cp.pgm.id&0x1C00)>>5)+((cp.pgm.id&0x300)>>8);
291
        RXB0EIDH = (cp.pgm.id&0xFF);
293
        RXB0EIDH = (cp.pgm.id&0xFF);
292
    }
294
    }
293
    RXB0EIDL = MY_ID;
295
    RXB0EIDL = MY_ID;
294
 
296
 
295
    // Data length
297
    // Data length
296
    RXB0DLC = 0;
298
    RXB0DLC = 0;
297
    if (cp.length>8) RXB0DLC=8; else RXB0DLC=cp.length;
299
    if (cp.length>8) RXB0DLC=8; else RXB0DLC=cp.length;
298
   
300
   
299
    // NOT Remote request
301
    // NOT Remote request
300
    _asm
302
    _asm
301
        bcf RXB0DLC, 6, 0
303
        bcf RXB0DLC, 6, 0
302
    _endasm
304
    _endasm
303
   
305
   
304
   
306
   
305
    // Data one bye one, for speed
307
    // Data one bye one, for speed
306
    RXB0D0=cp.data[0];  RXB0D1=cp.data[1];
308
    RXB0D0=cp.data[0];  RXB0D1=cp.data[1];
307
    RXB0D2=cp.data[2];  RXB0D3=cp.data[3];
309
    RXB0D2=cp.data[2];  RXB0D3=cp.data[3];
308
    RXB0D4=cp.data[4];  RXB0D5=cp.data[5];
310
    RXB0D4=cp.data[4];  RXB0D5=cp.data[5];
309
    RXB0D6=cp.data[6];  RXB0D7=cp.data[7];
311
    RXB0D6=cp.data[6];  RXB0D7=cp.data[7];
310
    // set extended
312
    // set extended
311
    RXB0SIDLbits.EXID=1;
313
    RXB0SIDLbits.EXID=1;
312
   
314
   
313
    // Priority
315
    // Priority
314
    RXB0CON = (RXB0CON & 0b11111100) | prio;
316
    RXB0CON = (RXB0CON & 0b11111100) | prio;
315
   
317
   
316
    // mark as redy to transmit
318
    // mark as redy to transmit
317
    _asm
319
    _asm
318
        bsf RXB0CON, 3, 0
320
        bsf RXB0CON, 3, 0
319
    _endasm
321
    _endasm
320
   
322
   
321
    return TRUE;
323
    return TRUE;
322
 
324
 
323
}
325
}
324
 
326