00001 #include "can-net.h"
00002 #include <stdlib.h>
00003 #include <string.h>
00004
00005 #define TYPE_SMALL_PACKET 0x3
00006 #define TYPE_PACKET_NORMAL 0x0
00007 #define TYPE_PACKET_START 0x1
00008 #define TYPE_PACKET_STOP 0x2
00009
00010 #define CANID_TO_TYPE(canid) ((canid) >> 8)
00011 #define CANID_TO_ID(canid) ((canid) & 0xff)
00012 #define TO_CANID(type, id) (((type) << 8) | (id))
00013
00014 #define ASEBA_MIN(a, b) (((a) < (b)) ? (a) : (b))
00015
00016
00018 static struct AsebaCan
00019 {
00020
00021 uint16 id;
00023
00024 AsebaCanSendFrameFP sendFrameFP;
00025 AsebaCanIntVoidFP isFrameRoomFP;
00026 AsebaCanVoidVoidFP receivedPacketDroppedFP;
00027 AsebaCanVoidVoidFP sentPacketDroppedFP;
00028
00029
00030 CanFrame* sendQueue;
00031 size_t sendQueueSize;
00032 uint16 sendQueueInsertPos;
00033 uint16 sendQueueConsumePos;
00034
00035
00036 CanFrame* recvQueue;
00037 size_t recvQueueSize;
00038 uint16 recvQueueInsertPos;
00039 uint16 recvQueueConsumePos;
00040
00041 uint16 volatile sendQueueLock;
00042
00043 } asebaCan;
00044
00047
00049 uint16 AsebaCanGetMinMultipleOfHeight(uint16 v)
00050 {
00051 uint16 m = v >> 3;
00052 if ((v & 0x7) != 0)
00053 m++;
00054 return m;
00055 }
00056
00058 static uint16 AsebaCanSendQueueGetUsedFrames()
00059 {
00060 uint16 ipos, cpos;
00061 ipos = asebaCan.sendQueueInsertPos;
00062 cpos = asebaCan.sendQueueConsumePos;
00063
00064 if (ipos >= cpos)
00065 return ipos - cpos;
00066 else
00067 return asebaCan.sendQueueSize - cpos + ipos;
00068 }
00069
00071 static uint16 AsebaCanSendQueueGetFreeFrames()
00072 {
00073 return asebaCan.sendQueueSize - AsebaCanSendQueueGetUsedFrames();
00074 }
00075
00077 static void AsebaCanSendQueueInsert(uint16 canid, const uint8 *data, size_t size)
00078 {
00079 uint16 temp;
00080 memcpy(asebaCan.sendQueue[asebaCan.sendQueueInsertPos].data, data, size);
00081 asebaCan.sendQueue[asebaCan.sendQueueInsertPos].id = canid;
00082 asebaCan.sendQueue[asebaCan.sendQueueInsertPos].len = size;
00083
00084
00085 temp = asebaCan.sendQueueInsertPos + 1;
00086 if (temp >= asebaCan.sendQueueSize)
00087 temp = 0;
00088 asebaCan.sendQueueInsertPos = temp;
00089 }
00090
00092 static void AsebaCanSendQueueToPhysicalLayer()
00093 {
00094 uint16 temp;
00095
00096 while (asebaCan.isFrameRoomFP() && (asebaCan.sendQueueConsumePos != asebaCan.sendQueueInsertPos))
00097 {
00098 asebaCan.sendQueueLock = 1;
00099 if(!(asebaCan.isFrameRoomFP() && (asebaCan.sendQueueConsumePos != asebaCan.sendQueueInsertPos)))
00100 {
00101 asebaCan.sendQueueLock = 0;
00102 continue;
00103 }
00104
00105 asebaCan.sendFrameFP(asebaCan.sendQueue + asebaCan.sendQueueConsumePos);
00106
00107 temp = asebaCan.sendQueueConsumePos + 1;
00108 if (temp >= asebaCan.sendQueueSize)
00109 temp = 0;
00110 asebaCan.sendQueueConsumePos = temp;
00111 asebaCan.sendQueueLock = 0;
00112 }
00113
00114 }
00115
00117 static uint16 AsebaCanRecvQueueGetMaxUsedFrames()
00118 {
00119 uint16 ipos, cpos;
00120 ipos = asebaCan.recvQueueInsertPos;
00121 cpos = asebaCan.recvQueueConsumePos;
00122 if (ipos >= cpos)
00123 return ipos - cpos;
00124 else
00125 return asebaCan.recvQueueSize - cpos + ipos;
00126 }
00127
00129 static uint16 AsebaCanRecvQueueGetMinFreeFrames()
00130 {
00131 return asebaCan.recvQueueSize - AsebaCanRecvQueueGetMaxUsedFrames();
00132 }
00133
00135 static void AsebaCanRecvQueueGarbageCollect()
00136 {
00137 uint16 temp;
00138 while (asebaCan.recvQueueConsumePos != asebaCan.recvQueueInsertPos)
00139 {
00140 if (asebaCan.recvQueue[asebaCan.recvQueueConsumePos].used)
00141 break;
00142
00143 temp = asebaCan.recvQueueConsumePos + 1;
00144 if (temp >= asebaCan.recvQueueSize)
00145 temp = 0;
00146 asebaCan.recvQueueConsumePos = temp;
00147 }
00148 }
00149
00151 static void AsebaCanRecvQueueFreeFrames(uint16 id)
00152 {
00153 uint16 i;
00154
00155
00156 for (i = asebaCan.recvQueueConsumePos; i != asebaCan.recvQueueInsertPos;)
00157 {
00158
00159 if (CANID_TO_ID(asebaCan.recvQueue[i].id) == id)
00160 asebaCan.recvQueue[i].used = 0;
00161
00162 i++;
00163 if (i >= asebaCan.recvQueueSize)
00164 i = 0;
00165 }
00166 }
00167
00168
00169 void AsebaCanInit(uint16 id, AsebaCanSendFrameFP sendFrameFP, AsebaCanIntVoidFP isFrameRoomFP, AsebaCanVoidVoidFP receivedPacketDroppedFP, AsebaCanVoidVoidFP sentPacketDroppedFP, CanFrame* sendQueue, size_t sendQueueSize, CanFrame* recvQueue, size_t recvQueueSize)
00170 {
00171 asebaCan.id = id;
00172
00173 asebaCan.sendFrameFP = sendFrameFP;
00174 asebaCan.isFrameRoomFP= isFrameRoomFP;
00175 asebaCan.receivedPacketDroppedFP = receivedPacketDroppedFP;
00176 asebaCan.sentPacketDroppedFP = sentPacketDroppedFP;
00177
00178 asebaCan.sendQueue = sendQueue;
00179 asebaCan.sendQueueSize = sendQueueSize;
00180 asebaCan.sendQueueInsertPos = 0;
00181 asebaCan.sendQueueConsumePos = 0;
00182
00183 asebaCan.recvQueue = recvQueue;
00184 asebaCan.recvQueueSize = recvQueueSize;
00185 asebaCan.recvQueueInsertPos = 0;
00186 asebaCan.recvQueueConsumePos = 0;
00187
00188 asebaCan.sendQueueLock = 0;
00189 }
00190
00191 uint16 AsebaCanSend(const uint8 *data, size_t size)
00192 {
00193 return AsebaCanSendSpecificSource(data, size, asebaCan.id);
00194 }
00195
00196 uint16 AsebaCanSendSpecificSource(const uint8 *data, size_t size, uint16 source)
00197 {
00198
00199 AsebaCanSendQueueToPhysicalLayer();
00200
00201
00202 uint16 frameRequired = AsebaCanGetMinMultipleOfHeight(size);
00203 if (AsebaCanSendQueueGetFreeFrames() <= frameRequired)
00204 {
00205 asebaCan.sentPacketDroppedFP();
00206 return 0;
00207 }
00208
00209
00210 if (size <= 8)
00211 {
00212 AsebaCanSendQueueInsert(TO_CANID(TYPE_SMALL_PACKET, source), data, size);
00213 }
00214 else
00215 {
00216 size_t pos = 8;
00217
00218 AsebaCanSendQueueInsert(TO_CANID(TYPE_PACKET_START, source), data, 8);
00219 while (pos + 8 < size)
00220 {
00221 AsebaCanSendQueueInsert(TO_CANID(TYPE_PACKET_NORMAL, source), data + pos, 8);
00222 pos += 8;
00223 }
00224 AsebaCanSendQueueInsert(TO_CANID(TYPE_PACKET_STOP, source), data + pos, size - pos);
00225 }
00226
00227
00228 AsebaCanSendQueueToPhysicalLayer();
00229
00230 return 1;
00231 }
00232
00233
00234 uint16 AsebaCanRecvBufferEmpty(void)
00235 {
00236 return asebaCan.recvQueueInsertPos == asebaCan.recvQueueConsumePos;
00237 }
00238
00239 void AsebaCanFrameSent()
00240 {
00241
00242 if (!asebaCan.sendQueueLock)
00243 AsebaCanSendQueueToPhysicalLayer();
00244 }
00245
00246 void AsebaCanFlushQueue(void)
00247 {
00248 while(asebaCan.sendQueueConsumePos != asebaCan.sendQueueInsertPos || !asebaCan.isFrameRoomFP())
00249 AsebaIdle();
00250 }
00251
00252 uint16 AsebaCanRecv(uint8 *data, size_t size, uint16 *source)
00253 {
00254 int stopPos = -1;
00255 uint16 stopId;
00256 uint16 pos = 0;
00257 uint16 i;
00258
00259
00260 for (i = asebaCan.recvQueueConsumePos; i != asebaCan.recvQueueInsertPos; )
00261 {
00262 if(asebaCan.recvQueue[i].used) {
00263
00264 if (CANID_TO_TYPE(asebaCan.recvQueue[i].id) == TYPE_SMALL_PACKET)
00265 {
00266
00267 uint16 len = ASEBA_MIN(size, asebaCan.recvQueue[i].len);
00268 memcpy(data, asebaCan.recvQueue[i].data, len);
00269 *source = CANID_TO_ID(asebaCan.recvQueue[i].id);
00270 asebaCan.recvQueue[i].used = 0;
00271
00272
00273 AsebaCanRecvQueueGarbageCollect();
00274
00275 return len;
00276 }
00277
00278 else if (CANID_TO_TYPE(asebaCan.recvQueue[i].id) == TYPE_PACKET_STOP)
00279 {
00280 stopPos = i;
00281 stopId = CANID_TO_ID(asebaCan.recvQueue[i].id);
00282 break;
00283 }
00284 }
00285 i++;
00286 if (i >= asebaCan.recvQueueSize)
00287 i = 0;
00288 }
00289
00290
00291 if (stopPos < 0)
00292 return 0;
00293
00294
00295 *source = CANID_TO_ID(stopId);
00296 i = asebaCan.recvQueueConsumePos;
00297 while (1)
00298 {
00299 if(asebaCan.recvQueue[i].used) {
00300
00301 if (CANID_TO_ID(asebaCan.recvQueue[i].id) == stopId)
00302 {
00303 if (pos < size)
00304 {
00305 uint16 amount = ASEBA_MIN(asebaCan.recvQueue[i].len, size - pos);
00306 memcpy(data + pos, asebaCan.recvQueue[i].data, amount);
00307 pos += amount;
00308 }
00309 asebaCan.recvQueue[i].used = 0;
00310 }
00311
00312 if (i == stopPos)
00313 break;
00314
00315 }
00316 i++;
00317 if (i >= asebaCan.recvQueueSize)
00318 i = 0;
00319 }
00320
00321
00322 AsebaCanRecvQueueGarbageCollect();
00323
00324 return pos;
00325 }
00326
00327 #define MAX_DROPPING_SOURCE 20
00328 static uint16 dropping[MAX_DROPPING_SOURCE];
00329
00330 void AsebaCanFrameReceived(const CanFrame *frame)
00331 {
00332
00333 uint16 source = CANID_TO_ID(frame->id);
00334
00335
00336 if (CANID_TO_TYPE(frame->id) == TYPE_SMALL_PACKET)
00337 {
00338 if (AsebaShouldDropPacket(source, frame->data))
00339 return;
00340 }
00341 else if (CANID_TO_TYPE(frame->id) == TYPE_PACKET_START)
00342 {
00343 if (AsebaShouldDropPacket(source, frame->data))
00344 {
00345 uint16 i;
00346 for (i = 0; i < MAX_DROPPING_SOURCE; i++)
00347 {
00348 if (dropping[i] == 0)
00349 {
00350 dropping[i] = source + 1;
00351 return;
00352 }
00353 }
00354 }
00355 }
00356 else
00357 {
00358 uint16 i;
00359 for (i = 0; i < MAX_DROPPING_SOURCE; i++)
00360 {
00361 if (dropping[i] == source + 1)
00362 {
00363 if (CANID_TO_TYPE(frame->id) == TYPE_PACKET_STOP)
00364 dropping[i] = 0;
00365 return;
00366 }
00367 }
00368 }
00369
00370 if (AsebaCanRecvQueueGetMinFreeFrames() <= 1)
00371 {
00372
00373 if (CANID_TO_TYPE(frame->id) == TYPE_PACKET_STOP) {
00374 AsebaCanRecvQueueFreeFrames(source);
00375 AsebaCanRecvQueueGarbageCollect();
00376 }
00377
00378
00379 asebaCan.receivedPacketDroppedFP();
00380 }
00381 else
00382 {
00383 uint16 temp;
00384
00385 asebaCan.recvQueue[asebaCan.recvQueueInsertPos] = *frame;
00386 asebaCan.recvQueue[asebaCan.recvQueueInsertPos].used = 1;
00387 temp = asebaCan.recvQueueInsertPos + 1;
00388 if (temp >= asebaCan.recvQueueSize)
00389 temp = 0;
00390 asebaCan.recvQueueInsertPos = temp;
00391 }
00392 }
00393
00394 void AsebaCanRecvFreeQueue(void)
00395 {
00396 int i;
00397 for(i = 0; i < asebaCan.recvQueueSize; i++)
00398 asebaCan.recvQueue[i].used = 0;
00399 asebaCan.recvQueueInsertPos = 0;
00400 asebaCan.recvQueueConsumePos = 0;
00401
00402 for(i = 0; i < MAX_DROPPING_SOURCE; i++)
00403 dropping[i] = 0;
00404 }
00405