Subversion Repositories HomeAutomation

Rev

Rev 1909 | Rev 2136 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 1909 Rev 2029
Line 1... Line -...
1
 
-
 
2
#include "stdcan.h"
1
#include "stdcan.h"
3
#if defined(_AVRLIB_BIOS_)
2
#if defined(_AVRLIB_BIOS_)
4
#include <bios.h>
3
#include <bios.h>
5
#define Can_Send BIOS_CanSend
4
#define Can_Send BIOS_CanSend
6
#else
5
#else
7
#include <drivers/can/mcp2515/mcp2515.h>
6
#include <drivers/can/mcp2515/mcp2515.h>
8
#endif
7
#endif
9
 
8
 
10
#include <avr/interrupt.h>
9
#include <avr/interrupt.h>
-
 
10
#include <util/atomic.h>
11
 
11
 
12
#if (STDCAN_TX_QUEUE_SIZE > 1)
12
#if (STDCAN_TX_QUEUE_SIZE > 1)
13
#error StdCan: Tx queue size longer than one msg not yet implemented.
13
#error StdCan: Tx queue size longer than one msg not yet implemented.
14
#endif
14
#endif
15
 
15
 
16
/**
16
/**
17
 * The receive queue.
17
 * The receive queue.
18
 */
18
 */
19
StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE];
19
StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE + 1];
20
unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
20
unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
21
unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
21
unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
22
unsigned char RxQ_Len; /**< Number of messages in receive queue. */
-
 
23
 
22
 
24
#if (STDCAN_TX_QUEUE_SIZE > 1)
23
#if (STDCAN_TX_QUEUE_SIZE > 1)
25
/**
24
/**
26
 * The transmit queue.
25
 * The transmit queue.
27
 */
26
 */
28
StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE];
27
StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE];
29
unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */
28
unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */
30
unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */
29
unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */
31
unsigned char TxQ_Len; /**< Number of messages in transmit queue. */
-
 
32
#endif
30
#endif
33
 
31
 
34
#if (STDCAN_FILTER)
32
#if (STDCAN_FILTER)
35
/**
33
/**
36
 * The message acceptance filters.
34
 * The message acceptance filters.
Line 38... Line 36...
38
typedef struct {
36
typedef struct {
39
    char Active; /**< True if this filter should be used. */
37
    char Active; /**< True if this filter should be used. */
40
    unsigned long Id; /**< Match if id matches the message id in all bit locations that are not masked. */
38
    unsigned long Id; /**< Match if id matches the message id in all bit locations that are not masked. */
41
    unsigned long Mask; /**< Each bit specifies if the corresponding id bit must match (mask[n] = 1) or is Don't Care (mask[n] = 0). */
39
    unsigned long Mask; /**< Each bit specifies if the corresponding id bit must match (mask[n] = 1) or is Don't Care (mask[n] = 0). */
42
} StdCan_Filter_t;
40
} StdCan_Filter_t;
43
 
41
 
44
StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS];
42
StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS];
45
#endif
43
#endif
46
 
44
 
47
/**
45
/**
48
 * CAN message callback.
46
 * CAN message callback.
49
 * Callback for when a message is received from the lower
47
 * Callback for when a message is received from the lower
50
 * layer (BIOS or CAN driver).
48
 * layer (BIOS or CAN driver).
51
 */
49
 */
52
void Can_Process(Can_Message_t* msg)
50
void Can_Process(Can_Message_t* msg)
53
{
51
{
54
    unsigned char n;
52
    /* What will the next write index be if the push goes well? */
55
    /* Check if there is room on the queue. */
53
    unsigned char Wr_next = RxQ_Wr_idx + 1;
56
    if (RxQ_Len < STDCAN_RX_QUEUE_SIZE) {
54
    if (Wr_next >= STDCAN_RX_QUEUE_SIZE + 1) Wr_next = 0;
57
 
55
 
-
 
56
    /* Check if there is room on the queue. */
-
 
57
    if (Wr_next != RxQ_Rd_idx) {
-
 
58
        unsigned char n;
58
#if (STDCAN_FILTER)
59
#if (STDCAN_FILTER)
59
        /* Try to match each filter in turn. */
60
        /* Try to match each filter in turn. */
60
        for (n = 0; n < STDCAN_NUM_FILTERS; n++) {
61
        for (n = 0; n < STDCAN_NUM_FILTERS; n++) {
61
            if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) {
62
            if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) {
62
                RxQ[RxQ_Wr_idx].Match = n;
63
                RxQ[RxQ_Wr_idx].Match = n;
63
                break;
64
                break;
64
            }
65
            }
65
        }
66
        }
66
 
67
 
67
        if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message.
68
        if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message.
68
#endif
69
#endif
69
        /* Copy the message from lower layer into the queue. */
70
        /* Copy the message from lower layer into the queue. */
70
        RxQ[RxQ_Wr_idx].Id     = msg->Id;
71
        RxQ[RxQ_Wr_idx].Id     = msg->Id;
71
        RxQ[RxQ_Wr_idx].Length = msg->DataLength;
72
        RxQ[RxQ_Wr_idx].Length = msg->DataLength;
72
        //TODO: This should be guarded against invalid DataLength.
73
        //TODO: This should be guarded against invalid DataLength.
73
        for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) {
74
        for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) {
74
            RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n];
75
            RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n];
