]> rtime.felk.cvut.cz Git - arc.git/blob - memory/Ea/Ea.c
Added lots of debug to Nvm
[arc.git] / memory / Ea / Ea.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 /** @req EA113 @req EA112 @req EA049 @req EA038 */\r
17 /** @req EA116 @req EA117 @req EA083 @req EA097 */\r
18 \r
19 #include "assert.h"\r
20 #include "string.h"\r
21 \r
22 #include "Ea.h"\r
23 #include "Ea_Cbk.h"\r
24 #include "Ea_Types.h"\r
25 \r
26 #include "Cpu.h"\r
27 //#include "Mcu.h"\r
28 \r
29 /** @req EA011 */\r
30 /** @req EA045 */\r
31 #if (STD_ON == EA_DEV_ERROR_DETECT)\r
32 #include "Det.h"\r
33 #endif\r
34 \r
35 \r
36 \r
37 // States used by EA_MainFunction to control the internal state of the module.\r
38 typedef enum\r
39 {\r
40         EA_PENDING_NONE,\r
41         EA_PENDING_WRITE,\r
42         EA_PENDING_READ,\r
43         EA_PENDING_ERASE,\r
44         EA_PENDING_ADMIN_WRITE\r
45 \r
46 } Ea_JobStatus;\r
47 \r
48 \r
49 /*\r
50                 define EA module notification callback macro    \r
51 */\r
52 #define EA_JOB_END_NOTIFICATION()       \\r
53         if (Ea_Global.EaGeneralPtr->EaNvmJobEndNotification != NULL_PTR){       \\r
54                 Ea_Global.EaGeneralPtr->EaNvmJobEndNotification();              \\r
55         }\r
56 \r
57 #define EA_JOB_ERROR_NOTIFICATION() \\r
58         if (Ea_Global.EaGeneralPtr->EaNvmJobErrorNotification != NULL_PTR) { \\r
59         Ea_Global.EaGeneralPtr->EaNvmJobErrorNotification(); \\r
60         }\r
61 \r
62 /*\r
63  * Defines for blockstates
64  */\r
65 /** @req EA047 */\r
66 #define BLOCK_INCONSISTENT  0x23\r
67 #define BLOCK_CONSISTENT    0x45\r
68 #define BLOCK_INVALIDATED   0x67\r
69 \r
70 /*\r
71  * Definition of the Admin block type
72  */\r
73 /** @req EA046 */\r
74 typedef struct {\r
75         uint16 blockNum;\r
76         uint8  blockState;\r
77         uint8  check;  // Simple checksum\r
78 } Ea_AdminBlock;\r
79 \r
80 /*\r
81  * Define EA Module Global Type\r
82  */\r
83 typedef struct {\r
84         const Ea_BlockConfigType *EaBlockConfig;\r
85         const Ea_GeneralType    *EaGeneralPtr;\r
86         MemIf_StatusType        ModuleStatus;\r
87         MemIf_JobResultType     JobResult;\r
88         Ea_JobType                      JobType;\r
89         uint16                                  CurrentBlock; // The block we are currentlty working on\r
90         Eep_AddressType                 EepAddress; // Start adress to read from\r
91         uint16                  Length;    // The length to read i.e the blockSize\r
92         Ea_JobStatus            JobStatus; // Internal state to be used by main function.\r
93         void*                                   Address;   // The adress to put the result into\r
94         uint16                  ReadLength; // The length of the block to read/write\r
95         uint16                  Offset; // The offset in the block to read from.\r
96 }Ea_GlobalType;\r
97 \r
98 /*\r
99  * Define EA Module Global\r
100  */\r
101 static Ea_GlobalType Ea_Global = {\r
102         NULL_PTR,\r
103         NULL_PTR,\r
104         MEMIF_UNINIT,\r
105         MEMIF_JOB_OK,\r
106         EA_JOB_NONE,\r
107 };\r
108 \r
109 static uint8 Ea_TempBuffer[EA_MAX_BLOCK_SIZE + sizeof(Ea_AdminBlock)];\r
110 \r
111 /*\r
112  * Function prototypes
113  */\r
114 static uint16 EA_GET_BLOCK(uint16 BlockNumber);\r
115 static Eep_AddressType calculateEepAddress(uint16 BlockIndex);\r
116 static uint16 calculateBlockLength(uint16 BlockIndex);\r
117 static void handleLowerLayerRead(void);\r
118 static void handleLowerLayerWrite(void);\r
119 static void handleLowerLayerErase(void);\r
120 static uint8 verifyChecksum(Ea_AdminBlock* block);\r
121 static void addChecksum(Ea_AdminBlock* block);\r
122 \r
123 /* Local functions */\r
124 static Std_ReturnType Ea_ValidateInitialized(Ea_APIServiceIDType apiId)\r
125 {\r
126         Std_ReturnType result = E_OK;\r
127     if( Ea_Global.ModuleStatus == MEMIF_UNINIT )\r
128     {\r
129 #if EA_DEV_ERROR_DETECT==STD_ON\r
130         Det_ReportError(EA_MODULE_ID,0, apiId, EA_E_NOT_INITIALIZED);\r
131         result = E_NOT_OK;\r
132 #endif\r
133     }\r
134     return result;\r
135 }\r
136 \r
137 static Std_ReturnType Ea_ValidateBlock(uint16 blockNumber, Ea_APIServiceIDType apiId)\r
138 {\r
139         Std_ReturnType result = E_OK;\r
140     if( (blockNumber == 0) || (blockNumber == 0xffff) )\r
141     {\r
142 #if EA_DEV_ERROR_DETECT==STD_ON\r
143         Det_ReportError(EA_MODULE_ID,0, apiId, EA_E_INVALID_BLOCK_NO);\r
144         result = E_NOT_OK;\r
145 #endif\r
146     }\r
147     return result;\r
148 }\r
149 \r
150 static Std_ReturnType Ea_ValidateBlockIndex(uint16 blockIndex, Ea_APIServiceIDType apiId)\r
151 {\r
152         Std_ReturnType result = E_OK;\r
153     if( blockIndex >= EA_NUMBER_OF_BLOCKS )\r
154     {\r
155 #if EA_DEV_ERROR_DETECT==STD_ON\r
156         Det_ReportError(EA_MODULE_ID,0, apiId, EA_E_INVALID_BLOCK_NO);\r
157         result = E_NOT_OK;\r
158 #endif\r
159     }\r
160     return result;\r
161 }\r
162 \r
163 /*@req <EA084>*/\r
164 /*@req <EA017>*/\r
165 void Ea_Init(void)\r
166 {\r
167         /*init internal variables*/\r
168         Ea_Global.EaBlockConfig = Ea_BlockConfigData;\r
169         Ea_Global.EaGeneralPtr = &Ea_GeneralData;\r
170         Ea_Global.JobResult = MEMIF_JOB_OK; /*@req <EA128> */\r
171         Ea_Global.JobType = EA_JOB_NONE;\r
172         Ea_Global.JobStatus = EA_PENDING_NONE;\r
173         Ea_Global.ModuleStatus = MEMIF_IDLE; /*@req <EA128> */\r
174 }\r
175 \r
176 /*@req <EA150> */\r
177 #if (STD_ON == EA_SET_MODE_SUPPORTED)\r
178 /*@req <EA085>*/\r
179 /*@req <EA020>*/\r
180 void Ea_SetMode(MemIf_ModeType Mode)\r
181 {\r
182         if (E_OK != Ea_ValidateInitialized(EA_SETMODE_ID))\r
183                 return;\r
184 \r
185         /*@req <EA020> */\r
186         Eep_SetMode(Mode);\r
187 }\r
188 #endif\r
189 \r
190 /*@req <EA086>*/\r
191 /*@req <EA021>*/\r
192 Std_ReturnType Ea_Read(uint16 BlockNumber, uint16 BlockOffset, uint8* DataBufferPtr, uint16 Length)\r
193 {\r
194         uint16 BlockIndex;\r
195         const Ea_BlockConfigType *EaBlockCon;\r
196     imask_t state;\r
197 \r
198         /*@req <EA130> */\r
199         if (E_OK != Ea_ValidateInitialized(EA_READ_ID)){\r
200                 return E_NOT_OK;\r
201         }\r
202         /*@req <EA147> */\r
203         if (E_OK != Ea_ValidateBlock(BlockNumber, EA_READ_ID)){\r
204                 return E_NOT_OK;\r
205         }\r
206         /*@req <EA137> */\r
207         /* Lock down the module to ourself */\r
208     Irq_Save(state);\r
209         if (Ea_Global.ModuleStatus != MEMIF_IDLE)\r
210         {\r
211             Irq_Restore(state);\r
212                 return E_NOT_OK;\r
213         }\r
214         /*set current state is internal busy*/\r
215         Ea_Global.ModuleStatus = MEMIF_BUSY_INTERNAL;\r
216     Irq_Restore(state);\r
217 \r
218         BlockIndex = EA_GET_BLOCK(BlockNumber);\r
219 \r
220         /*@req <EA147> */\r
221         if (E_OK != Ea_ValidateBlockIndex(BlockIndex, EA_READ_ID))\r
222         {\r
223                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
224                 return E_NOT_OK;\r
225         }\r
226 \r
227         /*whether block device index match underlying driver in which Eep_Read will be invoked*/\r
228         EaBlockCon = Ea_Global.EaBlockConfig;\r
229 \r
230         /*check whether BlockOffset add Length exceed the blocksize*/\r
231         if (BlockOffset + Length > EaBlockCon[BlockIndex].EaBlockSize)\r
232         {\r
233                 return E_NOT_OK;\r
234         }\r
235         \r
236         Ea_Global.Address = DataBufferPtr;\r
237         /*@req <EA021> :calculate the corresponding memory read address for underlying Eep_Read*/\r
238         Ea_Global.EepAddress = calculateEepAddress(BlockIndex);\r
239         Ea_Global.Length = EaBlockCon[BlockIndex].EaBlockSize +  sizeof(Ea_AdminBlock);\r
240         Ea_Global.Offset = BlockOffset;\r
241         Ea_Global.ReadLength = Length;\r
242         Ea_Global.CurrentBlock = BlockNumber;\r
243 \r
244         /*@req <EA022> */\r
245         Ea_Global.ModuleStatus = MEMIF_BUSY;\r
246         Ea_Global.JobType = EA_JOB_READ;\r
247         Ea_Global.JobResult = MEMIF_JOB_PENDING;\r
248         Ea_Global.JobStatus = EA_PENDING_NONE;\r
249 \r
250         return E_OK;\r
251 }\r
252 \r
253 /*@req <EA087> */\r
254 /*@req <EA024> */\r
255 /*@req <EA026> */\r
256 Std_ReturnType Ea_Write(uint16 BlockNumber, uint8* DataBufferPtr)\r
257 {\r
258         uint16 BlockIndex;\r
259         const Ea_BlockConfigType *EaBlockCon;\r
260         Ea_AdminBlock* adminBlock;\r
261     imask_t state;\r
262 \r
263         /*@req <EA131> */\r
264         if (E_OK != Ea_ValidateInitialized(EA_WRITE_ID)){\r
265                 return E_NOT_OK;\r
266         }\r
267         /*@req <EA148> */\r
268         if (E_OK != Ea_ValidateBlock(BlockNumber, EA_WRITE_ID)){\r
269                 return E_NOT_OK;\r
270         }\r
271         /*@req <EA137>\r
272         */\r
273         /* Lock down the module to ourself */\r
274     Irq_Save(state);\r
275         if (Ea_Global.ModuleStatus != MEMIF_IDLE)\r
276         {\r
277             Irq_Restore(state);\r
278                 return E_NOT_OK;\r
279         }\r
280         /*set current state is internal busy*/\r
281         Ea_Global.ModuleStatus = MEMIF_BUSY_INTERNAL;\r
282     Irq_Restore(state);\r
283 \r
284         BlockIndex = EA_GET_BLOCK(BlockNumber);\r
285 \r
286         /*@req <EA148> */\r
287         if (E_OK != Ea_ValidateBlockIndex(BlockIndex, EA_READ_ID))\r
288         {\r
289                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
290                 return E_NOT_OK;\r
291         }\r
292 \r
293         /*whether block device index match underlying driver in which Eep_Read will be invoked*/\r
294         EaBlockCon = Ea_Global.EaBlockConfig;\r
295 \r
296         /*caculate the EepAddress*/\r
297         Ea_Global.EepAddress = calculateEepAddress(BlockIndex);\r
298         Ea_Global.Length = EaBlockCon[BlockIndex].EaBlockSize + sizeof(Ea_AdminBlock);\r
299         Ea_Global.Address = (void*)DataBufferPtr;\r
300         Ea_Global.CurrentBlock = BlockNumber;\r
301 \r
302         /* Setup the admin block */\r
303         /*@req <EA047> */\r
304         adminBlock = (Ea_AdminBlock*) Ea_TempBuffer;\r
305         adminBlock->blockNum = BlockNumber;\r
306         adminBlock->blockState = BLOCK_INCONSISTENT;\r
307         addChecksum(adminBlock);\r
308 \r
309         /* Copy the data to the buffer */\r
310         uint8* destMem = (uint8*) (Ea_TempBuffer + sizeof(Ea_AdminBlock));\r
311         memcpy(destMem, DataBufferPtr, EaBlockCon[BlockIndex].EaBlockSize);\r
312 \r
313         /*@req <EA025> [set internal variables set the EA module status to MEMIF_BUSY, set the job result to MEMIF_JOB_PENDING.]*/\r
314         Ea_Global.ModuleStatus = MEMIF_BUSY;\r
315         Ea_Global.JobType = EA_JOB_WRITE;\r
316         Ea_Global.JobResult = MEMIF_JOB_PENDING;\r
317         Ea_Global.JobStatus = EA_PENDING_NONE;\r
318 \r
319         return E_OK;\r
320 }\r
321 \r
322 /*@req <EA088>*/\r
323 void Ea_Cancel(void)\r
324 {\r
325         /*@req <EA132> */\r
326         if (E_OK != Ea_ValidateInitialized(EA_CANCEL_ID)){\r
327                 // Do nothing.\r
328         } else {\r
329                 /*@req <EA078> [Reset the Ea module's internal variables to make the module ready for a new job request.]*/\r
330                 Ea_Global.JobType = EA_JOB_NONE;\r
331                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
332                 Ea_Global.JobResult = MEMIF_JOB_CANCELLED;\r
333 \r
334                 /*@req <EA077> [Call the cancel function of the underlying EEPROM driver.]*/\r
335                 Eep_Cancel();\r
336         }\r
337 \r
338         return;\r
339 }\r
340 \r
341 /*@req EA089 */\r
342 MemIf_StatusType Ea_GetStatus(void)\r
343 {\r
344         MemIf_StatusType rv;\r
345 \r
346         /*@req <EA133> */\r
347         /*@req <EA034> */\r
348         if (E_OK != Ea_ValidateInitialized(EA_GETSTATUS_ID)){\r
349                 rv = MEMIF_UNINIT;\r
350         }\r
351         /*@req <EA156> */\r
352         else if (MEMIF_IDLE == Ea_Global.ModuleStatus){\r
353                 rv = MEMIF_IDLE;\r
354         }\r
355         /*@req <EA073> [check if EA Module is busy with internal management operations.]*/      \r
356         else if (MEMIF_BUSY_INTERNAL == Ea_Global.ModuleStatus){\r
357                 rv = MEMIF_BUSY_INTERNAL;\r
358         } else {\r
359                 /*@req <EA157> */\r
360                 rv = MEMIF_BUSY;\r
361         }\r
362         return rv;\r
363 }\r
364 \r
365 /*@req <EA090> */\r
366 MemIf_JobResultType Ea_GetJobResult(void)\r
367 {\r
368         MemIf_JobResultType rv;\r
369         /*@req <EA134> */\r
370         if (E_OK != Ea_ValidateInitialized(EA_GETJOBRESULT_ID)){\r
371                 rv = MEMIF_JOB_FAILED;\r
372         } else {\r
373                 /*@req <EA035> */\r
374                 rv = Ea_Global.JobResult;\r
375         }\r
376         return rv;\r
377 }\r
378 \r
379 /*@req <EA091> */\r
380 Std_ReturnType Ea_InvalidateBlock(uint16 BlockNumber)\r
381 {\r
382         uint16 BlockIndex;\r
383         const Ea_BlockConfigType *EaBlockCon;\r
384         Ea_AdminBlock* adminBlock;\r
385         Std_ReturnType result;\r
386     imask_t state;\r
387 \r
388         /*@req <EA135> */\r
389         if (E_OK != Ea_ValidateInitialized(EA_INVALIDATEBLOCK_ID)){\r
390                 return E_NOT_OK;\r
391         }\r
392         /*@req <EA149> */\r
393         if (E_OK != Ea_ValidateBlock(BlockNumber, EA_INVALIDATEBLOCK_ID)){\r
394                 return E_NOT_OK;\r
395         }\r
396         /*@req <EA137>\r
397         */\r
398         /* Lock down the module to ourself */\r
399     Irq_Save(state);\r
400         if (Ea_Global.ModuleStatus != MEMIF_IDLE)\r
401         {\r
402             Irq_Restore(state);\r
403                 return E_NOT_OK;\r
404         }\r
405         /*set current state is internal busy*/\r
406         Ea_Global.ModuleStatus = MEMIF_BUSY_INTERNAL;\r
407     Irq_Restore(state);\r
408 \r
409         BlockIndex = EA_GET_BLOCK(BlockNumber);\r
410 \r
411         /*@req <EA149> */\r
412         if (E_OK != Ea_ValidateBlockIndex(BlockIndex, EA_INVALIDATEBLOCK_ID))\r
413         {\r
414                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
415                 return E_NOT_OK;\r
416         }\r
417 \r
418         /*whether block device index match underlying driver in which Eep_Read will be invoked*/\r
419         EaBlockCon = Ea_Global.EaBlockConfig;\r
420 \r
421         /*@req <EA036> [calculate address]*/\r
422         Ea_Global.EepAddress = calculateEepAddress(BlockIndex);\r
423         Ea_Global.Length = EaBlockCon[BlockIndex].EaBlockSize;\r
424         Ea_Global.CurrentBlock = BlockNumber;\r
425         Ea_Global.ModuleStatus = MEMIF_BUSY;\r
426         Ea_Global.JobType = EA_JOB_WRITE;\r
427         Ea_Global.JobStatus = EA_PENDING_ADMIN_WRITE;\r
428         Ea_Global.JobResult = MEMIF_JOB_PENDING;\r
429 \r
430         /*@req <EA037> [now we calling the erase function of the underlying device driver]*/\r
431         /* We just set the Invalidate status of the admin block */\r
432         /* Setup the admin block to be consistent again*/\r
433         /*@req <EA047> */\r
434         adminBlock = (Ea_AdminBlock*) Ea_TempBuffer;\r
435         adminBlock->blockNum = BlockNumber;\r
436         adminBlock->blockState = BLOCK_INVALIDATED;\r
437         addChecksum(adminBlock);\r
438 \r
439         result = Eep_Write(Ea_Global.EepAddress, (const uint8*) Ea_TempBuffer, sizeof(Ea_AdminBlock));\r
440         if (E_OK == result)\r
441         {\r
442             Irq_Save(state);\r
443                 MemIf_StatusType status = Eep_GetStatus();\r
444                 if ((status == MEMIF_BUSY) || (status == MEMIF_BUSY_INTERNAL)){\r
445                         Ea_Global.JobStatus = EA_PENDING_ADMIN_WRITE;\r
446                 }\r
447             Irq_Restore(state);\r
448         }\r
449         else\r
450         {\r
451                 Ea_Global.JobType = EA_JOB_NONE;\r
452                 Ea_Global.JobResult = MEMIF_JOB_FAILED;\r
453                 Ea_Global.JobStatus = EA_PENDING_NONE;\r
454                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
455                 return E_NOT_OK;\r
456         }\r
457 \r
458         return E_OK;\r
459 }\r
460 \r
461 /*@req <EA093>*/\r
462 Std_ReturnType Ea_EraseImmediateBlock(uint16 BlockNumber)\r
463 {\r
464         uint16 BlockIndex;\r
465         const Ea_BlockConfigType *EaBlockCon;\r
466         imask_t state;\r
467 \r
468         /*@req <EA136> */\r
469         if (E_OK != Ea_ValidateInitialized(EA_ERASEIMMEDIATEBLOCK_ID)){\r
470                 return E_NOT_OK;\r
471         }\r
472         /*@req <EA152> */\r
473         if (E_OK != Ea_ValidateBlock(BlockNumber, EA_ERASEIMMEDIATEBLOCK_ID)){\r
474                 return E_NOT_OK;\r
475         }\r
476         /*@req <EA137>\r
477         */\r
478         /* Lock down the module to ourself */\r
479     Irq_Save(state);\r
480         if (Ea_Global.ModuleStatus != MEMIF_IDLE)\r
481         {\r
482             Irq_Restore(state);\r
483                 return E_NOT_OK;\r
484         }\r
485         /*set current state is internal busy*/\r
486         Ea_Global.ModuleStatus = MEMIF_BUSY_INTERNAL;\r
487     Irq_Restore(state);\r
488 \r
489         BlockIndex = EA_GET_BLOCK(BlockNumber);\r
490 \r
491         /*@req <EA152> */\r
492         if (E_OK != Ea_ValidateBlockIndex(BlockIndex, EA_ERASEIMMEDIATEBLOCK_ID))\r
493         {\r
494                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
495                 return E_NOT_OK;\r
496         }\r
497 \r
498         EaBlockCon = Ea_Global.EaBlockConfig;\r
499         \r
500         /*@req <EA065> [check whether the addressed logical block is configured as containing immediate data]*/\r
501         if (false == EaBlockCon[BlockIndex].EaImmediateData)\r
502         {\r
503                 Det_ReportError(EA_MODULE_ID, 0, EA_ERASEIMMEDIATEBLOCK_ID, EA_E_INVALID_BLOCK_NO);\r
504 \r
505                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
506                 return E_NOT_OK;\r
507         }\r
508 \r
509         /*@req <EA063> [take the block number and calculate the corresponding memory block address.]*/\r
510         Ea_Global.EepAddress = calculateEepAddress(BlockIndex);\r
511         Ea_Global.Length = calculateBlockLength(BlockIndex); // Calculate the block length in full pages\r
512         Ea_Global.CurrentBlock = BlockNumber;\r
513 \r
514         /*@req <EA025> [set internal variables set the EA module status to MEMIF_BUSY, set the job result to MEMIF_JOB_PENDING.]*/\r
515         Ea_Global.ModuleStatus = MEMIF_BUSY;\r
516         Ea_Global.JobType = EA_JOB_ERASE;\r
517         Ea_Global.JobResult = MEMIF_JOB_PENDING;\r
518         Ea_Global.JobStatus = EA_PENDING_NONE;\r
519 \r
520         return E_OK;\r
521 }\r
522 \r
523 \r
524 /*@req <EA096>*/\r
525 /*@req <EA056>*/\r
526 void Ea_MainFunction(void)\r
527 {\r
528         Std_ReturnType result;\r
529         imask_t state;\r
530 \r
531         if ((MEMIF_JOB_PENDING == Ea_Global.JobResult) && (Ea_Global.JobStatus == EA_PENDING_NONE))\r
532         {\r
533                 switch (Ea_Global.JobType)\r
534                 {\r
535                         case EA_JOB_WRITE:\r
536                                 /*@req <EA026> */\r
537                                 if (MEMIF_IDLE == Eep_GetStatus())\r
538                                 {\r
539                                         result = Eep_Write(Ea_Global.EepAddress, (const uint8*) Ea_TempBuffer, Ea_Global.Length);\r
540                                         if (E_OK == result)\r
541                                         {\r
542                                             Irq_Save(state);\r
543                                                 MemIf_StatusType status = Eep_GetStatus();\r
544                                                 if ((status == MEMIF_BUSY) || (status == MEMIF_BUSY_INTERNAL)){\r
545                                                         Ea_Global.JobStatus = EA_PENDING_WRITE;\r
546                                                 }\r
547                                             Irq_Restore(state);\r
548                                         }\r
549                                 }\r
550                                 break;\r
551                         case EA_JOB_READ:\r
552                                 /*@req <EA072> */\r
553                                 if (MEMIF_IDLE == Eep_GetStatus())\r
554                                 {\r
555                                         result = Eep_Read(Ea_Global.EepAddress, (uint8*) Ea_TempBuffer, Ea_Global.Length);\r
556                                         if (E_OK == result)\r
557                                         {\r
558                                             Irq_Save(state);\r
559                                                 MemIf_StatusType status = Eep_GetStatus();\r
560                                                 if ((status == MEMIF_BUSY) || (status == MEMIF_BUSY_INTERNAL)){\r
561                                                         Ea_Global.JobStatus = EA_PENDING_READ;\r
562                                                 }\r
563                                             Irq_Restore(state);\r
564                                         }\r
565                                 }\r
566                                 break;\r
567                         case EA_JOB_ERASE:\r
568                                 if (MEMIF_IDLE == Eep_GetStatus())\r
569                                 {\r
570                                         result = Eep_Erase(Ea_Global.EepAddress, Ea_Global.Length);\r
571                                         if (E_OK == result)\r
572                                         {\r
573                                             Irq_Save(state);\r
574                                                 MemIf_StatusType status = Eep_GetStatus();\r
575                                                 if ((status == MEMIF_BUSY) || (status == MEMIF_BUSY_INTERNAL)){\r
576                                                         Ea_Global.JobStatus = EA_PENDING_ERASE;\r
577                                                 }\r
578                                             Irq_Restore(state);\r
579                                         }\r
580                                 }\r
581                                 break;\r
582 \r
583                         default:\r
584                                 break;\r
585                 }\r
586         }\r
587         else\r
588         {\r
589                 // We have pending jobs. Wait for them to finish.\r
590                 switch(Ea_Global.JobStatus)\r
591                 {\r
592                 default:\r
593                         // Nothing to do for this state. Just wait\r
594                         break;\r
595                 }\r
596         }\r
597 }\r
598 \r
599 \r
600 /*Callback notifications of the Ea module*/\r
601 /*@req <EA094> */\r
602 /*@req <EA153> */\r
603 /*@req <EA101> */\r
604 void Ea_JobEndNotification(void)\r
605 {\r
606         Ea_Global.JobResult = Eep_GetJobResult();\r
607 \r
608         if (Ea_Global.JobResult == MEMIF_JOB_CANCELLED)\r
609         {\r
610                 Ea_Global.JobType = EA_JOB_NONE;\r
611                 Ea_Global.JobResult = MEMIF_JOB_CANCELLED;\r
612                 Ea_Global.JobStatus = EA_PENDING_NONE;\r
613                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
614                 // Should we  call upper layer here?\r
615         } else {\r
616                 /*@req <EA051> */\r
617                 /*@req <EA054> */\r
618                 switch(Ea_Global.JobStatus)\r
619                 {\r
620                 case EA_PENDING_READ:\r
621                         handleLowerLayerRead();\r
622                         break;\r
623                 case EA_PENDING_WRITE:\r
624                         handleLowerLayerWrite();\r
625                         break;\r
626                 case EA_PENDING_ERASE:\r
627                         handleLowerLayerErase();\r
628                         break;\r
629                 case EA_PENDING_ADMIN_WRITE:\r
630                         Ea_Global.JobType = EA_JOB_NONE;\r
631                         Ea_Global.JobStatus = EA_PENDING_NONE;\r
632                         Ea_Global.ModuleStatus = MEMIF_IDLE;\r
633                         /*@req <EA141> */\r
634                         /*@req <EA054> */\r
635                         /*@req <EA142> */\r
636                         /*@req <EA143> */\r
637                         EA_JOB_END_NOTIFICATION();\r
638                         break;\r
639                 default:\r
640                         assert(0); // Should never come here\r
641                         break;\r
642                 }\r
643         }\r
644         return;\r
645 }\r
646 \r
647 static void handleLowerLayerRead()\r
648 {\r
649         Ea_AdminBlock* adminBlock;\r
650 \r
651         /* Check the admin block i.e the block is consistent */\r
652         /*@req <EA104> */\r
653         adminBlock = (Ea_AdminBlock*) Ea_TempBuffer;\r
654         if ((!verifyChecksum(adminBlock)) || (adminBlock->blockState == BLOCK_INCONSISTENT)\r
655                         || (adminBlock->blockNum != Ea_Global.CurrentBlock))\r
656         {\r
657                 Ea_Global.JobType = EA_JOB_NONE;\r
658                 /*@req <EA055> */\r
659                 Ea_Global.JobResult = MEMIF_BLOCK_INCONSISTENT;\r
660                 Ea_Global.JobStatus = EA_PENDING_NONE;\r
661                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
662                 EA_JOB_ERROR_NOTIFICATION();\r
663                 return;\r
664         }\r
665         /* Check if block is invalidated */\r
666         /*@req <EA074> */\r
667         if (adminBlock->blockState == BLOCK_INVALIDATED)\r
668         {\r
669                 Ea_Global.JobType = EA_JOB_NONE;\r
670                 /*@req <EA055> */\r
671                 Ea_Global.JobResult = MEMIF_BLOCK_INVALID;\r
672                 Ea_Global.JobStatus = EA_PENDING_NONE;\r
673                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
674                 EA_JOB_ERROR_NOTIFICATION();\r
675                 return;\r
676         }\r
677 \r
678         // Copy the data to the destination\r
679         uint8* srcadress = (uint8*) (Ea_TempBuffer + sizeof (Ea_AdminBlock) + Ea_Global.Offset);\r
680         memcpy(Ea_Global.Address, srcadress, Ea_Global.ReadLength);\r
681 \r
682         /* Sucess */\r
683         Ea_Global.JobType = EA_JOB_NONE;\r
684         Ea_Global.JobStatus = EA_PENDING_NONE;\r
685         Ea_Global.ModuleStatus = MEMIF_IDLE;\r
686         /*@req <EA054> */\r
687         EA_JOB_END_NOTIFICATION();\r
688 }\r
689 \r
690 static void handleLowerLayerWrite()\r
691 {\r
692         Ea_AdminBlock* adminBlock;\r
693         Std_ReturnType result;\r
694         imask_t state;\r
695 \r
696         if (Ea_Global.JobResult == MEMIF_JOB_OK)\r
697         {\r
698                 /* Setup the admin block to be consistent again*/\r
699                 /*@req <EA047> */\r
700                 adminBlock = (Ea_AdminBlock*) Ea_TempBuffer;\r
701                 adminBlock->blockNum = Ea_Global.CurrentBlock;\r
702                 adminBlock->blockState = BLOCK_CONSISTENT;\r
703                 addChecksum(adminBlock);\r
704 \r
705                 result = Eep_Write(Ea_Global.EepAddress, (const uint8*) Ea_TempBuffer, sizeof(Ea_AdminBlock));\r
706                 if (E_OK == result)\r
707                 {\r
708                     Irq_Save(state);\r
709                         MemIf_StatusType status = Eep_GetStatus();\r
710                         if ((status == MEMIF_BUSY) || (status == MEMIF_BUSY_INTERNAL)){\r
711                                 Ea_Global.JobStatus = EA_PENDING_ADMIN_WRITE;\r
712                         }\r
713                     Irq_Restore(state);\r
714                 } else\r
715                 {\r
716                         Ea_Global.JobResult = MEMIF_JOB_FAILED;\r
717                         Ea_Global.JobType = EA_JOB_NONE;\r
718                         Ea_Global.JobStatus = EA_PENDING_NONE;\r
719                         Ea_Global.ModuleStatus = MEMIF_IDLE;\r
720 \r
721                         /*@req <EA054> */\r
722                         EA_JOB_END_NOTIFICATION();\r
723                 }\r
724         }\r
725         else\r
726         {\r
727                 /* Report error upstreams */\r
728                 Ea_Global.JobType = EA_JOB_NONE;\r
729                 /*@req <EA055> */\r
730                 Ea_Global.JobResult = MEMIF_BLOCK_INVALID;\r
731                 Ea_Global.JobStatus = EA_PENDING_NONE;\r
732                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
733 \r
734                 /*@req <EA054> */\r
735                 EA_JOB_END_NOTIFICATION();\r
736         }\r
737 }\r
738 \r
739 static void handleLowerLayerErase()\r
740 {\r
741         Ea_AdminBlock* adminBlock;\r
742         Std_ReturnType result;\r
743         imask_t state;\r
744 \r
745         if (Ea_Global.JobResult == MEMIF_JOB_OK)\r
746         {\r
747                 /* Setup the admin block to be consistent again*/\r
748                 /*@req <EA047> */\r
749                 adminBlock = (Ea_AdminBlock*) Ea_TempBuffer;\r
750                 adminBlock->blockNum = Ea_Global.CurrentBlock;\r
751                 adminBlock->blockState = BLOCK_INCONSISTENT;\r
752                 addChecksum(adminBlock);\r
753 \r
754                 result = Eep_Write(Ea_Global.EepAddress, (const uint8*) Ea_TempBuffer, sizeof(Ea_AdminBlock));\r
755                 if (E_OK == result)\r
756                 {\r
757                     Irq_Save(state);\r
758                         MemIf_StatusType status = Eep_GetStatus();\r
759                         if ((status == MEMIF_BUSY) || (status == MEMIF_BUSY_INTERNAL)){\r
760                                 Ea_Global.JobStatus = EA_PENDING_ADMIN_WRITE;\r
761                         }\r
762                     Irq_Restore(state);\r
763                 } else\r
764                 {\r
765                         Ea_Global.JobResult = MEMIF_JOB_FAILED;\r
766                         Ea_Global.JobType = EA_JOB_NONE;\r
767                         Ea_Global.JobStatus = EA_PENDING_NONE;\r
768                         Ea_Global.ModuleStatus = MEMIF_IDLE;\r
769 \r
770                         /*@req <EA054> */\r
771                         EA_JOB_END_NOTIFICATION();\r
772                 }\r
773         }\r
774         else\r
775         {\r
776                 /* Report error upstreams */\r
777                 Ea_Global.JobType = EA_JOB_NONE;\r
778                 /*@req <EA055> */\r
779                 Ea_Global.JobResult = MEMIF_BLOCK_INVALID;\r
780                 Ea_Global.JobStatus = EA_PENDING_NONE;\r
781                 Ea_Global.ModuleStatus = MEMIF_IDLE;\r
782 \r
783                 /*@req <EA054> */\r
784                 EA_JOB_END_NOTIFICATION();\r
785         }\r
786 }\r
787 \r
788 \r
789 /*@req <EA095> */\r
790 /*@req <EA102> */\r
791 void Ea_JobErrorNotification(void)\r
792 {\r
793         imask_t state;\r
794     Irq_Save(state);\r
795 \r
796     /*@req EA154*/\r
797         if (Ea_Global.JobResult == MEMIF_JOB_PENDING){\r
798                 Ea_Global.JobResult = MEMIF_JOB_FAILED;\r
799         }\r
800 \r
801         Ea_Global.JobType = EA_JOB_NONE;\r
802         Ea_Global.JobStatus = EA_PENDING_NONE;\r
803         Ea_Global.ModuleStatus = MEMIF_IDLE;\r
804     Irq_Restore(state);\r
805 \r
806         /*@req <EA055> */\r
807         /*@req <EA144> */\r
808         /*@req <EA145> */\r
809         /*@req <EA146> */\r
810         /*@req <EA100> */\r
811         /*@req <EA053> */\r
812         EA_JOB_ERROR_NOTIFICATION();\r
813 }\r
814 \r
815 /*\r
816  * Local service to get block index in Ea_Lcfg.c\r
817  */\r
818 static uint16 EA_GET_BLOCK(uint16 BlockNumber)\r
819 {\r
820         const Ea_BlockConfigType *EaBlockCon;\r
821         uint16 BlockIndex;\r
822 \r
823         EaBlockCon = Ea_Global.EaBlockConfig;\r
824         for (BlockIndex = 0; BlockIndex < EA_NUMBER_OF_BLOCKS; BlockIndex++)\r
825         {\r
826                 if (EaBlockCon[BlockIndex].EaBlockNumber == BlockNumber)\r
827                 {\r
828                         break;\r
829                 }\r
830         }\r
831         return BlockIndex;\r
832 }\r
833 \r
834 /*\r
835  * Local service to calculate the actual eep address.\r
836  */\r
837 /*@req <EA007>*/\r
838 static Eep_AddressType calculateEepAddress(uint16 BlockIndex)\r
839 {\r
840         const Ea_BlockConfigType *EaBlockCon;\r
841         uint32 totalNumOfBlocks = 0;\r
842         uint16 i;\r
843 \r
844         EaBlockCon = Ea_Global.EaBlockConfig;\r
845         uint16 blockNum = EaBlockCon[BlockIndex].EaBlockNumber;\r
846         uint8 device = EaBlockCon[BlockIndex].EaDeviceIndex;\r
847 \r
848         for (i = 0; i < EA_NUMBER_OF_BLOCKS; i++)\r
849         {\r
850                 if (EaBlockCon[i].EaDeviceIndex == device) // Check that this is the same device\r
851                 {\r
852                         if (EaBlockCon[i].EaBlockNumber < blockNum) // Check that blocknum is less than the searched one\r
853                         {\r
854                                 int blocksize = EaBlockCon[i].EaBlockSize + sizeof(Ea_AdminBlock);\r
855                                 int numOfBlocks = blocksize / EA_VIRTUAL_PAGE_SIZE;\r
856                                 if (blocksize % EA_VIRTUAL_PAGE_SIZE){\r
857                                         numOfBlocks++;\r
858                                 }\r
859 \r
860                                 totalNumOfBlocks = totalNumOfBlocks + numOfBlocks;\r
861                         }\r
862                 }\r
863         }\r
864 \r
865         return totalNumOfBlocks * EA_VIRTUAL_PAGE_SIZE;\r
866 }\r
867 \r
868 static uint16 calculateBlockLength(uint16 BlockIndex)\r
869 {\r
870         const Ea_BlockConfigType *EaBlockCon;\r
871 \r
872         EaBlockCon = Ea_Global.EaBlockConfig;\r
873         int blocksize = EaBlockCon[BlockIndex].EaBlockSize + sizeof(Ea_AdminBlock);\r
874         int numOfBlocks = blocksize / EA_VIRTUAL_PAGE_SIZE;\r
875         if (blocksize % EA_VIRTUAL_PAGE_SIZE){\r
876                 numOfBlocks++;\r
877         }\r
878 \r
879         return numOfBlocks * EA_VIRTUAL_PAGE_SIZE;\r
880 }\r
881 \r
882 /* Some very simple checksum calculations */\r
883 /* Better than nothing :-) */\r
884 static uint8 verifyChecksum(Ea_AdminBlock* block)\r
885 {\r
886         uint8 result;\r
887         uint8* array = (uint8*) block;\r
888 \r
889         result = array[0];\r
890         result += array[1];\r
891         result += array[2];\r
892 \r
893         result = result ^ 0xaaU;\r
894 \r
895         return (result == block->check);\r
896 }\r
897 \r
898 static void addChecksum(Ea_AdminBlock* block)\r
899 {\r
900         uint8 result;\r
901         uint8* array = (uint8*) block;\r
902 \r
903         result = array[0];\r
904         result += array[1];\r
905         result += array[2];\r
906 \r
907         result = result ^ 0xaaU;\r
908 \r
909         block->check = result;\r
910 }\r