Subversion Repositories Code-Repo

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
113 Kevin 1
#include "maindefs.h"
2
#include "interrupts.h"
3
#include "msg_queues.h"
4
#include <delays.h>
5
#include <string.h>
6
 
7
// The key to making this code safe for interrupts is that
8
//  each queue is filled by only one writer and read by one reader.
9
// ToMainQueueFromLow: Writer is a low priority interrupt, Reader is main()
10
// ToMainQueueFromHigh: Writer is a high priority interrupt, Reader is main()
11
// FromMainQueueToLow: Writer is main(), Reader is a low priority interrupt
12
// FromMainQueueToHigh: Writer is main(), Reader is a high priority interrupt
13
 
14
#pragma udata msgqueue1_1
15
unsigned char MQ_ToMainFromLow_Data_1[MSGLEN];
16
#pragma udata msgqueue1_2
17
unsigned char MQ_ToMainFromLow_Data_2[MSGLEN];
18
 
19
#pragma udata msgqueue2_1
20
unsigned char MQ_ToMainFromHigh_Data_1[MSGLEN];
21
#pragma udata msgqueue2_2
22
unsigned char MQ_ToMainFromHigh_Data_2[MSGLEN];
23
 
24
#pragma udata msgqueue3_1
25
unsigned char MQ_FromMainToLow_Data_1[MSGLEN];
26
#pragma udata msgqueue3_2
27
unsigned char MQ_FromMainToLow_Data_2[MSGLEN];
28
 
29
#pragma udata msgqueue4_1
30
unsigned char MQ_FromMainToHigh_Data_1[MSGLEN];
31
#pragma udata msgqueue4_2
32
unsigned char MQ_FromMainToHigh_Data_2[MSGLEN];
33
 
34
#pragma udata 
35
msg_queue MQ_ToMainFromLow;
36
msg_queue MQ_ToMainFromHigh;
37
msg_queue MQ_FromMainToLow;
38
msg_queue MQ_FromMainToHigh;
39
 
40
unsigned char MQ_Main_Willing_To_Block;
41
 
42
void MQ_init_queue(msg_queue *qptr) {
43
    unsigned char i;
44
 
45
    qptr->cur_write_index = 0;
46
    qptr->cur_read_index = 0;
47
    for (i=0;i<MSGQUEUELEN;i++) {
48
        qptr->queue[i].full = 0;
49
    }
50
}
51
 
52
void MQ_init() {
53
    MQ_Main_Willing_To_Block = 0;
54
 
55
    MQ_ToMainFromLow.queue[0].data = MQ_ToMainFromLow_Data_1;
56
    MQ_ToMainFromLow.queue[1].data = MQ_ToMainFromLow_Data_2;
57
 
58
    MQ_ToMainFromHigh.queue[0].data = MQ_ToMainFromHigh_Data_1;
59
    MQ_ToMainFromHigh.queue[1].data = MQ_ToMainFromHigh_Data_2;
60
 
61
    MQ_FromMainToLow.queue[0].data = MQ_FromMainToLow_Data_1;
62
    MQ_FromMainToLow.queue[1].data = MQ_FromMainToLow_Data_2;
63
 
64
    MQ_FromMainToHigh.queue[0].data = MQ_FromMainToHigh_Data_1;
65
    MQ_FromMainToHigh.queue[1].data = MQ_FromMainToHigh_Data_2;
66
 
67
    MQ_init_queue(&MQ_ToMainFromLow);
68
    MQ_init_queue(&MQ_ToMainFromHigh);
69
    MQ_init_queue(&MQ_FromMainToLow);
70
    MQ_init_queue(&MQ_FromMainToHigh);
71
}
72
 
73
signed char MQ_send_msg(msg_queue *qptr,unsigned char length,unsigned char msgtype, void *data) {
74
    unsigned char slot;
75
    msg *qmsg;
76
    size_t tlength = length;
77
 
78
#ifdef DEBUG
79
    if (length > MSGLEN) {
80
            return(MSG_BAD_LEN);
81
    } else if (length < 0) {
82
            return(MSG_BAD_LEN);
83
    }
84
#endif
85
 
86
    // Get the index in the msg queue to write to
87
    slot = qptr->cur_write_index;
88
 
89
    // Retrieve the address of the slot in the queue to write to
90
    qmsg = &qptr->queue[slot];
91
 
92
    // If the slot isn't empty, then we should return
93
    if (qmsg->full != 0) {
94
            return(MSG_QUEUE_FULL);
95
    }
96
 
97
    // Otherwise fill in the message details
98
    qmsg->length = length;
99
    qmsg->msgtype = msgtype;
100
 
101
    // Copy the message itself
102
    memcpy(qmsg->data,data,tlength);
103
 
104
    // Increment the next location in the queue to write to
105
    // Note: the index will loop back to the start (implements a FIFO queue)
106
    qptr->cur_write_index = (qptr->cur_write_index + 1) % MSGQUEUELEN;
107
 
108
    // Mark the slot in the queue as filled and return
109
    qmsg->full = 1;
110
    return(MSG_SEND_OKAY);
111
}
112
 
