Add: image, signal and service status output
This commit is contained in:
parent
0976b5c8d0
commit
0495860996
@ -23,6 +23,8 @@ const (
|
|||||||
timeLayout = "01.09.06 15:04:05"
|
timeLayout = "01.09.06 15:04:05"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Some layout constants
|
||||||
|
|
||||||
type statusPage struct {
|
type statusPage struct {
|
||||||
drawer drawer.Drawer // Drawer with dysplay
|
drawer drawer.Drawer // Drawer with dysplay
|
||||||
|
|
||||||
@ -36,6 +38,9 @@ type statusPage struct {
|
|||||||
line1 components.Text
|
line1 components.Text
|
||||||
line2 components.Text
|
line2 components.Text
|
||||||
line3 components.Text
|
line3 components.Text
|
||||||
|
// Layout values
|
||||||
|
signalX int
|
||||||
|
serviceX int
|
||||||
|
|
||||||
// Threads sync
|
// Threads sync
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -78,6 +83,10 @@ func NewStatusPage(d drawer.Drawer) (StatusPage, error) {
|
|||||||
return nil, fmt.Errorf("create line3: %w", err)
|
return nil, fmt.Errorf("create line3: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate signal and service glyphs' pos
|
||||||
|
signalX := d.W() - drawer.CommonGlyphs[drawer.SignalStatusGlyphI].W - drawer.CommonGlyphs[drawer.ServiceStatusGlyphI].W - drawer.CharGap
|
||||||
|
serviceX := d.W() - drawer.CommonGlyphs[drawer.ServiceStatusGlyphI].W
|
||||||
|
|
||||||
return &statusPage{
|
return &statusPage{
|
||||||
drawer: d,
|
drawer: d,
|
||||||
|
|
||||||
@ -85,6 +94,9 @@ func NewStatusPage(d drawer.Drawer) (StatusPage, error) {
|
|||||||
line1: line1,
|
line1: line1,
|
||||||
line2: line2,
|
line2: line2,
|
||||||
line3: line3,
|
line3: line3,
|
||||||
|
|
||||||
|
signalX: signalX,
|
||||||
|
serviceX: serviceX,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +112,11 @@ func (p *statusPage) Activate() {
|
|||||||
p.line2.Draw()
|
p.line2.Draw()
|
||||||
p.line3.Draw()
|
p.line3.Draw()
|
||||||
|
|
||||||
|
// At the right-top corner there are signal then service status glyphs
|
||||||
|
// Layout:
|
||||||
|
// gap | signal | gap | service
|
||||||
|
p.SetRssi(0)
|
||||||
|
|
||||||
// Setup threads
|
// Setup threads
|
||||||
p.ctx, p.cancel = context.WithCancel(context.Background())
|
p.ctx, p.cancel = context.WithCancel(context.Background())
|
||||||
go p.timeUpdateLoop()
|
go p.timeUpdateLoop()
|
||||||
@ -130,9 +147,9 @@ func (p *statusPage) SetGps(newData gps.Data) {
|
|||||||
// Latitude and longitude output format:
|
// Latitude and longitude output format:
|
||||||
// DD° MM.MMM' N
|
// DD° MM.MMM' N
|
||||||
// DDD° MM.MMM' W
|
// DDD° MM.MMM' W
|
||||||
latStr := fmt.Sprintf(" %02d°%02.3f' %s", int(p.st.gpsData.Latitude)/100, math.Mod(p.st.gpsData.Latitude, 100), p.st.gpsData.LatitudeIndicator)
|
latStr := fmt.Sprintf(" %02d°%06.3f' %s", int(p.st.gpsData.Latitude)/100, math.Mod(p.st.gpsData.Latitude, 100), p.st.gpsData.LatitudeIndicator)
|
||||||
p.line2.SetStr(latStr)
|
p.line2.SetStr(latStr)
|
||||||
logStr := fmt.Sprintf(" %03d°%02.3f' %s", int(p.st.gpsData.Longitude)/100, math.Mod(p.st.gpsData.Longitude, 100), p.st.gpsData.LongitudeIndicator)
|
logStr := fmt.Sprintf(" %03d°%06.3f' %s", int(p.st.gpsData.Longitude)/100, math.Mod(p.st.gpsData.Longitude, 100), p.st.gpsData.LongitudeIndicator)
|
||||||
p.line3.SetStr(logStr)
|
p.line3.SetStr(logStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,18 +160,105 @@ func (p *statusPage) SetMpu(newData mpu.Data) {
|
|||||||
p.st.mpuData = newData
|
p.st.mpuData = newData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *statusPage) SetRssi(newData int) {
|
// Only safely updates local values
|
||||||
|
func (p *statusPage) setRssi(newData int) {
|
||||||
p.st.mutex.Lock()
|
p.st.mutex.Lock()
|
||||||
defer p.st.mutex.Unlock()
|
defer p.st.mutex.Unlock()
|
||||||
|
|
||||||
p.st.rssi = newData
|
p.st.rssi = newData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *statusPage) SetService(newData string) {
|
func (p *statusPage) setService(svc string) {
|
||||||
p.st.mutex.Lock()
|
p.st.mutex.Lock()
|
||||||
defer p.st.mutex.Unlock()
|
defer p.st.mutex.Unlock()
|
||||||
|
|
||||||
p.st.service = newData
|
p.st.service = svc
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSignalStrength(rssi int) int {
|
||||||
|
// Signal strength clasification (from google):
|
||||||
|
// 0 - no signal -110 to ...
|
||||||
|
// 1 - poor signal -90 to -110
|
||||||
|
// 2 - fair signal -70 to -90
|
||||||
|
// 3 - good signal -50 to -70
|
||||||
|
// 4 - excelent signal ... to -50
|
||||||
|
|
||||||
|
// Description from "sim-modem/api/modem/utils/signal.go"
|
||||||
|
// 0 -113 dBm or less
|
||||||
|
// 1 -111 dBm
|
||||||
|
// 2...30 -109... -53 dBm
|
||||||
|
// 31 -51 dBm or greater
|
||||||
|
// 99 not known or not detectable
|
||||||
|
// 100 -116 dBm or less
|
||||||
|
// 101 -115 dBm
|
||||||
|
// 102…191 -114... -26dBm
|
||||||
|
// 191 -25 dBm or greater
|
||||||
|
// 199 not known or not detectable
|
||||||
|
// 100…199 expand to TDSCDMA, indicate RSCPreceived
|
||||||
|
|
||||||
|
// Cut certain cases
|
||||||
|
switch rssi {
|
||||||
|
case 99, 199: // not known or not detectable
|
||||||
|
return 0
|
||||||
|
case 0, 1, 100, 101: // no signal
|
||||||
|
return 0
|
||||||
|
case 31, 191: // Excelent
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ranged values
|
||||||
|
if rssi >= 2 && rssi <= 30 {
|
||||||
|
// it is in -109...-53 dBm
|
||||||
|
// Simplified interpolation from 2..30 to -109...-53 and then to 0...4
|
||||||
|
return int((float64(rssi)*2-3)/20) + 1
|
||||||
|
}
|
||||||
|
if rssi >= 102 && rssi <= 191 {
|
||||||
|
// it is in -114...-26 dBm
|
||||||
|
// Simplified interpolation from 2..30 to -114...-26 and then to 0...4
|
||||||
|
return min(int((float64(rssi-102)+15)/20), 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 // Invalid value
|
||||||
|
}
|
||||||
|
|
||||||
|
func getServiceStrength(service string) int {
|
||||||
|
// Service clasification by speed:
|
||||||
|
// 0 - no service - "NO SERVICE"
|
||||||
|
// 1 - 1G - do not use
|
||||||
|
// 2 - 2G - "GSM"
|
||||||
|
// 3 - 3G - "WCDMA"
|
||||||
|
// 4 - 4G - "LTE", "TDS"
|
||||||
|
|
||||||
|
switch service {
|
||||||
|
case "NO SERVICE":
|
||||||
|
return 0
|
||||||
|
case "GSM":
|
||||||
|
return 2
|
||||||
|
case "WCDMA":
|
||||||
|
return 3
|
||||||
|
case "LTE", "TDS":
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 // Invalid value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *statusPage) SetRssi(rssi int) {
|
||||||
|
p.setRssi(rssi) // Save data (with short lock)
|
||||||
|
|
||||||
|
// Update screen image
|
||||||
|
ss := getSignalStrength(rssi) // Signal strength in [0; 4] range
|
||||||
|
p.drawer.CopyImg(p.signalX, 0, drawer.CommonGlyphs[drawer.SignalStatusGlyphI+ss])
|
||||||
|
p.drawer.GetDisplay().FlushByMask(p.drawer.GetDisplay().GetFlushMaskBit(1, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *statusPage) SetService(svc string) {
|
||||||
|
p.setService(svc) // Save data (with short lock)
|
||||||
|
|
||||||
|
// Update screen image
|
||||||
|
ss := getServiceStrength(svc) // Service strength in [0; 4] range
|
||||||
|
p.drawer.CopyImg(p.serviceX, 0, drawer.CommonGlyphs[drawer.ServiceStatusGlyphI+ss])
|
||||||
|
p.drawer.GetDisplay().FlushByMask(p.drawer.GetDisplay().GetFlushMaskBit(1, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *statusPage) timeUpdateLoop() {
|
func (p *statusPage) timeUpdateLoop() {
|
||||||
|
@ -25,6 +25,8 @@ type Drawer interface {
|
|||||||
|
|
||||||
PutBar(x0, y0, x1, y1 int, color byte)
|
PutBar(x0, y0, x1, y1 int, color byte)
|
||||||
FillBar(x0, y0, x1, y1 int, color byte)
|
FillBar(x0, y0, x1, y1 int, color byte)
|
||||||
|
|
||||||
|
CopyImg(x0, y0 int, img Image)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(dev display.Display) Drawer {
|
func New(dev display.Display) Drawer {
|
||||||
|
167
drawer/image.go
Normal file
167
drawer/image.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
package drawer
|
||||||
|
|
||||||
|
// Simple glyphs like signal or service status that are too simple to be whole image
|
||||||
|
|
||||||
|
const (
|
||||||
|
SignalStatusGlyphI = 0 // first of 5
|
||||||
|
ServiceStatusGlyphI = 5 // first of 5
|
||||||
|
)
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
W int
|
||||||
|
H int
|
||||||
|
Bits []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var CommonGlyphs = []Image{
|
||||||
|
{ // Signal 0/0
|
||||||
|
W: 7,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
1, 0, 0, 0, 1, 0, 0,
|
||||||
|
0, 1, 0, 1, 0, 0, 0,
|
||||||
|
0, 0, 1, 0, 0, 0, 0,
|
||||||
|
0, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1, 0, 1,
|
||||||
|
0, 0, 1, 0, 0, 0, 1,
|
||||||
|
1, 0, 1, 0, 1, 0, 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Signal 1/4
|
||||||
|
W: 7,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Signal 2/4
|
||||||
|
W: 7,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 1, 0, 0, 0, 0,
|
||||||
|
1, 0, 1, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Signal 3/4
|
||||||
|
W: 7,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0, 1, 0, 0,
|
||||||
|
1, 0, 1, 0, 1, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Signal 4/4
|
||||||
|
W: 7,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1, 0, 1,
|
||||||
|
0, 0, 0, 0, 1, 0, 1,
|
||||||
|
0, 0, 1, 0, 1, 0, 1,
|
||||||
|
0, 0, 1, 0, 1, 0, 1,
|
||||||
|
1, 0, 1, 0, 1, 0, 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Service 0/4
|
||||||
|
W: 9,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||||
|
0, 0, 0, 1, 0, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 1, 0, 1, 0, 0, 0,
|
||||||
|
0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Service 1/4
|
||||||
|
W: 9,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Service 2/4
|
||||||
|
W: 9,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Service 3/4
|
||||||
|
W: 9,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 1, 1, 1, 1, 1, 0, 0,
|
||||||
|
0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // Service 4/4
|
||||||
|
W: 9,
|
||||||
|
H: 7,
|
||||||
|
Bits: []byte{
|
||||||
|
0, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||||
|
0, 0, 1, 1, 1, 1, 1, 0, 0,
|
||||||
|
0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *drawer) CopyImg(x0, y0 int, img Image) {
|
||||||
|
d.dev.LockImg()
|
||||||
|
defer d.dev.UnlockImg()
|
||||||
|
|
||||||
|
// Coords in img coord space
|
||||||
|
|
||||||
|
minX := IntMax(x0, 0) - x0
|
||||||
|
minY := IntMax(y0, 0) - y0
|
||||||
|
maxX := IntMin(x0+img.W, d.img.Rect.Dx()) - x0
|
||||||
|
maxY := IntMin(y0+img.H, d.img.Rect.Dy()) - y0
|
||||||
|
|
||||||
|
w := maxX - minX
|
||||||
|
if w <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for yi := minY; yi < maxY; yi++ {
|
||||||
|
copy(d.img.Pix[(y0+yi)*d.img.Stride+x0:], img.Bits[yi*img.W:yi*img.W+w])
|
||||||
|
}
|
||||||
|
}
|
38
main.go
38
main.go
@ -176,6 +176,8 @@ func mainE(ctx context.Context) error {
|
|||||||
// return err
|
// return err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
logger.Println("")
|
||||||
|
|
||||||
a, err := api.New()
|
a, err := api.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("new api: %w", err)
|
return fmt.Errorf("new api: %w", err)
|
||||||
@ -204,16 +206,36 @@ func mainE(ctx context.Context) error {
|
|||||||
// !!! Status page simulating
|
// !!! Status page simulating
|
||||||
|
|
||||||
// Switch
|
// Switch
|
||||||
|
|
||||||
|
services := []string{"NO SIGNAL", "GSM", "WCDMA", "LTE", "TDS"}
|
||||||
sp := a.SwitchToStatusPage()
|
sp := a.SwitchToStatusPage()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
|
case <-time.After(1000 * time.Millisecond):
|
||||||
|
// Random coords
|
||||||
|
lat := float64(rand.Int()%10000) + float64(rand.Int()%1000000)/1000000
|
||||||
|
log := float64(rand.Int()%100000) + float64(rand.Int()%1000000)/1000000
|
||||||
|
latI := "N"
|
||||||
|
if rand.Int()%2 == 0 {
|
||||||
|
latI = "S"
|
||||||
|
}
|
||||||
|
logI := "E"
|
||||||
|
if rand.Int()%2 == 0 {
|
||||||
|
logI = "W"
|
||||||
|
}
|
||||||
sp.SetGps(gps.Data{
|
sp.SetGps(gps.Data{
|
||||||
Latitude: 3113.330650,
|
Latitude: lat,
|
||||||
LatitudeIndicator: "N",
|
LatitudeIndicator: latI,
|
||||||
Longitude: 12121.262554,
|
Longitude: log,
|
||||||
LongitudeIndicator: "E",
|
LongitudeIndicator: logI,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Just wait now
|
// Random rssi
|
||||||
<-ctx.Done()
|
sp.SetRssi(rand.Int() % 31)
|
||||||
|
sp.SetService(services[rand.Int()%len(services)])
|
||||||
return nil
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user