#ifndef FLASH_H
#define FLASH_H

#include <hardware/spi.h>

namespace lib
{

class Flash
{
public:
  class Page
  {
  public:
    static constexpr size_t SIZE = 256;
    static constexpr size_t COUNT_PER_SECTOR = 4096 / SIZE;

    operator uint8_t*();
    operator const uint8_t*() const;

    uint8_t& operator[](int address);
    uint8_t operator[](int address) const;

    uint8_t* begin();
    const uint8_t* begin() const;

    uint8_t* end();
    const uint8_t* end() const;

  private:
    uint8_t buffer[SIZE];
  };

  Flash(uint8_t sck, uint8_t tx, uint8_t rx, uint8_t cs, int baudrate);

  void read_page(uint16_t page_index);
  void write_page(uint16_t page_index);

  void erase_sector(uint16_t page_index);

  Page& page();
  const Page& page() const;

private:
  uint8_t sck, tx, rx, cs;
  spi_inst_t* spi;

  Page page_buffer;

  void write_enable();
  void wait_done();

  static constexpr uint8_t CMD_PAGE_PROGRAM = 0x02;
  static constexpr uint8_t CMD_READ = 0x03;
  static constexpr uint8_t CMD_STATUS = 0x05;
  static constexpr uint8_t CMD_WRITE_EN = 0x06;
  static constexpr uint8_t CMD_SECTOR_ERASE = 0x20;

  static constexpr uint8_t STATUS_BUSY_MASK = 0x01;
};

}

#endif // FLASH_H
