Subversion Repositories HomeAutomation

Rev

Rev 801 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
687 nattgris 1
 
2
#include "stdcan.h"
3
#if defined(_AVRLIB_BIOS_)
4
#include <bios.h>
5
#define Can_Send BIOS_CanSend
6
#else
7
#include <drivers/can/mcp2515/mcp2515.h>
8
#endif
9
 
10
#if (STDCAN_TX_QUEUE_SIZE > 1)
11
#error StdCan: Tx queue size longer than one msg not yet implemented.
12
#endif
13
 
14
/**
15
 * The receive queue.
16
 */
17
StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE];
18
unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
19
unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
20
unsigned char RxQ_Len; /**< Number of messages in receive queue. */
21
 
22
#if (STDCAN_TX_QUEUE_SIZE > 1)
23
/**
24
 * The transmit queue.
25
 */
26
StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE];
27
unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */
28
unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */
29
unsigned char TxQ_Len; /**< Number of messages in transmit queue. */
30
#endif
31
 
690 nattgris 32
#if (STDCAN_FILTER)
687 nattgris 33
/**
690 nattgris 34
 * The message acceptance filters.
35
 */
36
typedef struct {
37
    char Active; /**< True if this filter should be used. */
38
    unsigned long Id; /**< Match if id matches the message id in all bit locations that are not masked. */
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). */
40
} StdCan_Filter_t;
41
 
42
StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS];
43
#endif
44
 
45
/**
687 nattgris 46
 * CAN message callback.
47
 * Callback for when a message is received from the lower
48
 * layer (BIOS or CAN driver).
49
 */
50
void Can_Process(Can_Message_t* msg)
51
{
52
    unsigned char n;
53
    /* Check if there is room on the queue. */
54
    if (RxQ_Len < STDCAN_RX_QUEUE_SIZE) {
690 nattgris 55
 
56
#if (STDCAN_FILTER)
57
        /* Try to match each filter in turn. */
58
        for (n = 0; n < STDCAN_NUM_FILTERS; n++) {
59
            if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) {
60
                RxQ[RxQ_Wr_idx].Match = n;
61
                break;
62
            }
63
        }
64
 
65
        if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message.
66
#endif
687 nattgris 67
        /* Copy the message from lower layer into the queue. */
68
        RxQ[RxQ_Wr_idx].Id     = msg->Id;
69
        RxQ[RxQ_Wr_idx].Length = msg->DataLength;
70
        //TODO: This should be guarded against invalid DataLength.
71
        for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) {
72
            RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n];
73
        }
74
        /* Increment write index and queue length. */
75
        if (++RxQ_Wr_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Wr_idx = 0;
76
        RxQ_Len++;
77
    } else {
78
        /* Overflow, just drop the new message. In the future, some
79
         * form of priority scheme could be used to drop another
80
         * message in the queue.
81
         */
82
    }
83
}
84
 
804 migan 85
StdCan_Ret_t StdCan_Init(void)
687 nattgris 86
{
87
    StdCan_Ret_t retval;
88
 
89
    /* Reset all queue variables. */
90
    RxQ_Rd_idx = 0;
91
    RxQ_Wr_idx = 0;
92
    RxQ_Len    = 0;
690 nattgris 93
#if (STDCAN_TX_QUEUE_SIZE > 1)
687 nattgris 94
    TxQ_Rd_idx = 0;
95
    TxQ_Wr_idx = 0;
96
    TxQ_Len    = 0;
690 nattgris 97
#endif
687 nattgris 98
 
99
#if defined(_AVRLIB_BIOS_)
100
    /* Initialize BIOS' interface for CAN. */
101
    BIOS_CanCallback = Can_Process;
102
    retval = StdCan_Ret_OK;
103
#else
104
    /* Initialize CAN driver. */
105
    if (Can_Init() == CAN_OK)
106
        retval = StdCan_Ret_OK;
107
    else
108
        retval = StdCan_Ret_Fail;
109
#endif
110
 
789 arune 111
    //TODO: Do something with the Node Descriptor. 
112
    //(why have constats passed as parameters? they are defined at compiletime /arune)
113
#if defined(_AVRLIB_BIOS_)
114
    /* TODO: When a Tx queue is implemented, the startup message should
115
     * be sent via StdCan_Put instead of directly to lower layer.
116
     */
117
    Can_Message_t Startup;
687 nattgris 118
 
789 arune 119
    /* Set up Startup message format. */
120
    Startup.ExtendedFlag = 1;
121
    Startup.RemoteFlag = 0;
122
    Startup.DataLength = 4;
801 linlun 123
    Startup.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE);
124
    Startup.Data.bytes[0] = NODE_HW_ID&0xff;
