1
0
mirror of https://github.com/hybridgroup/gobot.git synced 2025-05-11 19:29:20 +08:00

go lint and documentation tweaks for the gpio package

This commit is contained in:
Adrian Zankich 2015-01-02 10:42:53 -08:00
parent de71de86cb
commit 5995982042
12 changed files with 239 additions and 87 deletions

View File

@ -8,17 +8,22 @@ import (
var _ gobot.Driver = (*AnalogSensorDriver)(nil)
// Represents an Analog Sensor
// AnalogSensorDriver represents an Analog Sensor
type AnalogSensorDriver struct {
name string
pin string
halt chan bool
interval time.Duration
connection AnalogReader
gobot.Eventer
gobot.Commander
}
// NewAnalogSensorDriver returns a new AnalogSensorDriver given an AnalogReader, name and pin.
// NewAnalogSensorDriver returns a new AnalogSensorDriver with a polling interval of
// 10 Milliseconds given an AnalogReader, name and pin.
//
// Optinally accepts:
// time.Duration: Interval at which the AnalogSensor is polled for new information
//
// Adds the following API Commands:
// "Read" - See AnalogSensor.Read
@ -30,6 +35,7 @@ func NewAnalogSensorDriver(a AnalogReader, name string, pin string, v ...time.Du
Eventer: gobot.NewEventer(),
Commander: gobot.NewCommander(),
interval: 10 * time.Millisecond,
halt: make(chan bool),
}
if len(v) > 0 {
@ -47,10 +53,10 @@ func NewAnalogSensorDriver(a AnalogReader, name string, pin string, v ...time.Du
return d
}
// Starts the AnalogSensorDriver and reads the Analog Sensor at the given Driver.Interval().
// Returns true on successful start of the driver.
// Start starts the AnalogSensorDriver and reads the Analog Sensor at the given interval.
// Emits the Events:
// "data" int - Event is emitted on change and represents the current reading from the sensor.
// Data int - Event is emitted on change and represents the current reading from the sensor.
// Error error - Event is emitted on error reading from the sensor.
func (a *AnalogSensorDriver) Start() (errs []error) {
value := 0
go func() {
@ -62,16 +68,29 @@ func (a *AnalogSensorDriver) Start() (errs []error) {
value = newValue
gobot.Publish(a.Event(Data), value)
}
<-time.After(a.interval)
select {
case <-time.After(a.interval):
case <-a.halt:
return
}
}
}()
return
}
// Halt returns true on a successful halt of the driver
func (a *AnalogSensorDriver) Halt() (errs []error) { return }
func (a *AnalogSensorDriver) Name() string { return a.name }
func (a *AnalogSensorDriver) Pin() string { return a.pin }
// Halt stops polling the analog sensor for new information
func (a *AnalogSensorDriver) Halt() (errs []error) {
a.halt <- true
return
}
// Name returns the AnalogSensorDrivers name
func (a *AnalogSensorDriver) Name() string { return a.name }
// Pin returns the AnalogSensorDrivers pin
func (a *AnalogSensorDriver) Pin() string { return a.pin }
// Connection returns the AnalogSensorDrivers Connection
func (a *AnalogSensorDriver) Connection() gobot.Connection { return a.connection.(gobot.Connection) }
// Read returns the current reading from the Analog Sensor

View File

@ -33,7 +33,7 @@ func TestAnalogSensorDriverStart(t *testing.T) {
gobot.Assert(t, len(d.Start()), 0)
gobot.On(d.Event(Data), func(data interface{}) {
gobot.Once(d.Event(Data), func(data interface{}) {
gobot.Assert(t, data.(int), 100)
sem <- true
})
@ -49,7 +49,7 @@ func TestAnalogSensorDriverStart(t *testing.T) {
t.Errorf("AnalogSensor Event \"Data\" was not published")
}
gobot.On(d.Event(Error), func(data interface{}) {
gobot.Once(d.Event(Error), func(data interface{}) {
gobot.Assert(t, data.(error).Error(), "read error")
sem <- true
})
@ -64,9 +64,29 @@ func TestAnalogSensorDriverStart(t *testing.T) {
case <-time.After(15 * time.Millisecond):
t.Errorf("AnalogSensor Event \"Error\" was not published")
}
gobot.Once(d.Event(Data), func(data interface{}) {
sem <- true
})
testAdaptorAnalogRead = func() (val int, err error) {
val = 200
return
}
d.halt <- true
select {
case <-sem:
t.Errorf("AnalogSensor Event should not published")
case <-time.After(30 * time.Millisecond):
}
}
func TestAnalogSensorDriverHalt(t *testing.T) {
d := NewAnalogSensorDriver(newGpioTestAdaptor("adaptor"), "bot", "1")
go func() {
<-d.halt
}()
gobot.Assert(t, len(d.Halt()), 0)
}

View File

@ -8,17 +8,22 @@ import (
var _ gobot.Driver = (*ButtonDriver)(nil)
// Represents a digital Button
// ButtonDriver Represents a digital Button
type ButtonDriver struct {
Active bool
pin string
name string
halt chan bool
interval time.Duration
connection DigitalReader
gobot.Eventer
}
// NewButtonDriver return a new ButtonDriver given a DigitalReader, name and pin
// NewButtonDriver returns a new ButtonDriver with a polling interval of
// 10 Milliseconds given a DigitalReader, name and pin.
//
// Optinally accepts:
// time.Duration: Interval at which the ButtonDriver is polled for new information
func NewButtonDriver(a DigitalReader, name string, pin string, v ...time.Duration) *ButtonDriver {
b := &ButtonDriver{
name: name,
@ -27,6 +32,7 @@ func NewButtonDriver(a DigitalReader, name string, pin string, v ...time.Duratio
Active: false,
Eventer: gobot.NewEventer(),
interval: 10 * time.Millisecond,
halt: make(chan bool),
}
if len(v) > 0 {
@ -40,13 +46,12 @@ func NewButtonDriver(a DigitalReader, name string, pin string, v ...time.Duratio
return b
}
// Starts the ButtonDriver and reads the state of the button at the given Driver.Interval().
// Returns true on successful start of the driver.
// Start starts the ButtonDriver and polls the state of the button at the given interval.
//
// Emits the Events:
// "push" int - On button push
// "release" int - On button release
// "error" error - On button error
// Push int - On button push
// Release int - On button release
// Error error - On button error
func (b *ButtonDriver) Start() (errs []error) {
state := 0
go func() {
@ -58,17 +63,29 @@ func (b *ButtonDriver) Start() (errs []error) {
state = newValue
b.update(newValue)
}
<-time.After(b.interval)
select {
case <-time.After(b.interval):
case <-b.halt:
return
}
}
}()
return
}
// Halt returns true on a successful halt of the driver
func (b *ButtonDriver) Halt() (errs []error) { return }
// Halt stops polling the button for new information
func (b *ButtonDriver) Halt() (errs []error) {
b.halt <- true
return
}
func (b *ButtonDriver) Name() string { return b.name }
func (b *ButtonDriver) Pin() string { return b.pin }
// Name returns the ButtonDrivers name
func (b *ButtonDriver) Name() string { return b.name }
// Pin returns the ButtonDrivers pin
func (b *ButtonDriver) Pin() string { return b.pin }
// Connection returns the ButtonDrivers Connection
func (b *ButtonDriver) Connection() gobot.Connection { return b.connection.(gobot.Connection) }
func (b *ButtonDriver) update(newValue int) {

View File

@ -14,6 +14,9 @@ func initTestButtonDriver() *ButtonDriver {
func TestButtonDriverHalt(t *testing.T) {
d := initTestButtonDriver()
go func() {
<-d.halt
}()
gobot.Assert(t, len(d.Halt()), 0)
}
@ -36,7 +39,7 @@ func TestButtonDriverStart(t *testing.T) {
return
}
gobot.On(d.Event(Push), func(data interface{}) {
gobot.Once(d.Event(Push), func(data interface{}) {
gobot.Assert(t, d.Active, true)
sem <- true
})
@ -52,7 +55,7 @@ func TestButtonDriverStart(t *testing.T) {
return
}
gobot.On(d.Event(Release), func(data interface{}) {
gobot.Once(d.Event(Release), func(data interface{}) {
gobot.Assert(t, d.Active, false)
sem <- true
})
@ -68,7 +71,7 @@ func TestButtonDriverStart(t *testing.T) {
return
}
gobot.On(d.Event(Error), func(data interface{}) {
gobot.Once(d.Event(Error), func(data interface{}) {
sem <- true
})
@ -77,4 +80,22 @@ func TestButtonDriverStart(t *testing.T) {
case <-time.After(15 * time.Millisecond):
t.Errorf("Button Event \"Error\" was not published")
}
testAdaptorDigitalRead = func() (val int, err error) {
val = 1
return
}
gobot.Once(d.Event(Push), func(data interface{}) {
sem <- true
})
d.halt <- true
select {
case <-sem:
t.Errorf("Button Event \"Press\" should not published")
case <-time.After(15 * time.Millisecond):
}
}

View File

@ -8,7 +8,7 @@ import (
var _ gobot.Driver = (*DirectPinDriver)(nil)
// Represents a raw GPIO pin
// DirectPinDriver represents a GPIO pin
type DirectPinDriver struct {
name string
pin string
@ -16,7 +16,7 @@ type DirectPinDriver struct {
gobot.Commander
}
// NewDirectPinDriver return a new DirectPinDriver given a DirectPin, name and pin.
// NewDirectPinDriver return a new DirectPinDriver given a Connection, name and pin.
//
// Adds the following API Commands:
// "DigitalRead" - See DirectPinDriver.DigitalRead
@ -57,14 +57,19 @@ func NewDirectPinDriver(a gobot.Connection, name string, pin string) *DirectPinD
return d
}
func (d *DirectPinDriver) Name() string { return d.name }
func (d *DirectPinDriver) Pin() string { return d.pin }
// Name returns the DirectPinDrivers name
func (d *DirectPinDriver) Name() string { return d.name }
// Pin returns the DirectPinDrivers pin
func (d *DirectPinDriver) Pin() string { return d.pin }
// Connection returns the DirectPinDrivers Connection
func (d *DirectPinDriver) Connection() gobot.Connection { return d.connection }
// Starts the DirectPinDriver. Returns true on successful start of the driver
// Start implements the Driver interface
func (d *DirectPinDriver) Start() (errs []error) { return }
// Halts the DirectPinDriver. Returns true on successful halt of the driver
// Halt implements the Driver interface
func (d *DirectPinDriver) Halt() (errs []error) { return }
// DigitalRead returns the current digital state of the pin
@ -76,7 +81,7 @@ func (d *DirectPinDriver) DigitalRead() (val int, err error) {
return
}
// DigitalWrite writes to the pin
// DigitalWrite writes to the pin. Acceptable values are 1 or 0
func (d *DirectPinDriver) DigitalWrite(level byte) (err error) {
if writer, ok := d.Connection().(DigitalWriter); ok {
return writer.DigitalWrite(d.Pin(), level)
@ -94,7 +99,7 @@ func (d *DirectPinDriver) AnalogRead() (val int, err error) {
return
}
// PwmWrite writes to the pin
// PwmWrite writes the 0-254 value to the specified pin
func (d *DirectPinDriver) PwmWrite(level byte) (err error) {
if writer, ok := d.Connection().(PwmWriter); ok {
return writer.PwmWrite(d.Pin(), level)
@ -103,7 +108,7 @@ func (d *DirectPinDriver) PwmWrite(level byte) (err error) {
return
}
// ServoWrite writes to the pin
// ServoWrite writes value to the specified pin
func (d *DirectPinDriver) ServoWrite(level byte) (err error) {
if writer, ok := d.Connection().(ServoWriter); ok {
return writer.ServoWrite(d.Pin(), level)

View File

@ -3,7 +3,7 @@ Package gpio provides Gobot drivers for General Purpose Input/Output devices.
Installing:
go get github.com/hybridgroup/gobot/platforms/gpio
go get -d -u github.com/hybridgroup/gobot/... && go install github.com/hybridgroup/gobot/platforms/gpio
For further information refer to gpio README:
https://github.com/hybridgroup/gobot/blob/master/platforms/gpio/README.md

View File

@ -7,41 +7,62 @@ import (
)
var (
ErrServoWriteUnsupported = errors.New("ServoWrite is not supported by this platform")
ErrPwmWriteUnsupported = errors.New("PwmWrite is not supported by this platform")
ErrAnalogReadUnsupported = errors.New("AnalogRead is not supported by this platform")
// ErrServoWriteUnsupported is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrServoWriteUnsupported = errors.New("ServoWrite is not supported by this platform")
// ErrPwmWriteUnsupported is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrPwmWriteUnsupported = errors.New("PwmWrite is not supported by this platform")
// ErrAnalogReadUnsupported is error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrAnalogReadUnsupported = errors.New("AnalogRead is not supported by this platform")
// ErrDigitalWriteUnsupported is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrDigitalWriteUnsupported = errors.New("DigitalWrite is not supported by this platform")
ErrDigitalReadUnsupported = errors.New("DigitalRead is not supported by this platform")
ErrServoOutOfRange = errors.New("servo angle must be between 0-180")
// ErrDigitalReadUnsupported is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrDigitalReadUnsupported = errors.New("DigitalRead is not supported by this platform")
// ErrServoOutOfRange is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrServoOutOfRange = errors.New("servo angle must be between 0-180")
)
const (
// Release event
Release = "release"
Push = "push"
Error = "error"
Data = "data"
// Push event
Push = "push"
// Error event
Error = "error"
// Data event
Data = "data"
)
// PwmWriter interface represents an Adaptor which has Pwm capabilities
type PwmWriter interface {
gobot.Adaptor
PwmWrite(string, byte) (err error)
}
// ServoWriter interface represents an Adaptor which has Servo capabilities
type ServoWriter interface {
gobot.Adaptor
ServoWrite(string, byte) (err error)
}
// AnalogReader interface represents an Adaptor which has Analog capabilities
type AnalogReader interface {
gobot.Adaptor
AnalogRead(string) (val int, err error)
}
// DigitalWriter interface represents an Adaptor which has DigitalWrite capabilities
type DigitalWriter interface {
gobot.Adaptor
DigitalWrite(string, byte) (err error)
}
// DigitalReader interface represents an Adaptor which has DigitalRead capabilities
type DigitalReader interface {
gobot.Adaptor
DigitalRead(string) (val int, err error)

View File

@ -4,7 +4,7 @@ import "github.com/hybridgroup/gobot"
var _ gobot.Driver = (*LedDriver)(nil)
// Represents a digital Led
// LedDriver represents a digital Led
type LedDriver struct {
pin string
name string
@ -13,7 +13,7 @@ type LedDriver struct {
gobot.Commander
}
// NewLedDriver return a new LedDriver given a PwmDigitalWriter, name and pin.
// NewLedDriver return a new LedDriver given a DigitalWriter, name and pin.
//
// Adds the following API Commands:
// "Brightness" - See LedDriver.Brightness
@ -49,14 +49,19 @@ func NewLedDriver(a DigitalWriter, name string, pin string) *LedDriver {
return l
}
// Start starts the LedDriver. Returns true on successful start of the driver
// Start implements the Driver interface
func (l *LedDriver) Start() (errs []error) { return }
// Halt halts the LedDriver. Returns true on successful halt of the driver
// Halt implements the Driver interface
func (l *LedDriver) Halt() (errs []error) { return }
// Name returns the LedDrivers name
func (l *LedDriver) Name() string { return l.name }
func (l *LedDriver) Pin() string { return l.pin }
// Pin returns the LedDrivers name
func (l *LedDriver) Pin() string { return l.pin }
// Connection returns the LedDrivers Connection
func (l *LedDriver) Connection() gobot.Connection {
return l.connection.(gobot.Connection)
}
@ -66,7 +71,7 @@ func (l *LedDriver) State() bool {
return l.high
}
// On sets the led to a high state. Returns true on success
// On sets the led to a high state.
func (l *LedDriver) On() (err error) {
if err = l.connection.DigitalWrite(l.Pin(), 1); err != nil {
return
@ -75,7 +80,7 @@ func (l *LedDriver) On() (err error) {
return
}
// Off sets the led to a low state. Returns true on success
// Off sets the led to a low state.
func (l *LedDriver) Off() (err error) {
if err = l.connection.DigitalWrite(l.Pin(), 0); err != nil {
return

View File

@ -8,18 +8,22 @@ import (
var _ gobot.Driver = (*MakeyButtonDriver)(nil)
// Represents a Makey Button
// MakeyButtonDriver Represents a Makey Button
type MakeyButtonDriver struct {
name string
pin string
halt chan bool
connection DigitalReader
Active bool
data []int
interval time.Duration
gobot.Eventer
}
// NewMakeyButtonDriver returns a new MakeyButtonDriver given a DigitalRead, name and pin.
// NewMakeyButtonDriver returns a new MakeyButtonDriver with a polling interval of
// 10 Milliseconds given a DigitalReader, name and pin.
//
// Optinally accepts:
// time.Duration: Interval at which the ButtonDriver is polled for new information
func NewMakeyButtonDriver(a DigitalReader, name string, pin string, v ...time.Duration) *MakeyButtonDriver {
m := &MakeyButtonDriver{
name: name,
@ -28,6 +32,7 @@ func NewMakeyButtonDriver(a DigitalReader, name string, pin string, v ...time.Du
Active: false,
Eventer: gobot.NewEventer(),
interval: 10 * time.Millisecond,
halt: make(chan bool),
}
if len(v) > 0 {
@ -41,38 +46,50 @@ func NewMakeyButtonDriver(a DigitalReader, name string, pin string, v ...time.Du
return m
}
func (b *MakeyButtonDriver) Name() string { return b.name }
func (b *MakeyButtonDriver) Pin() string { return b.pin }
// Name returns the MakeyButtonDrivers name
func (b *MakeyButtonDriver) Name() string { return b.name }
// Pin returns the MakeyButtonDrivers pin
func (b *MakeyButtonDriver) Pin() string { return b.pin }
// Connection returns the MakeyButtonDrivers Connection
func (b *MakeyButtonDriver) Connection() gobot.Connection { return b.connection.(gobot.Connection) }
// Starts the MakeyButtonDriver and reads the state of the button at the given Driver.Interval().
// Returns true on successful start of the driver.
// Start starts the MakeyButtonDriver and polls the state of the button at the given interval.
//
// Emits the Events:
// "push" int - On button push
// "release" int - On button release
func (m *MakeyButtonDriver) Start() (errs []error) {
// Push int - On button push
// Release int - On button release
// Error error - On button error
func (b *MakeyButtonDriver) Start() (errs []error) {
state := 1
go func() {
for {
newValue, err := m.connection.DigitalRead(m.Pin())
newValue, err := b.connection.DigitalRead(b.Pin())
if err != nil {
gobot.Publish(m.Event(Error), err)
gobot.Publish(b.Event(Error), err)
} else if newValue != state && newValue != -1 {
state = newValue
if newValue == 0 {
m.Active = true
gobot.Publish(m.Event(Push), newValue)
b.Active = true
gobot.Publish(b.Event(Push), newValue)
} else {
m.Active = false
gobot.Publish(m.Event(Release), newValue)
b.Active = false
gobot.Publish(b.Event(Release), newValue)
}
}
<-time.After(m.interval)
select {
case <-time.After(b.interval):
case <-b.halt:
return
}
}
}()
return
}
// Halt returns true on a successful halt of the driver
func (m *MakeyButtonDriver) Halt() (errs []error) { return }
// Halt stops polling the makey button for new information
func (b *MakeyButtonDriver) Halt() (errs []error) {
b.halt <- true
return
}

View File

@ -14,6 +14,9 @@ func initTestMakeyButtonDriver() *MakeyButtonDriver {
func TestMakeyButtonDriverHalt(t *testing.T) {
d := initTestMakeyButtonDriver()
go func() {
<-d.halt
}()
gobot.Assert(t, len(d.Halt()), 0)
}
@ -36,7 +39,7 @@ func TestMakeyButtonDriverStart(t *testing.T) {
return
}
gobot.On(d.Event(Push), func(data interface{}) {
gobot.Once(d.Event(Push), func(data interface{}) {
gobot.Assert(t, d.Active, true)
sem <- true
})
@ -52,7 +55,7 @@ func TestMakeyButtonDriverStart(t *testing.T) {
return
}
gobot.On(d.Event(Release), func(data interface{}) {
gobot.Once(d.Event(Release), func(data interface{}) {
gobot.Assert(t, d.Active, false)
sem <- true
})
@ -68,7 +71,7 @@ func TestMakeyButtonDriverStart(t *testing.T) {
return
}
gobot.On(d.Event(Error), func(data interface{}) {
gobot.Once(d.Event(Error), func(data interface{}) {
sem <- true
})
@ -77,4 +80,20 @@ func TestMakeyButtonDriverStart(t *testing.T) {
case <-time.After(15 * time.Millisecond):
t.Errorf("MakeyButton Event \"Error\" was not published")
}
gobot.Once(d.Event(Release), func(data interface{}) {
sem <- true
})
testAdaptorDigitalRead = func() (val int, err error) {
val = 1
return
}
d.halt <- true
select {
case <-sem:
t.Errorf("MakeyButton Event should not published")
case <-time.After(30 * time.Millisecond):
}
}

View File

@ -6,7 +6,7 @@ import (
var _ gobot.Driver = (*MotorDriver)(nil)
// Represents a Motor
// MotorDriver Represents a Motor
type MotorDriver struct {
name string
connection DigitalWriter
@ -34,13 +34,16 @@ func NewMotorDriver(a DigitalWriter, name string, speedPin string) *MotorDriver
}
}
func (m *MotorDriver) Name() string { return m.name }
// Name returns the MotorDrivers name
func (m *MotorDriver) Name() string { return m.name }
// Connection returns the MotorDrivers Connection
func (m *MotorDriver) Connection() gobot.Connection { return m.connection.(gobot.Connection) }
// Start starts the MotorDriver. Returns true on successful start of the driver
// Start implements the Driver interface
func (m *MotorDriver) Start() (errs []error) { return }
// Halt halts the MotorDriver. Returns true on successful halt of the driver
// Halt implements the Driver interface
func (m *MotorDriver) Halt() (errs []error) { return }
// Off turns the motor off or sets the motor to a 0 speed
@ -76,7 +79,7 @@ func (m *MotorDriver) Max() (err error) {
return m.Speed(255)
}
// InOn returns true if the motor is on
// IsOn returns true if the motor is on
func (m *MotorDriver) IsOn() bool {
if m.isDigital() {
return m.CurrentState == 1
@ -84,7 +87,7 @@ func (m *MotorDriver) IsOn() bool {
return m.CurrentSpeed > 0
}
// InOff returns true if the motor is off
// IsOff returns true if the motor is off
func (m *MotorDriver) IsOff() bool {
return !m.IsOn()
}

View File

@ -4,7 +4,7 @@ import "github.com/hybridgroup/gobot"
var _ gobot.Driver = (*ServoDriver)(nil)
// Represents a Servo
// ServoDriver Represents a Servo
type ServoDriver struct {
name string
pin string
@ -13,7 +13,7 @@ type ServoDriver struct {
CurrentAngle byte
}
// NewSerovDriver return a new ServoDriver given a Servo, name and pin.
// NewServoDriver returns a new ServoDriver given a ServoWriter, name and pin.
//
// Adds the following API Commands:
// "Move" - See ServoDriver.Move
@ -47,17 +47,22 @@ func NewServoDriver(a ServoWriter, name string, pin string) *ServoDriver {
}
func (s *ServoDriver) Name() string { return s.name }
func (s *ServoDriver) Pin() string { return s.pin }
// Name returns the ServoDrivers name
func (s *ServoDriver) Name() string { return s.name }
// Pin returns the ServoDrivers pin
func (s *ServoDriver) Pin() string { return s.pin }
// Connection returns the ServoDrivers connection
func (s *ServoDriver) Connection() gobot.Connection { return s.connection.(gobot.Connection) }
// Start starts the ServoDriver. Returns true on successful start of the driver.
// Start implements the Driver interface
func (s *ServoDriver) Start() (errs []error) { return }
// Halt halts the ServoDriver. Returns true on successful halt of the driver.
// Halt implements the Driver interface
func (s *ServoDriver) Halt() (errs []error) { return }
// Move sets the servo to the specified angle
// Move sets the servo to the specified angle. Acceptable angles are 0-180
func (s *ServoDriver) Move(angle uint8) (err error) {
if !(angle >= 0 && angle <= 180) {
return ErrServoOutOfRange