Skip to content

Commit

Permalink
proto in 4x4x2 electric box
Browse files Browse the repository at this point in the history
  • Loading branch information
tonygilkerson committed Jun 25, 2023
1 parent df33db9 commit 9cd9720
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 93 deletions.
193 changes: 109 additions & 84 deletions cmd/mbx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ import (
"fmt"
"log"
"machine"
"runtime"
"time"

"github.com/tonygilkerson/marty/pkg/road"
)

const (
HEARTBEAT_DURATION_SECONDS = 300
EVENT_DURATION_SECONDS = 3
TICKER_MS = 1000
ADC_THRESHOLD = 2_000
)

/////////////////////////////////////////////////////////////////////////////
Expand All @@ -40,27 +38,62 @@ func main() {
loraRadio := road.SetupLora(machine.SPI0)

//
// Init ADC
// Setup charger
//
machine.InitADC() // init the machine's ADC subsystem


// CHG - Charge status (active low) pulls to GND (open drain) lighting the connected led when the battery is charging.
// If the battery is charged or the charger is disabled, CHG is disconnected from ground (high impedance) and the LED will be off.
chgPin := machine.GP10
chgPin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
log.Printf("chgPin status: %v\n", chgPin.Get())

// PGOOD - Power Good Status (active low). PGOOD pulls to GND (open drain) lighting the connected led when a valid input source is connected.
// If the input power source is not within specified limits, PGOOD is disconnected from ground (high impedance) and the LED will be off.
pgoodPin := machine.GP11
pgoodPin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
log.Printf("pgoodPin status: %v\n", pgoodPin.Get())

//
// Setup Mule
//
muleADC := machine.ADC{Pin: machine.ADC0}
muleCh := make(chan string)
mulePin := machine.GP12
mulePin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
log.Printf("mulePin status: %v\n", mulePin.Get())

mulePin.SetInterrupt(machine.PinRising, func(p machine.Pin) {

// Use non-blocking send so if the channel buffer is full,
// the value will get dropped instead of crashing the system
select {
case muleCh <- "up":
default:
}

})

//
// Setup mail
//
mailADC := machine.ADC{Pin: machine.ADC1}
mailCh := make(chan string)
mailPin := machine.GP13
mailPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
log.Printf("mailPin status: %v\n", mulePin.Get())

mailPin.SetInterrupt(machine.PinRising, func(p machine.Pin) {

// Use non-blocking send so if the channel buffer is full,
// the value will get dropped instead of crashing the system
select {
case mailCh <- "up":
default:
}

})

//
// Launch go routines
//
go mailMonitor(&mailADC, &chLoraTxRx)
go muleMonitor(&muleADC, &chLoraTxRx)
go temperatureMonitor(&muleADC, &chLoraTxRx)
go mailMonitor(&mailCh, &chLoraTxRx)
go muleMonitor(&muleCh, &chLoraTxRx)
go road.LoraTx(loraRadio, &chLoraTxRx)

// Main loop
Expand All @@ -69,15 +102,26 @@ func main() {
for range ticker.C {

log.Printf("------------------MainLoopHeartbeat-------------------- %v", count)
msg := fmt.Sprintf("RoadMainLoopHeartbeat-%v", count)
chLoraTxRx <- msg
count += 1
log.Printf("mailPin status: %v\n", mailPin.Get())
log.Printf("mulePin status: %v\n", mulePin.Get())

// // DEVTODO - remove me after test
// for i := 0; i < 5; i++ {
// msg := fmt.Sprintf("BATCH-SEND-%v", i)
// chLoraTxRx <- msg
// }
//
// Send Heartbeat to Tx queue
//
chLoraTxRx <- "RoadMainLoopHeartbeat"

//
// send charger status
//
sendChargerStatus(chgPin, pgoodPin, &chLoraTxRx)

//
// Send Temperature to Tx queue
//
sendTemperature(&chLoraTxRx)

runtime.Gosched()
}

}
Expand All @@ -101,78 +145,59 @@ func runLight(led machine.Pin, count int) {

}

func mailMonitor(mailADC *machine.ADC, chLoraTxRx *chan string) {
lastEvent := time.Now()
lastHeartbeat := time.Now()
active := false
func mailMonitor(ch *chan string, chLoraTxRx *chan string) {

for range *ch {
log.Println("Mailbox light up")
*chLoraTxRx <- "MailboxDoorOpened"

runtime.Gosched()
// Wait a long time to give mail man time to shut the door
time.Sleep(time.Second * 60)
log.Println("Mailbox light down")

ticker := time.NewTicker(time.Millisecond * TICKER_MS)
for range ticker.C {
fmt.Printf("a")

if mailADC.Get() > ADC_THRESHOLD {
lastEvent = time.Now()
if !active {
active = true
log.Println("Mailbox light rising")
*chLoraTxRx <- "MailboxDoorOpened"
}
} else {

if active && time.Since(lastEvent) > EVENT_DURATION_SECONDS*time.Second {
active = false
log.Println("Mailbox light falling")
}

if time.Since(lastHeartbeat) > HEARTBEAT_DURATION_SECONDS*time.Second {
lastHeartbeat = time.Now()
log.Println("Mailbox Heartbeat")
*chLoraTxRx <- "MailboxDoorOpenedHeartbeat"
}
}
}

}

func muleMonitor(muleADC *machine.ADC, chLoraTxRx *chan string) {
lastEvent := time.Now()
lastHeartbeat := time.Now()
active := false
func muleMonitor(ch *chan string, chLoraTxRx *chan string) {

for range *ch {
log.Println("Mule light up")
*chLoraTxRx <- "MuleAlarm"

runtime.Gosched()
time.Sleep(time.Second * 4)
log.Println("Mule light down")

ticker := time.NewTicker(time.Millisecond * TICKER_MS)
for range ticker.C {
fmt.Printf("U")

if muleADC.Get() > ADC_THRESHOLD {
lastEvent = time.Now()
if !active {
active = true
log.Println("Mule light rising")
*chLoraTxRx <- "MuleAlarm"
}
} else {

if active && time.Since(lastEvent) > EVENT_DURATION_SECONDS*time.Second {
active = false
log.Println("Mule light falling")
}

if time.Since(lastHeartbeat) > HEARTBEAT_DURATION_SECONDS*time.Second {
lastHeartbeat = time.Now()
log.Println("Mule Heartbeat")
*chLoraTxRx <- "MuleAlarmHeartbeat"
}
}
}
}

func temperatureMonitor(muleADC *machine.ADC, chLoraTxRx *chan string) {
func sendTemperature(chLoraTxRx *chan string) {

ticker := time.NewTicker(time.Second * HEARTBEAT_DURATION_SECONDS)
for range ticker.C {
fmt.Printf("T")
// F = ( (ReadTemperature /1000) * 9/5) + 32
fahrenheit := ( (machine.ReadTemperature()/1000) * 9/5) + 32
fmt.Printf("fahrenheit: %v\n", fahrenheit)
*chLoraTxRx <- fmt.Sprintf("MailboxTemperature:%v", fahrenheit)
// F = ( (ReadTemperature /1000) * 9/5) + 32
fahrenheit := ((machine.ReadTemperature() / 1000) * 9 / 5) + 32
fmt.Printf("fahrenheit: %v\n", fahrenheit)
*chLoraTxRx <- fmt.Sprintf("MailboxTemperature:%v", fahrenheit)

}

func sendChargerStatus(chgPin machine.Pin, pgoodPin machine.Pin, chLoraTxRx *chan string) {

if pgoodPin.Get() {
log.Println("Power source bad")
*chLoraTxRx <- "ChargerPowerSourceBad"
} else {
log.Println("Power source good")
*chLoraTxRx <- "ChargerPowerSourceGood"
}

if chgPin.Get() {
log.Println("Charger off")
*chLoraTxRx <- "ChargerChargeStatusOff"
} else {
log.Println("Charger on")
*chLoraTxRx <- "ChargerChargeStatusOn"
}

}
33 changes: 24 additions & 9 deletions pkg/road/road.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package road
import (
"log"
"machine"
"runtime"
"time"

"tinygo.org/x/drivers/lora"
Expand All @@ -21,7 +22,7 @@ var (
SX127X_PIN_RST = machine.GP20
SX127X_PIN_CS = machine.GP17
SX127X_PIN_DIO0 = machine.GP21 // (GP21--G0) Must be connected from pico to breakout for radio events IRQ to work
SX127X_PIN_DIO1 = machine.GP22 // (GP22--G1)I don't now what this does, it is assigned but I did not connect form pico to breakout
SX127X_PIN_DIO1 = machine.GP22 // (GP22--G1)I don't now what this does but it seems to need to be connected
SX127X_SPI = machine.SPI0
)

Expand All @@ -34,8 +35,8 @@ func SetupLora(spi *machine.SPI) *sx127x.Device {

spi.Configure(machine.SPIConfig{
SCK: machine.SPI0_SCK_PIN, // GP18
SDO: machine.SPI0_SDO_PIN, // GP19
SDI: machine.SPI0_SDI_PIN, // GP16
SDO: machine.SPI0_SDO_PIN, // GP19 aka MOSI
SDI: machine.SPI0_SDI_PIN, // GP16 aka MISO
})

SX127X_SPI.Configure(machine.SPIConfig{Frequency: 500000, Mode: 0})
Expand Down Expand Up @@ -79,28 +80,38 @@ func LoraTx(loraRadio *sx127x.Device, ch *chan string) {

ticker := time.NewTicker(time.Second * 10)
for range ticker.C {

//
// If there are no messages in the channel then get out quick
//
if len(*ch) == 0 {
log.Println("LoraTx channel is empty, getting out early...")
continue
}

// Enable the radio
SX127X_PIN_EN.High()

//
// RX
//
tStart := time.Now()
log.Println("Receiving Lora for 5 seconds")
log.Println("RX Start - Receiving Lora for 5 seconds")
for time.Since(tStart) < 5*time.Second {
// for time.Since(tStart) < 2*time.Second {
buf, err := loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
if err != nil {
log.Println("RX Error: ", err)
} else if buf != nil {
log.Println("Packet Received: ", string(buf))
log.Println("Packet Received: ", buf)
}
}
log.Println("End Lora RX")
log.Println("RX End")

//
// TX
//
log.Println("Start Lora TX")
log.Println("TX Start")
var batchMsg string

// Concatenate all messages separated by \n
Expand All @@ -123,20 +134,24 @@ func LoraTx(loraRadio *sx127x.Device, ch *chan string) {
}
}

//
// Now that we have consumed all the messages from the channel Tx
//
if len(batchMsg) > 0 {
log.Println("LORA TX: ", batchMsg)
log.Println("TX: ", batchMsg)
err := loraRadio.Tx([]byte(batchMsg), LORA_DEFAULT_TXTIMEOUT_MS)
if err != nil {
log.Println("TX Error:", err)
}
} else {
log.Println("nothing to send")
}
log.Println("End Lora TX")
log.Println("TX End")

// Disable the radio to save power...
SX127X_PIN_EN.Low()

runtime.Gosched()
}

}

0 comments on commit 9cd9720

Please sign in to comment.