Subversion Repositories Code-Repo

Rev

Rev 107 | Details | Compare with Previous | 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
 
111 Kevin 14
#pragma udata msgqueue1_1
15
static msg MQ_ToMainFromLow_1;
16
#pragma udata msgqueue1_2
17
static msg MQ_ToMainFromLow_2;
107 Kevin 18
 
19
#pragma udata msgqueue2_1
20
static msg MQ_ToMainFromHigh_1;
21
#pragma udata msgqueue2_2
22
static msg MQ_ToMainFromHigh_2;
111 Kevin 23
//#pragma udata msgqueue2_3
24
//static msg MQ_ToMainFromHigh_3;
107 Kevin 25
 
111 Kevin 26
#pragma udata msgqueue3_1
27
static msg MQ_FromMainToLow_1;
28
#pragma udata msgqueue3_2
29
static msg MQ_FromMainToLow_2;
107 Kevin 30
 
31
#pragma udata msgqueue4_1
32
static msg MQ_FromMainToHigh_1;
33
#pragma udata msgqueue4_2
34
static msg MQ_FromMainToHigh_2;
111 Kevin 35
//#pragma udata msgqueue4_3
36
//static msg MQ_FromMainToHigh_3;
107 Kevin 37
 
38
#pragma udata 
111 Kevin 39
static msg_queue MQ_ToMainFromLow;
107 Kevin 40
static msg_queue MQ_ToMainFromHigh;
111 Kevin 41
static msg_queue MQ_FromMainToLow;
107 Kevin 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
 
111 Kevin 59
    MQ_ToMainFromLow.queue[0] = &MQ_ToMainFromLow_1;
60
    MQ_ToMainFromLow.queue[1] = &MQ_ToMainFromLow_2;
107 Kevin 61
 
62
    MQ_ToMainFromHigh.queue[0] = &MQ_ToMainFromHigh_1;
63
    MQ_ToMainFromHigh.queue[1] = &MQ_ToMainFromHigh_2;
111 Kevin 64
//    MQ_ToMainFromHigh.queue[2] = &MQ_ToMainFromHigh_3;
107 Kevin 65
 
111 Kevin 66
    MQ_FromMainToLow.queue[0] = &MQ_FromMainToLow_1;
67
    MQ_FromMainToLow.queue[1] = &MQ_FromMainToLow_2;
107 Kevin 68
 
69
    MQ_FromMainToHigh.queue[0] = &MQ_FromMainToHigh_1;
70
    MQ_FromMainToHigh.queue[1] = &MQ_FromMainToHigh_2;
111 Kevin 71
//    MQ_FromMainToHigh.queue[2] = &MQ_FromMainToHigh_3;
107 Kevin 72
 
111 Kevin 73
    MQ_init_queue(&MQ_ToMainFromLow);
107 Kevin 74
    MQ_init_queue(&MQ_ToMainFromHigh);
111 Kevin 75
    MQ_init_queue(&MQ_FromMainToLow);
107 Kevin 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
 
111 Kevin 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
}
107 Kevin 203
 
111 Kevin 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
 
107 Kevin 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
 
111 Kevin 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
}
107 Kevin 249
 
111 Kevin 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
 
107 Kevin 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
    }
111 Kevin 310
    if (MQ_check_msg_queue_unread(&MQ_ToMainFromLow)) {
311
        return;
312
    }
107 Kevin 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
        }
111 Kevin 332
        if (MQ_check_msg_queue_unread(&MQ_ToMainFromLow)) {
333
            MQ_Main_Willing_To_Block = 0;
334
            return;
335
        }
107 Kevin 336
        // Sleep for a period of time before checking again
337
        Delay1KTCYx(10);
338
    }
339
}