Merge pull request #279 from jpoirier/sdr_cleanup

better anonymous & tagged dongle handling, sdr file cleanup
pull/292/head
cyoung 2016-02-26 11:19:03 -05:00
commit 002a99f50e
2 zmienionych plików z 174 dodań i 174 usunięć

Wyświetl plik

@ -73,6 +73,8 @@ const (
TRACK_RESOLUTION = float32(360.0 / 256.0) TRACK_RESOLUTION = float32(360.0 / 256.0)
) )
var maxSignalStrength int
var uatReplayLog string var uatReplayLog string
var esReplayLog string var esReplayLog string
var gpsReplayLog string var gpsReplayLog string

Wyświetl plik

@ -24,31 +24,22 @@ import (
rtl "github.com/jpoirier/gortlsdr" rtl "github.com/jpoirier/gortlsdr"
) )
type UAT struct { type Device struct {
dev *rtl.Context dev *rtl.Context
wg *sync.WaitGroup
closeCh chan int
indexID int indexID int
ppm int ppm int
serial string serial string
idSet bool
} }
type ES struct { type UAT Device
dev *rtl.Context type ES Device
indexID int
ppm int
serial string
}
var UATDev *UAT var UATDev *UAT
var ESDev *ES var ESDev *ES
var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}
var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}
var maxSignalStrength int
func readToChan(fp io.ReadCloser, ch chan []byte) { func readToChan(fp io.ReadCloser, ch chan []byte) {
for { for {
buf := make([]byte, 1024) buf := make([]byte, 1024)
@ -62,7 +53,7 @@ func readToChan(fp io.ReadCloser, ch chan []byte) {
} }
func (e *ES) read() { func (e *ES) read() {
defer es_wg.Done() defer e.wg.Done()
log.Println("Entered ES read() ...") log.Println("Entered ES read() ...")
cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID), "--ppm", strconv.Itoa(e.ppm)) cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID), "--ppm", strconv.Itoa(e.ppm))
stdout, _ := cmd.StdoutPipe() stdout, _ := cmd.StdoutPipe()
@ -84,8 +75,7 @@ func (e *ES) read() {
select { select {
case buf := <-outputChan: case buf := <-outputChan:
replayLog(string(buf), MSGCLASS_DUMP1090) replayLog(string(buf), MSGCLASS_DUMP1090)
case <-e.closeCh:
case <-es_shutdown:
log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...") log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
err := cmd.Process.Kill() err := cmd.Process.Kill()
if err != nil { if err != nil {
@ -97,13 +87,12 @@ func (e *ES) read() {
return return
default: default:
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
} }
} }
func (u *UAT) read() { func (u *UAT) read() {
defer uat_wg.Done() defer u.wg.Done()
log.Println("Entered UAT read() ...") log.Println("Entered UAT read() ...")
var buffer = make([]uint8, rtl.DefaultBufLength) var buffer = make([]uint8, rtl.DefaultBufLength)
@ -120,7 +109,7 @@ func (u *UAT) read() {
buf := buffer[:nRead] buf := buffer[:nRead]
godump978.InChan <- buf godump978.InChan <- buf
} }
case <-uat_shutdown: case <-u.closeCh:
log.Println("UAT read(): shutdown msg received...") log.Println("UAT read(): shutdown msg received...")
return return
} }
@ -128,31 +117,41 @@ func (u *UAT) read() {
} }
func getPPM(serial string) int { func getPPM(serial string) int {
r, err := regexp.Compile("str?a?t?u?x:\\d+:?(-?\\d*)"); r, err := regexp.Compile("str?a?t?u?x:\\d+:?(-?\\d*)")
if err != nil { if err != nil {
return globalSettings.PPM return globalSettings.PPM
} }
arr := r.FindStringSubmatch(serial); arr := r.FindStringSubmatch(serial)
if arr == nil { if arr == nil {
return globalSettings.PPM return globalSettings.PPM
} }
if ppm, err := strconv.Atoi(arr[1]); err != nil { if ppm, err := strconv.Atoi(arr[1]); err != nil {
return globalSettings.PPM return globalSettings.PPM
} else { } else {
return ppm return ppm
} }
} }
func (e *ES) sdrConfig() (err error) { func (e *ES) sdrConfig() (err error) {
e.ppm = getPPM(e.serial) e.ppm = getPPM(e.serial)
log.Printf("===== ES Device Serial: %s PPM %d =====\n", e.serial, e.ppm)
return return
} }
const (
TunerGain = 480
SampleRate = 2083334
NewRTLFreq = 28800000
NewTunerFreq = 28800000
CenterFreq = 978000000
Bandwidth = 1000000
)
func (u *UAT) sdrConfig() (err error) { func (u *UAT) sdrConfig() (err error) {
log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID)) log.Printf("===== UAT Device Name : %s =====\n", rtl.GetDeviceName(u.indexID))
u.ppm = getPPM(u.serial) log.Printf("===== UAT Device Serial: %s=====\n", u.serial)
if u.dev, err = rtl.Open(u.indexID); err != nil { if u.dev, err = rtl.Open(u.indexID); err != nil {
log.Printf("\tUAT Open Failed...\n") log.Printf("\tUAT Open Failed...\n")
@ -170,8 +169,7 @@ func (u *UAT) sdrConfig() (err error) {
log.Printf("\tSetTunerGainMode Successful\n") log.Printf("\tSetTunerGainMode Successful\n")
} }
tgain := 480 err = u.dev.SetTunerGain(TunerGain)
err = u.dev.SetTunerGain(tgain)
if err != nil { if err != nil {
u.dev.Close() u.dev.Close()
log.Printf("\tSetTunerGain Failed - error: %s\n", err) log.Printf("\tSetTunerGain Failed - error: %s\n", err)
@ -181,14 +179,13 @@ func (u *UAT) sdrConfig() (err error) {
} }
//---------- Get/Set Sample Rate ---------- //---------- Get/Set Sample Rate ----------
samplerate := 2083334 err = u.dev.SetSampleRate(SampleRate)
err = u.dev.SetSampleRate(samplerate)
if err != nil { if err != nil {
u.dev.Close() u.dev.Close()
log.Printf("\tSetSampleRate Failed - error: %s\n", err) log.Printf("\tSetSampleRate Failed - error: %s\n", err)
return return
} else { } else {
log.Printf("\tSetSampleRate - rate: %d\n", samplerate) log.Printf("\tSetSampleRate - rate: %d\n", SampleRate)
} }
log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate()) log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())
@ -202,20 +199,18 @@ func (u *UAT) sdrConfig() (err error) {
log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq) log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
} }
newRTLFreq := 28800000 err = u.dev.SetXtalFreq(NewRTLFreq, NewTunerFreq)
newTunerFreq := 28800000
err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
if err != nil { if err != nil {
u.dev.Close() u.dev.Close()
log.Printf("\tSetXtalFreq Failed - error: %s\n", err) log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
return return
} else { } else {
log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n", log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
newRTLFreq, newTunerFreq) NewRTLFreq, NewTunerFreq)
} }
//---------- Get/Set Center Freq ---------- //---------- Get/Set Center Freq ----------
err = u.dev.SetCenterFreq(978000000) err = u.dev.SetCenterFreq(CenterFreq)
if err != nil { if err != nil {
u.dev.Close() u.dev.Close()
log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err) log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
@ -227,14 +222,13 @@ func (u *UAT) sdrConfig() (err error) {
log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq()) log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())
//---------- Set Bandwidth ---------- //---------- Set Bandwidth ----------
bw := 1000000 log.Printf("\tSetting Bandwidth: %d\n", Bandwidth)
log.Printf("\tSetting Bandwidth: %d\n", bw) if err = u.dev.SetTunerBw(Bandwidth); err != nil {
if err = u.dev.SetTunerBw(bw); err != nil {
u.dev.Close() u.dev.Close()
log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err) log.Printf("\tSetTunerBw %d Failed, error: %s\n", Bandwidth, err)
return return
} else { } else {
log.Printf("\tSetTunerBw %d Successful\n", bw) log.Printf("\tSetTunerBw %d Successful\n", Bandwidth)
} }
if err = u.dev.ResetBuffer(); err != nil { if err = u.dev.ResetBuffer(); err != nil {
@ -244,9 +238,12 @@ func (u *UAT) sdrConfig() (err error) {
} else { } else {
log.Printf("\tResetBuffer Successful\n") log.Printf("\tResetBuffer Successful\n")
} }
//---------- Get/Set Freq Correction ---------- //---------- Get/Set Freq Correction ----------
freqCorr := u.dev.GetFreqCorrection() freqCorr := u.dev.GetFreqCorrection()
log.Printf("\tGetFreqCorrection: %d\n", freqCorr) log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
u.ppm = getPPM(u.serial)
err = u.dev.SetFreqCorrection(u.ppm) err = u.dev.SetFreqCorrection(u.ppm)
if err != nil { if err != nil {
u.dev.Close() u.dev.Close()
@ -290,24 +287,22 @@ func (e *ES) writeID() error {
func (u *UAT) shutdown() { func (u *UAT) shutdown() {
log.Println("Entered UAT shutdown() ...") log.Println("Entered UAT shutdown() ...")
close(uat_shutdown) // signal to shutdown close(u.closeCh) // signal to shutdown
log.Println("UAT shutdown(): calling uat_wg.Wait() ...") log.Println("UAT shutdown(): calling u.wg.Wait() ...")
uat_wg.Wait() // Wait for the goroutine to shutdown u.wg.Wait() // Wait for the goroutine to shutdown
log.Println("UAT shutdown(): uat_wg.Wait() returned...") log.Println("UAT shutdown(): u.wg.Wait() returned...")
log.Println("UAT shutdown(): closing device ...") log.Println("UAT shutdown(): closing device ...")
u.dev.Close() // preempt the blocking ReadSync call u.dev.Close() // preempt the blocking ReadSync call
} }
func (e *ES) shutdown() { func (e *ES) shutdown() {
log.Println("Entered ES shutdown() ...") log.Println("Entered ES shutdown() ...")
close(es_shutdown) // signal to shutdown close(e.closeCh) // signal to shutdown
log.Println("ES shutdown(): calling es_wg.Wait() ...") log.Println("ES shutdown(): calling e.wg.Wait() ...")
es_wg.Wait() // Wait for the goroutine to shutdown e.wg.Wait() // Wait for the goroutine to shutdown
log.Println("ES shutdown(): es_wg.Wait() returned...") log.Println("ES shutdown(): e.wg.Wait() returned...")
} }
var devMap = map[int]string{0: "", 1: ""}
var sdrShutdown bool var sdrShutdown bool
func sdrKill() { func sdrKill() {
@ -319,20 +314,106 @@ func sdrKill() {
} }
} }
// Watch for config/device changes. func reCompile(s string) *regexp.Regexp {
func sdrWatcher() { // note , compile returns a nil pointer on error
var doSkip bool r, _ := regexp.Compile(s)
rES, err := regexp.Compile("str?a?t?u?x:1090") return r
if err != nil { }
rES = nil
log.Println("failed to compile ES regexp because %s", err.Error()) type regexUAT regexp.Regexp
type regexES regexp.Regexp
var rUAT = (*regexUAT)(reCompile("str?a?t?u?x:978"))
var rES = (*regexES)(reCompile("str?a?t?u?x:1090"))
func (r *regexUAT) hasID(serial string) bool {
if r == nil {
return strings.HasPrefix(serial, "stratux:978")
}
return (*regexp.Regexp)(r).MatchString(serial)
}
func (r *regexES) hasID(serial string) bool {
if r == nil {
return strings.HasPrefix(serial, "stratux:1090")
}
return (*regexp.Regexp)(r).MatchString(serial)
}
func createUATDev(id int, serial string, idSet bool) error {
UATDev = &UAT{indexID: id, serial: serial}
if err := UATDev.sdrConfig(); err != nil {
log.Printf("UATDev.sdrConfig() failed: %s\n", err)
UATDev = nil
return err
}
UATDev.wg = &sync.WaitGroup{}
UATDev.idSet = idSet
UATDev.closeCh = make(chan int)
UATDev.wg.Add(1)
go UATDev.read()
return nil
}
func createESDev(id int, serial string, idSet bool) error {
ESDev = &ES{indexID: id, serial: serial}
if err := ESDev.sdrConfig(); err != nil {
log.Printf("ESDev.sdrConfig() failed: %s\n", err)
ESDev = nil
return err
}
ESDev.wg = &sync.WaitGroup{}
ESDev.idSet = idSet
ESDev.closeCh = make(chan int)
ESDev.wg.Add(1)
go ESDev.read()
return nil
}
func configDevices(count int, es_enabled, uat_enabled bool) {
// entry to this function is only valid when both UATDev and ESDev are nil
// once the tagged dongles have been assigned, explicitly range over
// the remaining IDs and assign them to any anonymous dongles
unusedIDs := make(map[int]string)
// loop 1: assign tagged dongles
for i := 0; i < count; i++ {
_, _, s, err := rtl.GetDeviceUsbStrings(i)
if err == nil {
// no need to check if createXDev returned an error; if it
// failed to config the error is logged and we can ignore
// it here so it doesn't get queued up again
if uat_enabled && UATDev == nil && rUAT.hasID(s) {
createUATDev(i, s, true)
} else if es_enabled && ESDev == nil && rES.hasID(s) {
createESDev(i, s, true)
} else {
unusedIDs[i] = s
}
} else {
log.Printf("rtl.GetDeviceUsbStrings id %d: %s\n", i, err)
}
} }
rUAT, err := regexp.Compile("str?a?t?u?x:978") // loop 2; assign anonymous dongles, but sanity check the serial ids
if err != nil { // so we don't cross config for dual assigned dongles. E.g. when two
rUAT = nil // dongles are set to the same stratux id and the unconsumed, non-anonymous,
log.Println("failed to compile UAT regexp because %s", err.Error()) // dongle makes it to this loop.
for i, s := range unusedIDs {
if uat_enabled && UATDev == nil && !rES.hasID(s) {
createUATDev(i, s, false)
} else if es_enabled && ESDev == nil && !rUAT.hasID(s) {
createESDev(i, s, false)
}
} }
}
// Watch for config/device changes.
func sdrWatcher() {
prevCount := 0
prevUAT_Enabled := false
prevES_Enabled := false
for { for {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
@ -347,18 +428,17 @@ func sdrWatcher() {
} }
return return
} }
count := rtl.GetDeviceCount() count := rtl.GetDeviceCount()
atomic.StoreUint32(&globalStatus.Devices, uint32(count)) atomic.StoreUint32(&globalStatus.Devices, uint32(count))
// log.Println("DeviceCount...", count)
// support two and only two dongles // support two and only two dongles
if count > 2 { if count > 2 {
count = 2 count = 2
} }
// cleanup if necessary // check for either no dongles or none enabled
if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) { if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
// log.Println("count == 0, doing cleanup if necessary...")
if UATDev != nil { if UATDev != nil {
UATDev.shutdown() UATDev.shutdown()
UATDev = nil UATDev = nil
@ -367,117 +447,35 @@ func sdrWatcher() {
ESDev.shutdown() ESDev.shutdown()
ESDev = nil ESDev = nil
} }
prevCount = count
prevUAT_Enabled = false
prevES_Enabled = false
continue continue
} }
if count == 1 { // if the device count or the global settings change, do a reconfig.
if UATDev != nil && ESDev == nil { // both events are significant and the least convoluted way to handle it
UATDev.indexID = 0 // is to reconfigure all dongle/s across the board. The reconfig
} else if UATDev == nil && ESDev != nil { // should happen fairly quick so the user shouldn't notice any
ESDev.indexID = 0 // major disruption; if it is significant we can split the dongle
// count check from the global settings check where the gloabl settings
// check won't do a reconfig.
if count != prevCount || prevES_Enabled != globalSettings.ES_Enabled ||
prevUAT_Enabled != globalSettings.UAT_Enabled {
if UATDev != nil {
UATDev.shutdown()
UATDev = nil
} }
if ESDev != nil {
ESDev.shutdown()
ESDev = nil
}
configDevices(count, globalSettings.ES_Enabled, globalSettings.UAT_Enabled)
} }
// UAT specific handling prevCount = count
// When count is one, favor UAT in the case where the user prevUAT_Enabled = globalSettings.UAT_Enabled
// has enabled both UAT and ES via the web interface. prevES_Enabled = globalSettings.ES_Enabled
id := 0
if globalSettings.UAT_Enabled {
// log.Println("globalSettings.UAT_Enabled == true")
if count == 1 {
if ESDev != nil {
ESDev.shutdown()
ESDev = nil
}
} else { // count == 2
if UATDev == nil && ESDev != nil {
if ESDev.indexID == 0 {
id = 1
}
}
}
if UATDev == nil {
_, _, serial, err := rtl.GetDeviceUsbStrings(id)
if err != nil {
serial = ""
}
if (rES != nil) {
doSkip = rES.MatchString(serial)
} else {
doSkip = strings.Compare(serial, "stratux:1090") == 0
}
if !doSkip {
UATDev = &UAT{indexID: id, serial: serial}
if err := UATDev.sdrConfig(); err != nil {
log.Printf("UATDev = &UAT{indexID: id} failed: %s\n", err)
UATDev = nil
} else {
uat_shutdown = make(chan int)
uat_wg.Add(1)
go UATDev.read()
}
}
}
} else if UATDev != nil {
UATDev.shutdown()
UATDev = nil
if count == 1 && ESDev != nil {
ESDev.indexID = 0
}
}
// ES specific handling
id = 0
if globalSettings.ES_Enabled {
// log.Println("globalSettings.ES_Enabled == true")
if count == 1 {
if globalSettings.UAT_Enabled {
// defer to the UAT handler
goto End
}
} else { // count == 2
if ESDev == nil && UATDev != nil {
if UATDev.indexID == 0 {
id = 1
}
}
}
if ESDev == nil {
_, _, serial, err := rtl.GetDeviceUsbStrings(id)
if err != nil {
serial = ""
}
if (rUAT != nil) {
doSkip = rUAT.MatchString(serial)
} else {
doSkip = strings.Compare(serial, "stratux:978") == 0
}
if !doSkip {
ESDev = &ES{indexID: id, serial: serial}
if err := ESDev.sdrConfig(); err != nil {
log.Printf("ESDev = &ES{indexID: id} failed: %s\n", err)
ESDev = nil
} else {
es_shutdown = make(chan int)
es_wg.Add(1)
go ESDev.read()
}
}
}
} else if ESDev != nil {
ESDev.shutdown()
ESDev = nil
if count == 1 && UATDev != nil {
UATDev.indexID = 0
}
}
End:
} }
} }