tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/ds1307/ds1307.go (about)

     1  // Package ds1307 provides a driver for the DS1307 RTC
     2  //
     3  // Datasheet:
     4  // https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
     5  package ds1307 // import "tinygo.org/x/drivers/ds1307"
     6  
     7  import (
     8  	"errors"
     9  	"time"
    10  
    11  	"tinygo.org/x/drivers"
    12  	"tinygo.org/x/drivers/internal/legacy"
    13  )
    14  
    15  // Device wraps an I2C connection to a DS1307 device.
    16  type Device struct {
    17  	bus         drivers.I2C
    18  	Address     uint8
    19  	AddressSRAM uint8
    20  }
    21  
    22  // New creates a new DS1307 connection. I2C bus must be already configured.
    23  func New(bus drivers.I2C) Device {
    24  	return Device{bus: bus,
    25  		Address:     uint8(I2CAddress),
    26  		AddressSRAM: SRAMBeginAddres,
    27  	}
    28  }
    29  
    30  // SetTime sets the time and date
    31  func (d *Device) SetTime(t time.Time) error {
    32  	data := make([]byte, 8)
    33  	data[0] = uint8(TimeDate)
    34  	data[1] = decToBcd(t.Second())
    35  	data[2] = decToBcd(t.Minute())
    36  	data[3] = decToBcd(t.Hour())
    37  	data[4] = decToBcd(int(t.Weekday() + 1))
    38  	data[5] = decToBcd(t.Day())
    39  	data[6] = decToBcd(int(t.Month()))
    40  	data[7] = decToBcd(t.Year() - 2000)
    41  	err := d.bus.Tx(uint16(d.Address), data, nil)
    42  	return err
    43  }
    44  
    45  // ReadTime returns the date and time
    46  func (d *Device) ReadTime() (time.Time, error) {
    47  	data := make([]byte, 8)
    48  	err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
    49  	if err != nil {
    50  		return time.Time{}, err
    51  	}
    52  	seconds := bcdToDec(data[0] & 0x7F)
    53  	minute := bcdToDec(data[1])
    54  	hour := hoursBCDToInt(data[2])
    55  	day := bcdToDec(data[4])
    56  	month := time.Month(bcdToDec(data[5]))
    57  	year := bcdToDec(data[6])
    58  	year += 2000
    59  
    60  	t := time.Date(year, month, day, hour, minute, seconds, 0, time.UTC)
    61  	return t, nil
    62  }
    63  
    64  // Seek sets the offset for the next Read or Write on SRAM to offset, interpreted
    65  // according to whence: 0 means relative to the origin of the SRAM, 1 means
    66  // relative to the current offset, and 2 means relative to the end.
    67  // returns new offset and error, if any
    68  func (d *Device) Seek(offset int64, whence int) (int64, error) {
    69  	switch whence {
    70  	case 0:
    71  		whence = SRAMBeginAddres
    72  	case 1:
    73  		whence = int(d.AddressSRAM)
    74  	case 2:
    75  		whence = SRAMEndAddress
    76  	default:
    77  		return 0, errors.New("invalid starting point")
    78  	}
    79  	d.AddressSRAM = uint8(whence) + uint8(offset)
    80  	if d.AddressSRAM > SRAMEndAddress {
    81  		return 0, errors.New("EOF")
    82  	}
    83  	return int64(d.AddressSRAM), nil
    84  }
    85  
    86  // Write writes len(data) bytes to SRAM
    87  // returns number of bytes written and error, if any
    88  func (d *Device) Write(data []byte) (n int, err error) {
    89  	if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
    90  		return 0, errors.New("writing outside of SRAM")
    91  	}
    92  	buffer := make([]byte, len(data)+1)
    93  	buffer[0] = d.AddressSRAM
    94  	copy(buffer[1:], data)
    95  	err = d.bus.Tx(uint16(d.Address), buffer, nil)
    96  	if err != nil {
    97  		return 0, err
    98  	}
    99  	d.Seek(int64(len(data)), 1)
   100  	return len(data), nil
   101  }
   102  
   103  // Read reads len(data) from SRAM
   104  // returns number of bytes written and error, if any
   105  func (d *Device) Read(data []uint8) (n int, err error) {
   106  	if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
   107  		return 0, errors.New("EOF")
   108  	}
   109  	err = legacy.ReadRegister(d.bus, d.Address, d.AddressSRAM, data)
   110  	if err != nil {
   111  		return 0, err
   112  	}
   113  	d.Seek(int64(len(data)), 1)
   114  	return len(data), nil
   115  }
   116  
   117  // SetOscillatorFrequency sets output oscillator frequency
   118  // Available modes: SQW_OFF, SQW_1HZ, SQW_4KHZ, SQW_8KHZ, SQW_32KHZ
   119  func (d *Device) SetOscillatorFrequency(sqw uint8) error {
   120  	data := []byte{uint8(Control), sqw}
   121  	err := d.bus.Tx(uint16(d.Address), data, nil)
   122  	return err
   123  }
   124  
   125  // IsOscillatorRunning returns if the oscillator is running
   126  func (d *Device) IsOscillatorRunning() bool {
   127  	data := []byte{0}
   128  	err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
   129  	if err != nil {
   130  		return false
   131  	}
   132  	return (data[0] & (1 << CH)) == 0
   133  }
   134  
   135  // SetOscillatorRunning starts/stops internal oscillator by toggling halt bit
   136  func (d *Device) SetOscillatorRunning(running bool) error {
   137  	data := make([]byte, 3)
   138  	err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	if running {
   143  		data[0] &^= (1 << CH)
   144  	} else {
   145  		data[0] |= (1 << CH)
   146  	}
   147  	data[1], data[0] = data[0], uint8(TimeDate)
   148  	err = d.bus.Tx(uint16(d.Address), data[:2], nil)
   149  	return err
   150  }
   151  
   152  // decToBcd converts int to BCD
   153  func decToBcd(dec int) uint8 {
   154  	return uint8(dec + 6*(dec/10))
   155  }
   156  
   157  // bcdToDec converts BCD to int
   158  func bcdToDec(bcd uint8) int {
   159  	return int(bcd - 6*(bcd>>4))
   160  }
   161  
   162  // hoursBCDToInt converts the BCD hours to int
   163  func hoursBCDToInt(value uint8) (hour int) {
   164  	if value&0x40 != 0x00 {
   165  		hour = bcdToDec(value & 0x1F)
   166  		if (value & 0x20) != 0x00 {
   167  			hour += 12
   168  		}
   169  	} else {
   170  		hour = bcdToDec(value)
   171  	}
   172  	return
   173  }