diff --git a/examples/fsk4/noradio.go b/examples/fsk4/noradio.go index 640183c..879fe56 100644 --- a/examples/fsk4/noradio.go +++ b/examples/fsk4/noradio.go @@ -1,4 +1,4 @@ -//go:build !si5351 && !featherwing +//go:build !si5351 && !featherwing && !wio_sx1262 package main diff --git a/examples/fsk4/wio_sx126x.go b/examples/fsk4/wio_sx126x.go new file mode 100644 index 0000000..f5d1565 --- /dev/null +++ b/examples/fsk4/wio_sx126x.go @@ -0,0 +1,113 @@ +//go:build nicenano && wio_sx1262 + +// This is an FSK4 modem example using Wio SX1262 module as the radio transmitter. +// Build this example for NiceNano with Wio SX1262 module with command like this: +// tinygo build -target nicenano -tags wio_sx1262 +// For different targets, adjust the pin variables in this file accordingly. + +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/sx126x" + "tinygo.org/x/wireless/fsk4" +) + +const freq = 432_300_000 + +var ( + spi = machine.SPI0 + rstPin = machine.D009 + misoPin = machine.D002 + mosiPin = machine.D115 + sckPin = machine.D111 + nssPin = machine.D113 + busyPin = machine.D029 + dio1Pin = machine.D010 + rfSw = machine.D017 +) + +func initRadio() *fsk4.FSK4 { + time.Sleep(3 * time.Second) + + rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + rfSw.Configure(machine.PinConfig{Mode: machine.PinOutput}) + + err := spi.Configure(machine.SPIConfig{ + Frequency: 500_000, + Mode: 0, + SCK: sckPin, + SDO: mosiPin, + SDI: misoPin, + }) + if err != nil { + panic(err) + } + + println("Initializing SX126x...") + dev := sx126x.New(spi, rstPin) + rc := sx126x.NewRadioControlWio(nssPin, busyPin, dio1Pin, rfSw) + dev.SetRadioController(rc) + + println("Resetting device") + dev.Reset() + time.Sleep(100 * time.Millisecond) + + if !dev.DetectDevice() { + for { + println("SX126x device not found!") + time.Sleep(5 * time.Second) + } + } + println("SX126x device detected") + + // Wio specific configuration + dev.SetDio3AsTcxoCtrl(sx126x.SX126X_DIO3_OUTPUT_1_8, 5*time.Millisecond) + dev.SetRegulatorMode(sx126x.SX126X_REGULATOR_DC_DC) + dev.SetDeviceType(sx126x.DEVICE_TYPE_SX1262) + dev.Calibrate(sx126x.SX126X_CALIBRATE_ALL) + + dev.SetPacketType(sx126x.SX126X_PACKET_TYPE_GFSK) + dev.SetTxParams(0, sx126x.SX126X_PA_RAMP_200U) + dev.SetRfFrequency(freq) + dev.CalibrateImage(freq) + + dev.SetStandby() + + radio := &sx126xRadio{device: dev} + f := fsk4.NewFSK4(radio, freq, 270, 10*time.Millisecond) + _ = f.Configure() + return f +} + +type sx126xRadio struct { + device *sx126x.Device + transmitting bool +} + +func (r *sx126xRadio) Transmit(freq uint64) error { + // Put the radio to XOSC mode before first transmission + // Without this, the first tone after standby is not transmitted + if !r.transmitting { + r.device.ExecSetCommand(sx126x.SX126X_CMD_SET_STANDBY, []uint8{sx126x.SX126X_STANDBY_XOSC}) + } + r.transmitting = true + + freqHz := freq / 100 // freq is in hundredths of Hz + r.device.SetRfFrequency(uint32(freqHz)) + r.device.SetTxContinuousWave() + + return nil +} + +func (r *sx126xRadio) Standby() error { + r.transmitting = false + r.device.SetStandby() + return nil +} + +func (r *sx126xRadio) Close() error { + return r.Standby() +} diff --git a/examples/morse/noradio.go b/examples/morse/noradio.go index 1d45deb..5ffdd06 100644 --- a/examples/morse/noradio.go +++ b/examples/morse/noradio.go @@ -1,4 +1,4 @@ -//go:build !si5351 && !featherwing +//go:build !si5351 && !featherwing && !wio_sx1262 package main diff --git a/examples/morse/wio_sx126x.go b/examples/morse/wio_sx126x.go new file mode 100644 index 0000000..1c6a695 --- /dev/null +++ b/examples/morse/wio_sx126x.go @@ -0,0 +1,113 @@ +//go:build nicenano && wio_sx1262 + +// This is a Morse code modem example using Wio SX1262 module as the radio transmitter. +// Build this example for NiceNano with Wio SX1262 module with command like this: +// tinygo build -target nicenano -tags wio_sx1262 +// For different targets, adjust the pin variables in this file accordingly. + +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/sx126x" + "tinygo.org/x/wireless/morse" +) + +const freq = 432_300_000 + +var ( + spi = machine.SPI0 + rstPin = machine.D009 + misoPin = machine.D002 + mosiPin = machine.D115 + sckPin = machine.D111 + nssPin = machine.D113 + busyPin = machine.D029 + dio1Pin = machine.D010 + rfSw = machine.D017 +) + +func initRadio() *morse.Morse { + time.Sleep(3 * time.Second) + + rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + rfSw.Configure(machine.PinConfig{Mode: machine.PinOutput}) + + err := spi.Configure(machine.SPIConfig{ + Frequency: 500_000, + Mode: 0, + SCK: sckPin, + SDO: mosiPin, + SDI: misoPin, + }) + if err != nil { + panic(err) + } + + println("Initializing SX126x...") + dev := sx126x.New(spi, rstPin) + rc := sx126x.NewRadioControlWio(nssPin, busyPin, dio1Pin, rfSw) + dev.SetRadioController(rc) + + println("Resetting device") + dev.Reset() + time.Sleep(100 * time.Millisecond) + + if !dev.DetectDevice() { + for { + println("SX126x device not found!") + time.Sleep(5 * time.Second) + } + } + println("SX126x device detected") + + // Wio specific configuration + dev.SetDio3AsTcxoCtrl(sx126x.SX126X_DIO3_OUTPUT_1_8, 5*time.Millisecond) + dev.SetRegulatorMode(sx126x.SX126X_REGULATOR_DC_DC) + dev.SetDeviceType(sx126x.DEVICE_TYPE_SX1262) + dev.Calibrate(sx126x.SX126X_CALIBRATE_ALL) + + dev.SetPacketType(sx126x.SX126X_PACKET_TYPE_GFSK) + dev.SetTxParams(0, sx126x.SX126X_PA_RAMP_200U) + dev.SetRfFrequency(freq) + dev.CalibrateImage(freq) + + dev.SetStandby() + + m := morse.NewMorse(&sx126xRadio{device: dev}, freq, 20) + _ = m.Configure() + + return m +} + +type sx126xRadio struct { + device *sx126x.Device + transmitting bool +} + +func (r *sx126xRadio) Transmit(freq uint64) error { + // Put the radio to XOSC mode before first transmission + // Without this, the first tone after standby is not transmitted + if !r.transmitting { + r.device.ExecSetCommand(sx126x.SX126X_CMD_SET_STANDBY, []uint8{sx126x.SX126X_STANDBY_XOSC}) + } + r.transmitting = true + + freqHz := freq / 100 // freq is in hundredths of Hz + r.device.SetRfFrequency(uint32(freqHz)) + r.device.SetTxContinuousWave() + + return nil +} + +func (r *sx126xRadio) Standby() error { + r.transmitting = false + r.device.SetStandby() + return nil +} + +func (r *sx126xRadio) Close() error { + return r.Standby() +} diff --git a/examples/wspr/noradio.go b/examples/wspr/noradio.go index 8505b06..fa5548c 100644 --- a/examples/wspr/noradio.go +++ b/examples/wspr/noradio.go @@ -1,4 +1,4 @@ -//go:build !si5351 && !featherwing +//go:build !si5351 && !featherwing && !wio_sx1262 package main diff --git a/examples/wspr/wio_sx126x.go b/examples/wspr/wio_sx126x.go new file mode 100644 index 0000000..b279237 --- /dev/null +++ b/examples/wspr/wio_sx126x.go @@ -0,0 +1,113 @@ +//go:build nicenano && wio_sx1262 + +// This is an example using Wio SX1262 module as WSPR transmitter. +// Build this example for NiceNano with Wio SX1262 module with command like this: +// tinygo build -target nicenano -tags wio_sx1262 +// For different targets, adjust the pin variables in this file accordingly. + +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/sx126x" + "tinygo.org/x/wireless/fsk4" +) + +const freq = 432_300_000 + +var ( + spi = machine.SPI0 + rstPin = machine.D009 + misoPin = machine.D002 + mosiPin = machine.D115 + sckPin = machine.D111 + nssPin = machine.D113 + busyPin = machine.D029 + dio1Pin = machine.D010 + rfSw = machine.D017 +) + +func initRadio() *fsk4.FSK4 { + time.Sleep(3 * time.Second) + + rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + rfSw.Configure(machine.PinConfig{Mode: machine.PinOutput}) + + err := spi.Configure(machine.SPIConfig{ + Frequency: 500_000, + Mode: 0, + SCK: sckPin, + SDO: mosiPin, + SDI: misoPin, + }) + if err != nil { + panic(err) + } + + println("Initializing SX126x...") + dev := sx126x.New(spi, rstPin) + rc := sx126x.NewRadioControlWio(nssPin, busyPin, dio1Pin, rfSw) + dev.SetRadioController(rc) + + println("Resetting device") + dev.Reset() + time.Sleep(100 * time.Millisecond) + + if !dev.DetectDevice() { + for { + println("SX126x device not found!") + time.Sleep(5 * time.Second) + } + } + println("SX126x device detected") + + // Wio specific configuration + dev.SetDio3AsTcxoCtrl(sx126x.SX126X_DIO3_OUTPUT_1_8, 5*time.Millisecond) + dev.SetRegulatorMode(sx126x.SX126X_REGULATOR_DC_DC) + dev.SetDeviceType(sx126x.DEVICE_TYPE_SX1262) + dev.Calibrate(sx126x.SX126X_CALIBRATE_ALL) + + dev.SetPacketType(sx126x.SX126X_PACKET_TYPE_GFSK) + dev.SetTxParams(0, sx126x.SX126X_PA_RAMP_200U) + dev.SetRfFrequency(freq) + dev.CalibrateImage(freq) + + dev.SetStandby() + + radio := &sx126xRadio{device: dev} + f := fsk4.NewFSK4(radio, freq, 270, 10*time.Millisecond) + _ = f.Configure() + return f +} + +type sx126xRadio struct { + device *sx126x.Device + transmitting bool +} + +func (r *sx126xRadio) Transmit(freq uint64) error { + // Put the radio to XOSC mode before first transmission + // Without this, the first tone after standby is not transmitted + if !r.transmitting { + r.device.ExecSetCommand(sx126x.SX126X_CMD_SET_STANDBY, []uint8{sx126x.SX126X_STANDBY_XOSC}) + } + r.transmitting = true + + freqHz := freq / 100 // freq is in hundredths of Hz + r.device.SetRfFrequency(uint32(freqHz)) + r.device.SetTxContinuousWave() + + return nil +} + +func (r *sx126xRadio) Standby() error { + r.transmitting = false + r.device.SetStandby() + return nil +} + +func (r *sx126xRadio) Close() error { + return r.Standby() +} diff --git a/fsk4/fsk4.go b/fsk4/fsk4.go index b958358..10ded81 100644 --- a/fsk4/fsk4.go +++ b/fsk4/fsk4.go @@ -21,7 +21,7 @@ type FSK4 struct { // NewFSK4 creates a new FSK4 modem instance. // radio: the Radio interface implementation // base: the base frequency in Hz -// shift: the frequency shift in Hz*100 eg. 270 = 2.7 Hz +// shift: the frequency shift in Hz // rate: the send rate func NewFSK4(radio Radio, base uint64, shift uint32, rate time.Duration) *FSK4 { return &FSK4{ @@ -131,7 +131,7 @@ func (r *FSK4) writeByte(data byte) error { func (r *FSK4) tone(symbol byte) error { start := time.Now() - freq := r.base*100 + uint64(r.tones[symbol]) + freq := r.base + uint64(r.tones[symbol]) if err := r.radio.Transmit(freq); err != nil { return err } diff --git a/morse/morse.go b/morse/morse.go index 4a2e641..f8c4257 100644 --- a/morse/morse.go +++ b/morse/morse.go @@ -92,13 +92,13 @@ func (m *Morse) write(b byte) error { for code != guardBit { if (code & Dash) == 1 { // dash - if err := m.radio.Transmit(m.base * 100); err != nil { + if err := m.radio.Transmit(m.base); err != nil { return err } time.Sleep(m.dashLength) } else { // dot - if err := m.radio.Transmit(m.base * 100); err != nil { + if err := m.radio.Transmit(m.base); err != nil { return err } time.Sleep(m.dotLength) diff --git a/morse/radio.go b/morse/radio.go index 232bd6c..f0c65dd 100644 --- a/morse/radio.go +++ b/morse/radio.go @@ -2,7 +2,7 @@ package morse // Radio defines the interface for Morse radio transmitters. type Radio interface { - // Transmit sends a signal at the specified frequency passed in Hz * 100 + // Transmit sends a signal at the specified frequency passed in Hz Transmit(freq uint64) error // Standby puts the radio into standby mode. Standby() error