Vendoring updates
parent
16f7ddcd58
commit
8b0c907c3d
@ -1,25 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
# - "1.10"
|
||||
- "tip"
|
||||
|
||||
# first part of the GOARCH workaround
|
||||
# setting the GOARCH directly doesn't work, since the value will be overwritten later
|
||||
# so set it to a temporary environment variable first
|
||||
env:
|
||||
global:
|
||||
TRAVIS_CGO_ENABLED=1
|
||||
TRAVIS_GOOS=linux
|
||||
matrix:
|
||||
- TRAVIS_GOARCH=amd64
|
||||
- TRAVIS_GOARCH=arm TRAVIS_CC=arm-linux-gnueabi-gcc TRAVIS_GOARM=6
|
||||
|
||||
# second part of the GOARCH workaround
|
||||
# now actually set the GOARCH env variable to the value of the temporary variable set earlier
|
||||
before_install:
|
||||
- sudo apt-get install gcc-arm-linux-gnueabi # for CGO cross compile to ARM
|
||||
- export CGO_ENABLED=$TRAVIS_CGO_ENABLED GOARCH=$TRAVIS_GOARCH GOARM=$TRAVIS_GOARM GOOS=$TRAVIS_GOOS CC=$TRAVIS_CC
|
||||
- go env # for debugging
|
||||
- go tool dist env # for debugging
|
||||
|
||||
|
@ -1,91 +0,0 @@
|
||||
|
||||
BH1750 ambient light sensor
|
||||
=====================
|
||||
|
||||
[](https://travis-ci.org/d2r2/go-bh1750)
|
||||
[](https://goreportcard.com/report/github.com/d2r2/go-bh1750)
|
||||
[](https://godoc.org/github.com/d2r2/go-bh1750)
|
||||
[](./LICENSE)
|
||||
|
||||
BH1750 ([general specification](https://raw.github.com/d2r2/go-bh1750/master/docs/bh1750fvi-e-186247.pdf)) is a power effective ambient light sensor with spectral response close to human eye. Sensor returns measured ambient light value in lux units. Easily integrated with Arduino and Raspberry PI via i2c communication interface:
|
||||

|
||||
|
||||
Here is a library written in [Go programming language](https://golang.org/) for Raspberry PI and counterparts, which gives you in the output ambient light value (making all necessary i2c-bus interacting and values computing).
|
||||
|
||||
Golang usage
|
||||
------------
|
||||
|
||||
|
||||
```go
|
||||
func main() {
|
||||
// Create new connection to i2c-bus on 0 line with address 0x23.
|
||||
// Use i2cdetect utility to find device address over the i2c-bus
|
||||
i2c, err := i2c.NewI2C(0x23, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer i2c.Close()
|
||||
|
||||
sensor := bh1750.NewBH1750()
|
||||
|
||||
resolution := bh1750.HighResolution
|
||||
amb, err := sensor.MeasureAmbientLight(i2c, resolution)
|
||||
if err != nil {
|
||||
lg.Fatal(err)
|
||||
}
|
||||
log.Printf("Ambient light (%s) = %v lx", resolution, amb)
|
||||
```
|
||||
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
GoDoc [documentation](http://godoc.org/github.com/d2r2/go-bh1750)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/d2r2/go-bh1750
|
||||
```
|
||||
|
||||
Troubleshooting
|
||||
--------------
|
||||
|
||||
- *How to obtain fresh Golang installation to RPi device (either any RPi clone):*
|
||||
If your RaspberryPI golang installation taken by default from repository is outdated, you may consider
|
||||
to install actual golang manually from official Golang [site](https://golang.org/dl/). Download
|
||||
tar.gz file containing armv6l in the name. Follow installation instructions.
|
||||
|
||||
- *How to enable I2C bus on RPi device:*
|
||||
If you employ RaspberryPI, use raspi-config utility to activate i2c-bus on the OS level.
|
||||
Go to "Interfacing Options" menu, to active I2C bus.
|
||||
Probably you will need to reboot to load i2c kernel module.
|
||||
Finally you should have device like /dev/i2c-1 present in the system.
|
||||
|
||||
- *How to find I2C bus allocation and device address:*
|
||||
Use i2cdetect utility in format "i2cdetect -y X", where X may vary from 0 to 5 or more,
|
||||
to discover address occupied by peripheral device. To install utility you should run
|
||||
`apt install i2c-tools` on debian-kind system. `i2cdetect -y 1` sample output:
|
||||
```
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
00: -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
70: -- -- -- -- -- -- 76 --
|
||||
```
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
Please use [Github issue tracker](https://github.com/d2r2/go-bh1750/issues) for filing bugs or feature requests.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Go-bh1750 is licensed under MIT License.
|
@ -1,323 +0,0 @@
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2018 Denis Dyakov
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
// portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
package bh1750
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
i2c "github.com/d2r2/go-i2c"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
// Command bytes
|
||||
const (
|
||||
// No active state.
|
||||
CMD_POWER_DOWN = 0x00
|
||||
|
||||
// Waiting for measurement command.
|
||||
CMD_POWER_ON = 0x01
|
||||
|
||||
// Reset Data register value.
|
||||
// Reset command is not acceptable in Power Down mode.
|
||||
CMD_RESET = 0x07
|
||||
|
||||
// Start measurement at 1lx resolution.
|
||||
// Measurement Time is typically 120ms.
|
||||
CMD_CONTINUOUSLY_H_RES_MODE = 0x10
|
||||
|
||||
// Start measurement at 0.5lx resolution.
|
||||
// Measurement Time is typically 120ms.
|
||||
CMD_CONTINUOUSLY_H_RES_MODE2 = 0x11
|
||||
|
||||
// Start measurement at 4lx resolution.
|
||||
// Measurement Time is typically 16ms.
|
||||
CMD_CONTINUOUSLY_L_RES_MODE = 0x13
|
||||
|
||||
// Start measurement at 1lx resolution.
|
||||
// Measurement Time is typically 120ms.
|
||||
// It is automatically set to Power Down mode after measurement
|
||||
CMD_ONE_TIME_H_RES_MODE = 0x20
|
||||
|
||||
// Start measurement at 0.5lx resolution.
|
||||
// Measurement Time is typically 120ms.
|
||||
// It is automatically set to Power Down mode after measurement.
|
||||
CMD_ONE_TIME_H_RES_MODE2 = 0x21
|
||||
|
||||
// Start measurement at 4lx resolution.
|
||||
// Measurement Time is typically 16ms.
|
||||
// It is automatically set to Power Down mode after measurement.
|
||||
CMD_ONE_TIME_L_RES_MODE = 0x23
|
||||
|
||||
// Change measurement time. 01000_MT[7,6,5]
|
||||
CMD_CHANGE_MEAS_TIME_HIGH = 0x40
|
||||
|
||||
// Change measurement time. 011_MT[4,3,2,1,0]
|
||||
CMD_CHANGE_MEAS_TIME_LOW = 0x60
|
||||
)
|
||||
|
||||
// ResolutionMode define sensor sensitivity
|
||||
// and measure time. Be aware, that improving
|
||||
// sensitivity lead to increasing of measurement time.
|
||||
type ResolutionMode int
|
||||
|
||||
const (
|
||||
// LowResolution precision 4 lx, 16 ms measurement time
|
||||
LowResolution ResolutionMode = iota + 1
|
||||
// HighResolution precision 1 lx, 120 ms measurement time
|
||||
HighResolution
|
||||
// HighestResolution precision 0.5 lx, 120 ms measurement time
|
||||
HighestResolution
|
||||
)
|
||||
|
||||
// String define stringer interface.
|
||||
func (v ResolutionMode) String() string {
|
||||
switch v {
|
||||
case LowResolution:
|
||||
return "Low Resolution"
|
||||
case HighResolution:
|
||||
return "High Resolution"
|
||||
case HighestResolution:
|
||||
return "Highest Resolution"
|
||||
default:
|
||||
return "<unknown>"
|
||||
}
|
||||
}
|
||||
|
||||
// BH1750 it's a sensor itself.
|
||||
type BH1750 struct {
|
||||
// Since sensor have no register
|
||||
// to report current state, we save
|
||||
// last issued command to fill this gap.
|
||||
lastCmd byte
|
||||
lastResolution ResolutionMode
|
||||
factor byte
|
||||
}
|
||||
|
||||
// NewBH1750 return new sensor instance.
|
||||
func NewBH1750() *BH1750 {
|
||||
v := &BH1750{}
|
||||
v.factor = v.GetDefaultSensivityFactor()
|
||||
return v
|
||||
}
|
||||
|
||||
// Reset clear ambient light register value.
|
||||
func (v *BH1750) Reset(i2c *i2c.I2C) error {
|
||||
lg.Debug("Reset sensor...")
|
||||
_, err := i2c.WriteBytes([]byte{CMD_RESET})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.lastCmd = CMD_RESET
|
||||
time.Sleep(time.Microsecond * 3)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PowerDown return register to idle state.
|
||||
func (v *BH1750) PowerDown(i2c *i2c.I2C) error {
|
||||
lg.Debug("Power down sensor...")
|
||||
_, err := i2c.WriteBytes([]byte{CMD_POWER_DOWN})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.lastCmd = CMD_POWER_DOWN
|
||||
return nil
|
||||
}
|
||||
|
||||
// PowerOn activate sensor.
|
||||
func (v *BH1750) PowerOn(i2c *i2c.I2C) error {
|
||||
lg.Debug("Power on sensor...")
|
||||
_, err := i2c.WriteBytes([]byte{CMD_POWER_ON})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.lastCmd = CMD_POWER_ON
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get internal parameters used to program sensor.
|
||||
func (v *BH1750) getResolutionData(resolution ResolutionMode) (cmd byte,
|
||||
wait time.Duration, divider uint32) {
|
||||
|
||||
switch resolution {
|
||||
case LowResolution:
|
||||
cmd = CMD_ONE_TIME_L_RES_MODE
|
||||
divider = 1
|
||||
// typical measure time is 16 ms,
|
||||
// but as it was found 24 ms max time
|
||||
// gives better results
|
||||
wait = time.Millisecond * 24
|
||||
case HighResolution:
|
||||
cmd = CMD_ONE_TIME_H_RES_MODE
|
||||
divider = 1
|
||||
// typical measure time
|
||||
wait = time.Millisecond * 120
|
||||
case HighestResolution:
|
||||
cmd = CMD_ONE_TIME_H_RES_MODE2
|
||||
divider = 2
|
||||
// typical measure time
|
||||
wait = time.Millisecond * 120
|
||||
}
|
||||
wait = wait * time.Duration(v.factor) /
|
||||
time.Duration(v.GetDefaultSensivityFactor())
|
||||
|
||||
return cmd, wait, divider
|
||||
}
|
||||
|
||||
// MeasureAmbientLight measure and return ambient light once in lux.
|
||||
func (v *BH1750) MeasureAmbientLight(i2c *i2c.I2C,
|
||||
resolution ResolutionMode) (uint16, error) {
|
||||
|
||||
lg.Debug("Run one time measure...")
|
||||
|
||||
cmd, wait, divider := v.getResolutionData(resolution)
|
||||
|
||||
v.lastCmd = cmd
|
||||
v.lastResolution = resolution
|
||||
|
||||
_, err := i2c.WriteBytes([]byte{cmd})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
time.Sleep(wait)
|
||||
|
||||
var data struct {
|
||||
Data [2]byte
|
||||
}
|
||||
err = readDataToStruct(i2c, 2, binary.BigEndian, &data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
amb := uint16(uint32(uint16(data.Data[0])<<8|uint16(data.Data[1])) *
|
||||
5 / 6 / divider)
|
||||
|
||||
return amb, nil
|
||||
}
|
||||
|
||||
// StartMeasureAmbientLightContinuously start continuous
|
||||
// measurement process. Use FetchMeasuredAmbientLight to get
|
||||
// average ambient light amount collected and calculated over a time.
|
||||
// Use PowerDown to stop measurements and return sensor to idle state.
|
||||
func (v *BH1750) StartMeasureAmbientLightContinuously(i2c *i2c.I2C,
|
||||
resolution ResolutionMode) (wait time.Duration, err error) {
|
||||
|
||||
lg.Debug("Start measures continuously...")
|
||||
|
||||
cmd, wait, _ := v.getResolutionData(resolution)
|
||||
|
||||
v.lastCmd = cmd
|
||||
v.lastResolution = resolution
|
||||
|
||||
_, err = i2c.WriteBytes([]byte{cmd})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Wait first time to collect necessary
|
||||
// amount of light for correct results.
|
||||
// It's not necessary to wait next time
|
||||
// same amount of time, because
|
||||
// sensor accumulate average lux amount
|
||||
// without any overwrite old value.
|
||||
time.Sleep(wait)
|
||||
|
||||
// In any case we are returning same
|
||||
// recommended amount of time to wait
|
||||
// between measures.
|
||||
return wait, nil
|
||||
}
|
||||
|
||||
// FetchMeasuredAmbientLight return current average ambient light in lux.
|
||||
// Previous command should be any continuous measurement initiation,
|
||||
// otherwise error will be reported.
|
||||
func (v *BH1750) FetchMeasuredAmbientLight(i2c *i2c.I2C) (uint16, error) {
|
||||
|
||||
lg.Debug("Fetch measured data...")
|
||||
|
||||
cmd, _, divider := v.getResolutionData(v.lastResolution)
|
||||
|
||||
if v.lastCmd != cmd {
|
||||
return 0, errors.New(
|
||||
"can't fetch measured ambient light, since last command doesn't match")
|
||||
}
|
||||
|
||||
var data struct {
|
||||
Data [2]byte
|
||||
}
|
||||
err := readDataToStruct(i2c, 2, binary.BigEndian, &data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
amb := uint16(uint32(uint16(data.Data[0])<<8|uint16(data.Data[1])) *
|
||||
5 / 6 / divider)
|
||||
|
||||
return amb, nil
|
||||
}
|
||||
|
||||
// GetDefaultSensivityFactor return factor value
|
||||
// used when your sensor have no any protection cover.
|
||||
// This is default setting according to specification.
|
||||
func (v *BH1750) GetDefaultSensivityFactor() byte {
|
||||
return 69
|
||||
}
|
||||
|
||||
// ChangeSensivityFactor used when you close sensor
|
||||
// with protection cover, which change (ordinary decrease)
|
||||
// expected amount of light falling on the sensor.
|
||||
// In this case you should calibrate you sensor and find
|
||||
// appropriate factor to get in output correct ambient light value.
|
||||
// Be aware, that improving sensitivity will increase
|
||||
// measurement time.
|
||||
func (v *BH1750) ChangeSensivityFactor(i2c *i2c.I2C, factor byte) error {
|
||||
|
||||
lg.Debug("Change sensitivity factor...")
|
||||
|
||||
// minimum limit
|
||||
const minValue = 31
|
||||
// maximum limit
|
||||
const maxValue = 254
|
||||
|
||||
if factor < minValue || factor > maxValue {
|
||||
return errors.New(spew.Sprintf("sensitivity factor value exceed range [%d..%d]",
|
||||
minValue, maxValue))
|
||||
}
|
||||
|
||||
high := (factor & 0xE0) >> 5
|
||||
_, err := i2c.WriteBytes([]byte{CMD_CHANGE_MEAS_TIME_HIGH | high})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
low := (factor & 0x1F)
|
||||
_, err = i2c.WriteBytes([]byte{CMD_CHANGE_MEAS_TIME_LOW | low})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.factor = factor
|
||||
|
||||
return nil
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package bh1750
|
||||
|
||||
import logger "github.com/d2r2/go-logger"
|
||||
|
||||
// You can manage verbosity of log output
|
||||
// in the package by changing last parameter value.
|
||||
var lg = logger.NewPackageLogger("bh1750",
|
||||
logger.DebugLevel,
|
||||
// logger.InfoLevel,
|
||||
)
|
@ -1,106 +0,0 @@
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2018 Denis Dyakov
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
// portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
package bh1750
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"math"
|
||||
|
||||
i2c "github.com/d2r2/go-i2c"
|
||||
)
|
||||
|
||||
// Utility functions
|
||||
|
||||
// getS16BE extract 2-byte integer as signed big-endian.
|
||||
func getS16BE(buf []byte) int16 {
|
||||
v := int16(buf[0])<<8 + int16(buf[1])
|
||||
return v
|
||||
}
|
||||
|
||||
// getS16LE extract 2-byte integer as signed little-endian.
|
||||
func getS16LE(buf []byte) int16 {
|
||||
w := getS16BE(buf)
|
||||
// exchange bytes
|
||||
v := (w&0xFF)<<8 + w>>8
|
||||
return v
|
||||
}
|
||||
|
||||
// getU16BE extract 2-byte integer as unsigned big-endian.
|
||||
func getU16BE(buf []byte) uint16 {
|
||||
v := uint16(buf[0])<<8 + uint16(buf[1])
|
||||
return v
|
||||
}
|
||||
|
||||
// getU16LE extract 2-byte integer as unsigned little-endian.
|
||||
func getU16LE(buf []byte) uint16 {
|
||||
w := getU16BE(buf)
|
||||
// exchange bytes
|
||||
v := (w&0xFF)<<8 + w>>8
|
||||
return v
|
||||
}
|
||||
|
||||
func calcCRC1(seed byte, buf []byte) byte {
|
||||
for i := 0; i < len(buf); i++ {
|
||||
b := buf[ /*len(buf)-1-*/ i]
|
||||
for j := 0; j < 8; j++ {
|
||||
if (seed^b)&0x01 != 0 {
|
||||
seed ^= 0x18
|
||||
seed >>= 1
|
||||
seed |= 0x80
|
||||
// crc = crc ^ 0x8c
|
||||
} else {
|
||||
seed >>= 1
|
||||
}
|
||||
b >>= 1
|
||||
}
|
||||
}
|
||||
return seed
|
||||
}
|
||||
|
||||
// Round float amount to certain precision.
|
||||
func round64(value float64, precision int) float64 {
|
||||
value2 := math.Round(value*math.Pow10(precision)) /
|
||||
math.Pow10(precision)
|
||||
return value2
|
||||
}
|
||||
|
||||
// Round float amount to certain precision.
|
||||
func round32(value float32, precision int) float32 {
|
||||
return float32(round64(float64(value), precision))
|
||||
}
|
||||
|
||||
// Read byte block from i2c device to struct object.
|
||||
func readDataToStruct(i2c *i2c.I2C, byteCount int,
|
||||
byteOrder binary.ByteOrder, obj interface{}) error {
|
||||
buf1 := make([]byte, byteCount)
|
||||
_, err := i2c.ReadBytes(buf1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := bytes.NewBuffer(buf1)
|
||||
err = binary.Read(buf, byteOrder, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- "1.10"
|
||||
# - "tip"
|
||||
|
||||
# first part of the GOARCH workaround
|
||||
# setting the GOARCH directly doesn't work, since the value will be overwritten later
|
||||
# so set it to a temporary environment variable first
|
||||
env:
|
||||
global:
|
||||
TRAVIS_CGO_ENABLED=1
|
||||
TRAVIS_GOOS=linux
|
||||
matrix:
|
||||
- TRAVIS_GOARCH=amd64
|
||||
- TRAVIS_GOARCH=arm TRAVIS_CC=arm-linux-gnueabi-gcc TRAVIS_GOARM=6
|
||||
|
||||
# second part of the GOARCH workaround
|
||||
# now actually set the GOARCH env variable to the value of the temporary variable set earlier
|
||||
before_install:
|
||||
- sudo apt-get install gcc-arm-linux-gnueabi crossbuild-essential-armel # for CGO cross compile to ARM
|
||||
- export CGO_ENABLED=$TRAVIS_CGO_ENABLED GOARCH=$TRAVIS_GOARCH GOARM=$TRAVIS_GOARM GOOS=$TRAVIS_GOOS CC=$TRAVIS_CC
|
||||
- go env # for debugging
|
||||
- go tool dist env # for debugging
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Denis Dyakov
|
||||
Copyright (c) 2013 Dave Cheney
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,97 +0,0 @@
|
||||
I2C-bus interaction of peripheral sensors with Raspberry PI embedded linux or respective clones
|
||||
==============================================================================================
|
||||
|
||||
[](https://travis-ci.org/d2r2/go-i2c)
|
||||
[](https://goreportcard.com/report/github.com/d2r2/go-i2c)
|
||||
[](https://godoc.org/github.com/d2r2/go-i2c)
|
||||
[](./LICENSE)
|
||||
|
||||
This library written in [Go programming language](https://golang.org/) intended to activate and interact with the I2C bus by reading and writing data.
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
Tested on Raspberry Pi 1 (model B), Raspberry Pi 3 B+, Banana Pi (model M1), Orange Pi Zero, Orange Pi One.
|
||||
|
||||
Golang usage
|
||||
------------
|
||||
|
||||
```go
|
||||
func main() {
|
||||
// Create new connection to I2C bus on 2 line with address 0x27
|
||||
i2c, err := i2c.NewI2C(0x27, 2)
|
||||
if err != nil { log.Fatal(err) }
|
||||
// Free I2C connection on exit
|
||||
defer i2c.Close()
|
||||
....
|
||||
// Here goes code specific for sending and reading data
|
||||
// to and from device connected via I2C bus, like:
|
||||
_, err := i2c.Write([]byte{0x1, 0xF3})
|
||||
if err != nil { log.Fatal(err) }
|
||||
....
|
||||
}
|
||||
```
|
||||
|
||||
Tutorial
|
||||
--------
|
||||
|
||||
My [repositories](https://github.com/d2r2?tab=repositories) contain quite a lot projects, which use i2c library as a starting point to interact with various peripheral devices and sensors for use on embedded Linux devices. All these libraries start with a standard call to open I2C-connection to specific bus line and address, than pass i2c instance to device.
|
||||
|
||||
In its turn, go-i2c use [go-logger](https://github.com/d2r2/go-logger) library to output debug and other notification's lines which produce all necessary levels of logging. You can manage what level of verbosity you would like to see, by adding call:
|
||||
```go
|
||||
// Uncomment/comment next line to suppress/increase verbosity of output
|
||||
logger.ChangePackageLogLevel("i2c", logger.InfoLevel)
|
||||
```
|
||||
Once you put this call, it will decrease verbosity from default "Debug" up to next "Info" level, reducing the number of low-level console outputs that occur during interaction with the I2C bus. Please, find examples in corresponding I2C-driven sensors among my projects.
|
||||
|
||||
You will find here the list of all devices and sensors supported by me, that reference this library:
|
||||
|
||||
- [Liquid-crystal display driven by Hitachi HD44780 IC](https://github.com/d2r2/go-hd44780).
|
||||
- [BMP180/BMP280/BME280 temperature and pressure sensors](https://github.com/d2r2/go-bsbmp).
|
||||
- [DHT12/AM2320 humidity and temperature sensors](https://github.com/d2r2/go-aosong).
|
||||
- [Si7021 relative humidity and temperature sensor](https://github.com/d2r2/go-si7021).
|
||||
- [SHT3x humidity and temperature sensor](https://github.com/d2r2/go-sht3x).
|
||||
- [VL53L0X time-of-flight ranging sensor](https://github.com/d2r2/go-vl53l0x).
|
||||
- [BH1750 ambient light sensor](https://github.com/d2r2/go-bh1750).
|
||||
- [MPL3115A2 pressure and temperature sensor](https://github.com/d2r2/go-mpl3115a2).
|
||||
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
GoDoc [documentation](http://godoc.org/github.com/d2r2/go-i2c)
|
||||
|
||||
Troubleshooting
|
||||
--------------
|
||||
|
||||
- *How to obtain fresh Golang installation to RPi device (either any RPi clone):*
|
||||
If your RaspberryPI golang installation taken by default from repository is outdated, you may consider
|
||||
to install actual golang manually from official Golang [site](https://golang.org/dl/). Download
|
||||
tar.gz file containing armv6l in the name. Follow installation instructions.
|
||||
|
||||
- *How to enable I2C bus on RPi device:*
|
||||
If you employ RaspberryPI, use raspi-config utility to activate i2c-bus on the OS level.
|
||||
Go to "Interfacing Options" menu, to active I2C bus.
|
||||
Probably you will need to reboot to load i2c kernel module.
|
||||
Finally you should have device like /dev/i2c-1 present in the system.
|
||||
|
||||
- *How to find I2C bus allocation and device address:*
|
||||
Use i2cdetect utility in format "i2cdetect -y X", where X may vary from 0 to 5 or more,
|
||||
to discover address occupied by peripheral device. To install utility you should run
|
||||
`apt install i2c-tools` on debian-kind system. `i2cdetect -y 1` sample output:
|
||||
```
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
00: -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
70: -- -- -- -- -- -- 76 --
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Go-i2c is licensed under MIT License.
|
@ -1,12 +0,0 @@
|
||||
// +build linux,cgo
|
||||
|
||||
package i2c
|
||||
|
||||
// #include <linux/i2c-dev.h>
|
||||
import "C"
|
||||
|
||||
// Get I2C_SLAVE constant value from
|
||||
// Linux OS I2C declaration file.
|
||||
const (
|
||||
I2C_SLAVE = C.I2C_SLAVE
|
||||
)
|
@ -1,241 +0,0 @@
|
||||
// Package i2c provides low level control over the Linux i2c bus.
|
||||
//
|
||||
// Before usage you should load the i2c-dev kernel module
|
||||
//
|
||||
// sudo modprobe i2c-dev
|
||||
//
|
||||
// Each i2c bus can address 127 independent i2c devices, and most
|
||||
// Linux systems contain several buses.
|
||||
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// I2C represents a connection to I2C-device.
|
||||
type I2C struct {
|
||||
addr uint8
|
||||
bus int
|
||||
rc *os.File
|
||||
}
|
||||
|
||||
// NewI2C opens a connection for I2C-device.
|
||||
// SMBus (System Management Bus) protocol over I2C
|
||||
// supported as well: you should preliminary specify
|
||||
// register address to read from, either write register
|
||||
// together with the data in case of write operations.
|
||||
func NewI2C(addr uint8, bus int) (*I2C, error) {
|
||||
f, err := os.OpenFile(fmt.Sprintf("/dev/i2c-%d", bus), os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioctl(f.Fd(), I2C_SLAVE, uintptr(addr)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := &I2C{rc: f, bus: bus, addr: addr}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetBus return bus line, where I2C-device is allocated.
|
||||
func (v *I2C) GetBus() int {
|
||||
return v.bus
|
||||
}
|
||||
|
||||
// GetAddr return device occupied address in the bus.
|
||||
func (v *I2C) GetAddr() uint8 {
|
||||
return v.addr
|
||||
}
|
||||
|
||||
func (v *I2C) write(buf []byte) (int, error) {
|
||||
return v.rc.Write(buf)
|
||||
}
|
||||
|
||||
// WriteBytes send bytes to the remote I2C-device. The interpretation of
|
||||
// the message is implementation-dependent.
|
||||
func (v *I2C) WriteBytes(buf []byte) (int, error) {
|
||||
lg.Debugf("Write %d hex bytes: [%+v]", len(buf), hex.EncodeToString(buf))
|
||||
return v.write(buf)
|
||||
}
|
||||
|
||||
func (v *I2C) read(buf []byte) (int, error) {
|
||||
return v.rc.Read(buf)
|
||||
}
|
||||
|
||||
// ReadBytes read bytes from I2C-device.
|
||||
// Number of bytes read correspond to buf parameter length.
|
||||
func (v *I2C) ReadBytes(buf []byte) (int, error) {
|
||||
n, err := v.read(buf)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
lg.Debugf("Read %d hex bytes: [%+v]", len(buf), hex.EncodeToString(buf))
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Close I2C-connection.
|
||||
func (v *I2C) Close() error {
|
||||
return v.rc.Close()
|
||||
}
|
||||
|
||||
// ReadRegBytes read count of n byte's sequence from I2C-device
|
||||
// starting from reg address.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) ReadRegBytes(reg byte, n int) ([]byte, int, error) {
|
||||
lg.Debugf("Read %d bytes starting from reg 0x%0X...", n, reg)
|
||||
_, err := v.WriteBytes([]byte{reg})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
buf := make([]byte, n)
|
||||
c, err := v.ReadBytes(buf)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return buf, c, nil
|
||||
|
||||
}
|
||||
|
||||
// ReadRegU8 reads byte from I2C-device register specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) ReadRegU8(reg byte) (byte, error) {
|
||||
_, err := v.WriteBytes([]byte{reg})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buf := make([]byte, 1)
|
||||
_, err = v.ReadBytes(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
lg.Debugf("Read U8 %d from reg 0x%0X", buf[0], reg)
|
||||
return buf[0], nil
|
||||
}
|
||||
|
||||
// WriteRegU8 writes byte to I2C-device register specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) WriteRegU8(reg byte, value byte) error {
|
||||
buf := []byte{reg, value}
|
||||
_, err := v.WriteBytes(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lg.Debugf("Write U8 %d to reg 0x%0X", value, reg)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadRegU16BE reads unsigned big endian word (16 bits)
|
||||
// from I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) ReadRegU16BE(reg byte) (uint16, error) {
|
||||
_, err := v.WriteBytes([]byte{reg})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buf := make([]byte, 2)
|
||||
_, err = v.ReadBytes(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
w := uint16(buf[0])<<8 + uint16(buf[1])
|
||||
lg.Debugf("Read U16 %d from reg 0x%0X", w, reg)
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// ReadRegU16LE reads unsigned little endian word (16 bits)
|
||||
// from I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) ReadRegU16LE(reg byte) (uint16, error) {
|
||||
w, err := v.ReadRegU16BE(reg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// exchange bytes
|
||||
w = (w&0xFF)<<8 + w>>8
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// ReadRegS16BE reads signed big endian word (16 bits)
|
||||
// from I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) ReadRegS16BE(reg byte) (int16, error) {
|
||||
_, err := v.WriteBytes([]byte{reg})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buf := make([]byte, 2)
|
||||
_, err = v.ReadBytes(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
w := int16(buf[0])<<8 + int16(buf[1])
|
||||
lg.Debugf("Read S16 %d from reg 0x%0X", w, reg)
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// ReadRegS16LE reads signed little endian word (16 bits)
|
||||
// from I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) ReadRegS16LE(reg byte) (int16, error) {
|
||||
w, err := v.ReadRegS16BE(reg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// exchange bytes
|
||||
w = (w&0xFF)<<8 + w>>8
|
||||
return w, nil
|
||||
|
||||
}
|
||||
|
||||
// WriteRegU16BE writes unsigned big endian word (16 bits)
|
||||
// value to I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) WriteRegU16BE(reg byte, value uint16) error {
|
||||
buf := []byte{reg, byte((value & 0xFF00) >> 8), byte(value & 0xFF)}
|
||||
_, err := v.WriteBytes(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lg.Debugf("Write U16 %d to reg 0x%0X", value, reg)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteRegU16LE writes unsigned little endian word (16 bits)
|
||||
// value to I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) WriteRegU16LE(reg byte, value uint16) error {
|
||||
w := (value*0xFF00)>>8 + value<<8
|
||||
return v.WriteRegU16BE(reg, w)
|
||||
}
|
||||
|
||||
// WriteRegS16BE writes signed big endian word (16 bits)
|
||||
// value to I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) WriteRegS16BE(reg byte, value int16) error {
|
||||
buf := []byte{reg, byte((uint16(value) & 0xFF00) >> 8), byte(value & 0xFF)}
|
||||
_, err := v.WriteBytes(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lg.Debugf("Write S16 %d to reg 0x%0X", value, reg)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteRegS16LE writes signed little endian word (16 bits)
|
||||
// value to I2C-device starting from address specified in reg.
|
||||
// SMBus (System Management Bus) protocol over I2C.
|
||||
func (v *I2C) WriteRegS16LE(reg byte, value int16) error {
|
||||
w := int16((uint16(value)*0xFF00)>>8) + value<<8
|
||||
return v.WriteRegS16BE(reg, w)
|
||||
}
|
||||
|
||||
func ioctl(fd, cmd, arg uintptr) error {
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, cmd, arg, 0, 0, 0)
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package i2c
|
||||
|
||||
import logger "github.com/d2r2/go-logger"
|
||||
|
||||
// You can manage verbosity of log output
|
||||
// in the package by changing last parameter value
|
||||
// (comment/uncomment corresponding lines).
|
||||
var lg = logger.NewPackageLogger("i2c",
|
||||
logger.DebugLevel,
|
||||
// logger.InfoLevel,
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
// +build !cgo
|
||||
|
||||
package i2c
|
||||
|
||||
// Use hard-coded value for system I2C_SLAVE
|
||||
// constant, if OS not Linux or CGO disabled.
|
||||
// This is not a good approach, but
|
||||
// can be used as a last resort.
|
||||
const (
|
||||
I2C_SLAVE = 0x0703
|
||||
)
|
@ -1,2 +0,0 @@
|
||||
Golang logger functionality with logging separation by package to improve debug process
|
||||
|
@ -1,161 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
sync.RWMutex
|
||||
Path string
|
||||
File *os.File
|
||||
}
|
||||
|
||||
func (v *File) Flush() error {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
if v.File != nil {
|
||||
err := v.File.Sync()
|
||||
v.File = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *File) Close() error {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
if v.File != nil {
|
||||
err := v.File.Close()
|
||||
v.File = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *File) getRotatedFileList() ([]logFile, error) {
|
||||
var list []logFile
|
||||
err := filepath.Walk(path.Dir(v.Path), func(p string,
|
||||
info os.FileInfo, err error) error {
|
||||
pattern := "*" + path.Base(v.Path) + "*"
|
||||
if ok, err := path.Match(pattern, path.Base(p)); ok && err == nil {
|
||||
i := extractIndex(info)
|
||||
list = append(list, logFile{FileInfo: info, Index: i})
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &sortLogFiles{Items: list}
|
||||
sort.Sort(s)
|
||||
return s.Items, nil
|
||||
}
|
||||
|
||||
func (v *File) doRotate(items []logFile, rotateMaxCount int) error {
|
||||
if len(items) > 0 {
|
||||
// delete last files
|
||||
deleteCount := len(items) - rotateMaxCount + 1
|
||||
if deleteCount > 0 {
|
||||
for i := 0; i < deleteCount; i++ {
|
||||
err := os.Remove(items[i].FileInfo.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
items = items[deleteCount:]
|
||||
}
|
||||
// change names of rest files
|
||||
baseFilePath := items[len(items)-1].FileInfo.Name()
|
||||
movs := make([]int, len(items))
|
||||
// 1st round to change names
|
||||
for i, item := range items {
|
||||
movs[i] = i + 100000
|
||||
err := os.Rename(item.FileInfo.Name(),
|
||||
fmt.Sprintf("%s.%d", baseFilePath, movs[i]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 2nd round to change names
|
||||
for i, item := range movs {
|
||||
err := os.Rename(fmt.Sprintf("%s.%d", baseFilePath, item),
|
||||
fmt.Sprintf("%s.%d", baseFilePath, len(items)-i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *File) rotateFiles(rotateMaxSize int64, rotateMaxCount int) error {
|
||||
fs, err := v.File.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fs.Size() > rotateMaxSize {
|
||||
if v.File != nil {
|
||||
err := v.File.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.File = nil
|
||||
}
|
||||
list, err := v.getRotatedFileList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = v.doRotate(list, rotateMaxCount); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *File) getFile() (*os.File, error) {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
if v.File == nil {
|
||||
file, err := os.OpenFile(v.Path, os.O_RDWR|os.O_APPEND, 0660)
|
||||
if err != nil {
|
||||
file, err = os.Create(v.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
v.File = file
|
||||
}
|
||||
return v.File, nil
|
||||
}
|
||||
|
||||
func (v *File) writeToFile(msg string, rotateMaxSize int64, rotateMaxCount int) error {
|
||||
file, err := v.getFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(msg)
|
||||
buf.WriteString(fmt.Sprintln())
|
||||
if _, err := io.Copy(file, &buf); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err = file.Sync(); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if err := v.rotateFiles(rotateMaxSize, rotateMaxCount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package logger
|
||||
|
||||
import "os"
|
||||
|
||||
type LevelLength int
|
||||
|
||||
const (
|
||||
LevelShort LevelLength = iota
|
||||
LevelLong
|
||||
)
|
||||
|
||||
type FormatOptions struct {
|
||||
TimeFormat string
|
||||
PackageLength int
|
||||
LevelLength LevelLength
|
||||
}
|
||||
|
||||
func FormatMessage(options FormatOptions, level LogLevel, packageName, msg string, colored bool) string {
|
||||
appName := os.Args[0]
|
||||
out := metaFmtStr(colored, level, options, appName,
|
||||
packageName, msg, "%[1]s [%[3]s] %[4]s %[5]s")
|
||||
return out
|
||||
}
|
||||
|
||||
func (options FormatOptions) GetLevelStr(level LogLevel) string {
|
||||
if options.LevelLength == LevelLong {
|
||||
return level.LongStr()
|
||||
} else {
|
||||
return level.ShortStr()
|
||||
}
|
||||
}
|
@ -1,309 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
FatalLevel LogLevel = iota
|
||||
PanicLevel
|
||||
ErrorLevel
|
||||
WarnLevel
|
||||
NotifyLevel
|
||||
InfoLevel
|
||||
DebugLevel
|
||||
)
|
||||
|
||||
func (v LogLevel) String() string {
|
||||
switch v {
|
||||
case FatalLevel:
|
||||
return "Fatal"
|
||||
case PanicLevel:
|
||||
return "Panic"
|
||||
case ErrorLevel:
|
||||
return "Error"
|
||||
case WarnLevel:
|
||||
return "Warning"
|
||||
case NotifyLevel:
|
||||
return "Notice"
|
||||
case InfoLevel:
|
||||
return "Information"
|
||||
case DebugLevel:
|
||||
return "Debug"
|
||||
default:
|
||||
return "<undef>"
|
||||
}
|
||||
}
|
||||
|
||||
func (v LogLevel) LongStr() string {
|
||||
return v.String()
|
||||
}
|
||||
|
||||
func (v LogLevel) ShortStr() string {
|
||||
switch v {
|
||||
case FatalLevel:
|
||||
return "Fatal"
|
||||
case PanicLevel:
|
||||
return "Panic"
|
||||
case ErrorLevel:
|
||||
return "Error"
|
||||
case WarnLevel:
|
||||
return "Warn"
|
||||
case NotifyLevel:
|
||||
return "Notice"
|
||||
case InfoLevel:
|
||||
return "Info"
|
||||
case DebugLevel:
|
||||
return "Debug"
|
||||
default:
|
||||
return "<undef>"
|
||||
}
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
log *log.Logger
|
||||
colored bool
|
||||
level LogLevel
|
||||
}
|
||||
|
||||
func NewLog(log *log.Logger, colored bool, level LogLevel) *Log {
|
||||
v := &Log{log: log, colored: colored, level: level}
|
||||
return v
|
||||
}
|
||||
|
||||
type Logger struct {
|
||||
sync.RWMutex
|
||||
logs []*Log
|
||||
packages []*Package
|
||||
options FormatOptions
|
||||
logFile *File
|
||||
rotateMaxSize int64
|
||||
rotateMaxCount int
|
||||
enableSyslog bool
|
||||
}
|
||||
|
||||
func NewLogger() *Logger {
|
||||
stdout := NewLog(log.New(os.Stdout, "", 0), true, DebugLevel)
|
||||
logs := []*Log{stdout}
|
||||
options := FormatOptions{TimeFormat: "2006-01-02T15:04:05.000", LevelLength: LevelShort, PackageLength: 8}
|
||||
l := &Logger{
|
||||
logs: logs,
|
||||
options: options,
|
||||
rotateMaxSize: 1024 * 1024 * 512,
|
||||
rotateMaxCount: 3,
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (v *Logger) Close() error {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
|
||||
for _, pack := range v.packages {
|
||||
pack.Close()
|
||||
}
|
||||
v.packages = nil
|
||||
|
||||
if v.logFile != nil {
|
||||
v.logFile.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Logger) SetRotateParams(rotateMaxSize int64, rotateMaxCount int) {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
v.rotateMaxSize = rotateMaxSize
|
||||
v.rotateMaxCount = rotateMaxCount
|
||||
}
|
||||
|
||||
func (v *Logger) GetRotateMaxSize() int64 {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
return v.rotateMaxSize
|
||||
}
|
||||
|
||||
func (v *Logger) GetRotateMaxCount() int {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
return v.rotateMaxCount
|
||||
}
|
||||
|
||||
/*
|
||||
func (v *Logger) SetApplicationName(appName string) {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
v.appName = appName
|
||||
}
|
||||
|
||||
func (v *Logger) GetApplicationName() string {
|
||||
v.RLock()
|
||||
defer v.RUnlock()
|
||||
return v.appName
|
||||
}
|
||||
*/
|
||||
|
||||
func (v *Logger) EnableSyslog(enable bool) {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
v.enableSyslog = enable
|
||||
}
|
||||
|
||||
func (v *Logger) GetSyslogEnabled() bool {
|
||||
v.RLock()
|
||||
defer v.RUnlock()
|
||||
return v.enableSyslog
|
||||
}
|
||||
|
||||
func (v *Logger) SetFormatOptions(options FormatOptions) {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
v.options = options
|
||||
}
|
||||
|
||||
func (v *Logger) GetFormatOptions() FormatOptions {
|
||||
v.RLock()
|
||||
defer v.RUnlock()
|
||||
return v.options
|
||||
}
|
||||
|
||||
func (v *Logger) SetLogFileName(logFilePath string) error {
|
||||
if path.Ext(logFilePath) == "" {
|
||||
logFilePath += ".log"
|
||||
}
|
||||
fp, err := filepath.Abs(logFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
lf := &File{Path: fp}
|
||||
v.logFile = lf
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Logger) GetLogFileInfo() *File {
|
||||
v.RLock()
|
||||
defer v.RUnlock()
|
||||
return v.logFile
|
||||
}
|
||||
|
||||
func (v *Logger) NewPackageLogger(packageName string, level LogLevel) PackageLog {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
p := &Package{parent: v, packageName: packageName, level: level}
|
||||
v.packages = append(v.packages, p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (v *Logger) ChangePackageLogLevel(packageName string, level LogLevel) error {
|
||||
var p *Package
|
||||
for _, item := range v.packages {
|
||||
if item.packageName == packageName {
|
||||
p = item
|
||||
break
|
||||
}
|
||||
}
|
||||
if p != nil {
|
||||
p.SetLogLevel(level)
|
||||
} else {
|
||||
err := fmt.Errorf("Package log %q is not found", packageName)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Logger) AddCustomLog(writer io.Writer, colored bool, level LogLevel) {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
log := NewLog(log.New(writer, "", 0), colored, level)
|
||||
v.logs = append(v.logs, log)
|
||||
}
|
||||
|
||||
func (v *Logger) getLogs() []*Log {
|
||||
v.RLock()
|
||||
defer v.RUnlock()
|
||||
lst := []*Log{}
|
||||
for _, item := range v.logs {
|
||||
lst = append(lst, item)
|
||||
}
|
||||
return lst
|
||||
}
|
||||
|
||||
var (
|
||||
globalLock sync.RWMutex
|
||||
lgr *Logger
|
||||
)
|
||||
|
||||
func SetFormatOptions(format FormatOptions) {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
lgr.SetFormatOptions(format)
|
||||
}
|
||||
|
||||
func SetRotateParams(rotateMaxSize int64, rotateMaxCount int) {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
lgr.SetRotateParams(rotateMaxSize, rotateMaxCount)
|
||||
}
|
||||
|
||||
func NewPackageLogger(module string, level LogLevel) PackageLog {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
return lgr.NewPackageLogger(module, level)
|
||||
}
|
||||
|
||||
func ChangePackageLogLevel(packageName string, level LogLevel) error {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
return lgr.ChangePackageLogLevel(packageName, level)
|
||||
}
|
||||
|
||||
func SetLogFileName(logFilePath string) error {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
return lgr.SetLogFileName(logFilePath)
|
||||
}
|
||||
|
||||
/*
|
||||
func SetApplicationName(appName string) {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
lgr.SetApplicationName(appName)
|
||||
}
|
||||
*/
|
||||
|
||||
func EnableSyslog(enable bool) {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
lgr.EnableSyslog(enable)
|
||||
}
|
||||
|
||||
func AddCustomLog(writer io.Writer, colored bool, level LogLevel) {
|
||||
globalLock.RLock()
|
||||
defer globalLock.RUnlock()
|
||||
lgr.AddCustomLog(writer, colored, level)
|
||||
}
|
||||
|
||||
func FinalizeLogger() error {
|
||||
var err error
|
||||
if lgr != nil {
|
||||
err = lgr.Close()
|
||||
}
|
||||
globalLock.Lock()
|
||||
defer globalLock.Unlock()
|
||||
lgr = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func init() {
|
||||
lgr = NewLogger()
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/syslog"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type PackageLog interface {
|
||||
Printf(level LogLevel, format string, args ...interface{})
|
||||
Print(level LogLevel, args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Debug(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Notifyf(format string, args ...interface{})
|
||||
Notify(args ...interface{})
|
||||
Warningf(format string, args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warning(args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||