113
signed char MQ_recv_msg(msg_queue *qptr, unsigned char maxlength, unsigned char *msgtype, void *data) {
114
    unsigned char slot;
115
    msg *qmsg;
116
    size_t tlength;
117
 
118
    // Get the index in the message queue to read from
119
    slot = qptr->cur_read_index;
120
 
121
    // Retrieve the address of the message in the queue to read from
122
    qmsg = &qptr->queue[slot];
123
 
124
    // If the retrieved message contains data..
125
    if (qmsg->full == 1) {
126
        // Check if the recieving buffer can hold the message data
127
        if (qmsg->length > maxlength) {
128
                return(MSG_BUFFER_TOOSMALL);
129
        }
130
 
131
        // Get the length of the message data
132
        tlength = qmsg->length;
133
 
134
        // Copy the message data into *data
135
        memcpy(data,(const void*)qmsg->data,tlength);
136
 
137
        // Increment the read index to the next message to be read
138
        qptr->cur_read_index = (qptr->cur_read_index + 1) % MSGQUEUELEN;
139
 
140
        // Copy the message type to the returned message
141
        (*msgtype) = qmsg->msgtype;
142
 
143
        // Mark the slot in the queue as empty
144
        qmsg->full = 0;
145
 
146
        // Return the size of the message returned
147
        return (tlength);
148
 
149
    // Slot does not contain any messages
150
    } else {
151
        return(MSG_QUEUE_EMPTY);
152
    }
153
}
154
 
155
unsigned char MQ_peek_msg(msg_queue *qptr) {
156
    unsigned char slot;
157
    msg *qmsg;
158
 
159
    // Get the index in the message queue to read from
160
    slot = qptr->cur_read_index;
161
 
162
    // Retrieve the address of the message in the queue to read from
163
    qmsg = &qptr->queue[slot];
164
    if (qmsg->full == 1) {
165
 
166
        // Return the message type of the first message in queue
167
        return qmsg->msgtype;
168
 
169
    } else {
170
        // If there are no messages in the queue, return 0
171
        return 0;
172
    }
173
}
174
 
175
// Check if there is an unread message in the queue
176
unsigned char MQ_check_msg_queue_unread(msg_queue *qptr) {
177
    return (qptr->queue[qptr->cur_read_index].full);
178
}
179
 
180
void MQ_enter_sleep_mode(void) {
181
    OSCCONbits.IDLEN = 1; // set to idle on sleep
182
 
183
    _asm
184
    sleep
185
    _endasm
186
}
187
 
188
/* Message Queue 1 - Low Interrupt -> Main */
189
signed char MQ_sendmsg_ToMainFromLow(unsigned char length, unsigned char msgtype, void *data) {
190
#ifdef DEBUG
191
    if (!interrupt_in_low_interrupt_routine()) {
192
        return (MSG_NOT_IN_LOW);
193
    }
194
#endif
195
    return (MQ_send_msg(&MQ_ToMainFromLow, length, msgtype, data));
196
}
197
 
198
signed char MQ_recvmsg_ToMainFromLow(unsigned char maxlength, unsigned char *msgtype, void *data) {
199
#ifdef DEBUG
200
    if (!interrupt_in_main_routine()) {
201
        return (MSG_NOT_IN_MAIN);
202
    }
203
#endif
204
    return (MQ_recv_msg(&MQ_ToMainFromLow, maxlength, msgtype, data));
205
}
206
 
207
unsigned char MQ_peek_ToMainFromLow() {
208
    return (MQ_peek_msg(&MQ_ToMainFromLow));
209
}
210
 
211
/* Message Queue 2 - High Interrupt -> Main */
212
signed char MQ_sendmsg_ToMainFromHigh(unsigned char length, unsigned char msgtype, void *data) {
213
#ifdef DEBUG
214
    if (!interrupt_in_high_interrupt_routine()) {
215
        return (MSG_NOT_IN_HIGH);
216
    }
217
#endif
218
    return (MQ_send_msg(&MQ_ToMainFromHigh, length, msgtype, data));
219
}
220
 
