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