125
    Startup.Data.bytes[1] = (NODE_HW_ID>>8)&0xff;
126
    Startup.Data.bytes[2] = (NODE_HW_ID>>16)&0xff;
127
    Startup.Data.bytes[3] = (NODE_HW_ID>>24)&0xff;
789 arune 128
 
129
    /* Try to send it. */
130
    Can_Send(&Startup);
131
#endif
132
 
687 nattgris 133
    return retval;
134
}
135
 
136
StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
137
{
138
    unsigned char n;
139
 
140
    /* Check if there's a message waiting. */
141
    if (RxQ_Len) {
142
 
143
        /* Copy message to user buffer. */
144
        msg->Id     = RxQ[RxQ_Rd_idx].Id;
145
        msg->Length = RxQ[RxQ_Rd_idx].Length;
146
        //TODO: Consider a mempcy() of the entire message.
147
        for (n = 0; n < RxQ[RxQ_Rd_idx].Length; n++) {
148
            msg->Data[n] = RxQ[RxQ_Rd_idx].Data[n];
149
        }
150
 
151
        /* Increment read index and decrease queue length. */
152
        if (++RxQ_Rd_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Rd_idx = 0;
153
        RxQ_Len--;
154
 
155
        return StdCan_Ret_OK;
156
    } else {
157
        /* Queue is empty. */
158
        return StdCan_Ret_Empty;
159
    }
160
}
161
 
789 arune 162
unsigned char StdCan_Get_Pending(void)
163
{
164
    return RxQ_Len;
165
}
166
 
687 nattgris 167
StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg)
168
{
169
    Can_Message_t Can_Msg;
170
    unsigned char n;
171
 
172
    /* Validate message. */
173
    if ((unsigned)msg->Length > 8) return StdCan_Ret_DataErr;
174
 
175
    /* Copy message directly to lower layer until a proper
176
     * queue has been implemented.
177
     * TODO: Implement a proper queue. This requires TX interrupt
178
     * support in the driver and BIOS.
179
     */
180
    Can_Msg.ExtendedFlag = 1;
181
    Can_Msg.RemoteFlag = 0;
182
    Can_Msg.Id = msg->Id;
183
    Can_Msg.DataLength = msg->Length;
184
    for (n = 0; n < msg->Length; n++) {
693 arune 185
        Can_Msg.Data.bytes[n] = msg->Data[n];
687 nattgris 186
    }
801 linlun 187
 
188
    if (Can_Send(&Can_Msg) == CAN_OK) {
804 migan 189
#ifdef MODULE_APPLICATION
801 linlun 190
        Can_Process(&Can_Msg);
804 migan 191
#endif
687 nattgris 192
        return StdCan_Ret_OK;
801 linlun 193
    }
687 nattgris 194
    else
195
        return StdCan_Ret_Full;
196
}
197
 
198
void StdCan_SendHeartbeat(uint8_t n)
199
{
200
    /* TODO: When a Tx queue is implemented, the heartbeat should
201
     * be sent via StdCan_Put instead of directly to lower layer.
202
     */
203
    Can_Message_t Heartbeat;
204
 
205
    /* Set up Heartbeat message format. */
206
    Heartbeat.ExtendedFlag = 1;
207
    Heartbeat.RemoteFlag = 0;
801 linlun 208
    Heartbeat.DataLength = 4;
209
    Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE);
210
    Heartbeat.Data.bytes[0] = NODE_HW_ID&0xff;
211
    Heartbeat.Data.bytes[1] = (NODE_HW_ID>>8)&0xff;
212
    Heartbeat.Data.bytes[2] = (NODE_HW_ID>>16)&0xff;
213
    Heartbeat.Data.bytes[3] = (NODE_HW_ID>>24)&0xff;
687 nattgris 214
 
215
    /* Try to send it. */
216
    Can_Send(&Heartbeat);
217
}
690 nattgris 218
 
219
#if (STDCAN_FILTER)
220
StdCan_Ret_t StdCan_EnableFilter(unsigned char filter, unsigned long id, unsigned long mask)
221
{
222
    if (filter < STDCAN_NUM_FILTERS) {
223
        RxFilters[filter].Id = id;
224
        RxFilters[filter].Mask = mask;
225
        RxFilters[filter].Active = 1;
226
        return StdCan_Ret_OK;
227
    } else {
228
        return StdCan_Ret_DataErr;
229
    }
230
}
231
 
232
StdCan_Ret_t StdCan_DisableFilter(unsigned char filter)
233
{
234
    if (filter < STDCAN_NUM_FILTERS) {
235
        RxFilters[filter].Active = 0;
236
        return StdCan_Ret_OK;
237
    } else {
238
        return StdCan_Ret_DataErr;
239
    }
240
}
241
#endif