Subversion Repositories HomeAutomation

Rev

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

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