-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into ahrs_dev
# Conflicts: # Makefile # main/equations.go # main/gen_gdl90.go
- Loading branch information
Showing
11 changed files
with
293 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package main | ||
|
||
import ( | ||
"io/ioutil" | ||
"strconv" | ||
"strings" | ||
"time" | ||
) | ||
|
||
const invalidCpuTemp = float32(-99.0) | ||
|
||
type CpuTempUpdateFunc func(cpuTemp float32) | ||
|
||
/* cpuTempMonitor() reads the RPi board temperature every second and | ||
calls a callback. This is broken out into its own function (run as | ||
its own goroutine) because the RPi temperature monitor code is buggy, | ||
and often times reading this file hangs quite some time. */ | ||
|
||
func cpuTempMonitor(updater CpuTempUpdateFunc) { | ||
timer := time.NewTicker(1 * time.Second) | ||
for { | ||
<-timer.C | ||
|
||
// Update CPUTemp. | ||
temp, err := ioutil.ReadFile("/sys/class/thermal/thermal_zone0/temp") | ||
tempStr := strings.Trim(string(temp), "\n") | ||
t := invalidCpuTemp | ||
if err == nil { | ||
tInt, err := strconv.Atoi(tempStr) | ||
if err == nil { | ||
if tInt > 1000 { | ||
t = float32(tInt) / float32(1000.0) | ||
} else { | ||
t = float32(tInt) // case where Temp is returned as simple integer | ||
} | ||
} | ||
} | ||
if t >= invalidCpuTemp { // Only update if valid value was obtained. | ||
updater(t) | ||
} | ||
|
||
} | ||
} | ||
|
||
// Check if CPU temperature is valid. Assume <= 0 is invalid. | ||
func isCPUTempValid(cpuTemp float32) bool { | ||
return cpuTemp > 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"github.com/takama/daemon" | ||
"log" | ||
"net" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
) | ||
|
||
// #include <wiringPi.h> | ||
// #cgo LDFLAGS: -lwiringPi | ||
import "C" | ||
|
||
const ( | ||
// CPU temperature target, degrees C | ||
defaultTempTarget = 50. | ||
hysteresis = float32(1.) | ||
|
||
/* This puts our PWM frequency at 19.2 MHz / 128 = | ||
/* 150kHz. Higher frequencies will reduce audible switching | ||
/* noise but will be less efficient */ | ||
pwmClockDivisor = 128 | ||
|
||
/* Minimum duty cycle is the point below which the fan does | ||
/* not spin. This depends on both your fan and the switching | ||
/* transistor used. */ | ||
defaultPwmDutyMin = 20 | ||
pwmDutyMax = 256 | ||
|
||
// how often to update | ||
delaySeconds = 2 | ||
|
||
// GPIO-1/BCM "18"/Pin 12 on a Raspberry PI 3 | ||
defaultPin = 1 | ||
|
||
// name of the service | ||
name = "fancontrol" | ||
description = "cooling fan speed control based on CPU temperature" | ||
|
||
// port which daemon should be listen | ||
port = ":9977" | ||
) | ||
|
||
var stdlog, errlog *log.Logger | ||
|
||
func fanControl(pwmDutyMin int, pin int, tempTarget float32) { | ||
cPin := C.int(pin) | ||
C.wiringPiSetup() | ||
C.pwmSetMode(C.PWM_MODE_BAL) | ||
C.pinMode(cPin, C.PWM_OUTPUT) | ||
C.pwmSetRange(pwmDutyMax) | ||
C.pwmSetClock(pwmClockDivisor) | ||
C.pwmWrite(cPin, C.int(pwmDutyMin)) | ||
temp := float32(0.) | ||
go cpuTempMonitor(func(cpuTemp float32) { | ||
if isCPUTempValid(cpuTemp) { | ||
temp = cpuTemp | ||
} | ||
}) | ||
pwmDuty := 0 | ||
for { | ||
if temp > (tempTarget + hysteresis) { | ||
pwmDuty = iMax(iMin(pwmDutyMax, pwmDuty+1), pwmDutyMin) | ||
} else if temp < (tempTarget - hysteresis) { | ||
pwmDuty = iMax(pwmDuty-1, 0) | ||
if pwmDuty < pwmDutyMin { | ||
pwmDuty = 0 | ||
} | ||
} | ||
//log.Println(temp, " ", pwmDuty) | ||
C.pwmWrite(cPin, C.int(pwmDuty)) | ||
time.Sleep(delaySeconds * time.Second) | ||
} | ||
} | ||
|
||
// Service has embedded daemon | ||
type Service struct { | ||
daemon.Daemon | ||
} | ||
|
||
// Manage by daemon commands or run the daemon | ||
func (service *Service) Manage() (string, error) { | ||
|
||
tempTarget := flag.Float64("temp", defaultTempTarget, "Target CPU Temperature, degrees C") | ||
pwmDutyMin := flag.Int("minduty", defaultPwmDutyMin, "Minimum PWM duty cycle") | ||
pin := flag.Int("pin", defaultPin, "PWM pin (wiringPi numbering)") | ||
flag.Parse() | ||
|
||
usage := "Usage: " + name + " install | remove | start | stop | status" | ||
// if received any kind of command, do it | ||
if flag.NArg() > 0 { | ||
command := os.Args[flag.NFlag()+1] | ||
switch command { | ||
case "install": | ||
return service.Install() | ||
case "remove": | ||
return service.Remove() | ||
case "start": | ||
return service.Start() | ||
case "stop": | ||
return service.Stop() | ||
case "status": | ||
return service.Status() | ||
default: | ||
return usage, nil | ||
} | ||
} | ||
|
||
go fanControl(*pwmDutyMin, *pin, float32(*tempTarget)) | ||
|
||
// Set up channel on which to send signal notifications. | ||
// We must use a buffered channel or risk missing the signal | ||
// if we're not ready to receive when the signal is sent. | ||
interrupt := make(chan os.Signal, 1) | ||
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) | ||
|
||
// Set up listener for defined host and port | ||
listener, err := net.Listen("tcp", port) | ||
if err != nil { | ||
return "Possibly was a problem with the port binding", err | ||
} | ||
|
||
// set up channel on which to send accepted connections | ||
listen := make(chan net.Conn, 100) | ||
go acceptConnection(listener, listen) | ||
|
||
// loop work cycle with accept connections or interrupt | ||
// by system signal | ||
for { | ||
select { | ||
case conn := <-listen: | ||
go handleClient(conn) | ||
case killSignal := <-interrupt: | ||
stdlog.Println("Got signal:", killSignal) | ||
stdlog.Println("Stoping listening on ", listener.Addr()) | ||
listener.Close() | ||
if killSignal == os.Interrupt { | ||
return "Daemon was interrupted by system signal", nil | ||
} | ||
return "Daemon was killed", nil | ||
} | ||
} | ||
} | ||
|
||
// Accept a client connection and collect it in a channel | ||
func acceptConnection(listener net.Listener, listen chan<- net.Conn) { | ||
for { | ||
conn, err := listener.Accept() | ||
if err != nil { | ||
continue | ||
} | ||
listen <- conn | ||
} | ||
} | ||
|
||
func handleClient(client net.Conn) { | ||
for { | ||
buf := make([]byte, 4096) | ||
numbytes, err := client.Read(buf) | ||
if numbytes == 0 || err != nil { | ||
return | ||
} | ||
client.Write(buf[:numbytes]) | ||
} | ||
} | ||
|
||
func init() { | ||
stdlog = log.New(os.Stdout, "", 0) | ||
errlog = log.New(os.Stderr, "", 0) | ||
} | ||
|
||
func main() { | ||
srv, err := daemon.New(name, description, []string{}...) | ||
if err != nil { | ||
errlog.Println("Error: ", err) | ||
os.Exit(1) | ||
} | ||
service := &Service{srv} | ||
status, err := service.Manage() | ||
if err != nil { | ||
errlog.Println(status, "\nError: ", err) | ||
os.Exit(1) | ||
} | ||
fmt.Println(status) | ||
} |
Oops, something went wrong.