mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-04 06:57:48 +00:00
CSD logic shared between V1 and V2
This commit is contained in:
+13
-1
@@ -38,9 +38,21 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
cid := sdcard.CID()
|
||||
pname := cid.ProductName()
|
||||
csd := sdcard.CSD()
|
||||
fmt.Printf("cid=%+v\ncsd=%+v\ncsdfmt=\n%s\ndone!", sdcard.CID(), csd, csd.String())
|
||||
|
||||
valid := csd.IsValid()
|
||||
if !valid {
|
||||
data := csd.RawCopy()
|
||||
crc := sd.CRC7(data[:15])
|
||||
always1 := data[15]&(1<<7) != 0
|
||||
println("CSD not valid got", crc, "want", data[15]&^(1<<7), "always1:", always1)
|
||||
} else {
|
||||
println("CSD valid!")
|
||||
}
|
||||
fmt.Printf("name=%s\ncsd=\n%s\n", pname, csd.String())
|
||||
return
|
||||
var buf [512]byte
|
||||
for i := 1; i < 11; i += 1 {
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
+61
-7
@@ -35,6 +35,7 @@ type Card struct {
|
||||
cid CID
|
||||
csd CSD
|
||||
lastCRC uint16
|
||||
timers [2]timer
|
||||
}
|
||||
|
||||
func NewCard(spi drivers.SPI, cs digitalPinout) *Card {
|
||||
@@ -62,7 +63,7 @@ func (d *Card) Init() error {
|
||||
|
||||
// CMD0: init card; sould return _R1_IDLE_STATE (allow 5 attempts)
|
||||
ok := false
|
||||
tm := setTimeout(0, 2*time.Second)
|
||||
tm := d.timers[0].setTimeout(2 * time.Second)
|
||||
for !tm.expired() {
|
||||
// Wait up to 2 seconds to be the same as the Arduino
|
||||
result, err := d.cmd(CMD0_GO_IDLE_STATE, 0, 0x95)
|
||||
@@ -121,7 +122,7 @@ func (d *Card) Init() error {
|
||||
|
||||
// check for timeout
|
||||
ok = false
|
||||
tm = setTimeout(0, 2*time.Second)
|
||||
tm = tm.setTimeout(2 * time.Second)
|
||||
for !tm.expired() {
|
||||
r1, err = d.appCmd(ACMD41_SD_APP_OP_COND, arg)
|
||||
if err != nil {
|
||||
@@ -325,8 +326,10 @@ func (d *Card) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
|
||||
buf[0] = 0x40 | cmd
|
||||
binary.BigEndian.PutUint32(buf[1:5], arg)
|
||||
buf[5] = crc
|
||||
d.bus.Tx(buf, nil)
|
||||
|
||||
err := d.bus.Tx(buf, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if cmd == 12 {
|
||||
// skip 1 byte
|
||||
d.bus.Transfer(byte(0xFF))
|
||||
@@ -352,7 +355,7 @@ func (d *Card) cmd(cmd byte, arg uint32, crc byte) (response1, error) {
|
||||
}
|
||||
|
||||
func (d *Card) waitNotBusy(timeout time.Duration) error {
|
||||
tm := setTimeout(1, timeout)
|
||||
tm := d.timers[1].setTimeout(timeout)
|
||||
for !tm.expired() {
|
||||
r, err := d.bus.Transfer(byte(0xFF))
|
||||
if err != nil {
|
||||
@@ -368,8 +371,7 @@ func (d *Card) waitNotBusy(timeout time.Duration) error {
|
||||
|
||||
func (d *Card) waitStartBlock() error {
|
||||
status := byte(0xFF)
|
||||
|
||||
tm := setTimeout(0, 300*time.Millisecond)
|
||||
tm := d.timers[0].setTimeout(300 * time.Millisecond)
|
||||
for !tm.expired() {
|
||||
var err error
|
||||
status, err = d.bus.Transfer(byte(0xFF))
|
||||
@@ -380,6 +382,7 @@ func (d *Card) waitStartBlock() error {
|
||||
if status != 0xFF {
|
||||
break
|
||||
}
|
||||
runtime.Gosched()
|
||||
}
|
||||
|
||||
if status != 254 {
|
||||
@@ -396,14 +399,65 @@ type response1Err struct {
|
||||
}
|
||||
|
||||
func (e response1Err) Error() string {
|
||||
return e.status.Response()
|
||||
if e.context != "" {
|
||||
return "sd:" + e.context + " " + strconv.Itoa(int(e.status))
|
||||
}
|
||||
return "sd:status " + strconv.Itoa(int(e.status))
|
||||
}
|
||||
|
||||
func (e response1) Response() string {
|
||||
b := make([]byte, 0, 8)
|
||||
return string(e.appendf(b))
|
||||
}
|
||||
|
||||
func (r response1) appendf(b []byte) []byte {
|
||||
b = append(b, '[')
|
||||
if r.IsIdle() {
|
||||
b = append(b, "idle,"...)
|
||||
}
|
||||
if r.EraseReset() {
|
||||
b = append(b, "erase-rst,"...)
|
||||
}
|
||||
if r.EraseSeqError() {
|
||||
b = append(b, "erase-seq,"...)
|
||||
}
|
||||
if r.CRCError() {
|
||||
b = append(b, "crc-err,"...)
|
||||
}
|
||||
if r.AddressError() {
|
||||
b = append(b, "addr-err,"...)
|
||||
}
|
||||
if r.ParamError() {
|
||||
b = append(b, "param-err,"...)
|
||||
}
|
||||
if r.IllegalCmdError() {
|
||||
b = append(b, "illegal-cmd,"...)
|
||||
}
|
||||
if len(b) > 1 {
|
||||
b = b[:len(b)-1]
|
||||
}
|
||||
b = append(b, ']')
|
||||
return b
|
||||
}
|
||||
|
||||
func makeResponseError(status response1) error {
|
||||
return response1Err{
|
||||
status: status,
|
||||
}
|
||||
}
|
||||
|
||||
var timeoutTimer [2]timer
|
||||
|
||||
type timer struct {
|
||||
deadline time.Time
|
||||
}
|
||||
|
||||
func (t *timer) setTimeout(timeout time.Duration) *timer {
|
||||
t.deadline = time.Now().Add(timeout)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t timer) expired() bool {
|
||||
return time.Since(t.deadline) >= 0
|
||||
}
|
||||
|
||||
@@ -27,19 +27,3 @@ func TestCRC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CRC16(buf []byte) (sum uint16) {
|
||||
const poly uint16 = 0x1021 // Generator polynomial G(x) = x^16 + x^12 + x^5 + 1
|
||||
var crc uint16 = 0x0000 // Initial value
|
||||
for _, b := range buf {
|
||||
crc ^= (uint16(b) << 8) // Shift byte into MSB of crc
|
||||
for i := 0; i < 8; i++ { // Process each bit
|
||||
if crc&0x8000 != 0 {
|
||||
crc = (crc << 1) ^ poly
|
||||
} else {
|
||||
crc <<= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc
|
||||
}
|
||||
|
||||
+237
-62
@@ -48,54 +48,17 @@ func DecodeCID(b []byte) (CID, error) {
|
||||
return cid, nil
|
||||
}
|
||||
|
||||
func (c *CID) ProductName() []byte {
|
||||
return upToNull(c.prodName[:])
|
||||
func (c *CID) ProductName() string {
|
||||
return string(upToNull(c.prodName[:]))
|
||||
}
|
||||
|
||||
func (c *CID) ProductRevision() (n, m uint8) {
|
||||
return c.productRev >> 4, c.productRev & 0x0F
|
||||
}
|
||||
|
||||
/*
|
||||
CSD Register Fields:
|
||||
Name: Field: Width: Value: CSD-Slice:
|
||||
CSD Structure CSD_STRUCTURE 2 00b R[127:128]
|
||||
TAAC TAAC 8 00h R[119:113]
|
||||
NSAC NSAC 8 00h R[111:105]
|
||||
TRAN_SPEED TRAN_SPEED 8 32h or 5Ah R[103:97]
|
||||
CCC CCC 12 01x110110101b R[95:85]
|
||||
READ_BL_LEN READ_BL_LEN 4 xh R[83:81]
|
||||
READ_BL_PARTIAL READ_BL_PARTIAL 1 1b R[79:80]
|
||||
WRITE_BLK_MISALIGN WRITE_BLK_MISALIGN 1 xb R[78:79]
|
||||
READ_BLK_MISALIGN READ_BLK_MISALIGN 1 xb R[77:78]
|
||||
DSR_IMP DSR_IMP 1 xb R[76:77]
|
||||
C_SIZE C_SIZE 12 xxxh R[73:63]
|
||||
VDD_R_CURR_MIN VDD_R_CURR_MIN 3 xxxb R[61:60]
|
||||
VDD_R_CURR_MAX VDD_R_CURR_MAX 3 xxxb R[58:57]
|
||||
VDD_W_CURR_MIN VDD_W_CURR_MIN 3 xxxb R[55:54]
|
||||
VDD_W_CURR_MAX VDD_W_CURR_MAX 3 xxxb R[52:51]
|
||||
C_SIZE_MULT C_SIZE_MULT 3 xxxb R[49:48]
|
||||
ERASE_BLK_EN ERASE_BLK_EN 1 xb R[46:47]
|
||||
SECTOR_SIZE SECTOR_SIZE 7 xxxxxxxb R[45:40]
|
||||
WP_GRP_SIZE WP_GRP_SIZE 7 xxxxxxxb R[38:33]
|
||||
WP_GRP_ENABLE WP_GRP_ENABLE 1 xb R[31:32]
|
||||
R2W_FACTOR R2W_FACTOR 2 xxxb R[28:27]
|
||||
WRITE_BL_LEN WRITE_BL_LEN 4 xxxxb R[25:23]
|
||||
WRITE_BL_PARTIAL WRITE_BL_PARTIAL 1 xb R[21:22]
|
||||
FILE_FORMAT_GRP FILE_FORMAT_GRP 1 xb R[15:16]
|
||||
COPY COPY 1 xb R[14:15]
|
||||
PERM_WRITE_PROTECT PERM_WRITE_PROTECT 1 xb R[13:14]
|
||||
TMP_WRITE_PROTECT TMP_WRITE_PROTECT 1 xb R[12:13]
|
||||
FILE_FORMAT FILE_FORMAT 2 xxb R[11:11]
|
||||
CRC CRC 7 xxxxxxxb R[7:2]
|
||||
Not Used - 1 1b R[0:1]
|
||||
|
||||
Note: 'R' indicates read-only fields, 'R/W' indicates read/write fields.
|
||||
The values in the 'CSD-Slice' column indicate the bit positions in the CSD register.
|
||||
*/
|
||||
|
||||
// CSD is the Card Specific Data register, a 128-bit (16-byte) register that defines how
|
||||
// the SD card standard communicates with the memory field or register.
|
||||
// the SD card standard communicates with the memory field or register. This type is
|
||||
// shared among V1 and V2 type devices.
|
||||
type CSD struct {
|
||||
data [16]byte
|
||||
}
|
||||
@@ -104,6 +67,10 @@ type CSDv1 struct {
|
||||
CSD
|
||||
}
|
||||
|
||||
type CSDv2 struct {
|
||||
CSD
|
||||
}
|
||||
|
||||
func DecodeCSD(b []byte) (CSD, error) {
|
||||
if len(b) < 16 {
|
||||
return CSD{}, io.ErrShortBuffer
|
||||
@@ -117,57 +84,203 @@ func DecodeCSD(b []byte) (CSD, error) {
|
||||
func (c *CSD) CSDStructure() uint8 { return c.data[0] >> 6 }
|
||||
|
||||
func (c CSD) MustV1() CSDv1 {
|
||||
if c.CSDStructure() != 1 {
|
||||
panic("CSD is not version 1")
|
||||
if c.CSDStructure() != 0 {
|
||||
panic("CSD is not version 1.0")
|
||||
}
|
||||
return CSDv1{CSD: c}
|
||||
}
|
||||
|
||||
func (c CSD) MustV2() CSDv2 {
|
||||
if c.CSDStructure() != 1 {
|
||||
panic("CSD is not version 2.0")
|
||||
}
|
||||
return CSDv2{CSD: c}
|
||||
}
|
||||
|
||||
func (c *CSD) RawCopy() [16]byte { return c.data }
|
||||
|
||||
// TAAC returns the Time Access Attribute Class (data read access-time-1).
|
||||
func (c *CSD) TAAC() TAAC { return TAAC(c.data[1]) }
|
||||
|
||||
// NSAC returns the Data Read Access-time 2 in CLK cycles (NSAC*100).
|
||||
func (c *CSD) NSAC() uint8 { return c.data[2] }
|
||||
func (c *CSD) NSAC() NSAC { return NSAC(c.data[2]) }
|
||||
|
||||
// TransferSpeed returns the Max Data Transfer Rate. Either 0x32 or 0x5A.
|
||||
func (c *CSD) TransferSpeed() TransferSpeed { return TransferSpeed(c.data[3]) }
|
||||
|
||||
// CCC returns the Card Command Classes.
|
||||
func (c *CSD) CCC() uint16 {
|
||||
return uint16(c.data[4])<<4 | uint16(c.data[5]&0xf0)>>4
|
||||
// CommandClasses returns the supported Card Command Classes.
|
||||
// This is a bitfield, each bit position indicates whether the
|
||||
func (c *CSD) CommandClasses() CommandClasses {
|
||||
return CommandClasses(uint16(c.data[4])<<4 | uint16(c.data[5]&0xf0)>>4)
|
||||
}
|
||||
|
||||
// ReadBlockLen returns the Max Read Data Block Length in bytes.
|
||||
func (c *CSD) ReadBlockLen() uint16 { return 1 << (c.data[5] & 0x0F) }
|
||||
|
||||
func (c *CSD) ReadBlockPartial() bool { return c.data[6]&(1<<7) != 0 }
|
||||
func (c *CSD) WriteBlockMisalignment() bool { return c.data[6]&(1<<6) != 0 }
|
||||
func (c *CSD) ReadBlockMisalignment() bool { return c.data[6]&(1<<5) != 0 }
|
||||
// AllowsReadBlockPartial should always return true. Indicates that
|
||||
func (c *CSD) AllowsReadBlockPartial() bool { return c.data[6]&(1<<7) != 0 }
|
||||
|
||||
// ImplementsDSR returns whether the card implements the DSR register.
|
||||
// AllowsWriteBlockMisalignment defines if the data block to be written by one command
|
||||
// can be spread over more than one physical block of the memory device.
|
||||
func (c *CSD) AllowsWriteBlockMisalignment() bool { return c.data[6]&(1<<6) != 0 }
|
||||
|
||||
// AllowsReadBlockMisalignment defines if the data block to be read by one command
|
||||
// can be spread over more than one physical block of the memory device.
|
||||
func (c *CSD) AllowsReadBlockMisalignment() bool { return c.data[6]&(1<<5) != 0 }
|
||||
|
||||
// CRC7 returns the CRC read for this CSD. May be invalid. Use [IsValid] to check validity of CRC7+Always1 fields.
|
||||
func (c *CSD) CRC7() uint8 { return c.data[15] & 0b111_1111 }
|
||||
|
||||
// IsValid checks if the CRC and always1 fields are expected values.
|
||||
func (c *CSD) IsValid() bool {
|
||||
// Compare last byte with CRC and also the always1 bit.
|
||||
got := CRC7(c.data[:15])
|
||||
return got|(1<<7) == c.data[15]
|
||||
}
|
||||
|
||||
// ImplementsDSR defines if the configurable driver stage is integrated on the card.
|
||||
func (c *CSD) ImplementsDSR() bool { return c.data[6]&(1<<4) != 0 }
|
||||
|
||||
func (c *CSDv1) CSize() uint16 {
|
||||
// EraseSectorSizeInBlocks represents how much memory is erased in an erase
|
||||
// command in multiple of block size.
|
||||
func (c *CSD) EraseSectorSizeInBlocks() uint8 {
|
||||
return 1 + ((c.data[10]&0b11_1111)<<1 | (c.data[11] >> 7))
|
||||
}
|
||||
|
||||
// EraseBlockEnabled defines granularity of unit size of data to be erased.
|
||||
// If enabled the erase operation can erase either one or multiple units of 512 bytes.
|
||||
func (c *CSD) EraseBlockEnabled() bool { return (c.data[10]>>6)&1 != 0 }
|
||||
|
||||
func (c *CSD) ReadToWriteFactor() uint8 { return (c.data[12] >> 2) & 0b111 }
|
||||
|
||||
// WriteProtectGroupSizeInSectors indicates the size of a write protected
|
||||
// group in multiple of erasable sectors.
|
||||
func (c *CSD) WriteProtectGroupSizeInSectors() uint8 {
|
||||
return 1 + (c.data[11] & 0b111_1111)
|
||||
}
|
||||
|
||||
// WriteBlockLength represents maximum write data block length in bytes.
|
||||
func (c *CSD) WriteBlockLength() uint16 {
|
||||
return 1 << ((c.data[12]&0b11)<<2 | (c.data[13] >> 6))
|
||||
}
|
||||
|
||||
// WriteGroupEnabled indicates if write group protection is available.
|
||||
func (c *CSD) WriteGroupEnabled() bool { return c.data[12]&(1<<7) != 0 }
|
||||
|
||||
// AllowsWritePartial Defines whether partial block sizes can be used in write block sizes.
|
||||
func (c *CSD) AllowsWritePartial() bool { return c.data[13]&(1<<5) != 0 }
|
||||
|
||||
// FileFormat returns the file format on the card. This field is read-only for ROM.
|
||||
func (c *CSD) FileFormat() FileFormat { return FileFormat(c.data[14]>>2) & 0b11 }
|
||||
|
||||
// TmpWriteProtected indicates temporary protection over the entire card content from being overwritten or erased.
|
||||
func (c *CSD) TmpWriteProtected() bool { return c.data[14]&(1<<4) != 0 }
|
||||
|
||||
// PermWriteProtected indicates permanent protecttion of entire card content against overwriting or erasing (write+erase permanently disabled).
|
||||
func (c *CSD) PermWriteProtected() bool { return c.data[14]&(1<<5) != 0 }
|
||||
|
||||
// IsCopy whether contents are original or have been copied.
|
||||
func (c *CSD) IsCopy() bool { return c.data[14]&(1<<6) != 0 }
|
||||
|
||||
func (c *CSD) FileFormatGroup() bool { return c.data[14]&(1<<7) != 0 }
|
||||
|
||||
func (c *CSD) DeviceCapacity() (size uint64) {
|
||||
switch c.CSDStructure() {
|
||||
case 0:
|
||||
v1 := c.MustV1()
|
||||
size = uint64(v1.DeviceCapacity())
|
||||
case 1:
|
||||
v2 := c.MustV2()
|
||||
size = v2.DeviceCapacity()
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// After byte 5 CSDv1 and CSDv2 differ in structure at some fields.
|
||||
|
||||
// DeviceCapacity returns the device capacity in bytes.
|
||||
func (c *CSDv2) DeviceCapacity() uint64 {
|
||||
csize := c.csize()
|
||||
return uint64(csize) * 512_000
|
||||
}
|
||||
|
||||
func (c *CSDv2) csize() uint32 {
|
||||
return uint32(c.data[7]>>2)<<16 | uint32(c.data[8])<<8 | uint32(c.data[9])
|
||||
}
|
||||
|
||||
// DeviceCapacity returns the total memory capacity of the SDCard in bytes. Max is 2GB for V1.
|
||||
func (c *CSDv1) DeviceCapacity() uint32 {
|
||||
mult := c.mult()
|
||||
csize := c.csize()
|
||||
blklen := c.ReadBlockLen()
|
||||
blockNR := uint32(csize+1) * uint32(mult)
|
||||
return blockNR * uint32(blklen)
|
||||
}
|
||||
|
||||
func (c *CSDv1) csize() uint16 {
|
||||
// Jesus, why did SD make this so complicated?
|
||||
return uint16(c.data[8]>>6) | uint16(c.data[7])<<2 | uint16(c.data[6]&0b11)<<10
|
||||
}
|
||||
|
||||
func (c *CSD) String() string {
|
||||
buf := make([]byte, 0, 64)
|
||||
return string(c.appendf(buf, '\n'))
|
||||
// mult is a factor for computing total device size with csize and csizemult.
|
||||
func (c *CSDv1) mult() uint16 { return 1 << (2 + c.csizemult()) }
|
||||
|
||||
func (c *CSDv1) csizemult() uint8 {
|
||||
return (c.data[9]&0b11)<<1 | (c.data[10] >> 7)
|
||||
}
|
||||
|
||||
// VddReadCurrent indicates min and max values for read power supply currents.
|
||||
// - values min: 0=0.5mA; 1=1mA; 2=5mA; 3=10mA; 4=25mA; 5=35mA; 6=60mA; 7=100mA
|
||||
// - values max: 0=1mA; 1=5mA; 2=10mA; 3=25mA; 4=35mA; 5=45mA; 6=80mA; 7=200mA
|
||||
func (c *CSDv1) VddReadCurrent() (min, max uint8) {
|
||||
return (c.data[8] >> 3) & 0b111, c.data[8] & 0b111
|
||||
}
|
||||
|
||||
// VddWriteCurrent indicates min and max values for write power supply currents.
|
||||
// - values min: 0=0.5mA; 1=1mA; 2=5mA; 3=10mA; 4=25mA; 5=35mA; 6=60mA; 7=100mA
|
||||
// - values max: 0=1mA; 1=5mA; 2=10mA; 3=25mA; 4=35mA; 5=45mA; 6=80mA; 7=200mA
|
||||
func (c *CSDv1) VddWriteCurrent() (min, max uint8) {
|
||||
return c.data[9] >> 5, (c.data[9] >> 3) & 0b111
|
||||
}
|
||||
|
||||
func (c *CSD) String() string {
|
||||
version := c.CSDStructure() + 1
|
||||
if version > 2 {
|
||||
return "<unsupported CSD version>"
|
||||
}
|
||||
const delim = '\n'
|
||||
buf := make([]byte, 0, 64)
|
||||
buf = c.appendf(buf, delim)
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func (c *CSDv1) String() string { return c.CSD.String() }
|
||||
|
||||
func (c *CSDv2) String() string { return c.CSD.String() }
|
||||
|
||||
func (c *CSD) appendf(b []byte, delim byte) []byte {
|
||||
b = appendnum(b, "CSDStructure", uint64(c.CSDStructure()), delim)
|
||||
b = appendnum(b, "Version", uint64(c.CSDStructure()+1), delim)
|
||||
b = appendnum(b, "Capacity(bytes)", c.DeviceCapacity(), delim)
|
||||
b = appendnum(b, "TimeAccess_ns", uint64(c.TAAC().AccessTime()), delim)
|
||||
b = appendnum(b, "NSAC", uint64(c.NSAC()), delim)
|
||||
b = appendnum(b, "Tx_kb/s", uint64(c.TransferSpeed().RateKilobits()), delim)
|
||||
b = appendnum(b, "CCC", uint64(c.CCC()), delim)
|
||||
b = appendnum(b, "CCC", uint64(c.CommandClasses()), delim)
|
||||
b = appendnum(b, "ReadBlockLen", uint64(c.ReadBlockLen()), delim)
|
||||
b = appendbit(b, "ReadBlockPartial", c.ReadBlockPartial(), delim)
|
||||
b = appendbit(b, "WriteBlockMisalignment", c.WriteBlockMisalignment(), delim)
|
||||
b = appendbit(b, "ReadBlockMisalignment", c.ReadBlockMisalignment(), delim)
|
||||
b = appendbit(b, "ReadBlockPartial", c.AllowsReadBlockPartial(), delim)
|
||||
b = appendbit(b, "AllowWriteBlockMisalignment", c.AllowsWriteBlockMisalignment(), delim)
|
||||
b = appendbit(b, "AllowReadBlockMisalignment", c.AllowsReadBlockMisalignment(), delim)
|
||||
b = appendbit(b, "ImplementsDSR", c.ImplementsDSR(), delim)
|
||||
b = appendnum(b, "WProtectNumSectors", uint64(c.WriteProtectGroupSizeInSectors()), delim)
|
||||
b = appendnum(b, "WriteBlockLen", uint64(c.WriteBlockLength()), delim)
|
||||
b = appendbit(b, "WGrpEnable", c.WriteGroupEnabled(), delim)
|
||||
b = appendbit(b, "WPartialAllow", c.AllowsWritePartial(), delim)
|
||||
b = append(b, "FileFmt:"...)
|
||||
b = append(b, c.FileFormat().String()...)
|
||||
b = append(b, delim)
|
||||
b = appendbit(b, "TmpWriteProtect", c.TmpWriteProtected(), delim)
|
||||
b = appendbit(b, "PermWriteProtect", c.PermWriteProtected(), delim)
|
||||
b = appendbit(b, "IsCopy", c.IsCopy(), delim)
|
||||
b = appendbit(b, "FileFormatGrp", c.FileFormatGroup(), delim)
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -246,11 +359,38 @@ const (
|
||||
ACMD49_CHANGE_SECURE_AREA = 49
|
||||
)
|
||||
|
||||
// CSD enum types.
|
||||
type (
|
||||
TransferSpeed uint8
|
||||
TAAC uint8
|
||||
TransferSpeed uint8
|
||||
TAAC uint8
|
||||
FileFormat uint8
|
||||
CommandClasses uint16
|
||||
NSAC uint8
|
||||
)
|
||||
|
||||
const (
|
||||
FileFmtPartition FileFormat = iota // Hard disk like file system with partition table.
|
||||
FileFmtDOSFAT // DOS FAT (floppy like)
|
||||
FileFmtUFF // Universal File Format
|
||||
FileFmtUnknown
|
||||
)
|
||||
|
||||
func (ff FileFormat) String() (s string) {
|
||||
switch ff {
|
||||
case FileFmtPartition:
|
||||
s = "partition"
|
||||
case FileFmtDOSFAT:
|
||||
s = "DOS/FAT"
|
||||
case FileFmtUFF:
|
||||
s = "UFF"
|
||||
case FileFmtUnknown:
|
||||
s = "unknown"
|
||||
default:
|
||||
s = "<invalid format>"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var log10table = [...]int64{
|
||||
1,
|
||||
10,
|
||||
@@ -298,3 +438,38 @@ func b2u8(b bool) uint8 {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// CRC16 computes the CRC16 checksum for a given payload using the CRC-16-CCITT polynomial.
|
||||
func CRC16(buf []byte) (sum uint16) {
|
||||
const poly uint16 = 0x1021 // Generator polynomial G(x) = x^16 + x^12 + x^5 + 1
|
||||
var crc uint16 = 0x0000 // Initial value
|
||||
for _, b := range buf {
|
||||
crc ^= (uint16(b) << 8) // Shift byte into MSB of crc
|
||||
for i := 0; i < 8; i++ { // Process each bit
|
||||
if crc&0x8000 != 0 {
|
||||
crc = (crc << 1) ^ poly
|
||||
} else {
|
||||
crc <<= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc
|
||||
}
|
||||
|
||||
// CRC7 computes the CRC7 checksum for a given payload using the polynomial x^7 + x^3 + 1.
|
||||
func CRC7(data []byte) uint8 {
|
||||
const poly uint8 = 0x09 // Generator polynomial G(x) = x^7 + x^3 + 1
|
||||
var crc uint8 = 0x00 // Initial value
|
||||
|
||||
for _, b := range data {
|
||||
crc ^= b // Initial XOR
|
||||
for i := 0; i < 8; i++ { // Process each bit
|
||||
if crc&0x80 != 0 {
|
||||
crc = (crc << 1) ^ poly
|
||||
} else {
|
||||
crc <<= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc >> 1
|
||||
}
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package sd
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var timeoutTimer [2]timer
|
||||
|
||||
type timer struct {
|
||||
start int64
|
||||
timeout int64
|
||||
}
|
||||
|
||||
func setTimeout(timerID int, timeout time.Duration) *timer {
|
||||
timeoutTimer[timerID].start = time.Now().UnixNano()
|
||||
timeoutTimer[timerID].timeout = timeout.Nanoseconds()
|
||||
return &timeoutTimer[timerID]
|
||||
}
|
||||
|
||||
func (t timer) expired() bool {
|
||||
return time.Now().UnixNano() > (t.start + t.timeout)
|
||||
}
|
||||
Reference in New Issue
Block a user