added my Recipes
@@ -0,0 +1,51 @@
|
||||
# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
|
||||
SUMMARY = "Python script which launch several use-cases"
|
||||
LICENSE = "BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9"
|
||||
|
||||
SRC_URI = " \
|
||||
file://demo_launcher.py \
|
||||
file://start_up_demo_launcher.sh \
|
||||
file://pictures \
|
||||
file://application \
|
||||
file://board \
|
||||
"
|
||||
|
||||
PV = "2.1"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/
|
||||
install -d ${D}${prefix}/local/demo/bin
|
||||
install -d ${D}${prefix}/local/demo/pictures
|
||||
install -d ${D}${prefix}/local/demo/media
|
||||
install -d ${D}${prefix}/local/demo/application
|
||||
install -d ${D}${prefix}/local/demo/board
|
||||
|
||||
install -m 0755 ${WORKDIR}/demo_launcher.py ${D}${prefix}/local/demo/
|
||||
LIST=$(ls ${WORKDIR}/pictures/*)
|
||||
if [ -n "$LIST" ]; then
|
||||
install -m 0644 ${WORKDIR}/pictures/* ${D}${prefix}/local/demo/pictures/
|
||||
fi
|
||||
LIST=$(ls ${WORKDIR}/application/*)
|
||||
if [ -n "$LIST" ]; then
|
||||
cp -r ${WORKDIR}/application/* ${D}${prefix}/local/demo/application/
|
||||
fi
|
||||
LIST=$(ls ${WORKDIR}/board/*)
|
||||
if [ -n "$LIST" ]; then
|
||||
cp -r ${WORKDIR}/board/* ${D}${prefix}/local/demo/board/
|
||||
fi
|
||||
|
||||
# start at startup
|
||||
install -d ${D}${prefix}/local/weston-start-at-startup/
|
||||
install -m 0755 ${WORKDIR}/start_up_demo_launcher.sh ${D}${prefix}/local/weston-start-at-startup/
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/local/demo/ ${prefix}/local/weston-start-at-startup/"
|
||||
|
||||
RDEPENDS:${PN} += "python3-pygobject gtk+3 python3-resource python3-threading"
|
||||
#since zeus
|
||||
RDEPENDS:${PN} += " python3-core "
|
||||
@@ -0,0 +1,3 @@
|
||||
BOARD: STM32MP13
|
||||
LOGO: pictures/ST20578_Label_OpenSTlinux_V.png
|
||||
INFO: <span font='9' color='#FFFFFFFF'><b>STM32MP13x Board</b></span>|<span font='7' color='#FFFFFFFF'>Arm® Cortex®-A7</span>
|
||||
@@ -0,0 +1,4 @@
|
||||
BOARD: STM32MP15
|
||||
LOGO: pictures/ST20578_Label_OpenSTlinux_V.png
|
||||
INFO: <span font='14' color='#FFFFFFFF'><b>STM32MP15x Board</b></span>|<span font='10' color='#FFFFFFFF'>Dual Arm® Cortex®-A7</span>|<span font='10' color='#FFFFFFFF'>+</span>|<span font='10' color='#FFFFFFFF'>Copro Arm® Cortex®-M4</span>
|
||||
|
||||
861
meta-st/meta-st-openstlinux/recipes-samples/demo/demo-launcher/demo_launcher.py
Executable file
@@ -0,0 +1,861 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# Copyright (c) 2019 STMicroelectronics. All rights reserved.
|
||||
#
|
||||
# This software component is licensed by ST under BSD 3-Clause license,
|
||||
# the "License"; You may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at:
|
||||
# opensource.org/licenses/BSD-3-Clause
|
||||
|
||||
# to debug this script:
|
||||
# python3 -m pdb ./demo_launcher.py
|
||||
#
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
|
||||
import yaml
|
||||
|
||||
import subprocess
|
||||
import random
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import socket
|
||||
import fcntl
|
||||
import struct
|
||||
import string
|
||||
import random
|
||||
from collections import deque
|
||||
from time import sleep, time
|
||||
import threading
|
||||
|
||||
import importlib
|
||||
#
|
||||
# For simulating UI on PC , please use
|
||||
# the variable SIMULATE = 1
|
||||
# If SIMULATE = 1 then
|
||||
# the picture/icon must be present on pictures directory
|
||||
#
|
||||
SIMULATE = 0
|
||||
|
||||
|
||||
if SIMULATE > 0:
|
||||
#DEMO_PATH = os.environ['HOME']+"/Desktop/launcher"
|
||||
DEMO_PATH = "./"
|
||||
else:
|
||||
DEMO_PATH = "/usr/local/demo"
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Managment of lock file to have only excution of this script as same time
|
||||
lock = threading.Lock()
|
||||
|
||||
lock_handle = None
|
||||
lock_file_path = '/tmp/demo_launcher.lock'
|
||||
|
||||
def file_is_locked(file_path):
|
||||
global lock_handle
|
||||
lock_handle= open(file_path, 'w')
|
||||
try:
|
||||
fcntl.lockf(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
return False
|
||||
except IOError:
|
||||
return True
|
||||
|
||||
def file_lock_remove(file_path):
|
||||
try:
|
||||
os.remove(lock_file_path)
|
||||
except Exception as exc:
|
||||
print("Signal handler Exception: ", exc)
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def detroy_quit_application(widget):
|
||||
file_lock_remove(lock_file_path)
|
||||
Gtk.main_quit()
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# CONSTANT VALUES
|
||||
#
|
||||
SIMULATE_SCREEN_SIZE_WIDTH = 800
|
||||
SIMULATE_SCREEN_SIZE_HEIGHT = 480
|
||||
#SIMULATE_SCREEN_SIZE_WIDTH = 480
|
||||
#SIMULATE_SCREEN_SIZE_HEIGHT = 272
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
ICON_SIZE_1080 = 260
|
||||
ICON_SIZE_720 = 180
|
||||
ICON_SIZE_480 = 128
|
||||
ICON_SIZE_272 = 64
|
||||
|
||||
# return format:
|
||||
# [ icon_size, font_size, logo_size, exit_size, column_spacing, row_spacing ]
|
||||
SIZES_ID_ICON_SIZE = 0
|
||||
SIZES_ID_FONT_SIZE = 1
|
||||
SIZES_ID_LOGO_SIZE = 2
|
||||
SIZES_ID_EXIT_SIZE = 3
|
||||
SIZES_ID_COLUMN_SPACING = 4
|
||||
SIZES_ID_ROW_SPACING = 5
|
||||
def get_sizes_from_screen_size(width, height):
|
||||
minsize = min(width, height)
|
||||
icon_size = None
|
||||
font_size = None
|
||||
logo_size = None
|
||||
exit_size = None
|
||||
column_spacing = None
|
||||
row_spacing = None
|
||||
if minsize == 720:
|
||||
icon_size = ICON_SIZE_720
|
||||
font_size = 15
|
||||
logo_size = 160
|
||||
exit_size = 50
|
||||
column_spacing = 20
|
||||
row_spacing = 20
|
||||
elif minsize == 480:
|
||||
icon_size = ICON_SIZE_480
|
||||
font_size = 15
|
||||
logo_size = 160
|
||||
exit_size = 50
|
||||
column_spacing = 10
|
||||
row_spacing = 10
|
||||
elif minsize == 272:
|
||||
icon_size = ICON_SIZE_272
|
||||
font_size = 8
|
||||
logo_size = 60
|
||||
exit_size = 25
|
||||
column_spacing = 5
|
||||
row_spacing = 5
|
||||
elif minsize == 600:
|
||||
icon_size = ICON_SIZE_720
|
||||
font_size = 15
|
||||
logo_size = 160
|
||||
exit_size = 50
|
||||
column_spacing = 20
|
||||
row_spacing = 20
|
||||
elif minsize >= 1080:
|
||||
icon_size = ICON_SIZE_1080
|
||||
font_size = 32
|
||||
logo_size = 260
|
||||
exit_size = 50
|
||||
column_spacing = 20
|
||||
row_spacing = 20
|
||||
return [icon_size, font_size, logo_size, exit_size, column_spacing, row_spacing]
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Back video view
|
||||
class BackVideoWindow(Gtk.Dialog):
|
||||
def __init__(self, parent):
|
||||
Gtk.Dialog.__init__(self, "Wifi", parent, 0)
|
||||
self.previous_click_time=time()
|
||||
self.maximize()
|
||||
self.set_decorated(False)
|
||||
self.set_name("backed_bg")
|
||||
self.show_all()
|
||||
|
||||
# Info view
|
||||
class InfoWindow(Gtk.Dialog):
|
||||
def __init__(self, parent):
|
||||
Gtk.Dialog.__init__(self, "Wifi", parent, 0)
|
||||
self.previous_click_time=time()
|
||||
self.maximize()
|
||||
self.set_decorated(False)
|
||||
self.set_name("backed_bg")
|
||||
try:
|
||||
self.font_size = parent.font_size
|
||||
except:
|
||||
print("DEBUG take default font size")
|
||||
self.font_size = 15
|
||||
|
||||
mainvbox = self.get_content_area()
|
||||
|
||||
page_info = Gtk.VBox()
|
||||
page_info.set_border_width(10)
|
||||
|
||||
title = Gtk.Label()
|
||||
title.set_markup("<span font='%d' color='#FFFFFFFF'><b>About the application</b></span>" % (self.font_size+5))
|
||||
page_info.add(title)
|
||||
|
||||
label1 = Gtk.Label()
|
||||
label1.set_markup("<span font='%d' color='#FFFFFFFF'>\n\nTo get control of video playback and camera preview,\nSimple tap: pause/resume\nDouble tap: exit from demos\n\nAI demo: draw character on touchscreen to launch action</span>" % self.font_size)
|
||||
label1.set_justify(Gtk.Justification.LEFT)
|
||||
page_info.add(label1)
|
||||
|
||||
mainvbox.pack_start(page_info, False, False, 3)
|
||||
self.connect("button-release-event", self.on_page_press_event)
|
||||
self.show_all()
|
||||
|
||||
def on_page_press_event(self, widget, event):
|
||||
self.click_time = time()
|
||||
print(self.click_time - self.previous_click_time)
|
||||
# TODO : a fake click is observed, workaround hereafter
|
||||
if (self.click_time - self.previous_click_time) < 0.01:
|
||||
self.previous_click_time = self.click_time
|
||||
elif (self.click_time - self.previous_click_time) < 0.3:
|
||||
print ("double click")
|
||||
self.destroy()
|
||||
else:
|
||||
print ("simple click")
|
||||
self.previous_click_time = self.click_time
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def _load_image_eventBox(parent, filename, label_text1, label_text2, scale_w, scale_h, font_size):
|
||||
# Create box for xpm and label
|
||||
box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
# Create an eventBox
|
||||
eventBox = Gtk.EventBox()
|
||||
# Now on to the image stuff
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename=filename,
|
||||
width=scale_w,
|
||||
height=scale_h,
|
||||
preserve_aspect_ratio=True)
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
|
||||
label = Gtk.Label()
|
||||
label.set_markup("<span font='%d' color='#39A9DCFF'>%s\n</span>"
|
||||
"<span font='%d' color='#002052FF'>%s</span>" %
|
||||
(font_size, label_text1, font_size, label_text2))
|
||||
label.set_justify(Gtk.Justification.CENTER)
|
||||
label.set_line_wrap(True)
|
||||
|
||||
# Pack the pixmap and label into the box
|
||||
box.pack_start(image, True, False, 0)
|
||||
box.pack_start(label, True, False, 0)
|
||||
|
||||
# Add the image to the eventBox
|
||||
eventBox.add(box)
|
||||
|
||||
return eventBox
|
||||
|
||||
def _load_image_Box(parent, mp1filename, infofilename, label_text, scale_w, scale_h):
|
||||
box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename=mp1filename,
|
||||
width=scale_w,
|
||||
height=scale_h,
|
||||
preserve_aspect_ratio=True)
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
|
||||
# Create a label for the button
|
||||
label0 = Gtk.Label() #for padding
|
||||
label1 = Gtk.Label()
|
||||
label1.set_markup("%s\n" % label_text)
|
||||
label1.set_justify(Gtk.Justification.CENTER)
|
||||
label1.set_line_wrap(True)
|
||||
|
||||
eventBox = Gtk.EventBox()
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename=infofilename,
|
||||
width=scale_w,
|
||||
height=(scale_h/4),
|
||||
preserve_aspect_ratio=True)
|
||||
info = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
eventBox.add(info)
|
||||
eventBox.connect("button_release_event", parent.info_event)
|
||||
eventBox.connect("button_press_event", parent.highlight_eventBox)
|
||||
|
||||
label3 = Gtk.Label()
|
||||
label3.set_markup("<span font='10' color='#FFFFFFFF'><b>Python GTK launcher</b></span>\n")
|
||||
label3.set_justify(Gtk.Justification.CENTER)
|
||||
label3.set_line_wrap(True)
|
||||
|
||||
# Pack the pixmap and label into the box
|
||||
box.pack_start(label0, True, False, 0)
|
||||
box.pack_start(image, True, False, 0)
|
||||
box.pack_start(label1, True, False, 0)
|
||||
box.pack_start(eventBox, True, False, 0)
|
||||
box.pack_start(label3, True, False, 0)
|
||||
|
||||
return box
|
||||
|
||||
def _load_image_on_button(parent, filename, label_text, scale_w, scale_h):
|
||||
# Create box for xpm and label
|
||||
box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
box.set_border_width(2)
|
||||
# print("[DEBUG] image: %s " % filename)
|
||||
# Now on to the image stuff
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename=filename,
|
||||
width=scale_w,
|
||||
height=scale_h,
|
||||
preserve_aspect_ratio=True)
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
|
||||
# Create a label for the button
|
||||
label = Gtk.Label.new(label_text)
|
||||
|
||||
# Pack the pixmap and label into the box
|
||||
box.pack_start(image, True, False, 3)
|
||||
|
||||
image.show()
|
||||
label.show()
|
||||
return box
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def read_board_compatibility_name():
|
||||
if SIMULATE > 0:
|
||||
return "all"
|
||||
else:
|
||||
try:
|
||||
with open("/proc/device-tree/compatible") as fp:
|
||||
string = fp.read()
|
||||
return string.split(',')[-1].rstrip('\x00')
|
||||
except:
|
||||
return "all"
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
BOARD_CONFIG_ID_BOARD = 0
|
||||
BOARD_CONFIG_ID_LOGO = 1
|
||||
BOARD_CONFIG_ID_INFO_TEXT = 2
|
||||
def read_configuration_board_file(search_path):
|
||||
board_list = []
|
||||
yaml_configuration = None
|
||||
board_compatibility_name = read_board_compatibility_name()
|
||||
print("[DEBUG] compatiblity name ", read_board_compatibility_name())
|
||||
configuration_found = None
|
||||
for file in sorted(os.listdir(search_path)):
|
||||
if board_compatibility_name.find(file) > -1:
|
||||
configuration_found = file
|
||||
#print("DEBUG: found board configuration file: ", file)
|
||||
if configuration_found and os.path.isfile(os.path.join(search_path, configuration_found)):
|
||||
print("[DEBUG] read configuration box for ", configuration_found)
|
||||
with open(os.path.join(search_path, configuration_found)) as fp:
|
||||
yaml_configuration = yaml.load(fp, Loader=yaml.FullLoader)
|
||||
|
||||
# board name
|
||||
if yaml_configuration and yaml_configuration["BOARD"]:
|
||||
board_list.append(yaml_configuration["BOARD"])
|
||||
else:
|
||||
board_list.append('STM32MP')
|
||||
# logo to used
|
||||
if yaml_configuration and yaml_configuration["LOGO"]:
|
||||
board_list.append(yaml_configuration["LOGO"])
|
||||
else:
|
||||
board_list.append('pictures/ST20578_Label_OpenSTlinux_V.png')
|
||||
# info text to display
|
||||
if yaml_configuration and yaml_configuration["INFO"]:
|
||||
info = '\n'.join(yaml_configuration["INFO"].split('|'))
|
||||
board_list.append(info)
|
||||
else:
|
||||
board_list.append("<span font='14' color='#FFFFFFFF'><b>STM32MP BOARD</b></span>")
|
||||
return board_list
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
def import_module_by_name(module_name):
|
||||
''' module example:0application.netdata.netdata
|
||||
(corresponding to application/netdata/netdata.py file)
|
||||
'''
|
||||
try:
|
||||
print("[DEBUG] module_name=>%s<" % module_name)
|
||||
imported = importlib.import_module(module_name)
|
||||
except Exception as e:
|
||||
print("Module Load, error: ", e)
|
||||
return None
|
||||
return imported
|
||||
|
||||
class ApplicationButton():
|
||||
def __init__(self, parent, yaml_file, icon_size, font_size):
|
||||
self.event_box = None
|
||||
self.yaml_configuration = None
|
||||
self.icon_size = icon_size
|
||||
self.font_size = font_size
|
||||
self._parent = parent
|
||||
self._compatible = True
|
||||
|
||||
with open(yaml_file) as fp:
|
||||
self.yaml_configuration = yaml.load(fp, Loader=yaml.FullLoader)
|
||||
#print(self.yaml_configuration)
|
||||
#print("Name ", self.yaml_configuration["Application"]["Name"])
|
||||
|
||||
if self.yaml_configuration:
|
||||
# check board if it's compatible
|
||||
if (self._is_compatible(self.yaml_configuration["Application"]["Board"])):
|
||||
self._compatible = True
|
||||
self.event_box = _load_image_eventBox(self, "%s/%s" % (DEMO_PATH, self.yaml_configuration["Application"]["Icon"]),
|
||||
self.yaml_configuration["Application"]["Name"],
|
||||
self.yaml_configuration["Application"]["Description"],
|
||||
-1, self.icon_size, self.font_size)
|
||||
if (self.yaml_configuration["Application"]["Type"].rstrip() == "script"):
|
||||
self.event_box.connect("button_release_event", self.script_handle)
|
||||
self.event_box.connect("button_press_event", self._parent.highlight_eventBox)
|
||||
elif (self.yaml_configuration["Application"]["Type"].rstrip() == "python"):
|
||||
self.event_box.connect("button_release_event", self.python_start)
|
||||
self.event_box.connect("button_press_event", self._parent.highlight_eventBox)
|
||||
else:
|
||||
self._compatible = False
|
||||
print(" %s NOT compatible" % self.yaml_configuration["Application"]["Name"])
|
||||
|
||||
|
||||
def is_exist(self, data):
|
||||
try:
|
||||
#print("[DEBUG][is_exist] ", data)
|
||||
if (data):
|
||||
for masterkey in data:
|
||||
#print("[DEBUG][is_exist] key available: ", masterkey)
|
||||
if masterkey == "Exist":
|
||||
for key in data["Exist"]:
|
||||
#print("[DEBUG][is_exist] key detected: %s" % key)
|
||||
if key == "File" and len(data["Exist"]["File"].rstrip()):
|
||||
if (os.path.exists(data["Exist"]["File"].rstrip())):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif (key == "Command" and len(data["Exist"]["Command"].rstrip())):
|
||||
retcode = subprocess.call(data["Exist"]["Command"].rstrip(), shell=True);
|
||||
if (int(retcode) == 0):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
except:
|
||||
print("is_exist exception return true")
|
||||
return True
|
||||
|
||||
def exist_MSG_present(self, data):
|
||||
try:
|
||||
#print("[DEBUG][is_exist] ", data)
|
||||
if (data):
|
||||
for masterkey in data:
|
||||
#print("[DEBUG][is_exist] key available: ", masterkey)
|
||||
if masterkey == "Exist":
|
||||
for key in data["Exist"]:
|
||||
#print("[DEBUG][is_exist] key detected: %s" % key)
|
||||
if key == "Msg_false" and len(data["Exist"]["Msg_false"].rstrip()):
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def is_compatible(self):
|
||||
return self._compatible
|
||||
def _is_compatible(self, data):
|
||||
board_compatibility_name = read_board_compatibility_name()
|
||||
try:
|
||||
if (data):
|
||||
for key in data:
|
||||
if key == "List" and len(data["List"].rstrip()):
|
||||
#print("[DEBUG] List<", data["List"], "> %s" % board_compatibility_name, " ")
|
||||
if data["List"].find('all') > -1:
|
||||
return True
|
||||
for b in data["List"].split():
|
||||
#print("[DEBUG] test for List <", b, "> %s" % board_compatibility_name, " " , board_compatibility_name.find(b) )
|
||||
if board_compatibility_name.find(b) > -1:
|
||||
return True
|
||||
return False
|
||||
elif key == "NotList" and len(data["NotList"].rstrip()):
|
||||
#print("[DEBUG] NotList<", data["NotList"], "> %s" % board_compatibility_name, " "))
|
||||
for b in data["NotList"].split():
|
||||
#print("[DEBUG] test for Not List <", b, "> %s" % board_compatibility_name, " " , board_compatibility_name.find(b) )
|
||||
if board_compatibility_name.find(b) > -1:
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
except Exception as e:
|
||||
print("is_compatible exception return true ", e)
|
||||
return True
|
||||
return True
|
||||
|
||||
def get_event_box(self):
|
||||
return self.event_box
|
||||
|
||||
def python_start(self, widget, event):
|
||||
print("Python module =>", self.yaml_configuration["Application"]["Python"]["Module"], "<<<")
|
||||
if (self.is_exist(self.yaml_configuration["Application"]["Python"])):
|
||||
if (self.yaml_configuration["Application"]["Python"]["Module"] and
|
||||
len(self.yaml_configuration["Application"]["Python"]["Module"].rstrip()) > 0):
|
||||
module_imported = import_module_by_name(self.yaml_configuration["Application"]["Python"]["Module"].rstrip())
|
||||
if (module_imported):
|
||||
print("[Python_event start]")
|
||||
module_imported.create_subdialogwindow(self._parent)
|
||||
print("[Python_event stop]\n")
|
||||
widget.set_name("transparent_bg")
|
||||
self._parent.button_exit.show()
|
||||
elif (self.exist_MSG_present(self.yaml_configuration["Application"]["Python"])):
|
||||
print("[WARNING] %s not detected\n" % self.yaml_configuration["Application"]["Python"]["Exist"]["Msg_false"])
|
||||
self._parent.display_message("<span font='15' color='#FFFFFFFF'>%s\n</span>" % self.yaml_configuration["Application"]["Python"]["Exist"]["Msg_false"])
|
||||
widget.set_name("transparent_bg")
|
||||
self._parent.button_exit.show()
|
||||
|
||||
def script_start(self):
|
||||
global lock
|
||||
with lock:
|
||||
print("Lock Acquired")
|
||||
backscript_window = BackVideoWindow(self._parent)
|
||||
backscript_window.show_all()
|
||||
|
||||
print("[DEBUG][ApplicationButton][script_handle]:")
|
||||
print(" Name: ", self.yaml_configuration["Application"]["Name"])
|
||||
print(" Start script: ", self.yaml_configuration["Application"]["Script"]["Start"])
|
||||
|
||||
cmd = [os.path.join(DEMO_PATH,self.yaml_configuration["Application"]["Script"]["Start"])]
|
||||
subprocess.run(cmd, stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True)
|
||||
backscript_window.destroy()
|
||||
print("Lock Released")
|
||||
|
||||
def script_handle(self, widget, event):
|
||||
if (self.is_exist(self.yaml_configuration["Application"]["Script"])):
|
||||
print("Acquiring lock")
|
||||
self.script_start()
|
||||
|
||||
elif (self.exist_MSG_present(self.yaml_configuration["Application"]["Script"])):
|
||||
print("[WARNING] %s not detected\n" % self.yaml_configuration["Application"]["Script"]["Exist"]["Msg_false"])
|
||||
self._parent.display_message("<span font='15' color='#FFFFFFFF'>%s\n</span>" % self.yaml_configuration["Application"]["Script"]["Exist"]["Msg_false"])
|
||||
|
||||
print("[script_event stop]\n")
|
||||
widget.set_name("transparent_bg")
|
||||
self._parent.button_exit.show()
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def gtk_style():
|
||||
css = b"""
|
||||
|
||||
.widget .grid .label {
|
||||
background-color: rgba (100%, 100%, 100%, 1.0);
|
||||
}
|
||||
.textview {
|
||||
color: gray;
|
||||
}
|
||||
#normal_bg {
|
||||
background-color: rgba (100%, 100%, 100%, 1.0);
|
||||
}
|
||||
|
||||
#transparent_bg {
|
||||
background-color: rgba (0%, 0%, 0%, 0.0);
|
||||
}
|
||||
#highlight_bg {
|
||||
background-color: rgba (0%, 0%, 0%, 0.1);
|
||||
}
|
||||
#logo_bg {
|
||||
background-color: #03244b;
|
||||
}
|
||||
#backed_bg {
|
||||
background-color: rgba (31%, 32%, 31%, 0.8);
|
||||
}
|
||||
|
||||
"""
|
||||
style_provider = Gtk.CssProvider()
|
||||
style_provider.load_from_data(css)
|
||||
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
Gdk.Screen.get_default(),
|
||||
style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
class MainUIWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Demo Launcher")
|
||||
self.set_decorated(False)
|
||||
gtk_style()
|
||||
if SIMULATE > 0:
|
||||
self.screen_width = SIMULATE_SCREEN_SIZE_WIDTH
|
||||
self.screen_height = SIMULATE_SCREEN_SIZE_HEIGHT
|
||||
else:
|
||||
#self.fullscreen()
|
||||
self.maximize()
|
||||
try:
|
||||
display = Gdk.Display.get_default()
|
||||
monitor = display.get_primary_monitor()
|
||||
geometry = monitor.get_geometry()
|
||||
scale_factor = monitor.get_scale_factor()
|
||||
self.screen_width = scale_factor * geometry.width
|
||||
self.screen_height = scale_factor * geometry.height
|
||||
except:
|
||||
self.screen_width = self.get_screen().get_width()
|
||||
self.screen_height = self.get_screen().get_height()
|
||||
|
||||
self.board_name = "STM32MP board"
|
||||
|
||||
self.set_default_size(self.screen_width, self.screen_height)
|
||||
print("[DEBUG] screen size: %dx%d" % (self.screen_width, self.screen_height))
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.connect('destroy', detroy_quit_application)
|
||||
|
||||
self.previous_click_time=time()
|
||||
|
||||
self.application_path = os.path.join(DEMO_PATH,"./application/")
|
||||
self.board_path = os.path.join(DEMO_PATH,"./board/")
|
||||
|
||||
self.board_configuration = read_configuration_board_file(self.board_path)
|
||||
|
||||
sizes = get_sizes_from_screen_size(self.screen_width, self.screen_height)
|
||||
self.icon_size = sizes[SIZES_ID_ICON_SIZE]
|
||||
self.font_size = sizes[SIZES_ID_FONT_SIZE]
|
||||
self.logo_size = sizes[SIZES_ID_LOGO_SIZE]
|
||||
self.exit_size = sizes[SIZES_ID_EXIT_SIZE]
|
||||
self.column_spacing = sizes[SIZES_ID_COLUMN_SPACING]
|
||||
self.row_spacing = sizes[SIZES_ID_ROW_SPACING]
|
||||
|
||||
# page for basic information
|
||||
self.create_page_icon_autodetected()
|
||||
|
||||
def display_message(self, message):
|
||||
dialog = Gtk.Dialog("Error", self, 0, (Gtk.STOCK_OK, Gtk.ResponseType.OK))
|
||||
dialog.set_decorated(False)
|
||||
width, height = self.get_size()
|
||||
dialog.set_default_size(width, height)
|
||||
dialog.set_name("backed_bg")
|
||||
|
||||
label0 = Gtk.Label() #for padding
|
||||
|
||||
label1 = Gtk.Label()
|
||||
label1.set_markup(message)
|
||||
label1.set_justify(Gtk.Justification.CENTER)
|
||||
label1.set_line_wrap(True)
|
||||
|
||||
label2 = Gtk.Label() #for padding
|
||||
|
||||
# Create a centering alignment object
|
||||
align = Gtk.Alignment()
|
||||
align.set(0.5, 0, 0, 0)
|
||||
|
||||
dialog.vbox.pack_start(label0, True, False, 0)
|
||||
dialog.vbox.pack_start(label1, True, True, 0)
|
||||
dialog.vbox.pack_start(align, True, True, 0)
|
||||
dialog.vbox.pack_start(label2, True, False, 0)
|
||||
|
||||
dialog.action_area.reparent(align)
|
||||
dialog.show_all()
|
||||
|
||||
dialog.run()
|
||||
print("INFO dialog closed")
|
||||
|
||||
dialog.destroy()
|
||||
|
||||
|
||||
def info_event(self, widget, event):
|
||||
print("[info_event start]");
|
||||
info_window = InfoWindow(self)
|
||||
info_window.show_all()
|
||||
response = info_window.run()
|
||||
info_window.destroy()
|
||||
print("[info_event stop]\n");
|
||||
widget.set_name("transparent_bg")
|
||||
self.button_exit.show()
|
||||
|
||||
|
||||
# Button event of main screen
|
||||
def highlight_eventBox(self, widget, event):
|
||||
''' highlight the eventBox widget '''
|
||||
print("[highlight_eventBox start]")
|
||||
widget.set_name("highlight_bg")
|
||||
self.button_exit.hide()
|
||||
print("[highlight_eventBox stop]\n")
|
||||
|
||||
def create_page_icon_autodetected(self):
|
||||
self.yaml_application_list = None
|
||||
self.application_list = []
|
||||
self.application_eventbox_list = []
|
||||
self.application_start_previous = 0
|
||||
self.application_start_next = 0
|
||||
self.application_end = 0
|
||||
|
||||
self.page_main = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
self.page_main.set_border_width(0)
|
||||
|
||||
# create a grid of icon
|
||||
self.icon_grid = Gtk.Grid(column_homogeneous=True, row_homogeneous=True)
|
||||
self.icon_grid.set_column_spacing(self.column_spacing)
|
||||
self.icon_grid.set_row_spacing(self.row_spacing)
|
||||
|
||||
# STM32MP1 Logo and info area
|
||||
info_box_text = self.board_configuration[BOARD_CONFIG_ID_INFO_TEXT]
|
||||
info_box_logo = self.board_configuration[BOARD_CONFIG_ID_LOGO]
|
||||
self.logo_info_area = _load_image_Box(self, "%s/%s" % (DEMO_PATH,info_box_logo), "%s/pictures/ST13340_Info_white.png" % DEMO_PATH, info_box_text, -1, self.logo_size)
|
||||
self.logo_info_area.set_name("logo_bg")
|
||||
self.icon_grid.attach(self.logo_info_area, 3, 0, 1, 2)
|
||||
|
||||
self.back_box = self.create_eventbox_back_next(1)
|
||||
self.next_box = self.create_eventbox_back_next(0)
|
||||
|
||||
number_of_application = 0
|
||||
for file in sorted(os.listdir(self.application_path)):
|
||||
if os.path.isfile(os.path.join(self.application_path, file)) and file.endswith(".yaml"):
|
||||
print("[DEBUG] create event box for ", file)
|
||||
application_button = ApplicationButton(self, os.path.join(self.application_path, file), self.icon_size, self.font_size)
|
||||
if application_button.is_compatible():
|
||||
self.application_list.append(os.path.join(self.application_path, file))
|
||||
self.application_eventbox_list.append(application_button.get_event_box())
|
||||
number_of_application = number_of_application + 1
|
||||
print("[DEBUG] there is %d application(s) detected " % number_of_application)
|
||||
if number_of_application == 0:
|
||||
self.set_default_size(self.screen_width, self.screen_height)
|
||||
self.display_message("<span font='15' color='#FFFFFFFF'>There is no application detected\n</span>")
|
||||
self.destroy()
|
||||
|
||||
self.application_end = len(self.application_list)
|
||||
|
||||
#print("[DEBUG] application list:\n", self.application_list)
|
||||
self.create_page_icon_by_page(0)
|
||||
self.page_main.add(self.icon_grid)
|
||||
|
||||
overlay = Gtk.Overlay()
|
||||
overlay.add(self.page_main)
|
||||
self.button_exit = Gtk.Button()
|
||||
self.button_exit.connect("clicked", detroy_quit_application)
|
||||
self.button_exit_image = _load_image_on_button(self, "%s/pictures/close_70x70_white.png" % DEMO_PATH, "Exit", -1, self.exit_size)
|
||||
self.button_exit.set_halign(Gtk.Align.END)
|
||||
self.button_exit.set_valign(Gtk.Align.START)
|
||||
self.button_exit.add(self.button_exit_image)
|
||||
self.button_exit.set_relief(Gtk.ReliefStyle.NONE)
|
||||
overlay.add_overlay(self.button_exit)
|
||||
self.add(overlay)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def create_page_icon_by_page(self, app_start):
|
||||
'''
|
||||
--------------------------------------------------------------
|
||||
| 0,0: app1 | 1,0: app2 | 2,0: app2 | 3,0: information |
|
||||
--------------------------------------------------------------
|
||||
| 0,1: app1 | 1,1: app2 | 2,1: app2 | 3,1: information |
|
||||
--------------------------------------------------------------
|
||||
'''
|
||||
for ind in range(0,self.application_end):
|
||||
if (self.application_eventbox_list[ind]):
|
||||
self.icon_grid.remove(self.application_eventbox_list[ind])
|
||||
self.icon_grid.remove(self.back_box)
|
||||
self.icon_grid.remove(self.next_box)
|
||||
|
||||
#print("[ICON DEBUG] app_start ", app_start)
|
||||
# calculate next and previous
|
||||
if app_start > 0:
|
||||
if (app_start % 5) == 0:
|
||||
self.application_start_previous = app_start - 5
|
||||
else:
|
||||
self.application_start_previous = app_start - 4
|
||||
if self.application_start_previous < 0:
|
||||
self.application_start_previous = 0
|
||||
self.application_start_next = app_start + 4
|
||||
else:
|
||||
self.application_start_previous = 0
|
||||
self.application_start_next = 5
|
||||
#print("[ICON DEBUG] previous ", self.application_start_previous)
|
||||
#print("[ICON DEBUG] next ", self.application_start_next)
|
||||
|
||||
if app_start != 0:
|
||||
''' add previous button '''
|
||||
index = app_start
|
||||
# 0, 0
|
||||
self.icon_grid.attach(self.back_box, 0, 0, 1, 1)
|
||||
# 1, 0
|
||||
if self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 1, 0, 1, 1)
|
||||
index = index + 1
|
||||
else:
|
||||
index = app_start
|
||||
self.application_start_previous = app_start - 4
|
||||
if self.application_start_previous < 0:
|
||||
self.application_start_previous = 0
|
||||
# 0, 0
|
||||
if self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 0, 0, 1, 1)
|
||||
index = index + 1
|
||||
# 1, 0
|
||||
if (index < self.application_end) and self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 1, 0, 1, 1)
|
||||
else:
|
||||
self.icon_grid.show_all()
|
||||
return
|
||||
index = index + 1
|
||||
# 2, 0
|
||||
if (index < self.application_end) and self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 2, 0, 1, 1)
|
||||
else:
|
||||
self.icon_grid.show_all()
|
||||
return
|
||||
index = index + 1
|
||||
# 0, 1
|
||||
if (index < self.application_end) and self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 0, 1, 1, 1)
|
||||
else:
|
||||
self.icon_grid.show_all()
|
||||
return
|
||||
index = index + 1
|
||||
# 1, 1
|
||||
if (index < self.application_end) and self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 1, 1, 1, 1)
|
||||
else:
|
||||
self.icon_grid.show_all()
|
||||
return
|
||||
index = index + 1
|
||||
# 2, 1
|
||||
if ((index+1) < self.application_end) and self.application_eventbox_list[index]:
|
||||
''' add next button '''
|
||||
self.icon_grid.attach(self.next_box, 2, 1, 1, 1)
|
||||
else:
|
||||
if (index < self.application_end) and self.application_eventbox_list[index]:
|
||||
self.icon_grid.attach(self.application_eventbox_list[index], 2, 1, 1, 1)
|
||||
self.icon_grid.show_all()
|
||||
|
||||
|
||||
def create_eventbox_back_next(self,back):
|
||||
if back > 0:
|
||||
back_eventbox = _load_image_eventBox(self, "%s/pictures/ST10261_back_button_medium_grey.png" % DEMO_PATH,
|
||||
"BACK", "menu", -1, self.icon_size, self.font_size)
|
||||
back_eventbox.connect("button_release_event", self.on_back_menu_event)
|
||||
back_eventbox.connect("button_press_event", self.highlight_eventBox)
|
||||
return back_eventbox
|
||||
else:
|
||||
next_eventbox = _load_image_eventBox(self, "%s/pictures/ST10261_play_button_medium_grey.png" % DEMO_PATH,
|
||||
"NEXT", "menu", -1, self.icon_size, self.font_size)
|
||||
next_eventbox.connect("button_release_event", self.on_next_menu_event)
|
||||
next_eventbox.connect("button_press_event", self.highlight_eventBox)
|
||||
return next_eventbox
|
||||
|
||||
def on_back_menu_event(self, widget, event):
|
||||
self.create_page_icon_by_page(self.application_start_previous)
|
||||
widget.set_name("normal_bg")
|
||||
widget.set_name("transparent_bg")
|
||||
self.button_exit.show()
|
||||
def on_next_menu_event(self, widget, event):
|
||||
self.create_page_icon_by_page(self.application_start_next)
|
||||
widget.set_name("normal_bg")
|
||||
widget.set_name("transparent_bg")
|
||||
self.button_exit.show()
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Signal handler
|
||||
def demo_signal_handler(signum, frame):
|
||||
file_lock_remove(lock_file_path)
|
||||
sys.exit(0)
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Main
|
||||
if __name__ == "__main__":
|
||||
# add signal to catch CRTL+C
|
||||
import signal
|
||||
signal.signal(signal.SIGINT, demo_signal_handler)
|
||||
|
||||
if file_is_locked(lock_file_path):
|
||||
print("[ERROR] another instance is running exiting now\n")
|
||||
exit(0)
|
||||
try:
|
||||
win = MainUIWindow()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.show_all()
|
||||
Gtk.main()
|
||||
except Exception as exc:
|
||||
print("Main Exception: ", exc)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
Summary:
|
||||
=======
|
||||
1. Purpose
|
||||
2. Yaml description for each application
|
||||
3. File tree
|
||||
4. Example of application description
|
||||
|
||||
1. Purpose:
|
||||
-----------
|
||||
Propose a generic way to descibe an application and easily add it on the
|
||||
demo_launcher.
|
||||
To permit a better and dynamic management of application, each application are
|
||||
described on a yaml file.
|
||||
|
||||
2. Yaml description for each application:
|
||||
-----------------------------------------
|
||||
Format:
|
||||
Application:
|
||||
Name: <name of application>
|
||||
Description: <description of application>
|
||||
Icon: <icon of application>
|
||||
Type: <script|python>
|
||||
Board:
|
||||
<List|NotList>: <all|list of chip>
|
||||
Script:
|
||||
Exist:
|
||||
<File|Command>: <file or command to verify>
|
||||
Msg_false: <Message to display if <File|Command> are not true
|
||||
Start: <script or application to launch application>
|
||||
Python:
|
||||
Exist:
|
||||
<File|Command>: <file or command to verify>
|
||||
Msg_false: <Message to display if <File|Command> are not true
|
||||
Module: <Python module name to load>
|
||||
Action:
|
||||
button_release_event: <python_start|script_management>
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
Explaination:
|
||||
- Name: name of application displayed on demo_launcher
|
||||
- Description: description of application displayed on demo_launcher
|
||||
- Icon: icon of application displayed on demo_launcher
|
||||
- Board: define which board the application are compatible
|
||||
List: list of chip/soc the application are compatible
|
||||
NotList: List of chip/soc the application are NOT compatible
|
||||
- Type: Type of script to launch the application,
|
||||
type available:
|
||||
* "script": shell script or application (without parameters) to execute
|
||||
* "python": python script to load for launching application
|
||||
This two type have a specific declaration available: Script, Python
|
||||
- Script: it'a s section for describe the script (shell or application) to
|
||||
launch the application.
|
||||
This section have several sub section:
|
||||
Exist: verify some requirement before to launch start command
|
||||
Start: command to start the application
|
||||
|
||||
Exist section:
|
||||
File: <verify presence of specific file>
|
||||
Command: <command to execute, if return are Ok then we can launch start command>
|
||||
|
||||
- Python: it'a s section for describe the python script to load for accessing
|
||||
to application functionality. The python script must have the function
|
||||
"create_subdialogwindow(<parent window>)"
|
||||
This section have several sub section:
|
||||
Exist: verify some requirement before to launch start command
|
||||
Module: Python module name to load, it's corresponding to path and scirpt
|
||||
name.
|
||||
ex.:
|
||||
path = application/netdata/netdata.py
|
||||
module name = application.netdata.netdata
|
||||
Tips: you need to add an empty file name "__init__.py" on each sub
|
||||
directory to permit to launch the python module
|
||||
|
||||
Exist section:
|
||||
File: <verify presence of specific file>
|
||||
Command: <command to execute, if return are Ok then we can launch start command>
|
||||
|
||||
|
||||
3. File Tree:
|
||||
------------
|
||||
application/
|
||||
├── 000-netdata.yaml
|
||||
├── 010-camera.yaml
|
||||
├── 020-video.yaml
|
||||
├── 030-3d_cube.yaml
|
||||
├── 040-m4_ai.yaml
|
||||
├── 060-bluetooth_audio_output.yaml
|
||||
├── 3d_cube
|
||||
│ ├── bin
|
||||
│ │ └── launch_cube_3D.sh
|
||||
│ └── pictures
|
||||
│ └── ST153_cube_purple.png
|
||||
├── bluetooth
|
||||
│ ├── bluetooth_audio.py
|
||||
│ ├── __init__.py
|
||||
│ ├── pictures
|
||||
│ │ └── ST11012_bluetooth_speaker_light_green.png
|
||||
│ └── wrap_blctl.py
|
||||
├── camera
|
||||
│ ├── bin
|
||||
│ │ └── launch_camera_preview.sh
|
||||
│ ├── pictures
|
||||
│ │ └── ST1077_webcam_dark_blue.png
|
||||
│ └── shaders
|
||||
│ └── edge_InvertLuma.fs
|
||||
├── __init__.py
|
||||
├── m4_ai
|
||||
│ ├── bin
|
||||
│ │ └── launch_AI.sh
|
||||
│ └── pictures
|
||||
│ └── ST7079_AI_neural_pink.png
|
||||
├── netdata
|
||||
│ ├── bin
|
||||
│ │ └── build_qrcode.sh
|
||||
│ ├── __init__.py
|
||||
│ ├── netdata.py
|
||||
│ └── pictures
|
||||
│ └── netdata-icon-192x192.png
|
||||
└── video
|
||||
├── bin
|
||||
│ └── launch_video.sh
|
||||
└── pictures
|
||||
└── Video_playback_logo.pn
|
||||
4. Example of application:
|
||||
-----------------------
|
||||
Example 1:
|
||||
Application:
|
||||
Name: 3D Pict
|
||||
Description: GPU with picture
|
||||
Icon: application/3d_cube/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
NotList: stm32mp151
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GPU capabilities to run 3D GPU demo
|
||||
Start: application/3d_cube/bin/launch_cube_3D.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
Example 2:
|
||||
Application:
|
||||
Name: Camera
|
||||
Description: shader
|
||||
Icon: application/camera/pictures/ST1077_webcam_dark_blue.png
|
||||
Board:
|
||||
List: all
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/video0
|
||||
Msg_false: Webcam is not connected,
|
||||
/dev/video0 doesn't exist
|
||||
Start: application/camera/bin/launch_camera_shader.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
Example 3:
|
||||
Application:
|
||||
Name: Bluetooth
|
||||
Description: speaker
|
||||
Icon: application/bluetooth/pictures/ST11012_bluetooth_speaker_light_green.png
|
||||
Type: python
|
||||
Board:
|
||||
List: stm32mp157 stm32mp153
|
||||
Python:
|
||||
Exist:
|
||||
Command: hciconfig hci0 up
|
||||
Msg_false: Please connect a bluetooth controller on the board
|
||||
Module: application.bluetooth.bluetooth_audio
|
||||
Action:
|
||||
button_release_event: python_start
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 800 B |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
source /etc/profile.d/weston_profile.sh
|
||||
source /etc/profile.d/pulse_profile.sh
|
||||
|
||||
# wait pulseaudio starting
|
||||
while [ 1 ]; do
|
||||
if [ $(pgrep pulseaudio | wc -l) -ge 1 ]; then
|
||||
break;
|
||||
else
|
||||
sleep 1;
|
||||
fi
|
||||
done
|
||||
|
||||
# this magic line permit to create the link to pulseaudio
|
||||
script -qc 'su -l weston -c "source /etc/profile.d/pulse_profile.sh;pactl info; pactl list sinks"'
|
||||
|
||||
while [ 1 ]; do
|
||||
pactl info
|
||||
if [ $? -eq 0 ]; then
|
||||
break;
|
||||
else
|
||||
sleep 1;
|
||||
fi
|
||||
done
|
||||
if [ -f /usr/bin/pulseaudio_hdmi_switch.sh ]; then
|
||||
/usr/bin/pulseaudio_hdmi_switch.sh
|
||||
else
|
||||
pactl info; pactl list sinks
|
||||
|
||||
cards=`pactl list cards | egrep -i 'alsa.card_name' | sed 's/ //g'| sed 's/alsa.card_name=\"//g'| sed 's/\"//g'`
|
||||
index=0
|
||||
for i in $cards;
|
||||
do
|
||||
found=`echo $i | grep -n STM32MP | wc -l`
|
||||
if [ $found -eq 1 ];
|
||||
then
|
||||
pactl set-card-profile $index output:analog-stereo
|
||||
fi
|
||||
index=$((index+1))
|
||||
done
|
||||
fi
|
||||
# force pulseaudio sink and source to be on SUSPENDED state (cf: pactl list sinks)
|
||||
pactl suspend-source 0
|
||||
for sink in $(pactl list short sinks | awk '{ print $1 }'); do
|
||||
pactl suspend-sink $sink
|
||||
done
|
||||
|
||||
/usr/local/demo/demo_launcher.py
|
||||
24
meta-st/meta-st-openstlinux/recipes-samples/demo/qrenc.bb
Normal file
@@ -0,0 +1,24 @@
|
||||
SUMMARY = "qrenc which uses libqrencode to generate QR-code"
|
||||
|
||||
LICENSE = "LGPL-2.1-only"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/LGPL-2.1-only;md5=1a6d268fd218675ffea8be556788b780"
|
||||
|
||||
DEPENDS += "qrencode"
|
||||
DEPENDS += "libpng"
|
||||
|
||||
inherit pkgconfig
|
||||
|
||||
SRC_URI = " file://qrenc.c \
|
||||
file://Makefile \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/bin/
|
||||
install -m 0755 ${B}/qrencode ${D}${prefix}/bin/
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/bin/"
|
||||
|
||||
RDEPENDS:${PN} += "qrencode libpng"
|
||||
@@ -0,0 +1,9 @@
|
||||
all: qrencode
|
||||
|
||||
CFLAGS += -Wall $(shell pkg-config --cflags libqrencode libpng)
|
||||
LDFLAGS += $(shell pkg-config --libs libqrencode libpng)
|
||||
|
||||
qrencode: qrenc.c
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
clean: ; rm -rf *.o qrencode
|
||||
1187
meta-st/meta-st-openstlinux/recipes-samples/demo/qrenc/qrenc.c
Normal file
@@ -0,0 +1,28 @@
|
||||
# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
|
||||
SUMMARY = "Python script which monitor temperature from sensor on Nucleo extension board iks01a2a"
|
||||
LICENSE = "Proprietary"
|
||||
LIC_FILES_CHKSUM = "file://${OPENSTLINUX_BASE}/files/licenses/ST-Proprietary;md5=7cb1e55a9556c7dd1a3cae09db9cc85f"
|
||||
|
||||
SRC_URI = " \
|
||||
file://sensors_temperature.py \
|
||||
\
|
||||
file://pictures \
|
||||
file://README.txt\
|
||||
"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/pictures
|
||||
|
||||
|
||||
install -m 0755 ${WORKDIR}/sensors_temperature.py ${D}${prefix}/local/demo/
|
||||
|
||||
install -m 0644 ${WORKDIR}/pictures/* ${D}${prefix}/local/demo/pictures
|
||||
install -m 0644 ${WORKDIR}/README.txt ${D}${prefix}/local/demo/README_sensor_iks01a2.txt
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/local/demo/"
|
||||
RDEPENDS:${PN} += "python3-core python3-pygobject python3-pycairo gtk+3 "
|
||||
@@ -0,0 +1,71 @@
|
||||
How to deploy demonstration:
|
||||
----------------------------
|
||||
Materials:
|
||||
* Nucleo extension board with mems, here IKS01A2
|
||||
* connection between extension board and stm32mp15 board.
|
||||
|
||||
Pre-requisite:
|
||||
--------------
|
||||
1. Kernel:
|
||||
You need to configure the kernel to support the Nucleo extension
|
||||
board with the devitree configuration and the kernel configuration.
|
||||
|
||||
1.1 DeviceTree:
|
||||
* Enable the sensor on I2C
|
||||
For Discovery board (stm32mp157c-dk2), the sensors are linked on ic25.
|
||||
Add the following line on your devicetree associateds to the board
|
||||
|
||||
&i2c5 {
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&i2c5_pins_a>;
|
||||
pinctrl-1 = <&i2c5_pins_sleep_a>;
|
||||
i2c-scl-rising-time-ns = <124>;
|
||||
i2c-scl-falling-time-ns = <3>;
|
||||
/delete-property/dmas;
|
||||
/delete-property/dma-names;
|
||||
|
||||
status = "okay";
|
||||
|
||||
hts221@5f {
|
||||
compatible = "st,hts221";
|
||||
reg = <0x5f>;
|
||||
};
|
||||
lsm6dsl@6b {
|
||||
compatible = "st,lsm6dsl";
|
||||
reg = <0x6b>;
|
||||
};
|
||||
};
|
||||
|
||||
NOTE: the i2c depend of the pin-muxing of the board and could be different of
|
||||
i2c5.
|
||||
|
||||
1.2 Kernel configuration:
|
||||
Add the following config on your kernel configuraturation
|
||||
(best way are via a new fragment)
|
||||
CONFIG_IIO_BUFFER=y
|
||||
CONFIG_IIO_KFIFO_BUF=y
|
||||
CONFIG_IIO_TRIGGERED_BUFFER=y
|
||||
CONFIG_HTS221=y
|
||||
CONFIG_IIO_ST_PRESS=y
|
||||
CONFIG_IIO_ST_LSM6DSX=y
|
||||
CONFIG_IIO_ST_LSM6DSX_I2C=y
|
||||
|
||||
2. Software
|
||||
You need to have some framework available on the board for executing the
|
||||
python script:
|
||||
|
||||
List of packages already present on st-example-image-weston:
|
||||
weston
|
||||
gtk+3
|
||||
python3 and several python3 addons
|
||||
|
||||
Execution of script on board:
|
||||
-----------------------------
|
||||
Files:
|
||||
/usr/local/demo/
|
||||
/usr/local/demo/sensors_temperature.py
|
||||
|
||||
Put the files on board and launch the python script:
|
||||
BOARD > /usr/local/demo/sensors_temperature.py
|
||||
|
||||
To quit the application, just click on ST logo.
|
||||
@@ -0,0 +1,7 @@
|
||||
CONFIG_IIO_BUFFER=y
|
||||
CONFIG_IIO_KFIFO_BUF=y
|
||||
CONFIG_IIO_TRIGGERED_BUFFER=y
|
||||
CONFIG_HTS221=y
|
||||
CONFIG_IIO_ST_PRESS=y
|
||||
CONFIG_IIO_ST_LSM6DSX=y
|
||||
CONFIG_IIO_ST_LSM6DSX_I2C=y
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 61 KiB |
269
meta-st/meta-st-openstlinux/recipes-samples/demo/sensors-iks01a2/sensor.py
Executable file
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/python3
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GdkPixbuf
|
||||
import cairo
|
||||
|
||||
import random
|
||||
import math
|
||||
import os
|
||||
from time import sleep, time
|
||||
|
||||
# time between each sensor mesearuement (1s)
|
||||
TIME_UPATE = 2000
|
||||
|
||||
|
||||
class Sensors():
|
||||
def __init__(self):
|
||||
''' '''
|
||||
self.sensor_dictionnary = {}
|
||||
|
||||
def found_iio_device_with_name(self, data, name):
|
||||
prefix = "/sys/bus/iio/devices/"
|
||||
of_name = 'OF_NAME=' + name
|
||||
try:
|
||||
for filefolder in os.listdir(prefix):
|
||||
with open(prefix + '/' + filefolder + '/uevent') as f:
|
||||
for line in f:
|
||||
if line.split('\n')[0] == of_name:
|
||||
''' return directory which contains "data" '''
|
||||
if os.path.exists(prefix + '/' + filefolder + '/' + data):
|
||||
return (prefix + '/' + filefolder + '/')
|
||||
except OSError:
|
||||
pass
|
||||
except Exception as exc:
|
||||
pass
|
||||
return None
|
||||
|
||||
def found_all_sensor_path(self):
|
||||
self.sensor_dictionnary['temperature'] = self.found_iio_device_with_name("in_temp_raw", "hts221")
|
||||
self.sensor_dictionnary['humidity'] = self.found_iio_device_with_name("in_humidityrelative_raw", "hts221")
|
||||
self.sensor_dictionnary['accelerometer'] = self.found_iio_device_with_name("in_accel_x_raw", "lsm6dsl")
|
||||
self.sensor_dictionnary['gyroscope'] = self.found_iio_device_with_name("in_anglvel_x_raw", "lsm6dsl")
|
||||
|
||||
print("[DEBUG] temperature -> ", self.sensor_dictionnary['temperature'], "<")
|
||||
print("[DEBUG] humidity -> ", self.sensor_dictionnary['humidity'], "<")
|
||||
print("[DEBUG] accelerometer -> ", self.sensor_dictionnary['accelerometer'], "<")
|
||||
print("[DEBUG] gyroscope -> ", self.sensor_dictionnary['gyroscope'], "<")
|
||||
|
||||
def temperature_read(self):
|
||||
prefix_path = self.sensor_dictionnary['temperature']
|
||||
try:
|
||||
with open(prefix_path + "in_temp_" + 'raw', 'r') as f:
|
||||
raw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_temp_" + 'raw', exc)
|
||||
raw = 0.0
|
||||
try:
|
||||
with open(prefix_path + "in_temp_" + 'scale', 'r') as f:
|
||||
scale = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_temp_" + 'scale', exc)
|
||||
scale = 0.0
|
||||
try:
|
||||
with open(prefix_path + "in_temp_" + 'offset', 'r') as f:
|
||||
offset = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_temp_" + 'offset', exc)
|
||||
offset = 0.0
|
||||
return (offset + raw) * scale
|
||||
|
||||
def humidity_read(self):
|
||||
prefix_path = self.sensor_dictionnary['humidity']
|
||||
try:
|
||||
with open(prefix_path + "in_humidityrelative_" + 'raw', 'r') as f:
|
||||
raw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_humidityrelative_" + 'raw', exc)
|
||||
raw = 0.0
|
||||
try:
|
||||
with open(prefix_path + "in_humidityrelative_" + 'scale', 'r') as f:
|
||||
scale = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_humidityrelative_" + 'scale', exc)
|
||||
scale = 0.0
|
||||
try:
|
||||
with open(prefix_path + "in_humidityrelative_" + 'offset', 'r') as f:
|
||||
offset = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_humidityrelative_" + 'offset', exc)
|
||||
offset = 0.0
|
||||
return (offset + raw) * scale
|
||||
|
||||
def accelerometer_read(self):
|
||||
prefix_path = self.sensor_dictionnary['accelerometer']
|
||||
try:
|
||||
with open(prefix_path + "in_accel_" + 'scale', 'r') as f:
|
||||
rscale = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_accel_" + 'scale', exc)
|
||||
rscale = 0.0
|
||||
|
||||
try:
|
||||
with open(prefix_path + "in_accel_" + 'x_raw', 'r') as f:
|
||||
xraw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_accel_" + 'x_raw', exc)
|
||||
xraw = 0.0
|
||||
accel_x = int(xraw * rscale * 256.0 / 9.81)
|
||||
|
||||
try:
|
||||
with open(prefix_path + "in_accel_" + 'y_raw', 'r') as f:
|
||||
yraw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_accel_" + 'y_raw', exc)
|
||||
yraw = 0.0
|
||||
accel_y = int(yraw * rscale * 256.0 / 9.81)
|
||||
|
||||
try:
|
||||
with open(prefix_path + "in_accel_" + 'z_raw', 'r') as f:
|
||||
zraw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_accel_" + 'z_raw', exc)
|
||||
zraw = 0.0
|
||||
accel_z = int(zraw * rscale * 256.0 / 9.81)
|
||||
|
||||
return [ accel_x, accel_y, accel_z]
|
||||
|
||||
def gyroscope_read(self):
|
||||
prefix_path = self.sensor_dictionnary['gyroscope']
|
||||
try:
|
||||
with open(prefix_path + "in_anglvel_" + 'scale', 'r') as f:
|
||||
rscale = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_anglvel_" + 'scale', exc)
|
||||
rscale = 0.0
|
||||
|
||||
try:
|
||||
with open(prefix_path + "in_anglvel_" + 'x_raw', 'r') as f:
|
||||
xraw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_anglvel_" + 'x_raw', exc)
|
||||
xraw = 0.0
|
||||
gyro_x = int(xraw * rscale * 256.0 / 9.81)
|
||||
|
||||
try:
|
||||
with open(prefix_path + "in_anglvel_" + 'y_raw', 'r') as f:
|
||||
yraw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_anglvel_" + 'y_raw', exc)
|
||||
yraw = 0.0
|
||||
gyro_y = int(yraw * rscale * 256.0 / 9.81)
|
||||
|
||||
try:
|
||||
with open(prefix_path + "in_anglvel_" + 'z_raw', 'r') as f:
|
||||
zraw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % prefix_path + "in_anglvel_" + 'z_raw', exc)
|
||||
zraw = 0.0
|
||||
gyro_z = int(zraw * rscale * 256.0 / 9.81)
|
||||
|
||||
return [ gyro_x, gyro_y, gyro_z]
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
class MainUIWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Sensor usage")
|
||||
#self.set_decorated(False)
|
||||
self.maximize()
|
||||
self.screen_width = self.get_screen().get_width()
|
||||
self.screen_height = self.get_screen().get_height()
|
||||
|
||||
self.set_default_size(self.screen_width, self.screen_height)
|
||||
print("[DEBUG] screen size: %dx%d" % (self.screen_width, self.screen_height))
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.connect('destroy', Gtk.main_quit)
|
||||
|
||||
# search sensor interface
|
||||
self.sensors = Sensors()
|
||||
self.sensors.found_all_sensor_path()
|
||||
|
||||
sensor_box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
|
||||
# temperature
|
||||
temp_label = Gtk.Label()
|
||||
temp_label.set_markup("<span font_desc='LiberationSans 25'>Temperature</span>")
|
||||
self.temp_value_label = Gtk.Label()
|
||||
self.temp_value_label.set_markup("<span font_desc='LiberationSans 25'>--.-- °C</span>")
|
||||
temp_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
temp_box.add(temp_label)
|
||||
temp_box.add(self.temp_value_label)
|
||||
sensor_box.add(temp_box)
|
||||
|
||||
# humidity
|
||||
humidity_label = Gtk.Label()
|
||||
humidity_label.set_markup("<span font_desc='LiberationSans 25'>Humidity</span>")
|
||||
self.humidity_value_label = Gtk.Label()
|
||||
self.humidity_value_label.set_markup("<span font_desc='LiberationSans 25'>--.-- %c</span>" % '%')
|
||||
humidity_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
humidity_box.add(humidity_label)
|
||||
humidity_box.add(self.humidity_value_label)
|
||||
sensor_box.add(humidity_box)
|
||||
|
||||
# Accel
|
||||
accel_label = Gtk.Label()
|
||||
accel_label.set_markup("<span font_desc='LiberationSans 25'>Accelerometer</span>")
|
||||
self.accel_value_label = Gtk.Label()
|
||||
self.accel_value_label.set_markup("<span font_desc='LiberationSans 25'> [ --.--, --.--, --.--]</span>")
|
||||
accel_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
accel_box.add(accel_label)
|
||||
accel_box.add(self.accel_value_label)
|
||||
sensor_box.add(accel_box)
|
||||
|
||||
# Gyroscope
|
||||
gyro_label = Gtk.Label()
|
||||
gyro_label.set_markup("<span font_desc='LiberationSans 25'>Gyroscope</span>")
|
||||
self.gyro_value_label = Gtk.Label()
|
||||
self.gyro_value_label.set_markup("<span font_desc='LiberationSans 25'> [ --.--, --.--, --.--]</span>")
|
||||
gyro_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
gyro_box.add(gyro_label)
|
||||
gyro_box.add(self.gyro_value_label)
|
||||
sensor_box.add(gyro_box)
|
||||
|
||||
self.add(sensor_box)
|
||||
|
||||
# Add a timer callback to update
|
||||
# this takes 2 args: (how often to update in millisec, the method to run)
|
||||
GLib.timeout_add(TIME_UPATE, self.update_ui)
|
||||
|
||||
|
||||
def destroy(self, widget, data=None):
|
||||
Gtk.main_quit()
|
||||
|
||||
|
||||
def update_ui(self):
|
||||
# temperature
|
||||
temp = self.sensors.temperature_read()
|
||||
self.temp_value_label.set_markup("<span font_desc='LiberationSans 25'>%.02f °C</span>" % temp)
|
||||
# humidity
|
||||
hum = self.sensors.humidity_read()
|
||||
self.humidity_value_label.set_markup("<span font_desc='LiberationSans 25'>%.02f %c</span>" % (hum, '%'))
|
||||
# accel
|
||||
accel = self.sensors.accelerometer_read()
|
||||
self.accel_value_label.set_markup("<span font_desc='LiberationSans 25'>[ %.02f, %.02f, %.02f]</span>" % (accel[0], accel[1], accel[2]))
|
||||
# gyro
|
||||
gyro = self.sensors.gyroscope_read()
|
||||
self.gyro_value_label.set_markup("<span font_desc='LiberationSans 25'>[ %.02f, %.02f, %.02f]</span>" % (gyro[0], gyro[1], gyro[2]))
|
||||
|
||||
# As this is a timeout function, return True so that it
|
||||
# continues to get called
|
||||
return True
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Main
|
||||
if __name__ == "__main__":
|
||||
# add signal to catch CRTL+C
|
||||
import signal
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
win = MainUIWindow()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.show_all()
|
||||
|
||||
Gtk.main()
|
||||
91
meta-st/meta-st-openstlinux/recipes-samples/demo/sensors-iks01a2/sensor.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/bin/sh
|
||||
|
||||
for d in `ls -d1 /sys/bus/iio/devices/*device*`;
|
||||
do
|
||||
# for hts221: Temperature + Humidity
|
||||
if grep -q hts221 $d/name ;
|
||||
then
|
||||
echo "============================="
|
||||
echo "=== HTS221 ==="
|
||||
echo "=== (temperature) ==="
|
||||
echo "============================="
|
||||
raw=`cat $d/in_temp_raw`
|
||||
offset=`cat $d/in_temp_offset`
|
||||
scale=`cat $d/in_temp_scale`
|
||||
|
||||
printf "Value read: raw %0f\n" $raw
|
||||
printf "Value read: offset %0f\n" $offset
|
||||
printf "Value read: scale %0f\n" $scale
|
||||
|
||||
temperature=`echo "scale=2;$raw*$scale + $offset*$scale" | bc`
|
||||
|
||||
echo "Temperature $temperature"
|
||||
printf "Temperature %.02f\n" $temperature
|
||||
|
||||
echo "============================="
|
||||
echo "=== HTS221 ==="
|
||||
echo "=== (humidity) ==="
|
||||
echo "============================="
|
||||
raw=`cat $d/in_humidityrelative_raw`
|
||||
offset=`cat $d/in_humidityrelative_offset`
|
||||
scale=`cat $d/in_humidityrelative_scale`
|
||||
|
||||
printf "Value read: raw %0f\n" $raw
|
||||
printf "Value read: offset %0f\n" $offset
|
||||
printf "Value read: scale %0f\n" $scale
|
||||
|
||||
humidity=`echo "scale=2;$raw*$scale + $offset*$scale" | bc`
|
||||
|
||||
echo "Humidity $humidity"
|
||||
printf "Humidity %.02f\n" $humidity
|
||||
fi
|
||||
|
||||
# for lsm6dsl: accelerometer
|
||||
if grep -q lsm6dsl_accel $d/name ;
|
||||
then
|
||||
echo "============================="
|
||||
echo "=== LSM6DSL ==="
|
||||
echo "=== (accelerometer) ==="
|
||||
echo "============================="
|
||||
rscale=`cat $d/in_accel_scale`
|
||||
|
||||
xraw=`cat $d/in_accel_x_raw`
|
||||
yraw=`cat $d/in_accel_y_raw`
|
||||
zraw=`cat $d/in_accel_z_raw`
|
||||
|
||||
printf "Value read: X (raw/scale) %d / %.06f \n" $xraw $rscale
|
||||
printf "Value read: Y (raw/scale) %d / %.06f \n" $yraw $rscale
|
||||
printf "Value read: Z (raw/scale) %d / %.06f \n" $zraw $rscale
|
||||
|
||||
factor=`echo "scale=2;256.0 / 9.81" | bc`
|
||||
xval=`echo "scale=2;$xraw*$rscale*$factor" | bc`
|
||||
yval=`echo "scale=2;$yraw*$rscale*$factor" | bc`
|
||||
zval=`echo "scale=2;$zraw*$rscale*$factor" | bc`
|
||||
|
||||
printf "Accelerometer value: [ %.02f, %.02f, %.02f ]\n" $xval $yval $zval
|
||||
fi
|
||||
|
||||
# for lsm6dsl: gyroscope
|
||||
if grep -q lsm6dsl_gyro $d/name ;
|
||||
then
|
||||
echo "============================="
|
||||
echo "=== LSM6DSL ==="
|
||||
echo "=== (gyroscope) ==="
|
||||
echo "============================="
|
||||
rscale=`cat $d/in_anglvel_scale`
|
||||
xraw=`cat $d/in_anglvel_x_raw`
|
||||
yraw=`cat $d/in_anglvel_y_raw`
|
||||
zraw=`cat $d/in_anglvel_z_raw`
|
||||
|
||||
printf "Value read: X (raw/scale) %d / %.06f \n" $xraw $rscale
|
||||
printf "Value read: Y (raw/scale) %d / %.06f \n" $yraw $rscale
|
||||
printf "Value read: Z (raw/scale) %d / %.06f \n" $zraw $rscale
|
||||
|
||||
factor=`echo "scale=2;256.0 / 9.81" | bc`
|
||||
xval=`echo "scale=2;$xraw*$rscale*$factor" | bc`
|
||||
yval=`echo "scale=2;$yraw*$rscale*$factor" | bc`
|
||||
zval=`echo "scale=2;$zraw*$rscale*$factor" | bc`
|
||||
|
||||
printf "Gyroscope value: [ %.02f, %.02f, %.02f ]\n" $xval $yval $zval
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,767 @@
|
||||
#!/usr/bin/python3
|
||||
# to debug this script:
|
||||
# python3 -m pdb ./sensors_temperature.py
|
||||
#
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GdkPixbuf
|
||||
import cairo
|
||||
|
||||
import random
|
||||
import math
|
||||
import os
|
||||
import socket
|
||||
from collections import deque
|
||||
from time import sleep, time
|
||||
|
||||
#
|
||||
# For simulating the presence of sensor, please use
|
||||
# the variable SIMULATE_SENSORS = 1
|
||||
# If SIMULATE_SENSORS = 1 then
|
||||
# the picture/icon must be present on pictures directory
|
||||
#
|
||||
SIMULATE_SENSORS = 0
|
||||
|
||||
ICON_PICTURES_PATH = "/usr/local/demo/pictures"
|
||||
|
||||
WITH_PRESSURE = 0
|
||||
WITH_GYRO = 1
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# CONSTANT VALUES
|
||||
#
|
||||
SIMULATE_SCREEN_SIZE_WIDTH = 480
|
||||
SIMULATE_SCREEN_SIZE_HEIGHT = 800
|
||||
DEFAULT_SCREEN_WIDTH = 400
|
||||
DEFAULT_SCREEN_HEIGHT = 600
|
||||
|
||||
# time between each sensor mesearuement (1s)
|
||||
TIME_UPATE = 2000
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# SPLASH SCREEN class
|
||||
# the splash screen display a logo and the different step of boot
|
||||
#
|
||||
class SplashScreen():
|
||||
def __init__(self, picture_filename, timeout):
|
||||
#DONT connect 'destroy' event here!
|
||||
self.window = Gtk.Window()
|
||||
self.window.set_title('Sensor IKS01A2')
|
||||
self.window.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.window.set_decorated(False)
|
||||
if SIMULATE_SENSORS > 0:
|
||||
screen_width = SIMULATE_SCREEN_SIZE_WIDTH
|
||||
screen_height = SIMULATE_SCREEN_SIZE_HEIGHT
|
||||
else:
|
||||
self.window.fullscreen()
|
||||
#self.maximize()
|
||||
screen_width = self.window.get_screen().get_width()
|
||||
screen_height = self.window.get_screen().get_height()
|
||||
|
||||
self.window.set_default_size(screen_width, screen_height)
|
||||
self.window.set_border_width(1)
|
||||
|
||||
# Add Vbox with image and label
|
||||
main_vbox = Gtk.VBox(False, 1)
|
||||
self.window.add(main_vbox)
|
||||
# load picture
|
||||
print("[DEBUG] Splash screen with picture: %s" % picture_filename)
|
||||
if os.path.exists(picture_filename):
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename=picture_filename,
|
||||
width=400, # TODO: change size
|
||||
height=600, # TODO: change size
|
||||
preserve_aspect_ratio=True)
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
main_vbox.pack_start(image, True, True, 0)
|
||||
|
||||
#self.lbl = Gtk.Label("Init: splash screen")
|
||||
#self.lbl.set_alignment(0, 0.5)
|
||||
#main_vbox.pack_start(self.lbl, True, True, 0)
|
||||
|
||||
self.window.set_auto_startup_notification(False)
|
||||
self.window.show_all()
|
||||
self.window.set_auto_startup_notification(True)
|
||||
|
||||
# Ensure the splash is completely drawn before moving on
|
||||
GLib.timeout_add(1000, self.loop)
|
||||
self.loops = 0
|
||||
self.loops_timeout = timeout
|
||||
self.loops_break = 0
|
||||
|
||||
def update_text(self, text):
|
||||
self.lbl.set_text(text)
|
||||
|
||||
def loop_stop(self):
|
||||
self.loops_break = 1
|
||||
|
||||
def loop(self):
|
||||
global var
|
||||
var = time ()
|
||||
print ("[DEBUG] ", var)
|
||||
self.loops += 1
|
||||
if self.loops_break or self.loops == self.loops_timeout:
|
||||
Gtk.main_quit()
|
||||
self.window.destroy()
|
||||
return False
|
||||
return True
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def _load_image_on_button(parent, filename, label_text, scale_w, scale_h):
|
||||
# Create box for xpm and label
|
||||
box1 = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
box1.set_border_width(2)
|
||||
# Now on to the image stuff
|
||||
#image = Gtk.Image()
|
||||
#image.set_from_file(filename)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename=filename,
|
||||
width=scale_w,
|
||||
height=scale_h,
|
||||
preserve_aspect_ratio=True)
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
|
||||
# Create a label for the button
|
||||
label = Gtk.Label(label_text)
|
||||
|
||||
# Pack the pixmap and label into the box
|
||||
box1.pack_start(image, True, False, 3)
|
||||
#box1.pack_start(label, False, False, 3)
|
||||
|
||||
image.show()
|
||||
label.show()
|
||||
return box1
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def _load_image(parent, filename_without_prefix):
|
||||
img = Gtk.Image()
|
||||
img.set_from_file("%s/%s" % (ICON_PICTURES_PATH, filename_without_prefix))
|
||||
return img
|
||||
|
||||
# scale_width and scale_height are sht siez disired after scale,
|
||||
# It can be -1 for no scale on one value
|
||||
def _load_image_constrained(parent, filename_without_prefix, scale_width, scale_height):
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
filename="%s/%s" % (ICON_PICTURES_PATH, filename_without_prefix),
|
||||
width=scale_width,
|
||||
height=scale_height,
|
||||
preserve_aspect_ratio=True)
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
return image
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
class Sensors():
|
||||
key_temperature = 'temp'
|
||||
key_humidity = 'humidity'
|
||||
key_pressure = 'pressure'
|
||||
|
||||
key_accelerometer = 'accel'
|
||||
key_gyroscope = 'gyro'
|
||||
key_magnetometer = 'magneto'
|
||||
|
||||
driver_name_temperature = 'driver_temp'
|
||||
driver_name_humidity = 'driver_humidity'
|
||||
driver_name_pressure = 'driver_pressure'
|
||||
driver_name_accelerometer = 'driver_accel'
|
||||
driver_name_gyroscope = 'driver_gyro'
|
||||
driver_name_magnetometer = 'driver_magneto'
|
||||
|
||||
|
||||
prefix_temp = "in_temp_"
|
||||
prefix_humidity = "in_humidityrelative_"
|
||||
prefix_pressure = "in_pressure_"
|
||||
|
||||
prefix_accel = "in_accel_"
|
||||
prefix_gyro = "in_anglvel_"
|
||||
prefix_magneto = "in_magn_" # TODO: verify
|
||||
|
||||
def __init__(self):
|
||||
''' '''
|
||||
self.sensor_dictionnary = {}
|
||||
|
||||
def init_pressure_sampling_frequency(self):
|
||||
if not self.sensor_dictionnary[self.key_pressure] is None and len(self.sensor_dictionnary[self.key_pressure]) > 5:
|
||||
with open(self.sensor_dictionnary[self.key_pressure] + 'sampling_frequency', 'w') as f:
|
||||
f.write('10')
|
||||
|
||||
def found_iio_device(self, data):
|
||||
prefix = "/sys/bus/iio/devices/"
|
||||
try:
|
||||
for filefolder in os.listdir(prefix):
|
||||
if os.path.exists(prefix + '/' + filefolder + '/' + data):
|
||||
''' return directory which contains "data" '''
|
||||
return (prefix + '/' + filefolder + '/')
|
||||
except OSError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def found_iio_device_with_name(self, data, name):
|
||||
prefix = "/sys/bus/iio/devices/"
|
||||
of_name = 'OF_NAME=' + name
|
||||
try:
|
||||
for filefolder in os.listdir(prefix):
|
||||
with open(prefix + '/' + filefolder + '/uevent') as f:
|
||||
for line in f:
|
||||
if line.split('\n')[0] == of_name:
|
||||
''' return directory which contains "data" '''
|
||||
if os.path.exists(prefix + '/' + filefolder + '/' + data):
|
||||
return (prefix + '/' + filefolder + '/')
|
||||
except OSError:
|
||||
pass
|
||||
except Exception as exc:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def driver_name_iio_device(self, key):
|
||||
if SIMULATE_SENSORS > 0:
|
||||
val_name = "-Simulated-"
|
||||
else:
|
||||
if self.sensor_dictionnary[key] == None:
|
||||
val_name = "-Not present / Simulated-"
|
||||
else:
|
||||
try:
|
||||
with open(self.sensor_dictionnary[key] + "name", 'r') as f:
|
||||
val_name = f.read()
|
||||
except Exception as exc:
|
||||
val_name = "-Not present-"
|
||||
return val_name
|
||||
|
||||
def found_all_sensor_path(self):
|
||||
self.sensor_dictionnary[self.key_temperature] = self.found_iio_device_with_name("in_temp_raw", "hts221")
|
||||
self.sensor_dictionnary[self.key_humidity] = self.found_iio_device("in_humidityrelative_raw")
|
||||
self.sensor_dictionnary[self.key_pressure] = self.found_iio_device("in_pressure_raw")
|
||||
|
||||
self.sensor_dictionnary[self.key_accelerometer] = self.found_iio_device("in_accel_x_raw")
|
||||
if WITH_GYRO:
|
||||
self.sensor_dictionnary[self.key_gyroscope] = self.found_iio_device("in_anglvel_x_raw")
|
||||
else:
|
||||
self.sensor_dictionnary[self.key_gyroscope] = ""
|
||||
|
||||
self.sensor_dictionnary[self.key_magnetometer] = "" #TODO
|
||||
|
||||
self.sensor_dictionnary[self.driver_name_temperature] = self.driver_name_iio_device(self.key_temperature)
|
||||
self.sensor_dictionnary[self.driver_name_humidity] = self.driver_name_iio_device(self.key_humidity)
|
||||
self.sensor_dictionnary[self.driver_name_pressure] = self.driver_name_iio_device(self.key_pressure)
|
||||
|
||||
self.sensor_dictionnary[self.driver_name_accelerometer] = self.driver_name_iio_device(self.key_accelerometer)
|
||||
self.sensor_dictionnary[self.driver_name_gyroscope] = self.driver_name_iio_device(self.key_gyroscope)
|
||||
self.sensor_dictionnary[self.driver_name_magnetometer] = self.driver_name_iio_device(self.key_magnetometer)
|
||||
|
||||
self.init_pressure_sampling_frequency()
|
||||
print("[DEBUG] " , self.key_temperature, " -> ", self.sensor_dictionnary[self.key_temperature], "<")
|
||||
print("[DEBUG] " , self.key_humidity, " -> ", self.sensor_dictionnary[self.key_humidity], "<")
|
||||
print("[DEBUG] " , self.key_pressure, " -> ", self.sensor_dictionnary[self.key_pressure], "<")
|
||||
print("[DEBUG] " , self.key_accelerometer, " -> ", self.sensor_dictionnary[self.key_accelerometer], "<")
|
||||
print("[DEBUG] " , self.key_gyroscope, " -> ", self.sensor_dictionnary[self.key_gyroscope], "<")
|
||||
print("[DEBUG] " , self.key_magnetometer, " -> ", self.sensor_dictionnary[self.key_magnetometer], "<")
|
||||
|
||||
|
||||
def read_sensor_basic(self, key, prefix):
|
||||
if SIMULATE_SENSORS > 0:
|
||||
if self.key_temperature == key:
|
||||
return random.uniform(0.0, 50.0)
|
||||
elif self.key_humidity == key:
|
||||
return random.uniform(0.0, 100.0)
|
||||
else:
|
||||
return random.uniform(800.0, 1200.0)
|
||||
else:
|
||||
if self.sensor_dictionnary[key] is None or len(self.sensor_dictionnary[key]) < 5:
|
||||
return 0.0
|
||||
try:
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'raw', 'r') as f:
|
||||
raw = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % self.sensor_dictionnary[key] + prefix + 'raw', exc)
|
||||
raw = 0.0
|
||||
try:
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'scale', 'r') as f:
|
||||
scale = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % self.sensor_dictionnary[key] + prefix + 'scale', exc)
|
||||
scale = 0.0
|
||||
if self.key_pressure != key:
|
||||
try:
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'offset', 'r') as f:
|
||||
offset = float(f.read())
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % self.sensor_dictionnary[key] + prefix + 'offset', exc)
|
||||
offset = 0.0
|
||||
else:
|
||||
offset = 0.0
|
||||
scale = scale * 10
|
||||
|
||||
temp = (offset + raw) * scale
|
||||
#print("[DEBUG] [%s] %f" % (key, temp))
|
||||
return temp
|
||||
def read_sensor_move(self, key, prefix):
|
||||
if SIMULATE_SENSORS > 0:
|
||||
in_x = random.randint(-180, 180)
|
||||
in_y = random.randint(-180, 180)
|
||||
in_z = random.randint(-180, 180)
|
||||
return [in_x, in_y, in_z]
|
||||
else:
|
||||
if self.sensor_dictionnary[key] is None or len(self.sensor_dictionnary[key]) < 5:
|
||||
return [0, 0, 0]
|
||||
try:
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'x_raw', 'r') as f:
|
||||
scale = float(f.read())
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'x_scale', 'r') as f:
|
||||
raw = float(f.read())
|
||||
in_x = int(raw * scale * 256.0 / 9.81)
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'y_raw', 'r') as f:
|
||||
scale = float(f.read())
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'y_scale', 'r') as f:
|
||||
raw = float(f.read())
|
||||
in_y = int(raw * scale * 256.0 / 9.81)
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'z_raw', 'r') as f:
|
||||
scale = float(f.read())
|
||||
with open(self.sensor_dictionnary[key] + prefix + 'z_scale', 'r') as f:
|
||||
raw = float(f.read())
|
||||
in_z = int(raw * scale * 256.0 / 9.81)
|
||||
except Exception as exc:
|
||||
print("[ERROR] read %s " % self.sensor_dictionnary[key] + prefix + '[x_ , y_ , z_ ]', exc)
|
||||
return [0, 0, 0]
|
||||
return [in_x, in_y, in_z]
|
||||
|
||||
def read_temperature(self):
|
||||
return self.read_sensor_basic(self.key_temperature, self.prefix_temp)
|
||||
def read_humidity(self):
|
||||
return self.read_sensor_basic(self.key_humidity, self.prefix_humidity)
|
||||
def read_pressure(self):
|
||||
return self.read_sensor_basic(self.key_pressure, self.prefix_pressure)
|
||||
|
||||
def read_accelerometer(self):
|
||||
return self.read_sensor_move(self.key_accelerometer, self.prefix_accel)
|
||||
def read_gyroscope(self):
|
||||
return self.read_sensor_move(self.key_gyroscope, self.prefix_gyro)
|
||||
def read_magnetometer(self):
|
||||
return self.read_sensor_move(self.key_magnetometer, self.prefix_magneto)
|
||||
|
||||
def get_driver_name_temperature(self):
|
||||
return self.sensor_dictionnary[self.driver_name_temperature]
|
||||
def get_driver_name_humidity(self):
|
||||
return self.sensor_dictionnary[self.driver_name_humidity]
|
||||
def get_driver_name_pressure(self):
|
||||
return self.sensor_dictionnary[self.driver_name_pressure]
|
||||
def get_driver_name_accelerometer(self):
|
||||
return self.sensor_dictionnary[self.driver_name_accelerometer]
|
||||
def get_driver_name_gyroscope(self):
|
||||
return self.sensor_dictionnary[self.driver_name_gyroscope]
|
||||
def get_driver_name_magnetometer(self):
|
||||
return self.sensor_dictionnary[self.driver_name_magnetometer]
|
||||
|
||||
def calculate_imu(self, accel):
|
||||
x = accel[0]
|
||||
y = accel[1]
|
||||
z = accel[2]
|
||||
if x == 0 and y == 0 and z == 0:
|
||||
return [0, 0, 0]
|
||||
pitch = round(math.atan(x / math.sqrt(y * y + z * z)) * (180.0 / math.pi))
|
||||
roll = round(math.atan(y / math.sqrt(x * x + z * z)) * (180.0 / math.pi))
|
||||
yaw = round(math.atan(z / math.sqrt(x * x + z * z)) * (180.0 / math.pi))
|
||||
|
||||
return [pitch, roll, yaw]
|
||||
def get_imu_orientation(self, pitch, roll):
|
||||
if abs(pitch) > 35:
|
||||
''' (rotation > 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP;'''
|
||||
if pitch > 0:
|
||||
return "left-up"
|
||||
else:
|
||||
return "right-up"
|
||||
else:
|
||||
if abs(roll) > 35:
|
||||
'''ret = (rotation > 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL;'''
|
||||
if roll > 0:
|
||||
return "bottom-up"
|
||||
else:
|
||||
return "normal"
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
class MainUIWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Sensor usage")
|
||||
self.set_decorated(False)
|
||||
if SIMULATE_SENSORS > 0:
|
||||
self.screen_width = SIMULATE_SCREEN_SIZE_WIDTH
|
||||
self.screen_height = SIMULATE_SCREEN_SIZE_HEIGHT
|
||||
else:
|
||||
self.fullscreen()
|
||||
#self.maximize()
|
||||
self.screen_width = self.get_screen().get_width()
|
||||
self.screen_height = self.get_screen().get_height()
|
||||
|
||||
self.set_default_size(self.screen_width, self.screen_height)
|
||||
print("[DEBUG] screen size: %dx%d" % (self.screen_width, self.screen_height))
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.connect('destroy', Gtk.main_quit)
|
||||
|
||||
# search sensor interface
|
||||
self.sensors = Sensors()
|
||||
self.sensors.found_all_sensor_path()
|
||||
|
||||
# variable for sensor
|
||||
self._axis_ranges = {} # {axis_num: [min_seen, max_seen]}
|
||||
self._axis_values = {} # {axis_num: deque([val0, ..., valN])}
|
||||
# create nodebook
|
||||
self.notebook = Gtk.Notebook()
|
||||
self.add(self.notebook)
|
||||
|
||||
# page for basic information
|
||||
# current temperature / Humidity / Pressure
|
||||
self.create_notebook_page_basic_sensor()
|
||||
|
||||
# page for accel / gyro / magentic
|
||||
self.create_notebook_page_basic_accel()
|
||||
|
||||
# page for IMU
|
||||
self.create_notebook_page_imu()
|
||||
|
||||
# page sensor information
|
||||
self.create_notebook_page_sensor_information()
|
||||
|
||||
# page for quitting application
|
||||
self.create_notebook_page_exit()
|
||||
|
||||
# Add a timer callback to update
|
||||
# this takes 2 args: (how often to update in millisec, the method to run)
|
||||
self.timer = GObject.timeout_add(TIME_UPATE, self.update_ui, None)
|
||||
self.timer_enable = True
|
||||
|
||||
self.show_all()
|
||||
|
||||
def _set_basic_temperature(self, val):
|
||||
self.temperature_basic_label.set_markup("<span font_desc='LiberationSans 25'>%.02f °C</span>" % val)
|
||||
#self.temperature_basic_label.set_text("%.02f °C" % val)
|
||||
def _set_basic_humidity(self, val):
|
||||
self.humidity_basic_label.set_markup("<span font_desc='LiberationSans 25'>%.02f %c</span>" % (val, '%'))
|
||||
#self.humidity_basic_label.set_text("%.02f %c" % (val, '%'))
|
||||
def _set_basic_pressure(self, val):
|
||||
self.pressure_basic_label.set_markup("<span font_desc='LiberationSans 25'>%.02f hP</span>" % val)
|
||||
#self.pressure_basic_label.set_text("%.02f hP" % val)
|
||||
def _set_basic_accelerometer(self, x, y, z):
|
||||
self.liststore[self.accel_store][1] = '%d' % x
|
||||
self.liststore[self.accel_store][2] = '%d' % y
|
||||
self.liststore[self.accel_store][3] = '%d' % z
|
||||
def _set_basic_gyroscope(self, x, y, z):
|
||||
self.liststore[self.gyro_store][1] = '%d' % x
|
||||
self.liststore[self.gyro_store][2] = '%d' % y
|
||||
self.liststore[self.gyro_store][3] = '%d' % z
|
||||
def _set_basic_magnetometer(self, x, y, z):
|
||||
self.liststore[self.magneto_store][1] = '%d' % x
|
||||
self.liststore[self.magneto_store][2] = '%d' % y
|
||||
self.liststore[self.magneto_store][3] = '%d' % z
|
||||
def _set_imu_roll(self, val):
|
||||
self.imu_liststore[self.roll_store][1] = '%d' % val
|
||||
def _set_imu_pitch(self, val):
|
||||
self.imu_liststore[self.pitch_store][1] = '%d' % val
|
||||
def _set_imu_yaw(self, val):
|
||||
self.imu_liststore[self.yaw_store][1] = '%d' % val
|
||||
def _update_orientation(self, val):
|
||||
self.orientation_label.set_markup("<span font_desc='LiberationSans 25'>Orientation: %s</span>" % val)
|
||||
|
||||
def create_notebook_page_basic_sensor(self):
|
||||
'''
|
||||
create notebook page for displaying basic current
|
||||
sensor information: temperature, humidity, pressure
|
||||
'''
|
||||
page_basic = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
page_basic.set_border_width(10)
|
||||
|
||||
# temperature
|
||||
temp_box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
temp_image = _load_image_constrained(self, "RS1069_climate_change_light_blue.png", -1, 100)
|
||||
self.temperature_basic_label = Gtk.Label('--.-- °C')
|
||||
temp_image.show()
|
||||
self.temperature_basic_label.show()
|
||||
temp_box.pack_start(temp_image, True, False, 1)
|
||||
temp_box.add(self.temperature_basic_label)
|
||||
# humidity
|
||||
humidity_box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
humidity_image = _load_image_constrained(self, "RS1902_humidity_light_blue.png", -1, 100)
|
||||
self.humidity_basic_label = Gtk.Label('--.-- °C')
|
||||
humidity_image.show()
|
||||
self.humidity_basic_label.show()
|
||||
humidity_box.pack_start(humidity_image, True, False, 1)
|
||||
humidity_box.add(self.humidity_basic_label)
|
||||
# Pressure
|
||||
if WITH_PRESSURE:
|
||||
pressure_box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
pressure_image = _load_image_constrained(self, "RS6355_FORCE_PRESSURE_light_blue.png", -1, 100)
|
||||
self.pressure_basic_label = Gtk.Label('--.-- °C')
|
||||
pressure_image.show()
|
||||
self.pressure_basic_label.show()
|
||||
pressure_box.pack_start(pressure_image, True, False, 1)
|
||||
pressure_box.add(self.pressure_basic_label)
|
||||
|
||||
page_basic.add(temp_box)
|
||||
page_basic.add(humidity_box)
|
||||
if WITH_PRESSURE:
|
||||
page_basic.add(pressure_box)
|
||||
notebook_title = Gtk.Label()
|
||||
notebook_title.set_markup("<span font_desc='LiberationSans 25'>Sensors</span>")
|
||||
self.notebook.append_page(page_basic, notebook_title)
|
||||
|
||||
def create_notebook_page_basic_accel(self):
|
||||
'''
|
||||
create notebook page for displaying movement
|
||||
sensor information: accellerometer, gyroscope, magentometer
|
||||
'''
|
||||
page_basic_movement = Gtk.Box()
|
||||
page_basic_movement.set_border_width(10)
|
||||
|
||||
self.liststore = Gtk.ListStore(str, str, str, str)
|
||||
self.accel_store = self.liststore.append([ "Accelerometer", "0.0", "0.0", "0.0" ])
|
||||
if WITH_GYRO:
|
||||
self.gyro_store = self.liststore.append([ "Gyroscope", "0.0", "0.0", "0.0" ])
|
||||
#if WITH_MAGNETO:
|
||||
# self.magneto_store = self.liststore.append([ "Magnetometer", "0.0", "0.0", "0.0" ])
|
||||
treeview = Gtk.TreeView(model=self.liststore)
|
||||
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
column_text = Gtk.TreeViewColumn("Sensor", renderer_text, text=0)
|
||||
treeview.append_column(column_text)
|
||||
|
||||
renderer_x = Gtk.CellRendererText()
|
||||
column_x = Gtk.TreeViewColumn("X", renderer_x, text=1)
|
||||
treeview.append_column(column_x)
|
||||
|
||||
renderer_y = Gtk.CellRendererText()
|
||||
column_y = Gtk.TreeViewColumn("Y", renderer_y, text=2)
|
||||
treeview.append_column(column_y)
|
||||
|
||||
renderer_z = Gtk.CellRendererText()
|
||||
column_z = Gtk.TreeViewColumn("Z", renderer_z, text=3)
|
||||
treeview.append_column(column_z)
|
||||
|
||||
page_basic_movement.add(treeview)
|
||||
notebook_title = Gtk.Label()
|
||||
notebook_title.set_markup("<span font_desc='LiberationSans 25'>Move</span>")
|
||||
self.notebook.append_page(page_basic_movement, notebook_title)
|
||||
|
||||
|
||||
def create_notebook_page_imu(self):
|
||||
'''
|
||||
display the IMU: Inertial Measurement Unit
|
||||
Roll(X-axis), Pitch(Y-axis) and Yaw(Z-axis).
|
||||
'''
|
||||
page_imu_all = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
imu_frame = Gtk.Frame(label="IMU")
|
||||
orientation_frame = Gtk.Frame(label="Orientation")
|
||||
|
||||
page_imu = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
|
||||
#page_imu_all.add(page_imu)
|
||||
page_imu_all.add(imu_frame)
|
||||
page_imu_all.add(orientation_frame)
|
||||
|
||||
page_imu.set_border_width(10)
|
||||
# explanation
|
||||
imu_label = Gtk.Label()
|
||||
imu_label.set_markup("<span font_desc='LiberationSans 25'>Inertial Measurement Unit</span>")
|
||||
|
||||
page_imu.add(imu_label)
|
||||
|
||||
imu_h_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
# picture which describe IMU
|
||||
picture_filename = "%s/RS10670_Aereo-lpr.jpg" % ICON_PICTURES_PATH
|
||||
image_imu = _load_image(self, "RS10670_Aereo-lpr.jpg")
|
||||
|
||||
imu_h_box.pack_start(image_imu, True, True, 10)
|
||||
# add tree view with roll, picth, yaw
|
||||
self.imu_liststore = Gtk.ListStore(str, str)
|
||||
self.roll_store = self.imu_liststore.append([ "Roll (X-axis)", "0.0"])
|
||||
self.pitch_store = self.imu_liststore.append([ "Pitch (Y-axis)", "0.0"])
|
||||
self.yaw_store = self.imu_liststore.append([ "Yaw (Z-axis)", "0.0"])
|
||||
imu_treeview = Gtk.TreeView(model=self.imu_liststore)
|
||||
imu_h_box.add(imu_treeview)
|
||||
page_imu.add(imu_h_box)
|
||||
imu_frame.add(page_imu)
|
||||
|
||||
self.orientation_label = Gtk.Label()
|
||||
self.orientation_label.set_markup("<span font_desc='LiberationSans 25'>Orientation: --none--</span>")
|
||||
orientation_frame.add(self.orientation_label)
|
||||
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
#renderer_text.set_property("size", 18)
|
||||
column_imu_text = Gtk.TreeViewColumn('Type', renderer_text, text=0)
|
||||
imu_treeview.append_column(column_imu_text)
|
||||
renderer_val = Gtk.CellRendererText()
|
||||
column_val = Gtk.TreeViewColumn("Value", renderer_val, text=1)
|
||||
imu_treeview.append_column(column_val)
|
||||
|
||||
notebook_title = Gtk.Label()
|
||||
notebook_title.set_markup("<span font_desc='LiberationSans 25'>IMU</span>")
|
||||
self.notebook.append_page(page_imu_all, notebook_title)
|
||||
|
||||
def _create_frame_with_image_and_label(self, title, img_file_name, label_text):
|
||||
frame = Gtk.Frame(label=title)
|
||||
box = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
img = _load_image(self, img_file_name)
|
||||
img = _load_image_constrained(self, img_file_name, -1, 100)
|
||||
label = Gtk.Label()
|
||||
label.set_markup("<span font_desc='LiberationSans 18'>%s</span>" % label_text)
|
||||
box.add(img)
|
||||
box.add(label)
|
||||
frame.add(box)
|
||||
return frame
|
||||
|
||||
def create_notebook_page_sensor_information(self):
|
||||
''' Display all the sensor used for this demo '''
|
||||
page_sensor_info = Gtk.Grid()
|
||||
|
||||
frame_temp = self._create_frame_with_image_and_label(
|
||||
"%25s" % "Temperature",
|
||||
"RS1069_climate_change_light_blue.png",
|
||||
self.sensors.get_driver_name_temperature()
|
||||
)
|
||||
frame_humidity = self._create_frame_with_image_and_label(
|
||||
"%25s" % "Humidity",
|
||||
"RS1902_humidity_light_blue.png",
|
||||
self.sensors.get_driver_name_humidity()
|
||||
)
|
||||
if WITH_PRESSURE:
|
||||
frame_pressure = self._create_frame_with_image_and_label(
|
||||
"%25s" % "Pressure",
|
||||
"RS6355_FORCE_PRESSURE_light_blue.png",
|
||||
self.sensors.get_driver_name_pressure()
|
||||
)
|
||||
frame_accel = self._create_frame_with_image_and_label(
|
||||
"%25s" % "Accelerometer",
|
||||
"RS1761_MEMS_accelerometer_light_blue.png",
|
||||
self.sensors.get_driver_name_accelerometer()
|
||||
)
|
||||
if WITH_GYRO:
|
||||
frame_gyro = self._create_frame_with_image_and_label(
|
||||
"%25s" % "Gyroscope",
|
||||
"RS1760_MEMS_gyroscope_light_blue.png",
|
||||
self.sensors.get_driver_name_gyroscope()
|
||||
)
|
||||
#if WITH_MAGNETO:
|
||||
# frame_magneto = self._create_frame_with_image_and_label(
|
||||
# "%25s" % "Magnetometer",
|
||||
# "RS1762_MEMS_compass_light_blue.png",
|
||||
# self.sensors.get_driver_name_magnetometer()
|
||||
# )
|
||||
|
||||
page_sensor_info.set_column_spacing(2)
|
||||
page_sensor_info.set_row_spacing(2)
|
||||
|
||||
page_sensor_info.attach(frame_temp, 1, 1, 3, 1)
|
||||
page_sensor_info.attach_next_to(frame_humidity, frame_temp,
|
||||
Gtk.PositionType.RIGHT, 1, 1)
|
||||
if WITH_PRESSURE:
|
||||
page_sensor_info.attach_next_to(frame_pressure, frame_humidity,
|
||||
Gtk.PositionType.RIGHT, 1, 1)
|
||||
page_sensor_info.attach_next_to(frame_accel, frame_temp,
|
||||
Gtk.PositionType.BOTTOM, 1, 1)
|
||||
if WITH_GYRO:
|
||||
page_sensor_info.attach_next_to(frame_gyro, frame_accel,
|
||||
Gtk.PositionType.RIGHT, 1, 1)
|
||||
#if WITH_MAGNETO:
|
||||
# page_sensor_info.attach_next_to(frame_magneto, frame_gyro,
|
||||
# Gtk.PositionType.RIGHT, 1, 1)
|
||||
|
||||
#self.notebook.append_page(page_sensor_info,
|
||||
# Gtk.Image.new_from_icon_name(
|
||||
# "dialog-information",
|
||||
# Gtk.IconSize.MENU
|
||||
# ))
|
||||
notebook_title = Gtk.Label()
|
||||
notebook_title.set_markup("<span font_desc='LiberationSans 25'>Infos</span>")
|
||||
self.notebook.append_page(page_sensor_info, notebook_title)
|
||||
|
||||
def create_notebook_page_exit(self):
|
||||
''' notebook page for quitting application '''
|
||||
page = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
page.set_border_width(10)
|
||||
''' button '''
|
||||
lastbutton = Gtk.Button()
|
||||
lastbutton.connect("clicked", self.destroy)
|
||||
image_to_add = _load_image_on_button(self, "%s/RS70_ST_Logo_Qi.png" % ICON_PICTURES_PATH, "Quit", -1, 200)
|
||||
lastbutton.add(image_to_add)
|
||||
lastbutton.show()
|
||||
|
||||
page.pack_start(lastbutton, True, True, 0)
|
||||
exit_label = Gtk.Label()
|
||||
exit_label.set_markup("<span font_desc='LiberationSans 25'>To exit, click on logo.</span>")
|
||||
page.pack_start(exit_label, False, False, 0)
|
||||
|
||||
notebook_title = Gtk.Label()
|
||||
notebook_title.set_markup("<span font_desc='LiberationSans 25'>EXIT</span>")
|
||||
|
||||
self.notebook.append_page(page, notebook_title)
|
||||
def destroy(self, widget, data=None):
|
||||
Gtk.main_quit()
|
||||
|
||||
def rearm_timer(self):
|
||||
if self.timer_enable:
|
||||
self.timer = GObject.timeout_add(TIME_UPATE, self.update_ui, None)
|
||||
|
||||
def update_ui(self, user_data):
|
||||
if False == self.timer_enable:
|
||||
return False;
|
||||
|
||||
# temperature
|
||||
temp = self.sensors.read_temperature()
|
||||
self._set_basic_temperature(temp)
|
||||
# humidity
|
||||
hum = self.sensors.read_humidity()
|
||||
self._set_basic_humidity(hum)
|
||||
# pressure
|
||||
if WITH_PRESSURE:
|
||||
press = self.sensors.read_pressure()
|
||||
self._set_basic_pressure(press)
|
||||
|
||||
# accel
|
||||
accel = self.sensors.read_accelerometer()
|
||||
self._set_basic_accelerometer(accel[0], accel[1], accel[2])
|
||||
# gyro
|
||||
if WITH_GYRO:
|
||||
gyro = self.sensors.read_gyroscope()
|
||||
self._set_basic_gyroscope(gyro[0], gyro[1], gyro[2])
|
||||
# magneto
|
||||
#if WITH_MAGNETO:
|
||||
# magneto = self.sensors.read_magnetometer()
|
||||
# self._set_basic_magnetometer(magneto[0], magneto[1], magneto[2])
|
||||
|
||||
# imu
|
||||
pitch, roll, yaw = self.sensors.calculate_imu(accel)
|
||||
self._set_imu_pitch(pitch)
|
||||
self._set_imu_roll(roll)
|
||||
self._set_imu_yaw(yaw)
|
||||
self._update_orientation(self.sensors.get_imu_orientation(pitch, roll))
|
||||
|
||||
#print("[DEBUG] visibility: ", self.get_property("visible"))
|
||||
|
||||
# As this is a timeout function, return True so that it
|
||||
# continues to get called
|
||||
return True
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Main
|
||||
if __name__ == "__main__":
|
||||
# add signal to catch CRTL+C
|
||||
import signal
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
try:
|
||||
#splScr = SplashScreen("%s/RS70_ST_Logo_Qi.png" % ICON_PICTURES_PATH, 5)
|
||||
#Gtk.main()
|
||||
|
||||
win = MainUIWindow()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.show_all()
|
||||
except Exception as exc:
|
||||
print("Main Exception: ", exc )
|
||||
|
||||
Gtk.main()
|
||||
@@ -0,0 +1,505 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gdk
|
||||
import cairo
|
||||
|
||||
import random
|
||||
import math
|
||||
from collections import deque
|
||||
import os
|
||||
|
||||
#for testing on PC without sensors, put REAL to 0
|
||||
MAKE_REAL_MESUREMENT = 1
|
||||
|
||||
NUM_SAMPLES = 112
|
||||
HMARGIN = 20
|
||||
VMARGIN = 10
|
||||
CHARTHEIGHT = 40
|
||||
|
||||
GRAPH_V_PADDING = 4
|
||||
GRAPH_H_PADDING = 4
|
||||
|
||||
#TIME_UPATE = 5000
|
||||
TIME_UPATE = 1000
|
||||
|
||||
|
||||
# example of orientation
|
||||
# https://github.com/hadess/iio-sensor-proxy/blob/master/src/test-orientation-gtk.c
|
||||
ORIENTATION_UNDEFINED = 0
|
||||
ORIENTATION_NORMAL = 1
|
||||
ORIENTATION_BOTTOM_UP = 2
|
||||
ORIENTATION_LEFT_UP = 3
|
||||
ORIENTATION_RIGHT_UP = 4
|
||||
|
||||
def _load_image_on_button(parent, filename, label_text):
|
||||
# Create box for xpm and label
|
||||
box1 = Gtk.HBox(False, 0)
|
||||
box1.set_border_width(2)
|
||||
# Now on to the image stuff
|
||||
image = Gtk.Image()
|
||||
image.set_from_file(filename)
|
||||
|
||||
# Create a label for the button
|
||||
label = Gtk.Label(label_text)
|
||||
|
||||
# Pack the pixmap and label into the box
|
||||
box1.pack_start(image, True, False, 3)
|
||||
#box1.pack_start(label, False, False, 3)
|
||||
|
||||
image.show()
|
||||
label.show()
|
||||
return box1
|
||||
|
||||
class SensorWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Temperature/Humidity")
|
||||
if MAKE_REAL_MESUREMENT > 0:
|
||||
self.fullscreen()
|
||||
#self.maximize()
|
||||
screen_width = self.get_screen().get_width()
|
||||
screen_height = 600
|
||||
else:
|
||||
screen_width = 400
|
||||
screen_height = 600
|
||||
|
||||
self.temperature_prefix_path = self.found_iio_device("in_temp_raw")
|
||||
self.humidity_prefix_path = self.found_iio_device("in_humidityrelative_raw")
|
||||
self.accelerometer_prefix_path = self.found_iio_device("in_accel_x_raw")
|
||||
|
||||
#screen_height = self.get_screen().get_height()
|
||||
|
||||
self.set_default_size(screen_width, screen_height)
|
||||
|
||||
# current, Max, Min
|
||||
self.temperature_max = 0.0
|
||||
self.temperature_min = 35.0
|
||||
self.humidity_max = 0.0
|
||||
self.humidity_min = 35.0
|
||||
|
||||
'''
|
||||
0: "undefined"
|
||||
1: "normal"
|
||||
2: "bottom-up",
|
||||
3: "left-up",
|
||||
4: "right-up",
|
||||
'''
|
||||
self.previous_orientation = ORIENTATION_UNDEFINED
|
||||
|
||||
''' TreeView '''
|
||||
self.liststore = Gtk.ListStore(str, str, str, str)
|
||||
self.temperature_store = self.liststore.append([ "Temperature", "0.0", "0.0", "0.0" ])
|
||||
self.humidity_store = self.liststore.append([ "Humidity", "0.0", "0.0", "0.0" ])
|
||||
self.accel_store = self.liststore.append([ "Accelerometer", "0.0", "0.0", "0.0" ])
|
||||
|
||||
self.treeview = Gtk.TreeView(model=self.liststore)
|
||||
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
column_text = Gtk.TreeViewColumn("Sensor", renderer_text, text=0)
|
||||
self.treeview.append_column(column_text)
|
||||
|
||||
renderer_current = Gtk.CellRendererText()
|
||||
column_cur = Gtk.TreeViewColumn("Current", renderer_current, text=1)
|
||||
self.treeview.append_column(column_cur)
|
||||
|
||||
renderer_max = Gtk.CellRendererText()
|
||||
column_max = Gtk.TreeViewColumn("Max", renderer_max, text=2)
|
||||
self.treeview.append_column(column_max)
|
||||
|
||||
renderer_min = Gtk.CellRendererText()
|
||||
column_min = Gtk.TreeViewColumn("Min", renderer_min, text=3)
|
||||
self.treeview.append_column(column_min)
|
||||
|
||||
# Add a timer callback to update
|
||||
# this takes 2 args: (how often to update in millisec, the method to run)
|
||||
self.timer = GObject.timeout_add(TIME_UPATE, self.update_ui, None)
|
||||
|
||||
''' DrawView '''
|
||||
self.drawarea = Gtk.DrawingArea()
|
||||
|
||||
self.drawing_area_width = screen_width
|
||||
self.drawing_area_height = screen_height/2
|
||||
|
||||
self.drawarea.set_size_request(self.drawing_area_width, self.drawing_area_height)
|
||||
self.drawarea.connect("draw", self._draw_event)
|
||||
self._axis_ranges = {} # {axis_num: [min_seen, max_seen]}
|
||||
self._axis_values = {} # {axis_num: deque([val0, ..., valN])}
|
||||
|
||||
''' spinner '''
|
||||
# add scale
|
||||
grid_scale_hor = Gtk.Grid()
|
||||
grid_scale_hor.set_column_spacing(10)
|
||||
grid_scale_hor.set_column_homogeneous(True)
|
||||
|
||||
self.x_adj = Gtk.Adjustment(0, -256, 256, 2, 2, 0)
|
||||
self.x_scale = Gtk.Scale(orientation=Gtk.Orientation.VERTICAL)
|
||||
self.x_scale.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.x_scale.set_adjustment(self.x_adj)
|
||||
self.x_scale.set_digits(0)
|
||||
self.x_scale.set_draw_value(True)
|
||||
self.x_scale.set_vexpand(True)
|
||||
grid_scale_hor.attach(self.x_scale, 0, 0, 1, 1)
|
||||
|
||||
self.y_adj = Gtk.Adjustment(0, -256, 256, 2, 2, 0)
|
||||
self.y_scale = Gtk.Scale()
|
||||
self.y_scale.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.y_scale.set_adjustment(self.y_adj)
|
||||
self.y_scale.set_digits(0)
|
||||
self.y_scale.set_draw_value(True)
|
||||
self.y_scale.set_vexpand(True)
|
||||
grid_scale_hor.attach_next_to(self.y_scale, self.x_scale, Gtk.PositionType.RIGHT, 1, 1)
|
||||
|
||||
self.z_adj = Gtk.Adjustment(0.0, -256.0, 256.0, 2.0, 2.0, 0.0)
|
||||
self.z_scale = Gtk.Scale()
|
||||
self.z_scale.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.z_scale.set_adjustment(self.z_adj)
|
||||
self.z_scale.set_digits(0)
|
||||
self.z_scale.set_draw_value(True)
|
||||
self.z_scale.set_vexpand(True)
|
||||
grid_scale_hor.attach_next_to(self.z_scale, self.y_scale, Gtk.PositionType.RIGHT, 1, 1)
|
||||
|
||||
self.orientation = Gtk.Label("Orientation")
|
||||
#grid_scale_hor.attach_next_to(self.orientation, self.z_scale, Gtk.PositionType.RIGHT, 1, 1)
|
||||
grid_scale_hor.attach(self.orientation, 0, 1, 2, 1)
|
||||
|
||||
''' button '''
|
||||
lastbutton = Gtk.Button()
|
||||
lastbutton.connect("clicked", self.destroy)
|
||||
if MAKE_REAL_MESUREMENT > 0:
|
||||
image_to_add = _load_image_on_button(self, "/home/root/stlogo.png", "Quit")
|
||||
else:
|
||||
image_to_add = _load_image_on_button(self, "./stlogo.png", "Quit")
|
||||
lastbutton.add(image_to_add)
|
||||
lastbutton.show()
|
||||
|
||||
"""
|
||||
UI:
|
||||
---------------------------------------------------
|
||||
| | |
|
||||
| DrawingArea with two graph | Treeview |
|
||||
| | |
|
||||
---------------------------------------------------
|
||||
| | |
|
||||
| Spinner for accelerometer | Button with |
|
||||
| | ST image |
|
||||
---------------------------------------------------
|
||||
"""
|
||||
box_outer = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||
self.add(box_outer)
|
||||
|
||||
# to activate draw area
|
||||
boxdraw_vert = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||
boxdraw_vert.pack_start(self.drawarea, False, True, 0)
|
||||
boxdraw_vert.pack_start(grid_scale_hor, True, True, 0)
|
||||
|
||||
box_outer.pack_start(boxdraw_vert, False, True, 0)
|
||||
|
||||
box_vert = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||
|
||||
self.tree_frame = Gtk.Frame(label="Temperature & Humidity")
|
||||
box_vert.pack_start(self.tree_frame, True, True, 0)
|
||||
self.tree_frame.add(self.treeview)
|
||||
|
||||
box_vert.pack_start(lastbutton, True, True, 0)
|
||||
|
||||
box_outer.pack_start(box_vert, True, True, 0)
|
||||
|
||||
def destroy(self, widget, data=None):
|
||||
Gtk.main_quit()
|
||||
|
||||
def found_iio_device(self, data):
|
||||
prefix = "/sys/bus/iio/devices/"
|
||||
try:
|
||||
for filefolder in os.listdir(prefix):
|
||||
if os.path.exists(prefix + '/' + filefolder + '/' + data):
|
||||
''' return directory which contains "data" '''
|
||||
return (prefix + '/' + filefolder + '/')
|
||||
except OSError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def _draw_cb(self, drawingarea, ctx):
|
||||
width = self.drawing_area_width
|
||||
height = self.drawing_area_height
|
||||
|
||||
axis_ids = set(self._axis_ranges.keys())
|
||||
axis_ids.intersection_update(set(self._axis_values.keys()))
|
||||
for i in sorted(axis_ids):
|
||||
if i == 1:
|
||||
# temperature value
|
||||
|
||||
#draw rectangle
|
||||
ctx.set_source_rgb(0.8, 0.8, 0.8)
|
||||
ctx.rectangle(0, 0, width, height/2)
|
||||
ctx.fill()
|
||||
|
||||
#draw axes
|
||||
ctx.set_source_rgb(0, 1, 1)
|
||||
ctx.move_to(30 + 0.5, height/4)
|
||||
ctx.line_to(width - 0.5, height/4)
|
||||
ctx.stroke()
|
||||
|
||||
# value (text)
|
||||
ctx.select_font_face("sans-serif")
|
||||
ctx.set_font_size(20.0)
|
||||
ctx.set_source_rgb(0, 0, 0)
|
||||
ctx.move_to(0, 20)
|
||||
ctx.show_text("T (°C)")
|
||||
ctx.set_font_size(10.0)
|
||||
ctx.move_to(0, height/4 + 4)
|
||||
ctx.show_text("20 °C")
|
||||
# temperateure between 0 and 40
|
||||
values = self._axis_values[i]
|
||||
ctx.set_source_rgb(0, 0, 0)
|
||||
for x, v in enumerate(values):
|
||||
val = 30 + x*GRAPH_H_PADDING
|
||||
ctx.move_to(val, height/2)
|
||||
ctx.line_to(val, (40.0 - v) * height/80)
|
||||
ctx.stroke()
|
||||
|
||||
if i == 2:
|
||||
# Humidity values
|
||||
|
||||
offset = 10
|
||||
#draw rectangle
|
||||
ctx.set_source_rgb(0.8, 0.8, 0.8)
|
||||
ctx.rectangle(0, height/2 + offset, width, height/2)
|
||||
ctx.fill()
|
||||
|
||||
#draw axes
|
||||
ctx.set_source_rgb(0, 1, 1)
|
||||
ctx.move_to(25 + 0.5, height/2 + offset + height/4)
|
||||
ctx.line_to(width - 0.5, height/2 + offset + height/4)
|
||||
ctx.stroke()
|
||||
|
||||
# value (text)
|
||||
ctx.select_font_face("sans-serif")
|
||||
ctx.set_font_size(20.0)
|
||||
ctx.set_source_rgb(0, 0, 0)
|
||||
ctx.move_to(0, height/2 + offset + 20)
|
||||
ctx.show_text("H (%)")
|
||||
ctx.set_font_size(10.0)
|
||||
ctx.set_source_rgb(0, 0, 0)
|
||||
ctx.move_to(0, height/2 + offset + height/4 + 4)
|
||||
ctx.show_text("50 %")
|
||||
|
||||
values = self._axis_values[i]
|
||||
ctx.set_source_rgb(0, 0, 0)
|
||||
for x, v in enumerate(values):
|
||||
val = 25 + x*GRAPH_H_PADDING
|
||||
ctx.move_to(val, height/2 + offset + height/2)
|
||||
ctx.line_to(val, height/2 + offset + (100.0 - v) * height/200)
|
||||
ctx.stroke()
|
||||
return False
|
||||
|
||||
def _orientation_calc(self, x, y, z):
|
||||
rotation = round( math.atan(x / math.sqrt(y * y + z * z)) * 180.0 * math.pi)
|
||||
if abs(rotation) > 35:
|
||||
''' (rotation > 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP;'''
|
||||
if self.previous_orientation == ORIENTATION_LEFT_UP or self.previous_orientation == ORIENTATION_NORMAL:
|
||||
if abs(rotation) < 5:
|
||||
self.update_movement(self.previous_orientation)
|
||||
else:
|
||||
if rotation > 0:
|
||||
self.update_movement(ORIENTATION_LEFT_UP)
|
||||
else:
|
||||
self.update_movement(ORIENTATION_RIGHT_UP)
|
||||
else:
|
||||
rotation = round( math.atan(y / math.sqrt(x * x + z * z)) * 180.0 * math.pi)
|
||||
if abs(rotation) > 35:
|
||||
'''ret = (rotation > 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL;'''
|
||||
if self.previous_orientation == ORIENTATION_BOTTOM_UP or self.previous_orientation == ORIENTATION_NORMAL:
|
||||
if abs(rotation) < 5:
|
||||
self.update_movement(self.previous_orientation)
|
||||
else:
|
||||
if rotation > 0:
|
||||
self.update_movement(ORIENTATION_BOTTOM_UP)
|
||||
else:
|
||||
self.update_movement(ORIENTATION_NORMAL)
|
||||
|
||||
def orientation_calc(self, x, y, z):
|
||||
rotation = round( math.atan(x / math.sqrt(y * y + z * z)) * 180.0 * math.pi)
|
||||
|
||||
if abs(rotation) > 35:
|
||||
''' (rotation > 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP;'''
|
||||
if rotation > 0:
|
||||
self.update_movement(ORIENTATION_LEFT_UP)
|
||||
else:
|
||||
self.update_movement(ORIENTATION_RIGHT_UP)
|
||||
else:
|
||||
rotation = round( math.atan(y / math.sqrt(x * x + z * z)) * 180.0 * math.pi)
|
||||
if abs(rotation) > 35:
|
||||
'''ret = (rotation > 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL;'''
|
||||
if rotation > 0:
|
||||
self.update_movement(ORIENTATION_BOTTOM_UP)
|
||||
else:
|
||||
self.update_movement(ORIENTATION_NORMAL)
|
||||
|
||||
def udate_temperature(self, cur_val):
|
||||
self.liststore[self.temperature_store][1] = '%.2f' % cur_val
|
||||
if cur_val > self.temperature_max:
|
||||
self.temperature_max = cur_val
|
||||
if cur_val < self.temperature_min:
|
||||
self.temperature_min = cur_val
|
||||
self.liststore[self.temperature_store][2] = '%.2f' % self.temperature_max
|
||||
self.liststore[self.temperature_store][3] = '%.2f' % self.temperature_min
|
||||
|
||||
''' for drawing '''
|
||||
values = self._axis_values.get(1, None)
|
||||
if values is None:
|
||||
values = deque(maxlen=NUM_SAMPLES)
|
||||
self._axis_values[1] = values
|
||||
if len(list(values)) > (NUM_SAMPLES - 1):
|
||||
values. popleft()
|
||||
values.append(cur_val)
|
||||
self._axis_ranges[1] = (0.0, 60.0)
|
||||
|
||||
#print("TEMPERATURE: cur_val = %0.2f Max: %0.2f" % (cur_val, self.temperature_max))
|
||||
#print(self.liststore[self.temperature_store][0:])
|
||||
|
||||
def udate_humidity(self, cur_val):
|
||||
self.liststore[self.humidity_store][1] = '%.2f' % cur_val
|
||||
if cur_val > self.humidity_max:
|
||||
self.humidity_max = cur_val
|
||||
if cur_val < self.humidity_min:
|
||||
self.humidity_min = cur_val
|
||||
self.liststore[self.humidity_store][2] = '%.2f' % self.humidity_max
|
||||
self.liststore[self.humidity_store][3] = '%.2f' % self.humidity_min
|
||||
|
||||
''' for drawing '''
|
||||
values = self._axis_values.get(2, None)
|
||||
if values is None:
|
||||
values = deque(maxlen=NUM_SAMPLES)
|
||||
self._axis_values[2] = values
|
||||
values.append(cur_val)
|
||||
self._axis_ranges[2] = (0.0, 60.0)
|
||||
|
||||
def update_accel(self, x, y, z):
|
||||
self.liststore[self.accel_store][1] = '%d' % x
|
||||
self.liststore[self.accel_store][2] = '%d' % y
|
||||
self.liststore[self.accel_store][3] = '%d' % z
|
||||
self.x_adj.set_value(x)
|
||||
self.y_adj.set_value(y)
|
||||
self.z_adj.set_value(z)
|
||||
|
||||
def update_movement(self, m):
|
||||
self.previous_orientation = m
|
||||
if m == ORIENTATION_UNDEFINED:
|
||||
self.orientation.set_text("undefined")
|
||||
elif m == ORIENTATION_NORMAL:
|
||||
self.orientation.set_text("normal")
|
||||
elif m == ORIENTATION_BOTTOM_UP:
|
||||
self.orientation.set_text("bottom-up")
|
||||
elif m == ORIENTATION_LEFT_UP:
|
||||
self.orientation.set_text("left-up")
|
||||
elif m == ORIENTATION_RIGHT_UP:
|
||||
self.orientation.set_text("right-up")
|
||||
else:
|
||||
self.orientation.set_text("undefined")
|
||||
|
||||
def read_temperature(self):
|
||||
offset = 0.0
|
||||
raw = 0.0
|
||||
scale = 0.0
|
||||
temp = 0.0
|
||||
if MAKE_REAL_MESUREMENT > 0:
|
||||
if self.temperature_prefix_path:
|
||||
with open(self.temperature_prefix_path + 'in_temp_offset', 'r') as f:
|
||||
offset = float(f.read())
|
||||
with open(self.temperature_prefix_path + 'in_temp_raw', 'r') as f:
|
||||
raw = float(f.read())
|
||||
with open(self.temperature_prefix_path + 'in_temp_scale', 'r') as f:
|
||||
scale = float(f.read())
|
||||
temp = (offset + raw) * scale
|
||||
self.udate_temperature(temp)
|
||||
else:
|
||||
# randomly generated
|
||||
self.udate_temperature(random.uniform(18.0, 35.0))
|
||||
else:
|
||||
# randomly generated
|
||||
self.udate_temperature(random.uniform(18.0, 35.0))
|
||||
|
||||
def read_humidity(self):
|
||||
offset = 0.0
|
||||
raw = 0.0
|
||||
scale = 0.0
|
||||
temp = 0.0
|
||||
if MAKE_REAL_MESUREMENT > 0:
|
||||
if self.humidity_prefix_path:
|
||||
with open(self.humidity_prefix_path + 'in_humidityrelative_offset', 'r') as f:
|
||||
offset = float(f.read())
|
||||
with open(self.humidity_prefix_path + 'in_humidityrelative_raw', 'r') as f:
|
||||
raw = float(f.read())
|
||||
with open(self.humidity_prefix_path + 'in_humidityrelative_scale', 'r') as f:
|
||||
scale = float(f.read())
|
||||
temp = (offset + raw) * scale
|
||||
self.udate_humidity(temp)
|
||||
else:
|
||||
# randomly generated
|
||||
self.udate_humidity(random.uniform(18.0, 35.0))
|
||||
else:
|
||||
# randomly generated
|
||||
self.udate_humidity(random.uniform(18.0, 35.0))
|
||||
|
||||
def read_accel(self):
|
||||
raw = 0.0
|
||||
scale = 0.0
|
||||
in_x = 0.0
|
||||
in_y = 0.0
|
||||
in_z = 0.0
|
||||
if MAKE_REAL_MESUREMENT > 0:
|
||||
if self.accelerometer_prefix_path:
|
||||
with open(self.accelerometer_prefix_path + 'in_accel_x_raw', 'r') as f:
|
||||
scale = float(f.read())
|
||||
with open(self.accelerometer_prefix_path + 'in_accel_x_scale', 'r') as f:
|
||||
raw = float(f.read())
|
||||
in_x = int(raw * scale * 256.0 / 9.81)
|
||||
with open(self.accelerometer_prefix_path + 'in_accel_y_raw', 'r') as f:
|
||||
scale = float(f.read())
|
||||
with open(self.accelerometer_prefix_path + 'in_accel_y_scale', 'r') as f:
|
||||
raw = float(f.read())
|
||||
in_y = int(raw * scale * 256.0 / 9.81)
|
||||
with open(self.accelerometer_prefix_path + 'in_accel_z_raw', 'r') as f:
|
||||
scale = float(f.read())
|
||||
with open(self.accelerometer_prefix_path + 'in_accel_z_scale', 'r') as f:
|
||||
raw = float(f.read())
|
||||
in_z = int(raw * scale * 256.0 / 9.81)
|
||||
self.update_accel(in_x, in_y, in_z)
|
||||
else:
|
||||
in_x = random.randint(-256, 256)
|
||||
in_y = random.randint(-256, 256)
|
||||
in_z = random.randint(-256, 256)
|
||||
self.update_accel(in_x, in_y, in_z)
|
||||
else:
|
||||
in_x = random.randint(-256, 256)
|
||||
in_y = random.randint(-256, 256)
|
||||
in_z = random.randint(-256, 256)
|
||||
self.update_accel(in_x, in_y, in_z)
|
||||
|
||||
self.orientation_calc(in_x, in_y, in_z)
|
||||
|
||||
def _draw_event(self, drawingarea, user_data):
|
||||
win = self.drawarea.get_window()
|
||||
ctx = win.cairo_create()
|
||||
self._draw_cb(win, ctx)
|
||||
|
||||
def update_ui(self, user_data):
|
||||
self.read_temperature()
|
||||
self.read_humidity()
|
||||
self.read_accel()
|
||||
|
||||
win = self.drawarea.get_window()
|
||||
ctx = win.cairo_create()
|
||||
self._draw_cb(win, ctx)
|
||||
|
||||
# As this is a timeout function, return True so that it
|
||||
# continues to get called
|
||||
return True
|
||||
|
||||
win = SensorWindow()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.show_all()
|
||||
Gtk.main()
|
||||