text: /*
   *  Copyright (c) 2016, The OpenThread Authors.
   *  All rights reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions are met:
   *  1. Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   *  2. Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in the
   *     documentation and/or other materials provided with the distribution.
   *  3. Neither the name of the copyright holder nor the
   *     names of its contributors may be used to endorse or promote products
   *     derived from this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   *  POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include "platform-simulation.h"
  
  #include <fcntl.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/stat.h>
  #include <unistd.h>
  
  #include <openthread/config.h>
  
  #include "utils/code_utils.h"
  #include "utils/flash.h"
  
  static int sFlashFd = -1;
  uint32_t   sEraseAddress;
  
  enum
  {
      FLASH_SIZE      = 0x40000,
      FLASH_PAGE_SIZE = 0x800,
      FLASH_PAGE_NUM  = 128,
  };
  
  otError utilsFlashInit(void)
  {
      otError     error = OT_ERROR_NONE;
      const char *path  = OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH;
      char        fileName[sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32];
      struct stat st;
      bool        create = false;
      const char *offset = getenv("PORT_OFFSET");
  
      memset(&st, 0, sizeof(st));
  
      if (stat(path, &st) == -1)
      {
          mkdir(path, 0777);
      }
  
      if (offset == NULL)
      {
          offset = "0";
      }
  
      snprintf(fileName, sizeof(fileName), "%s/%s_%d.flash", path, offset, gNodeId);
  
      if (access(fileName, 0))
      {
          create = true;
      }
  
      sFlashFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
      lseek(sFlashFd, 0, SEEK_SET);
  
      otEXPECT_ACTION(sFlashFd >= 0, error = OT_ERROR_FAILED);
  
      if (create)
      {
          for (uint16_t index = 0; index < FLASH_PAGE_NUM; index++)
          {
              error = utilsFlashErasePage(index * FLASH_PAGE_SIZE);
              otEXPECT(error == OT_ERROR_NONE);
          }
      }
  
  exit:
      return error;
  }
  
  uint32_t utilsFlashGetSize(void)
  {
      return FLASH_SIZE;
  }
  
  otError utilsFlashErasePage(uint32_t aAddress)
  {
      otError  error = OT_ERROR_NONE;
      uint32_t address;
      uint8_t  dummyPage[FLASH_SIZE];
  
      otEXPECT_ACTION(sFlashFd >= 0, error = OT_ERROR_FAILED);
      otEXPECT_ACTION(aAddress < FLASH_SIZE, error = OT_ERROR_INVALID_ARGS);
  
      // Get start address of the flash page that includes aAddress
      address = aAddress & (~(uint32_t)(FLASH_PAGE_SIZE - 1));
  
      // set the page to the erased state.
      memset((void *)(&dummyPage[0]), 0xff, FLASH_PAGE_SIZE);
  
      // Write the page
      ssize_t r;
      r = pwrite(sFlashFd, &(dummyPage[0]), FLASH_PAGE_SIZE, (off_t)address);
      otEXPECT_ACTION(((int)r) == ((int)(FLASH_PAGE_SIZE)), error = OT_ERROR_FAILED);
  
  exit:
      return error;
  }
  
  otError utilsFlashStatusWait(uint32_t aTimeout)
  {
      OT_UNUSED_VARIABLE(aTimeout);
  
      return OT_ERROR_NONE;
  }
  
  uint32_t utilsFlashWrite(uint32_t aAddress, uint8_t *aData, uint32_t aSize)
  {
      uint32_t ret   = 0;
      uint32_t index = 0;
      uint8_t  byte;
  
      otEXPECT(sFlashFd >= 0 && aAddress < FLASH_SIZE);
  
      for (index = 0; index < aSize; index++)
      {
          otEXPECT((ret = utilsFlashRead(aAddress + index, &byte, 1)) == 1);
          // Use bitwise AND to emulate the behavior of flash memory
          byte &= aData[index];
          otEXPECT((ret = (uint32_t)pwrite(sFlashFd, &byte, 1, (off_t)(aAddress + index))) == 1);
      }
  
  exit:
      return index;
  }
  
  uint32_t utilsFlashRead(uint32_t aAddress, uint8_t *aData, uint32_t aSize)
  {
      uint32_t ret = 0;
  
      otEXPECT(sFlashFd >= 0 && aAddress < FLASH_SIZE);
      ret = (uint32_t)pread(sFlashFd, aData, aSize, (off_t)aAddress);
  
  exit:
      return ret;
  }
  