221
signed char MQ_recvmsg_ToMainFromHigh(unsigned char maxlength, unsigned char *msgtype, void *data) {
222
#ifdef DEBUG
223
    if (!interrupt_in_main_routine()) {
224
        return (MSG_NOT_IN_MAIN);
225
    }
226
#endif
227
    return (MQ_recv_msg(&MQ_ToMainFromHigh, maxlength, msgtype, data));
228
}
229
 
230
unsigned char MQ_peek_ToMainFromHigh() {
231
    return (MQ_peek_msg(&MQ_ToMainFromHigh));
232
}
233
 
234
/* Message Queue 3 - Main -> Low Interrupt */
235
signed char MQ_sendmsg_FromMainToLow(unsigned char length, unsigned char msgtype, void *data) {
236
#ifdef DEBUG
237
    if (!interrupt_in_main_routine()) {
238
        return (MSG_NOT_IN_MAIN);
239
    }
240
#endif
241
    return (MQ_send_msg(&MQ_FromMainToLow, length, msgtype, data));
242
}
243
 
244
signed char MQ_recvmsg_FromMainToLow(unsigned char maxlength, unsigned char *msgtype, void *data) {
245
#ifdef DEBUG
246
    if (!interrupt_in_low_interrupt_routine()) {
247
        return (MSG_NOT_IN_LOW);
248
    }
249
#endif
250
    return (MQ_recv_msg(&MQ_FromMainToLow, maxlength, msgtype, data));
251
}
252
 
253
unsigned char MQ_peek_FromMainToLow() {
254
    return (MQ_peek_msg(&MQ_FromMainToLow));
255
}
256
 
257
/* Message Queue 4 - Main -> High Interrupt */
258
signed char MQ_sendmsg_FromMainToHigh(unsigned char length, unsigned char msgtype, void *data) {
259
#ifdef DEBUG
260
    if (!interrupt_in_main_routine()) {
261
        return (MSG_NOT_IN_MAIN);
262
    }
263
#endif
264
    return (MQ_send_msg(&MQ_FromMainToHigh, length, msgtype, data));
265
}
266
 
267
signed char MQ_recvmsg_FromMainToHigh(unsigned char maxlength, unsigned char *msgtype, void *data) {
268
#ifdef DEBUG
269
    if (!interrupt_in_high_interrupt_routine()) {
270
        return (MSG_NOT_IN_HIGH);
271
    }
272
#endif
273
    return (MQ_recv_msg(&MQ_FromMainToHigh, maxlength, msgtype, data));
274
}
275
 
276
unsigned char MQ_peek_FromMainToHigh() {
277
    return (MQ_peek_msg(&MQ_FromMainToHigh));
278
}
279
 
280
// This should only be called from a High Priority Interrupt
281
void MQ_sleep_high_interrupt_if_okay() {
282
    // Check to see if main is willing to block
283
    if (MQ_Main_Willing_To_Block == 0) {
284
        return;
285
    }
286
    // Dont sleep if currently handling low interrupt
287
    if (interrupt_in_low_interrupt_routine()) {
288
        return;
289
    }
290
 
291
    // Check to make sure that we're in high interrupt
292
    if (!interrupt_in_high_interrupt_routine()) {
293
        return;
294
    }
295
 
296
    // Since we are the only thing executing that could be
297
    //  putting something into a message queue destined for main()
298
    //  we can safely check the message queues now
299
 
300
    // Check the message queues to make sure that they're empty
301
    if (MQ_check_msg_queue_unread(&MQ_ToMainFromHigh)) {
302
        return;
303
    }
304
    if (MQ_check_msg_queue_unread(&MQ_ToMainFromLow)) {
305
        return;
306
    }
307
 
308
    // If everything checks out, go to sleep
309
    MQ_enter_sleep_mode();
310
}
311
 
312
/* Called from main(), blocks until message recieved in queue to main */
313
void MQ_wait_on_incoming_msg_queues() {
314
    // Only run from the main function
315
    if (!interrupt_in_main_routine()) {
316
        return;
317
    }
318
 
319
    MQ_Main_Willing_To_Block = 1;
320
    while (1) {
321
        // If any incoming message queues are not empty, break out of wait
322
        if (MQ_check_msg_queue_unread(&MQ_ToMainFromHigh)) {
323
            MQ_Main_Willing_To_Block = 0;
324
            return;
325
        }
326
        if (MQ_check_msg_queue_unread(&MQ_ToMainFromLow)) {
327
            MQ_Main_Willing_To_Block = 0;
328
            return;
329
        }
330
        // Sleep for a period of time before checking again
331
        Delay1KTCYx(10);
332
    }
333
}