#pragma once

#include <hardware/spi.h>
#include "types.h"

typedef struct sdcard_t {
    // need to fill before initialize
    spi_inst_t *spi;
    int pin_cs;

    // filled when initialize
    i32 version;
    u32 ocr;
    u64 csd_low;
    u64 csd_high;

    bool initialized;
} sdcard_t;

void sd_init(sdcard_t *sdcard);

void sd_write(sdcard_t *sdcard, const u8 *buf, u32 start_block_id, usz count);
void sd_read(sdcard_t *sdcard, u8 *buf, u32 start_block_id, usz count);
void sd_read_block(sdcard_t *sdcard, u8 *buf, u32 start_block_id);
void sd_write_block(sdcard_t *sdcard, const u8 *buf, u32 start_block_id);
void sd_write_dma(sdcard_t *sdcard, const u8 *buf, u32 start_block_id, usz count);
void sd_read_dma(sdcard_t *sdcard, const u8 *buf, u32 start_block_id, usz count);

// sdcard information extract
#define BIT(X) (1<<(X))

static inline bool
sd_is_hc(sdcard_t *sd) {
    return (sd->version == 1) ? true : ((sd->ocr & BIT(30)) != 0);
}

u64 sd_size_byte(sdcard_t *sd);


// SD card code related to r/w
#define SD_START_DATA_SINGLE_BLOCK_READ    0xFE
#define SD_START_DATA_MULTIPLE_BLOCK_READ  0xFE
#define SD_START_DATA_SINGLE_BLOCK_WRITE   0xFE
#define SD_START_DATA_MULTIPLE_BLOCK_WRITE 0xFC
#define SD_STOP_DATA_MULTIPLE_BLOCK_WRITE  0xFD

// SD card commands
#define SD_CMD0   0   // Software reset
#define SD_CMD8   8   // Check voltage range (SDC V2)
#define SD_CMD9   9   // Read CSD register
#define SD_CMD10  10  // Read CID register
#define SD_CMD12  12  // Stop to read data
#define SD_CMD16  16  // Change R/W block size
#define SD_CMD17  17  // Read block
#define SD_CMD18  18  // Read multiple blocks
#define SD_ACMD23 23  // Number of blocks to erase (SDC)
#define SD_CMD24  24  // Write a block
#define SD_CMD25  25  // Write multiple blocks
#define SD_ACMD41 41  // Initiate initialization process (SDC)
#define SD_CMD55  55  // Leading command for ACMD*
#define SD_CMD58  58  // Read OCR
#define SD_CMD59  59  // Enable/disable CRC check

// SD R1 response bits
#define SD_R1_IN_IDLE_STATE (1)
#define SD_R1_ERASE_STATE   (1<<1)
#define SD_R1_ILLEGAL_CMD   (1<<2)
#define SD_R1_CMD_CRC_ERR   (1<<3)
#define SD_R1_ERASE_SEQ_ERR (1<<4)
#define SD_R1_ADDR_ERR      (1<<5)
#define SD_R1_PARAM_ERR     (1<<6)

// SD OCR bits
#define SD_OCR_VOLTAGE_27_28     (1<<15)
#define SD_OCR_VOLTAGE_28_29     (1<<16)
#define SD_OCR_VOLTAGE_29_30     (1<<17)
#define SD_OCR_VOLTAGE_30_31     (1<<18)
#define SD_OCR_VOLTAGE_31_32     (1<<19)
#define SD_OCR_VOLTAGE_32_33     (1<<20)
#define SD_OCR_VOLTAGE_33_34     (1<<21)
#define SD_OCR_VOLTAGE_34_35     (1<<22)
#define SD_OCR_VOLTAGE_35_36     (1<<23)
#define SD_OCR_CAPACITY_HC       (1<<30)
#define SD_OCR_POWER_UP_COMPLETE (1<<31)
