Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_internalFlash.c Source File

pal_internalFlash.c

00001 /*******************************************************************************
00002  * Copyright 2016, 2017 ARM Ltd.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  *******************************************************************************/
00016 #include "pal.h"
00017 #include "pal_plat_internalFlash.h"
00018 #include "stdio.h"
00019 
00020 #if (PAL_USE_INTERNAL_FLASH)
00021 
00022 #define BITS_ALIGNED_TO_32  0x3
00023 #define PAL_MAX_PAGE_SIZE   16
00024 
00025 //////////////////////////GLOBALS SECTION ////////////////////////////
00026 #if PAL_THREAD_SAFETY   
00027 // Use semaphore and not mutex, as mutexes don't behave well when trying to delete them while taken (which may happen in our tests).
00028 static palSemaphoreID_t flashSem = NULLPTR;
00029 #endif
00030 
00031 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00032     PAL_PRIVATE palFileDescriptor_t g_fd = 0;
00033 #endif
00034 //////////////////////////END GLOBALS SECTION ////////////////////////////
00035 
00036 
00037 //////////////////////////START PRIVATE SECTION////////////////////////////
00038 // Verify that the alignment  to sector size
00039 // Parameters :
00040 // @param[in] address     - Address to verify.
00041 // @param[in] size        - Size to write
00042 // Return     : None.
00043 PAL_PRIVATE bool pal_isAlignedToSector(uint32_t address, size_t size)
00044 {
00045     uint32_t currentSectorSize = pal_internalFlashGetSectorSize(address);
00046     if ((size % currentSectorSize) || (address % currentSectorSize))
00047     {
00048         return false;
00049     }
00050     else
00051     {
00052         return true;
00053     }
00054 }
00055 
00056 
00057 
00058 #if !PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00059 
00060 // Program to Flash with alignments to page size
00061 // Parameters :
00062 // @param[in]   buffer - pointer to the buffer to be written
00063 // @param[in]   size - the size of the buffer in bytes.
00064 // @param[in]   address - the address of the internal flash, must be aligned to minimum writing unit (page size).
00065 // Return     : None.
00066 PAL_PRIVATE palStatus_t pal_programToFlashAligned(const size_t size, const uint32_t address, const uint32_t * buffer)
00067 {
00068     palStatus_t ret = PAL_SUCCESS;
00069     uint32_t pageSize = 0, alignmentLeft = 0;
00070 
00071     pageSize = pal_internalFlashGetPageSize();
00072     alignmentLeft = size % pageSize; //Keep the leftover to be copied separately
00073 
00074     if (size >= pageSize)
00075     {
00076         ret = pal_plat_internalFlashWrite(size - alignmentLeft, address, buffer);
00077     }
00078 
00079     if ((ret == PAL_SUCCESS) && (alignmentLeft != 0))
00080     {
00081         uint32_t * pageBuffer = (uint32_t *)malloc(pageSize);
00082         if (pageBuffer == NULL)
00083         {
00084             ret = PAL_ERR_NO_MEMORY ;
00085         }
00086         else
00087         {
00088             memset(pageBuffer, 0xFF, pageSize);
00089             memcpy(pageBuffer, (uint8_t*)buffer + (size - alignmentLeft), alignmentLeft);
00090             ret = pal_plat_internalFlashWrite(pageSize, address + (size - alignmentLeft), pageBuffer);
00091             free(pageBuffer);
00092         }       
00093     }
00094     return ret;
00095 }
00096 
00097 #else //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00098 
00099 // Append root folder to path 
00100 // Parameters :
00101 // @param[in] input        - string to add the root prefix
00102 // @param[out] path        - output buffer
00103 // Return     : None.
00104 PAL_PRIVATE palStatus_t pal_addRootToPath(const char* input, char* path)
00105 {
00106     char root[PAL_MAX_FILE_AND_FOLDER_LENGTH] = { 0 };
00107     palStatus_t status = PAL_SUCCESS;
00108 
00109     memset(path, 0, PAL_MAX_FILE_AND_FOLDER_LENGTH);
00110     status = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, root);
00111     if(PAL_SUCCESS == status)
00112     {
00113         snprintf(path, PAL_MAX_FILE_AND_FOLDER_LENGTH -1,"%s/%s", root, input);
00114     }
00115     
00116     return status;
00117 }
00118 
00119 // Check whether area file exists. Create it if not. 
00120 // Parameters :
00121 // @param[in] area        - Flash area.
00122 // Return     : None.
00123 // Note - If file does not exist create and fill with 0xFF this simulate erased flash
00124 PAL_PRIVATE palStatus_t pal_verifyAndCreateFlashFile(void)
00125 {
00126     uint32_t index;
00127     uint8_t writeBuffer[SIMULATE_FLASH_PAGE_SIZE] = {0};
00128     char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0};
00129     palStatus_t ret = PAL_SUCCESS;
00130     size_t numOfBytes = 0;
00131     palSotpAreaData_t areaData_1, areaData_2;
00132 
00133     pal_internalFlashGetAreaInfo(0, &areaData_1);
00134     pal_internalFlashGetAreaInfo(1, &areaData_2);
00135 
00136     ret = pal_addRootToPath(SIMULATE_FLASH_FILE_NAME, buffer);
00137     if(PAL_SUCCESS == ret )
00138     {
00139         ret = pal_fsFopen(buffer, PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd);
00140         if(PAL_ERR_FS_NAME_ALREADY_EXIST == ret)
00141         {
00142             return PAL_SUCCESS; //file exist nothing else to do
00143         }
00144         else if(PAL_SUCCESS == ret)
00145         {
00146             memset(writeBuffer, PAL_INT_FLASH_BLANK_VAL, SIMULATE_FLASH_PAGE_SIZE);
00147             for (index = 0; index < (areaData_1.size + areaData_2.size) / SIMULATE_FLASH_PAGE_SIZE; index++) 
00148             {       
00149                 ret = pal_fsFwrite(&g_fd, (void *)writeBuffer, SIMULATE_FLASH_PAGE_SIZE, &numOfBytes);
00150                 if(PAL_SUCCESS != ret)
00151                 {
00152                     break;
00153                 }
00154             }
00155             pal_fsFclose(&g_fd);
00156         }
00157     }
00158     return ret;
00159 }
00160 #endif //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00161 
00162 
00163 //////////////////////////END PRIVATE SECTION////////////////////////////
00164 
00165 
00166 size_t pal_internalFlashGetPageSize(void)
00167 {
00168 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00169     size_t ret = SIMULATE_FLASH_PAGE_SIZE;
00170 #else
00171     size_t ret = pal_plat_internalFlashGetPageSize();
00172 #endif  //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00173     if(ret > PAL_MAX_PAGE_SIZE)
00174     {
00175         ret = PAL_MAX_PAGE_SIZE;
00176     }
00177     return ret;
00178 }
00179 
00180 size_t pal_internalFlashGetSectorSize(uint32_t address)
00181 {
00182 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00183     size_t ret = SIMULATE_FLASH_SECTOR_SIZE;
00184 #else
00185     size_t ret = pal_plat_internalFlashGetSectorSize(address);
00186 #endif  //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00187     return ret;
00188 }
00189 
00190 palStatus_t pal_internalFlashInit(void)
00191 {
00192     palStatus_t ret = PAL_SUCCESS;
00193 #if !PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM   
00194     ret = pal_plat_internalFlashInit();
00195 #endif  
00196     if(PAL_SUCCESS == ret)
00197     {
00198 #if PAL_THREAD_SAFETY       
00199         ret = pal_osSemaphoreCreate(1, &flashSem);
00200         if (PAL_SUCCESS != ret) 
00201         {
00202             PAL_LOG(ERR, "Semaphore Create Error %" PRId32 ".", ret);       
00203         }
00204         else
00205 #endif      
00206         {
00207 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00208             char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0};
00209             int32_t ctrs = 0;
00210 
00211             if(SIMULATE_FLASH_DIR[0] != '\0')
00212             {                       
00213                 ret = pal_addRootToPath(SIMULATE_FLASH_DIR, buffer);
00214                 if (PAL_SUCCESS == ret )
00215                 {
00216                     ret = pal_fsMkDir(buffer); //Create Directory       
00217                     if ((PAL_ERR_FS_NAME_ALREADY_EXIST == ret))
00218                     {
00219                         ret = PAL_SUCCESS;
00220                     }
00221                 }
00222             }
00223             if (PAL_SUCCESS == ret )
00224             {                                           
00225 #if PAL_THREAD_SAFETY                           
00226                 ret = pal_osSemaphoreWait(flashSem, PAL_RTOS_WAIT_FOREVER, &ctrs);
00227                 if (PAL_SUCCESS == ret) 
00228 #endif                  
00229                 {
00230                     ret = pal_verifyAndCreateFlashFile();
00231 #if PAL_THREAD_SAFETY                       
00232                     palStatus_t error = pal_osSemaphoreRelease(flashSem);
00233                     if(PAL_SUCCESS != error)
00234                     {
00235                         PAL_LOG(ERR, "SemaphoreRelease Error %" PRId32 ".", error);
00236                     }
00237 #endif                      
00238                 }
00239             }       
00240 #endif  //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00241         }
00242     }
00243 
00244 #if !PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00245     if(PAL_SUCCESS != ret)
00246     {//Clean resources 
00247         pal_plat_internalFlashDeInit();
00248     }
00249 #endif  //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00250 
00251     return ret;
00252 }
00253 
00254 
00255 palStatus_t pal_internalFlashDeInit(void)
00256 {
00257     palStatus_t ret = PAL_SUCCESS;
00258 #if !PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM   
00259     ret = pal_plat_internalFlashDeInit();
00260 #endif
00261 
00262     // Semaphore may be taken, so deleting it would fail. Try releasing (without checking return code).
00263     if(PAL_SUCCESS == ret)
00264     {
00265 #if PAL_THREAD_SAFETY
00266         pal_osSemaphoreRelease(flashSem);
00267         ret = pal_osSemaphoreDelete(&flashSem);
00268 #endif      
00269     }
00270     return ret;
00271 }
00272 
00273 palStatus_t pal_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer)
00274 {
00275     palStatus_t ret = PAL_SUCCESS;
00276     int32_t ctrs = 0;
00277 
00278 
00279     PAL_VALIDATE_CONDITION_WITH_ERROR ((buffer == NULL), PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED)
00280     PAL_VALIDATE_CONDITION_WITH_ERROR ((size == 0),PAL_ERR_INTERNAL_FLASH_WRONG_SIZE)
00281 
00282 #if PAL_THREAD_SAFETY
00283     ret = pal_osSemaphoreWait(flashSem, PAL_RTOS_WAIT_FOREVER, &ctrs);
00284     if (PAL_SUCCESS != ret) 
00285     {
00286         return ret;
00287     }
00288 #endif
00289 
00290 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM    
00291     size_t numberOfBytesRead = 0;
00292     char fileBuffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0};
00293 
00294     pal_addRootToPath(SIMULATE_FLASH_FILE_NAME, fileBuffer);
00295     ret = pal_fsFopen(fileBuffer, PAL_FS_FLAG_READONLY, &g_fd); 
00296     if(PAL_SUCCESS == ret)
00297     {
00298         ret = pal_fsFseek(&g_fd, address, PAL_FS_OFFSET_SEEKSET);
00299         if(PAL_SUCCESS == ret)
00300         {
00301             ret = pal_fsFread(&g_fd, buffer, size, &numberOfBytesRead); 
00302         }
00303         pal_fsFclose(&g_fd);
00304     }
00305 #else
00306     ret = pal_plat_internalFlashRead(size, address, buffer);
00307 #endif  //PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00308 
00309 #if PAL_THREAD_SAFETY
00310     palStatus_t error = pal_osSemaphoreRelease(flashSem);
00311     if(PAL_SUCCESS != error)
00312     {
00313         PAL_LOG(ERR, "SemaphoreRelease Error %" PRId32 ".", error);
00314     }
00315 #endif
00316 
00317     return ret;
00318 }
00319 
00320 
00321 palStatus_t pal_internalFlashErase(uint32_t address, size_t size)
00322 {
00323     palStatus_t ret = PAL_SUCCESS;
00324 
00325     int32_t ctrs = 0;
00326     
00327     PAL_VALIDATE_CONDITION_WITH_ERROR ((size == 0),PAL_ERR_INTERNAL_FLASH_WRONG_SIZE)
00328     PAL_VALIDATE_ARG_RLZ ((address & BITS_ALIGNED_TO_32),PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED)//Address not aligned to 32 bit
00329     PAL_VALIDATE_ARG_RLZ ((!pal_isAlignedToSector(address,size)),PAL_ERR_INTERNAL_FLASH_SECTOR_NOT_ALIGNED)//not aligned to sector
00330 
00331 #if PAL_THREAD_SAFETY
00332     ret = pal_osSemaphoreWait(flashSem, PAL_RTOS_WAIT_FOREVER, &ctrs);
00333     if (PAL_SUCCESS != ret) 
00334     {
00335         return ret;
00336     }
00337 #endif 
00338 
00339 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00340     char fileBuffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0};
00341     size_t numOfBytes = 0, index = 0;
00342     uint8_t writeBuffer[SIMULATE_FLASH_PAGE_SIZE] = {0};
00343     
00344     pal_addRootToPath(SIMULATE_FLASH_FILE_NAME, fileBuffer);
00345     ret = pal_fsFopen(fileBuffer, PAL_FS_FLAG_READWRITE, &g_fd);
00346     if (PAL_SUCCESS == ret) 
00347     {
00348         ret = pal_fsFseek(&g_fd, address, PAL_FS_OFFSET_SEEKSET);
00349         if (PAL_SUCCESS == ret)
00350         {
00351             memset(writeBuffer, PAL_INT_FLASH_BLANK_VAL, SIMULATE_FLASH_PAGE_SIZE);
00352             for (index = 0; index < size / SIMULATE_FLASH_PAGE_SIZE; index++)
00353             {
00354                 ret = pal_fsFwrite(&g_fd, (void *)writeBuffer, SIMULATE_FLASH_PAGE_SIZE, &numOfBytes);
00355                 if(PAL_SUCCESS != ret)
00356                 {
00357                     break;
00358                 }
00359             }
00360         }
00361         pal_fsFclose(&g_fd);
00362     }
00363 #else   
00364     size_t sectorSize = 0;
00365     sectorSize = pal_internalFlashGetSectorSize(address);
00366     while(size)
00367     {
00368         ret = pal_plat_internalFlashErase(address, size);
00369         size -= sectorSize;
00370         address += pal_internalFlashGetSectorSize(address + sectorSize);
00371         sectorSize = pal_internalFlashGetSectorSize(address);
00372     }
00373 #endif
00374 
00375 #if PAL_THREAD_SAFETY
00376     palStatus_t error = pal_osSemaphoreRelease(flashSem);
00377     if(PAL_SUCCESS != error)
00378     {
00379         PAL_LOG(ERR, "SemaphoreRelease Error %" PRId32 ".", error);
00380     }
00381 #endif  
00382     return ret;
00383 }
00384 
00385 
00386 palStatus_t pal_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer)
00387 {
00388     palStatus_t ret = PAL_SUCCESS;
00389     uint32_t pageSize = 0;
00390     int32_t ctrs = 0;
00391 
00392     PAL_VALIDATE_CONDITION_WITH_ERROR ((buffer == NULL), PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED)
00393     PAL_VALIDATE_ARG_RLZ ((address & BITS_ALIGNED_TO_32),PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED)//Address not aligned to 32 bit
00394     PAL_VALIDATE_ARG_RLZ ((size == 0),PAL_ERR_INTERNAL_FLASH_WRONG_SIZE)
00395 
00396 
00397     pageSize = pal_internalFlashGetPageSize();  
00398     if (address % pageSize)
00399     {
00400         ret =  PAL_ERR_INTERNAL_FLASH_ADDRESS_NOT_ALIGNED;
00401     }
00402     else
00403     {   
00404 #if PAL_THREAD_SAFETY
00405         ret = pal_osSemaphoreWait(flashSem, PAL_RTOS_WAIT_FOREVER, &ctrs);
00406         if (PAL_SUCCESS != ret) 
00407         {
00408             return ret;
00409         }
00410 #endif
00411 #if PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM
00412         char fileBuffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0};
00413         uint32_t alignmentLeft = 0;
00414         size_t numOfBytes = 0;
00415 
00416         pal_addRootToPath(SIMULATE_FLASH_FILE_NAME, fileBuffer);
00417         ret = pal_fsFopen(fileBuffer, PAL_FS_FLAG_READWRITE, &g_fd);    
00418         if (PAL_SUCCESS == ret)         
00419         {
00420             alignmentLeft = size % pageSize; //Keep the leftover to be copied separately        
00421             if (size >= pageSize)
00422             {                           
00423                 ret = pal_fsFseek(&g_fd, address, PAL_FS_OFFSET_SEEKSET);
00424                 if (PAL_SUCCESS == ret)
00425                 {
00426                     ret = pal_fsFwrite(&g_fd, (void *)buffer, size - alignmentLeft, &numOfBytes);               
00427                 }                       
00428             }
00429 
00430             if ((ret == PAL_SUCCESS) && (alignmentLeft != 0))
00431             {
00432                 uint32_t * pageBuffer = (uint32_t *)malloc(pageSize);
00433                 if (pageBuffer == NULL)
00434                 {
00435                     ret = PAL_ERR_NO_MEMORY ;
00436                 }
00437                 else
00438                 {
00439                     memset(pageBuffer, 0xFF, pageSize);
00440                     memcpy(pageBuffer, (uint8_t*)buffer + (size - alignmentLeft), alignmentLeft);               
00441                     ret = pal_fsFseek(&g_fd, address + (size - alignmentLeft), PAL_FS_OFFSET_SEEKSET);
00442                     if(PAL_SUCCESS == ret)
00443                     {
00444                         ret = pal_fsFwrite(&g_fd, (void *)pageBuffer, pageSize, &numOfBytes);
00445                     }
00446                     free(pageBuffer);
00447                 }
00448             }
00449             pal_fsFclose(&g_fd);
00450         }
00451 #else   
00452         size_t sizeLeft = size;
00453         uint32_t tempAddress = address;
00454         uint32_t sectorSize = pal_internalFlashGetSectorSize(address);
00455         
00456         //This section handles writing on cross sectors
00457         while (((tempAddress % sectorSize) + sizeLeft) > sectorSize)
00458         {
00459             size_t tmpSize = sectorSize - (tempAddress % sectorSize);           
00460             ret = pal_programToFlashAligned(tmpSize, tempAddress, buffer); //Fill the sector to the end
00461             if( PAL_SUCCESS != ret)
00462             {
00463                 break;
00464             }
00465             sizeLeft -= tmpSize;
00466             tempAddress += tmpSize;
00467             buffer += tmpSize / sizeof(uint32_t);
00468             //Read sector size again because Sector size can change when crossing sectors.
00469             sectorSize = pal_internalFlashGetSectorSize(address); 
00470         }
00471 
00472         //Write part of a sector (remainder of the buffer)
00473         if ((PAL_SUCCESS == ret) && (sizeLeft > 0))
00474         {
00475             ret = pal_programToFlashAligned(sizeLeft, tempAddress, buffer);
00476         }
00477 #endif
00478 #if PAL_THREAD_SAFETY
00479         palStatus_t error = pal_osSemaphoreRelease(flashSem);
00480         if(PAL_SUCCESS != error)
00481         {
00482             PAL_LOG(ERR, "SemaphoreRelease Error %" PRId32 ".", error);
00483         }
00484 #endif      
00485         
00486     }
00487     return ret;
00488 }
00489 
00490 
00491 palStatus_t pal_internalFlashGetAreaInfo(uint8_t section, palSotpAreaData_t *data)
00492 {
00493     palStatus_t ret = PAL_SUCCESS;
00494     const palSotpAreaData_t internalFlashArea[] =
00495     {
00496             {PAL_INTERNAL_FLASH_SECTION_1_ADDRESS, PAL_INTERNAL_FLASH_SECTION_1_SIZE},
00497             {PAL_INTERNAL_FLASH_SECTION_2_ADDRESS, PAL_INTERNAL_FLASH_SECTION_2_SIZE}
00498     };
00499 
00500     PAL_VALIDATE_CONDITION_WITH_ERROR ((data == NULL), PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED)
00501     
00502     data->address = internalFlashArea[section].address;
00503     data->size = internalFlashArea[section].size;
00504     return ret;
00505 }
00506 
00507 #endif //(PAL_USE_INTERNAL_FLASH)