75
        }
76
        }
76
        /* Increment write index and queue length. */
77
        /* Update write index. */
77
        if (++RxQ_Wr_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Wr_idx = 0;
-
 
78
        RxQ_Len++;
78
        RxQ_Wr_idx = Wr_next;
79
    } else {
79
    } else {
80
        /* Overflow, just drop the new message. In the future, some
80
        /* Overflow, just drop the new message. In the future, some
81
         * form of priority scheme could be used to drop another
81
         * form of priority scheme could be used to drop another
82
         * message in the queue.
82
         * message in the queue.
83
         */
83
         */
84
    }
84
    }
85
}
85
}
86
 
86
 
87
#ifdef MODULE_APPLICATION
87
#ifdef MODULE_APPLICATION
88
StdCan_Ret_t StdCan_Init(void)
88
StdCan_Ret_t StdCan_Init(void)
89
{
89
{
90
#else
90
#else
91
StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc)
91
StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc)
Line 94... Line 94...
94
    StdCan_Ret_t retval;
94
    StdCan_Ret_t retval;
95
 
95
 
96
    /* Reset all queue variables. */
96
    /* Reset all queue variables. */
97
    RxQ_Rd_idx = 0;
97
    RxQ_Rd_idx = 0;
98
    RxQ_Wr_idx = 0;
98
    RxQ_Wr_idx = 0;
99
    RxQ_Len    = 0;
-
 
100
#if (STDCAN_TX_QUEUE_SIZE > 1)
99
#if (STDCAN_TX_QUEUE_SIZE > 1)
101
    TxQ_Rd_idx = 0;
100
    TxQ_Rd_idx = 0;
102
    TxQ_Wr_idx = 0;
101
    TxQ_Wr_idx = 0;
103
    TxQ_Len    = 0;
-
 
104
#endif
102
#endif
105
 
103
 
106
#if defined(_AVRLIB_BIOS_)
104
#if defined(_AVRLIB_BIOS_)
107
    /* Initialize BIOS' interface for CAN. */
105
    /* Initialize BIOS' interface for CAN. */
108
    BIOS_CanCallback = Can_Process;
106
    BIOS_CanCallback = Can_Process;
Line 143... Line 141...
143
    /* Try to send it. */
141
    /* Try to send it. */
144
    Can_Send(&Startup);
142
    Can_Send(&Startup);
145
#endif
143
#endif
146
 
144
 
147
    return retval;
145
    return retval;
148
}
146
}
149
 
147
 
150
StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
148
StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
151
{
149
{
-
 
150
    unsigned char Wr_idx;
152
    unsigned char n;
151
    unsigned char Rd_idx;
-
 
152
 
-
 
153
    /* Read indices atomically into local copies. */
-
 
154
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-
 
155
        Wr_idx = *(volatile unsigned char*)&RxQ_Wr_idx;
-
 
156
        Rd_idx = *(volatile unsigned char*)&RxQ_Rd_idx;
153
    cli();
157
    }
-
 
158
 
154
    /* Check if there's a message waiting. */
159
    /* Check if there's a message waiting. */
155
    if (RxQ_Len) {
160
    if (Rd_idx != Wr_idx) {
-
 
161
        unsigned char n;
156
 
162
 
157
        /* Copy message to user buffer. */
163
        /* Copy message to user buffer. */
158
        msg->Id     = RxQ[RxQ_Rd_idx].Id;
164
        msg->Id     = RxQ[Rd_idx].Id;
159
        msg->Length = RxQ[RxQ_Rd_idx].Length;
165
        msg->Length = RxQ[Rd_idx].Length;
160
        //TODO: Consider a mempcy() of the entire message.
166
        //TODO: Consider a mempcy() of the entire message.
161
        for (n = 0; n < RxQ[RxQ_Rd_idx].Length; n++) {
167
        for (n = 0; n < RxQ[Rd_idx].Length; n++) {
162
            msg->Data[n] = RxQ[RxQ_Rd_idx].Data[n];
168
            msg->Data[n] = RxQ[Rd_idx].Data[n];
163
        }
169
        }
164
 
170
 
165
        /* Increment read index and decrease queue length. */
171
        /* Update read index and store back atomically. */
166
        if (++RxQ_Rd_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Rd_idx = 0;
172
        if (++Rd_idx >= STDCAN_RX_QUEUE_SIZE + 1) Rd_idx = 0;
-
 
173
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-
 
174
            *(volatile unsigned char*)&RxQ_Rd_idx = Rd_idx;
167
        RxQ_Len--;
175
        }
168
       
176
 
169
        sei();
-
 
170
        return StdCan_Ret_OK;
177
        return StdCan_Ret_OK;
171
    } else {
178
    } else {
172
        /* Queue is empty. */
179
        /* Queue is empty. */
173
        sei();
-
 
174
        return StdCan_Ret_Empty;
180
        return StdCan_Ret_Empty;
175
    }
181
    }
176
}
-
 
177
 
-
 
178
unsigned char StdCan_Get_Pending(void)
-
 
179
{
-
 
180
    return RxQ_Len;
-
 
181
}
182
}
182
 
183
 
183
StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg)
184
StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg)
184
{
185
{
185
    Can_Message_t Can_Msg;
186
    Can_Message_t Can_Msg;