Subversion Repositories Code-Repo

Rev

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

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