LCOV - code coverage report
Current view: top level - SITL - SIM_JEDEC.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 105 121 86.8 %
Date: 2026-09-09 11:02:08 Functions: 8 8 100.0 %

          Line data    Source code
       1             : #include "SIM_JEDEC.h"
       2             : 
       3             : #if AP_SIM_JEDEC_ENABLED
       4             : 
       5             : #include <errno.h>
       6             : #include <unistd.h>
       7             : #include <sys/types.h>
       8             : #include <sys/stat.h>
       9             : #include <fcntl.h>
      10             : 
      11             : #include <AP_HAL_SITL/AP_HAL_SITL.h>
      12             : 
      13             : using namespace SITL;
      14             : 
      15             : extern const HAL_SITL& hal_sitl;
      16             : 
      17           5 : void JEDEC::open_storage_fd()
      18             : {
      19           5 :     if (storage_fd != -1) {
      20           0 :         AP_HAL::panic("Should not have been called");
      21             :     }
      22           5 :     const char *filepath = filename();
      23           5 :     if (hal_sitl.get_wipe_storage()) {
      24           0 :         unlink(filepath);
      25             :     }
      26           5 :     storage_fd = open(filepath, O_RDWR|O_CREAT, 0644);
      27           5 :     if (storage_fd == -1) {
      28           0 :         AP_HAL::panic("open(%s): %s", filepath, strerror(errno));
      29             :     }
      30           5 :     if (ftruncate(storage_fd, get_storage_size()) != 0) {
      31           0 :         AP_HAL::panic("truncate(%s): %s", filepath, strerror(errno));
      32             :     }
      33           5 : }
      34             : 
      35        9879 : void JEDEC::sector4k_erase (uint32_t addr)
      36             : {
      37      167943 :     for (uint8_t i=0; i<get_page_per_sector(); i++) {
      38      158064 :         page_erase(addr + i*get_page_size());
      39             :     }
      40        9879 : }
      41             : 
      42         617 : void JEDEC::block64k_erase (uint32_t addr)
      43             : {
      44             :     // we have 16 sectors in a block
      45       10489 :     for (uint16_t i=0; i<16; i++) {
      46        9872 :         sector4k_erase(addr + i*get_page_per_sector()*get_page_size());
      47             :     }
      48         617 : }
      49             : 
      50      158064 : void JEDEC::page_erase (uint32_t addr)
      51             : {
      52      316128 :     const uint32_t fill_length = get_page_size();
      53      158064 :     uint8_t fill[fill_length];
      54      158064 :     if (addr + fill_length > get_storage_size()) {
      55           0 :         AP_HAL::panic("trying to write outside memory");
      56             :     }
      57      158064 :     memset(fill, 0xFF, sizeof(fill));
      58      158064 :     const size_t write_ret = pwrite(storage_fd, fill, sizeof(fill), addr);
      59      158064 :     if (write_ret != sizeof(fill)) {
      60           0 :         printf("Failed page erase");
      61             :     }
      62      158064 : }
      63             : 
      64           7 : void JEDEC::bulk_erase()
      65             : {
      66         455 :     for (uint16_t i=0; i<get_num_blocks(); i++) {
      67         448 :         block64k_erase(i*get_page_per_block()*get_page_size());
      68             :     }
      69           7 : }
      70             : 
      71       72986 : uint32_t JEDEC::parse_addr (uint8_t* buffer, uint32_t len)
      72             : {
      73       72986 :     if (len<4) {
      74           0 :         AP_HAL::panic("address too short");
      75             :     }
      76             : 
      77             :     // buffer[0] is cmd
      78       72986 :     return buffer[1] << 16 | buffer[2] << 8 | buffer[3];
      79             : }
      80             : 
      81       42708 : void JEDEC::assert_writes_enabled()
      82             : {
      83       42708 :     if (!write_enabled) {
      84           0 :         AP_HAL::panic("Writes not enabled");
      85             :     }
      86       42708 : }
      87             : 
      88      261521 : int JEDEC::rdwr(uint8_t count, SPI::spi_ioc_transfer *&tfrs)
      89             : {
      90      261521 :     if (storage_fd == -1) {
      91           5 :         open_storage_fd();
      92             :     }
      93             : 
      94             :     // commands:
      95             :     static const uint8_t JEDEC_RDID             = 0x9f;
      96             :     static const uint8_t JEDEC_READ             = 0x03;
      97             :     static const uint8_t JEDEC_WREN             = 0x06;
      98             :     static const uint8_t JEDEC_WRITE            = 0x02;
      99             :     static const uint8_t JEDEC_RDSR             = 0x05;
     100             :     static const uint8_t JEDEC_SECTOR4_ERASE    = 0x20;
     101             :     static const uint8_t JEDEC_BULK_ERASE       = 0xC7;
     102             :     static const uint8_t JEDEC_BLOCK64_ERASE    = 0xD8;
     103             : 
     104      596052 :     for (uint8_t i=0; i<count; i++) {
     105      334531 :         SPI::spi_ioc_transfer &tfr = tfrs[i];
     106      334531 :         uint8_t *tx_buf = (uint8_t*)(tfr.tx_buf);
     107      334531 :         uint8_t *rx_buf = (uint8_t*)(tfr.rx_buf);
     108             : 
     109      334531 :         switch (state) {
     110      188711 :         case State::WAITING: {
     111             :             // find a command
     112      188711 :             uint8_t command = tx_buf[0];
     113      188711 :             switch (command) {
     114           5 :             case JEDEC_RDID:
     115           5 :                 state = State::READING_RDID;
     116           5 :                 break;
     117       30285 :             case JEDEC_READ:
     118       30285 :                 xfr_addr = parse_addr(tx_buf, tfr.len);
     119       30285 :                 state = State::READING;
     120       30285 :                 break;
     121       42525 :             case JEDEC_WRITE:
     122       42525 :                 xfr_addr = parse_addr(tx_buf, tfr.len);
     123       42525 :                 state = State::WRITING;
     124       42525 :                 break;
     125       42708 :             case JEDEC_WREN:
     126       42708 :                 write_enabled = true;
     127       42708 :                 break;
     128       73005 :             case JEDEC_RDSR:
     129       73005 :                 state = State::READING_RDSR;
     130       73005 :                 break;
     131           7 :             case JEDEC_SECTOR4_ERASE:   {
     132           7 :                 xfr_addr = parse_addr(tx_buf, tfr.len);
     133           7 :                 assert_writes_enabled();
     134           7 :                 sector4k_erase(xfr_addr);
     135           7 :                 write_enabled = false;
     136           7 :                 break;
     137             :             }
     138           7 :             case JEDEC_BULK_ERASE:  {
     139           7 :                 assert_writes_enabled();
     140           7 :                 bulk_erase();
     141           7 :                 write_enabled = false;
     142           7 :                 break;
     143             :             }
     144         169 :             case JEDEC_BLOCK64_ERASE:   {
     145         169 :                 xfr_addr = parse_addr(tx_buf, tfr.len);
     146         169 :                 assert_writes_enabled();
     147         169 :                 block64k_erase(xfr_addr);
     148         169 :                 write_enabled = false;
     149         169 :                 break;
     150             :             }
     151           0 :             default:
     152           0 :                 AP_HAL::panic("Unhandled command received");
     153             :             }
     154      188711 :             break;
     155             :         }
     156           5 :         case State::READING_RDID:
     157           5 :             fill_rdid(rx_buf, tfr.len);
     158           5 :             state = State::WAITING;
     159           5 :             break;
     160       73005 :         case State::READING_RDSR:
     161       73005 :             fill_rdsr(rx_buf, tfr.len);
     162       73005 :             state = State::WAITING;
     163       73005 :             break;
     164       30285 :         case State::READING: {
     165       30285 :             if (xfr_addr + tfr.len > get_storage_size()) {
     166           0 :                 AP_HAL::panic("trying to read outside memory");
     167             :             }
     168       30285 :             if (lseek(storage_fd, xfr_addr, SEEK_SET) == -1) {
     169           0 :                 AP_HAL::panic("lseek(): %s", strerror(errno));
     170             :             }
     171       30285 :             const size_t read_ret = read(storage_fd, rx_buf, tfr.len);
     172       30285 :             if (read_ret != tfr.len) {
     173           0 :                 AP_HAL::panic("read(): %s (%d/%u)", strerror(errno), (signed)read_ret, (unsigned)tfr.len);
     174             :             }
     175       30285 :             state = State::WAITING;
     176       30285 :             break;
     177             :         }
     178       42525 :         case State::WRITING: {
     179       42525 :             assert_writes_enabled();
     180       42525 :             if (xfr_addr + tfr.len > get_storage_size()) {
     181           0 :                 AP_HAL::panic("trying to write outside memory");
     182             :             }
     183       42525 :             if (lseek(storage_fd, xfr_addr, SEEK_SET) == -1) {
     184           0 :                 AP_HAL::panic("lseek(): %s", strerror(errno));
     185             :             }
     186       42525 :             const size_t write_ret = write(storage_fd, tx_buf, tfr.len);
     187       42525 :             if (write_ret != tfr.len) {
     188           0 :                 AP_HAL::panic("write(): %s (%d/%u)", strerror(errno), (signed)write_ret, (unsigned)tfr.len);
     189             :             }
     190       42525 :             state = State::WAITING;
     191       42525 :             write_enabled = false;
     192       42525 :             break;
     193             :         }
     194             :         }
     195             :     }
     196      261521 :     return 0;
     197             : }
     198             : 
     199             : #endif // AP_SIM_JEDEC_ENABLED

Generated by: LCOV version 1.14