added my Recipes
@@ -0,0 +1,53 @@
|
||||
SUMMARY = "Hand writing character recognition launcher based on HCR Neural Network"
|
||||
|
||||
LICENSE = "GPL-2.0-only & BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
|
||||
|
||||
DEPENDS = "gtk+3 gstreamer1.0-plugins-base demo-launcher"
|
||||
DEPENDS:append:stm32mpcommon = " m4projects-stm32mp1 "
|
||||
|
||||
inherit pkgconfig
|
||||
|
||||
SRC_URI = " file://ai_char_reco_launcher.c \
|
||||
file://apps_launcher_example.sh \
|
||||
file://copro.c \
|
||||
file://copro.h \
|
||||
file://Makefile \
|
||||
file://timer.c \
|
||||
file://timer.h \
|
||||
\
|
||||
file://media \
|
||||
\
|
||||
file://demo \
|
||||
"
|
||||
|
||||
PV = "2.1"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
|
||||
#Provides the firmware location for DK2 and EV1 boards
|
||||
EXTRA_OEMAKE = 'FIRMWARE_PATH_DK2="${STM32MP_USERFS_MOUNTPOINT}/Cube-M4-examples/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition/lib/firmware"'
|
||||
EXTRA_OEMAKE += 'FIRMWARE_PATH_EV1="${STM32MP_USERFS_MOUNTPOINT}/Cube-M4-examples/STM32MP157C-EV1/Demonstrations/AI_Character_Recognition/lib/firmware"'
|
||||
|
||||
#Provides the firmware name
|
||||
EXTRA_OEMAKE += 'FIRMWARE_NAME="AI_Character_Recognition.elf"'
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/bin/
|
||||
install -d ${D}${prefix}/local/demo/media/
|
||||
install -d ${D}${prefix}/local/demo/application/m4_ai/bin
|
||||
install -d ${D}${prefix}/local/demo/application/m4_ai/pictures
|
||||
|
||||
install -m 0755 ${B}/ai_char_reco_launcher ${D}${prefix}/local/demo/bin/
|
||||
install -m 0755 ${B}/apps_launcher_example.sh ${D}${prefix}/local/demo/bin/
|
||||
install -m 0644 ${B}/media/* ${D}${prefix}/local/demo/media/
|
||||
install -m 0755 -D ${WORKDIR}/demo/application/m4_ai/bin/* ${D}${prefix}/local/demo/application/m4_ai/bin/
|
||||
install -m 0755 -D ${WORKDIR}/demo/application/m4_ai/pictures/* ${D}${prefix}/local/demo/application/m4_ai/pictures/
|
||||
install -m 0644 -D ${WORKDIR}/demo/application/*.yaml ${D}${prefix}/local/demo/application/
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/local/demo/"
|
||||
RDEPENDS:${PN} += "gtk+3 gstreamer1.0-plugins-base demo-launcher"
|
||||
RDEPENDS:${PN}:append:stm32mpcommon = " m4projects-stm32mp1-userfs "
|
||||
@@ -0,0 +1,15 @@
|
||||
FIRMWARE_PATH_DK2?="/usr/local/Cube-M4-examples/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition/lib/firmware"
|
||||
FIRMWARE_PATH_EV1?="/usr/local/Cube-M4-examples/STM32MP157C-EV1/Demonstrations/AI_Character_Recognition/lib/firmware"
|
||||
FIRMWARE_NAME?="AI_Character_Recognition.elf"
|
||||
|
||||
|
||||
# support GTK
|
||||
CFLAGS += -Wall $(shell pkg-config --cflags gtk+-3.0)
|
||||
LDFLAGS += $(shell pkg-config --libs gtk+-3.0)
|
||||
|
||||
all: ai_char_reco_launcher
|
||||
|
||||
ai_char_reco_launcher: copro.c timer.c ai_char_reco_launcher.c
|
||||
$(CC) -DFIRMWARE_PATH_DK2='"${FIRMWARE_PATH_DK2}"' -DFIRMWARE_PATH_EV1='"${FIRMWARE_PATH_EV1}"' -DFIRMWARE_NAME='"${FIRMWARE_NAME}"' -o $@ $^ $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
clean: ; rm -rf *.o ai_char_reco_launcher
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
|
||||
video() {
|
||||
echo "Launch video"
|
||||
gst-launch-1.0 playbin uri=file:///usr/local/demo/media/Teaser-STM32MP1.webm video-sink="waylandsink sync=false" audio-sink="fakesink" &
|
||||
}
|
||||
|
||||
audio() {
|
||||
echo "Launch audio"
|
||||
gst-launch-1.0 playbin uri=file:///usr/local/demo/media/ST12266_269_full_technology-freaks_0160.ogg &
|
||||
}
|
||||
|
||||
picture() {
|
||||
echo "Display picture"
|
||||
gst-launch-1.0 filesrc location=/usr/local/demo/media/stm32cubeai.png ! pngdec ! videoconvert ! imagefreeze ! glimagesink &
|
||||
}
|
||||
|
||||
camera() {
|
||||
echo "Launch preview camera"
|
||||
v4l2-ctl --set-parm=20
|
||||
gst-launch-1.0 v4l2src ! "video/x-raw, format=YUY2, width=320, height=240" ! waylandsink &
|
||||
}
|
||||
|
||||
kill_all() {
|
||||
echo "kill previous app"
|
||||
killall gst-launch-1.0
|
||||
}
|
||||
|
||||
quit() {
|
||||
kill_all
|
||||
killall ai_char_reco_launcher
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
V)
|
||||
video
|
||||
;;
|
||||
S)
|
||||
kill_all
|
||||
;;
|
||||
A)
|
||||
audio
|
||||
;;
|
||||
P)
|
||||
picture
|
||||
;;
|
||||
C)
|
||||
camera
|
||||
;;
|
||||
Q)
|
||||
quit
|
||||
;;
|
||||
*)
|
||||
echo "HELP: $0 [command]"
|
||||
echo "available commands:"
|
||||
echo " V (launch video)"
|
||||
echo " A (Launch audio)"
|
||||
echo " P (Display picture)"
|
||||
echo " C (Launch preview camera)"
|
||||
echo " S (kill previous app)"
|
||||
echo " Q (quit the launcher)"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* copro.c
|
||||
* Implements Copro's abstraction layer
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "copro.h"
|
||||
|
||||
#define MAX_BUF 80
|
||||
|
||||
/* The file descriptor used to manage our TTY over RPMSG */
|
||||
static int mFdRpmsg = -1;
|
||||
|
||||
int copro_isFwRunning(void)
|
||||
{
|
||||
int fd;
|
||||
size_t byte_read;
|
||||
int result = 0;
|
||||
unsigned char bufRead[MAX_BUF];
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root", 4)) {
|
||||
system("XTERM=xterm su root -c 'cat /sys/class/remoteproc/remoteproc0/state' > /tmp/remoteproc0_state");
|
||||
fd = open("/tmp/remoteproc0_state", O_RDONLY);
|
||||
} else {
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/state", O_RDONLY);
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/state, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
byte_read = (size_t) read (fd, bufRead, MAX_BUF);
|
||||
if (byte_read >= strlen("running")) {
|
||||
char* pos = strstr((char*)bufRead, "running");
|
||||
if(pos) {
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_stopFw(void)
|
||||
{
|
||||
int fd;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("su root -c 'echo stop > /sys/class/remoteproc/remoteproc0/state'");
|
||||
return 0;
|
||||
}
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/state", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/state, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
write(fd, "stop", strlen("stop"));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_startFw(void)
|
||||
{
|
||||
int fd;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("su root -c 'echo start > /sys/class/remoteproc/remoteproc0/state'");
|
||||
return 0;
|
||||
}
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/state", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/state, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
write(fd, "start", strlen("start"));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_getFwPath(char* pathStr)
|
||||
{
|
||||
int fd;
|
||||
int byte_read;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("XTERM=xterm su root -c 'cat /sys/module/firmware_class/parameters/path' > /tmp/parameters_path");
|
||||
fd = open("/tmp/parameters_path", O_RDONLY);
|
||||
} else {
|
||||
fd = open("/sys/module/firmware_class/parameters/path", O_RDONLY);
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("Error opening firmware_class/parameters/path, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
byte_read = read (fd, pathStr, MAX_BUF);
|
||||
close(fd);
|
||||
return byte_read;
|
||||
}
|
||||
|
||||
int copro_setFwPath(char* pathStr)
|
||||
{
|
||||
int fd;
|
||||
int result = 0;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
char cmd[1024];
|
||||
snprintf(cmd, 1024, "su root -c 'echo %s > /sys/module/firmware_class/parameters/path'", pathStr);
|
||||
system(cmd);
|
||||
return strlen(pathStr);
|
||||
}
|
||||
fd = open("/sys/module/firmware_class/parameters/path", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening firmware_class/parameters/path, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
result = write(fd, pathStr, strlen(pathStr));
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_getFwName(char* name)
|
||||
{
|
||||
int fd;
|
||||
int byte_read;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
system("XTERM=xterm su root -c 'cat /sys/class/remoteproc/remoteproc0/firmware' > /tmp/remoteproc0_firmware");
|
||||
fd = open("/tmp/remoteproc0_firmware", O_RDONLY);
|
||||
} else {
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/firmware", O_RDWR);
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/firmware, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
byte_read = read (fd, name, MAX_BUF);
|
||||
close(fd);
|
||||
/* remove \n from the read character */
|
||||
return byte_read - 1;
|
||||
}
|
||||
|
||||
int copro_setFwName(char* nameStr)
|
||||
{
|
||||
int fd;
|
||||
int result = 0;
|
||||
char *user = getenv("USER");
|
||||
if (user && strncmp(user, "root",4)) {
|
||||
char cmd[1024];
|
||||
snprintf(cmd, 1024, "su root -c 'echo %s > /sys/class/remoteproc/remoteproc0/firmware'", nameStr);
|
||||
system(cmd);
|
||||
return strlen(nameStr);
|
||||
}
|
||||
fd = open("/sys/class/remoteproc/remoteproc0/firmware", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Error opening remoteproc0/firmware, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
result = write(fd, nameStr, strlen(nameStr));
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_openTtyRpmsg(int modeRaw)
|
||||
{
|
||||
struct termios tiorpmsg;
|
||||
mFdRpmsg = open("/dev/ttyRPMSG0", O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (mFdRpmsg < 0) {
|
||||
printf("Error opening ttyRPMSG0, err=-%d\n", errno);
|
||||
return (errno * -1);
|
||||
}
|
||||
/* get current port settings */
|
||||
tcgetattr(mFdRpmsg,&tiorpmsg);
|
||||
if (modeRaw) {
|
||||
tiorpmsg.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
||||
| INLCR | IGNCR | ICRNL | IXON);
|
||||
tiorpmsg.c_oflag &= ~OPOST;
|
||||
tiorpmsg.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tiorpmsg.c_cflag &= ~(CSIZE | PARENB);
|
||||
tiorpmsg.c_cflag |= CS8;
|
||||
} else {
|
||||
/* ECHO off, other bits unchanged */
|
||||
tiorpmsg.c_lflag &= ~ECHO;
|
||||
/*do not convert LF to CR LF */
|
||||
tiorpmsg.c_oflag &= ~ONLCR;
|
||||
}
|
||||
tcsetattr(mFdRpmsg, TCSANOW, &tiorpmsg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_closeTtyRpmsg(void)
|
||||
{
|
||||
close(mFdRpmsg);
|
||||
mFdRpmsg = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copro_writeTtyRpmsg(int len, char* pData)
|
||||
{
|
||||
int result = 0;
|
||||
if (mFdRpmsg < 0) {
|
||||
printf("Error writing ttyRPMSG0, fileDescriptor is not set\n");
|
||||
return mFdRpmsg;
|
||||
}
|
||||
result = write(mFdRpmsg, pData, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
int copro_readTtyRpmsg(int len, char* pData)
|
||||
{
|
||||
int byte_rd, byte_avail;
|
||||
int result = 0;
|
||||
if (mFdRpmsg < 0) {
|
||||
printf("Error reading ttyRPMSG0, fileDescriptor is not set\n");
|
||||
return mFdRpmsg;
|
||||
}
|
||||
ioctl(mFdRpmsg, FIONREAD, &byte_avail);
|
||||
if (byte_avail > 0) {
|
||||
if (byte_avail >= len) {
|
||||
byte_rd = read (mFdRpmsg, pData, len);
|
||||
} else {
|
||||
byte_rd = read (mFdRpmsg, pData, byte_avail);
|
||||
}
|
||||
/*printf("copro_readTtyRpmsg, read successfully %d bytes to %p, [0]=0x%x\n", byte_rd, pData, pData[0]);*/
|
||||
result = byte_rd;
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char copro_computeCRC(char *bb, int size)
|
||||
{
|
||||
short sum = 0;
|
||||
|
||||
for (int i = 0; i < size - 1; i++)
|
||||
sum += (bb[i] & 0xFF);
|
||||
|
||||
char res = (char) (sum & 0xFF);
|
||||
res += (char) (sum >> 8);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* copro.h
|
||||
* Implements Copro's abstraction layer
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __COPRO_H__
|
||||
#define __COPRO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int copro_isFwRunning(void);
|
||||
int copro_stopFw(void);
|
||||
int copro_startFw(void);
|
||||
int copro_getFwPath(char* pathStr);
|
||||
int copro_setFwPath(char* pathStr);
|
||||
int copro_getFwName(char* pathStr);
|
||||
int copro_setFwName(char* nameStr);
|
||||
int copro_openTtyRpmsg(int modeRaw);
|
||||
int copro_closeTtyRpmsg(void);
|
||||
int copro_writeTtyRpmsg(int len, char* pData);
|
||||
int copro_readTtyRpmsg(int len, char* pData);
|
||||
char copro_computeCRC(char *bb, int size);
|
||||
|
||||
#endif /* __COPRO_H__ */
|
||||
@@ -0,0 +1,14 @@
|
||||
Application:
|
||||
Name: Artificial
|
||||
Description: Intelligence
|
||||
Icon: application/m4_ai/pictures/ST7079_AI_neural_pink.png
|
||||
Type: script
|
||||
Board:
|
||||
List: stm32mp15
|
||||
Script:
|
||||
Start: application/m4_ai/bin/launch_AI.sh
|
||||
Action:
|
||||
button_release_event: script_start
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
script -qc "/usr/local/demo/bin/ai_char_reco_launcher /usr/local/demo/bin/apps_launcher_example.sh"
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
*************************************************************************************************
|
||||
* @file readme.txt
|
||||
* @author MCD Application Team
|
||||
* @brief Description of the Artificial Intelligence Hand Writing Character Recognition example.
|
||||
*************************************************************************************************
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*************************************************************************************************
|
||||
*/
|
||||
|
||||
This project demonstrate a complex application that is running on both CPU1(CA7) and CPU2(CM4).
|
||||
The application is a launcher that recognize hand writing character drawn on the touch screen in order
|
||||
to execute specific actions.
|
||||
|
||||
CPU1 (CA7) control the touch event and the Graphic User Interface.
|
||||
CPU2 (CM4) is used to offload the processing of a Cube.AI pre-build Neural Network.
|
||||
|
||||
The communication between the CPU1(CA7) and the CPU2(CM4) is done through a Virtual UART to create an
|
||||
Inter-Processor Communication channel seen as a TTY device in Linux.
|
||||
The implementation is based on:
|
||||
* RPMSG framework on CPU1(CA7) side
|
||||
* and OpenAMP MW on the CPU2(CM4) side
|
||||
|
||||
OpenAMP MW uses the following HW resources
|
||||
* IPCC peripheral for event signal (mailbox) between CPU1(CA7) and CPU2(CM4)
|
||||
* MCUSRAM peripheral for buffer communications (virtio buffers) between CPU1(CA7) and CPU2(CM4)
|
||||
Reserved shared memeory region for this example: SHM_ADDR=0x10040000 and SHM_SIZE=128k.
|
||||
It is defined in platform_info.c file
|
||||
|
||||
A communication protocol has been defined between the CPU1(CA7 and the CPU2(CM4).
|
||||
The data frames exchanged have the follwowing structure:
|
||||
----------------------------------------------------------------
|
||||
| msg ID | data Length | data Byte 1 | ... | data Byte n | CRC |
|
||||
----------------------------------------------------------------
|
||||
|
||||
- 3 types of message could be received by CPU2(CM4):
|
||||
* Set the Neural Network input type (0x20, 0x01, data, CRC)
|
||||
* data = 0 => NN input is letter or digit
|
||||
* data = 1 => NN input is letter only
|
||||
* data = 2 => NN input is digit only
|
||||
|
||||
* Provide the touch screen coordinate (0x20, n, data_x1, data_y1, ... , data_xn, data_yn, CRC)
|
||||
* n => the number of coordinate points
|
||||
* data_xn => x coordinate of the point n
|
||||
* data_yn => y coordinate of the point n
|
||||
|
||||
* Start ai nn processing (0x22, 0x00, CRC)
|
||||
|
||||
- 4 types of acknowledges could be received on CPU1(CA7) side:
|
||||
* Bad acknowledge (0xFF, 0x00, CRC)
|
||||
|
||||
* Good acknowledge (0xF0, 0x00, CRC)
|
||||
|
||||
* Touch screen acknowledge (0xF0, 0x01, n, CRC)
|
||||
* n => number of screen coordinate points acknowledged
|
||||
|
||||
* AI processing result acknowledge (0xF0, 0x04, char, accuracy, time_1, time_2, CRC)
|
||||
* char => this is the recognized letter (or digit)
|
||||
* accuracy => this is the confidence expressed in percentage
|
||||
* time_1 => upper Bytes of the time (word) expressed in ms
|
||||
* time_2 => lower Bytes of the time (word) expressed in ms
|
||||
|
||||
On CPU2(CM4) side:
|
||||
- CPU2(CM4) initialize OPenAMP MW which initializes/configures IPCC peripheral through HAL
|
||||
and setup openamp-rpmsg framwork infrastructure
|
||||
- CPU2(CM4) creates 1 rpmsg channels for 1 virtual UART instance UART0
|
||||
- CPU2(CM4) initialize the Character Recognition Neural Network
|
||||
- CPU2(CM4) is waiting for messages from CPU1(CA7) on this channels
|
||||
- When CPU2(CM4) receives a message on 1 Virtual UART instance/rpmsg channel, it processes the message
|
||||
to execute the associated action:
|
||||
* set the NN input type to the desire value
|
||||
* or register the touch event coordinate to generate the picture that will be processed by the NN
|
||||
* or start the NN processing and wait for the results
|
||||
- On every previous action, the CPU(CM4) is sending back to the CPU1(CA7) and acknowledge already defined
|
||||
above.
|
||||
|
||||
On CPU1(CA7) side:
|
||||
- CPU1(CA7) open the input event to register the touch events generated by the user's finger drawing
|
||||
- CPU1(CA7) configure the input type (Letter only) of the Neural Network running on the CPU2(CM4) by
|
||||
sending a message throught the virtual TTY communication channel
|
||||
- when the drawing is finished, CPU1(CA7) process the touch event data and send it to the CPU2(CM4)
|
||||
- CPU1(CA7) start the Neural Network processing wait for the result and display the recognized character on
|
||||
the diplay
|
||||
|
||||
Some information about the Character Recognition Neural Network:
|
||||
The Character Recognition Neural Network used is a Keras model processed by Cube.AI to generate the executable
|
||||
that can be run on the CPU2(CM4).
|
||||
The Keras model used is located in the root directory of this project:
|
||||
model-ABC123-112.h5
|
||||
This model has been used in Cube.AI to generate the Neural Network binary.
|
||||
The model accept as input a 28x28 picture encoded with float in black and white (black = 0.0 or White = 1.0).
|
||||
The output layer of the Neural Network contains 36 neurons (A -> Z and 0 -> 9).
|
||||
|
||||
Notes:
|
||||
- It requires Linux console to run the application.
|
||||
- CM4 logging is redirected in Shared memory in MCUSRAM and can be displayed using following command:
|
||||
cat /sys/kernel/debug/remoteproc/remoteproc0/trace0
|
||||
|
||||
Following command should be done in Linux console on CA7 to run the example :
|
||||
> /usr/local/demo/bin/ai_char_reco_launcher /usr/local/demo/bin/apps_launcher_example.sh
|
||||
|
||||
You are ready to draw letter on the touch screen
|
||||
|
||||
Hardware and Software environment:
|
||||
- This example runs on STM32MP157CACx devices.
|
||||
- This example has been tested with STM32MP157C-DK2 and STM32MP157c-EVAL board and can be
|
||||
easily tailored to any other supported device and development board.
|
||||
|
||||
Where to find the M4 firmware source code:
|
||||
The M4 firmware source code is delivered as demonstration inside the STM32CubeMP1.
|
||||
For the DK2 board:
|
||||
<STM32CubeMP1>/Firmware/Projects/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition
|
||||
For the EV1 board:
|
||||
<STM32CubeMP1>/Firmware/Projects/STM32MP157C-DK2/Demonstrations/AI_Character_Recognition
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* timer.c
|
||||
* Implements timer services
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <pthread.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
#define MAX_TIMER_COUNT 1000
|
||||
|
||||
struct timer_node
|
||||
{
|
||||
int fd;
|
||||
timer_handler callback;
|
||||
void * user_data;
|
||||
unsigned int interval;
|
||||
struct timer_node * next;
|
||||
};
|
||||
|
||||
static void * _timer_thread(void * data);
|
||||
static pthread_t g_thread_id;
|
||||
static struct timer_node *g_head = NULL;
|
||||
|
||||
int timer_init()
|
||||
{
|
||||
if(pthread_create(&g_thread_id, NULL, _timer_thread, NULL))
|
||||
{
|
||||
/*Thread creation failed*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void timer_finalize()
|
||||
{
|
||||
while(g_head) timer_stop((size_t)g_head);
|
||||
|
||||
pthread_cancel(g_thread_id);
|
||||
pthread_join(g_thread_id, NULL);
|
||||
}
|
||||
|
||||
size_t timer_start(unsigned int interval,
|
||||
timer_handler handler,
|
||||
void * user_data)
|
||||
{
|
||||
struct timer_node * new_node = NULL;
|
||||
struct itimerspec new_value;
|
||||
|
||||
new_node = (struct timer_node *)malloc(sizeof(struct timer_node));
|
||||
|
||||
if(new_node == NULL) return 0;
|
||||
|
||||
new_node->callback = handler;
|
||||
new_node->user_data = user_data;
|
||||
new_node->interval = interval;
|
||||
|
||||
new_node->fd = timerfd_create(CLOCK_REALTIME, 0);
|
||||
|
||||
if (new_node->fd == -1)
|
||||
{
|
||||
free(new_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_value.it_value.tv_sec = interval / 1000;
|
||||
new_value.it_value.tv_nsec = (interval % 1000) * 1000 * 1000;
|
||||
new_value.it_interval.tv_sec = 0;
|
||||
new_value.it_interval.tv_nsec = 0;
|
||||
|
||||
timerfd_settime(new_node->fd, 0, &new_value, NULL);
|
||||
|
||||
/*Inserting the timer node into the list*/
|
||||
new_node->next = g_head;
|
||||
g_head = new_node;
|
||||
|
||||
return (size_t)new_node;
|
||||
}
|
||||
|
||||
void timer_stop(size_t timer_id)
|
||||
{
|
||||
struct timer_node * tmp = NULL;
|
||||
struct timer_node * node = (struct timer_node *)timer_id;
|
||||
|
||||
if (node == NULL) return;
|
||||
|
||||
close(node->fd);
|
||||
|
||||
if(node == g_head)
|
||||
{
|
||||
g_head = g_head->next;
|
||||
}
|
||||
|
||||
tmp = g_head;
|
||||
|
||||
while(tmp && tmp->next != node) tmp = tmp->next;
|
||||
|
||||
if(tmp && tmp->next)
|
||||
{
|
||||
tmp->next = tmp->next->next;
|
||||
}
|
||||
|
||||
if(node) free(node);
|
||||
}
|
||||
|
||||
struct timer_node * _get_timer_from_fd(int fd)
|
||||
{
|
||||
struct timer_node * tmp = g_head;
|
||||
|
||||
while(tmp)
|
||||
{
|
||||
if(tmp->fd == fd) return tmp;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * _timer_thread(void * data)
|
||||
{
|
||||
struct pollfd ufds[MAX_TIMER_COUNT] = {{0}};
|
||||
int iMaxCount = 0;
|
||||
struct timer_node * tmp = NULL;
|
||||
int read_fds = 0, i, s;
|
||||
uint64_t exp;
|
||||
|
||||
while(1)
|
||||
{
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_testcancel();
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
|
||||
iMaxCount = 0;
|
||||
tmp = g_head;
|
||||
|
||||
memset(ufds, 0, sizeof(struct pollfd)*MAX_TIMER_COUNT);
|
||||
while(tmp)
|
||||
{
|
||||
ufds[iMaxCount].fd = tmp->fd;
|
||||
ufds[iMaxCount].events = POLLIN;
|
||||
iMaxCount++;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
read_fds = poll(ufds, iMaxCount, 100);
|
||||
|
||||
if (read_fds <= 0) continue;
|
||||
|
||||
for (i = 0; i < iMaxCount; i++)
|
||||
{
|
||||
if (ufds[i].revents & POLLIN)
|
||||
{
|
||||
s = read(ufds[i].fd, &exp, sizeof(uint64_t));
|
||||
|
||||
if (s != sizeof(uint64_t)) continue;
|
||||
|
||||
tmp = _get_timer_from_fd(ufds[i].fd);
|
||||
|
||||
if(tmp && tmp->callback) tmp->callback((size_t)tmp, tmp->user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* timer.h
|
||||
* Implements timer services
|
||||
*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License type: GPLv2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_H
|
||||
#define __TIMER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef void (*timer_handler)(size_t timer_id, void * user_data);
|
||||
|
||||
int timer_init();
|
||||
void timer_finalize();
|
||||
size_t timer_start(unsigned int interval, timer_handler handler, void * user_data);
|
||||
void timer_stop(size_t timer_id);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
SUMMARY = "Add support of 3d Cube application on Demo Launcher"
|
||||
HOMEPAGE = "wiki.st.com"
|
||||
LICENSE = "BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9"
|
||||
|
||||
DEPENDS = "weston-cube demo-launcher"
|
||||
|
||||
PV = "3.0"
|
||||
SRC_URI = " \
|
||||
file://100-3d-cube.yaml \
|
||||
file://101-3d-cube-shader.yaml \
|
||||
file://105-3d-cube-picture-shader.yaml \
|
||||
file://110-3d-cube-video.yaml \
|
||||
file://111-3d-cube-video-shader.yaml \
|
||||
file://115-3d_cube_camera.yaml \
|
||||
file://116-3d_cube_camera_shader.yaml \
|
||||
file://120-3d-cube-pictures-shader.yaml \
|
||||
file://launch_cube_3D_1_picture_shader.sh \
|
||||
file://launch_cube_3D_3_pictures_shader.sh \
|
||||
file://launch_cube_3D_camera.sh \
|
||||
file://launch_cube_3D_camera_shader.sh \
|
||||
file://launch_cube_3D_color.sh \
|
||||
file://launch_cube_3D_color_shader.sh \
|
||||
file://launch_cube_3D_video.sh \
|
||||
file://launch_cube_3D_video_shader.sh \
|
||||
file://ST153_cube_purple.png \
|
||||
\
|
||||
file://040-3d_cube.yaml \
|
||||
file://launch_cube_3D.sh \
|
||||
"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/application/3d-cube/bin
|
||||
install -d ${D}${prefix}/local/demo/application/3d-cube/pictures
|
||||
install -d ${D}${prefix}/local/demo/application/3d-cube-extra/bin
|
||||
install -d ${D}${prefix}/local/demo/application/3d-cube-extra/pictures
|
||||
|
||||
# install yaml file
|
||||
install -m 0644 ${WORKDIR}/*.yaml ${D}${prefix}/local/demo/application/
|
||||
# install bin
|
||||
install -m 0755 ${WORKDIR}/*.sh ${D}${prefix}/local/demo/application/3d-cube-extra/bin
|
||||
install -m 0755 ${WORKDIR}/launch_cube_3D.sh ${D}${prefix}/local/demo/application/3d-cube/bin
|
||||
|
||||
# install pictures
|
||||
install -m 0644 ${WORKDIR}/*.png ${D}${prefix}/local/demo/application/3d-cube-extra/pictures
|
||||
install -m 0644 ${WORKDIR}/*.png ${D}${prefix}/local/demo/application/3d-cube/pictures
|
||||
}
|
||||
|
||||
PACKAGES += "${PN}-extra"
|
||||
FILES:${PN} = " \
|
||||
${prefix}/local/demo/application/3d-cube \
|
||||
${prefix}/local/demo/application/040-3d_cube.yaml \
|
||||
"
|
||||
RDEPENDS:${PN} = "weston-cube demo-launcher"
|
||||
|
||||
FILES:${PN}-extra = " \
|
||||
${prefix}/local/demo/application/3d-cube-extra \
|
||||
${prefix}/local/demo/application/100-3d-cube.yaml \
|
||||
${prefix}/local/demo/application/101-3d-cube-shader.yaml \
|
||||
${prefix}/local/demo/application/105-3d-cube-picture-shader.yaml \
|
||||
${prefix}/local/demo/application/110-3d-cube-video.yaml \
|
||||
${prefix}/local/demo/application/111-3d-cube-video-shader.yaml \
|
||||
${prefix}/local/demo/application/115-3d_cube_camera.yaml \
|
||||
${prefix}/local/demo/application/116-3d_cube_camera_shader.yaml \
|
||||
${prefix}/local/demo/application/120-3d-cube-pictures-shader.yaml \
|
||||
"
|
||||
RDEPENDS:${PN}-extra = "${PN} weston-cube demo-launcher"
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Pict
|
||||
Description: GPU
|
||||
Icon: application/3d-cube/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK 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
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Color
|
||||
Description: GPU
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_color.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Color
|
||||
Description: GPU Shader
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_color_shader.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Pict
|
||||
Description: GPU shader
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_1_picture_shader.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Video
|
||||
Description: GPU
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_video.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Video
|
||||
Description: GPU shader
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_video_shader.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Cam
|
||||
Description: GPU
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_camera.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Cam
|
||||
Description: GPU & shader
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_camera_shader.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: 3D Picts
|
||||
Description: GPU shader
|
||||
Icon: application/3d-cube-extra/pictures/ST153_cube_purple.png
|
||||
Board:
|
||||
List: stm32mp157
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
File: /dev/galcore
|
||||
Msg_false: No GCNANO GPU STACK capabilities to run 3D GPU demo
|
||||
Start: application/3d-cube-extra/bin/launch_cube_3D_3_pictures_shader.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
# with one picture
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -1 /usr/local/demo/pictures/ST20578_Label_OpenSTlinux_V.png -f
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -1 /usr/local/demo/pictures/ST20578_Label_OpenSTlinux_V.png -f -a
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -3 /usr/local/demo/pictures/ST13028_Linux_picto_13.png /usr/local/demo/pictures/ST4439_ST_logo.png /usr/local/demo/pictures/ST20578_Label_OpenSTlinux_V.png -f -a
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
if v4l2-ctl -d /dev/video0 -D > /dev/null 2>&1
|
||||
then
|
||||
printf "Video present and "
|
||||
if fuser /dev/video0 > /dev/null 2>&1
|
||||
then
|
||||
printf '%s\n' "device in use"
|
||||
else
|
||||
printf '%s\n' "device available"
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -v /dev/video0 -f
|
||||
fi
|
||||
else
|
||||
printf "Video not present\n"
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -3 /usr/local/demo/pictures/ST13028_Linux_picto_13.png /usr/local/demo/pictures/ST4439_ST_logo.png /usr/local/demo/pictures/ST20578_Label_OpenSTlinux_V.png -f
|
||||
fi
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
if v4l2-ctl -d /dev/video0 -D > /dev/null 2>&1
|
||||
then
|
||||
printf "Video present and "
|
||||
if fuser /dev/video0 > /dev/null 2>&1
|
||||
then
|
||||
printf '%s\n' "device in use"
|
||||
else
|
||||
printf '%s\n' "device available"
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -v /dev/video0 -f -a
|
||||
fi
|
||||
else
|
||||
printf "Video not present\n"
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -3 /usr/local/demo/pictures/ST13028_Linux_picto_13.png /usr/local/demo/pictures/ST4439_ST_logo.png /usr/local/demo/pictures/ST20578_Label_OpenSTlinux_V.png -f -a
|
||||
fi
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -f
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex -f -a
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex --video=/usr/local/demo/media/ST2297_visionv3.webm -f
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/demo/bin/weston-st-egl-cube-tex --video=/usr/local/demo/media/ST2297_visionv3.webm -f -a
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
SUMMARY = "Add support of audio bluetooth speaker on Demo Launcher"
|
||||
HOMEPAGE = "wiki.st.com"
|
||||
LICENSE = "BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9"
|
||||
|
||||
DEPENDS = "demo-launcher"
|
||||
|
||||
PV = "2.1"
|
||||
|
||||
SRC_URI = " \
|
||||
file://060-bluetooth_audio_output.yaml \
|
||||
file://bluetooth_audio.py \
|
||||
file://wrap_blctl.py \
|
||||
file://__init__.py \
|
||||
file://ST11012_bluetooth_speaker_light_green.png \
|
||||
file://check_ble.sh \
|
||||
"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/application/bluetooth/bin
|
||||
install -d ${D}${prefix}/local/demo/application/bluetooth/pictures
|
||||
|
||||
# install yaml file
|
||||
install -m 0644 ${WORKDIR}/*.yaml ${D}${prefix}/local/demo/application/
|
||||
# install pictures
|
||||
install -m 0644 ${WORKDIR}/*.png ${D}${prefix}/local/demo/application/bluetooth/pictures
|
||||
# python script
|
||||
install -m 0755 ${WORKDIR}/*.py ${D}${prefix}/local/demo/application/bluetooth/
|
||||
# install check script
|
||||
install -m 0755 ${WORKDIR}/*.sh ${D}${prefix}/local/demo/application/bluetooth/bin/
|
||||
}
|
||||
RDEPENDS:${PN} += "python3-core python3-pexpect python3-pickle python3-pygobject gtk+3 demo-launcher"
|
||||
FILES:${PN} += "${prefix}/local/demo/application/"
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: Bluetooth
|
||||
Description: speaker
|
||||
Icon: application/bluetooth/pictures/ST11012_bluetooth_speaker_light_green.png
|
||||
Type: python
|
||||
Board:
|
||||
List: all
|
||||
Python:
|
||||
Exist:
|
||||
Command: /usr/local/demo/application/bluetooth/bin/check_ble.sh
|
||||
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: 7.5 KiB |
@@ -0,0 +1 @@
|
||||
#print('Importing bluetooth __init__')
|
||||
@@ -0,0 +1,596 @@
|
||||
#!/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
|
||||
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
|
||||
import re
|
||||
import os
|
||||
import subprocess
|
||||
import pexpect
|
||||
from time import sleep, time
|
||||
|
||||
try:
|
||||
from application.bluetooth.wrap_blctl import wrapper_blctl as Bluetoothctl
|
||||
except ModuleNotFoundError:
|
||||
from wrap_blctl import wrapper_blctl as Bluetoothctl
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
SUBMODULE_PATH = "application/bluetooth"
|
||||
DEMO_PATH = "/usr/local/demo"
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
ICON_SIZE_1080 = 260
|
||||
ICON_SIZE_720 = 180
|
||||
ICON_SIZE_480 = 128
|
||||
ICON_SIZE_272 = 48
|
||||
|
||||
TREELIST_HEIGHT_1080 = 500
|
||||
TREELIST_HEIGHT_720 = 400
|
||||
TREELIST_HEIGHT_480 = 160
|
||||
TREELIST_HEIGHT_272 = 68
|
||||
|
||||
# return format:
|
||||
# [ icon_size, font_size, treelist_height, button_height ]
|
||||
SIZES_ID_ICON_SIZE = 0
|
||||
SIZES_ID_FONT_SIZE = 1
|
||||
SIZES_ID_TREELIST_HEIGHT = 2
|
||||
SIZES_ID_BUTTON_HEIGHT = 3
|
||||
def get_sizes_from_screen_size(width, height):
|
||||
minsize = min(width, height)
|
||||
icon_size = None
|
||||
font_size = None
|
||||
treelist_height = None
|
||||
button_height = None
|
||||
if minsize == 720:
|
||||
icon_size = ICON_SIZE_720
|
||||
font_size = 25
|
||||
treelist_height = TREELIST_HEIGHT_720
|
||||
button_height = 60
|
||||
elif minsize == 480:
|
||||
icon_size = ICON_SIZE_480
|
||||
font_size = 20
|
||||
treelist_height = TREELIST_HEIGHT_480
|
||||
button_height = 60
|
||||
elif minsize == 272:
|
||||
icon_size = ICON_SIZE_272
|
||||
font_size = 15
|
||||
treelist_height = TREELIST_HEIGHT_272
|
||||
button_height = 25
|
||||
elif minsize == 600:
|
||||
icon_size = ICON_SIZE_720
|
||||
font_size = 15
|
||||
treelist_height = TREELIST_HEIGHT_720
|
||||
button_height = 60
|
||||
elif minsize >= 1080:
|
||||
icon_size = ICON_SIZE_1080
|
||||
font_size = 32
|
||||
treelist_height = TREELIST_HEIGHT_1080
|
||||
button_height = 80
|
||||
return [icon_size, font_size, treelist_height, button_height]
|
||||
|
||||
def get_treelist_height_from_screen_size(width, height):
|
||||
minsize = min(width, height)
|
||||
if minsize == 720:
|
||||
return TREELIST_HEIGHT_720
|
||||
elif minsize == 480:
|
||||
return TREELIST_HEIGHT_480
|
||||
elif minsize == 272:
|
||||
return TREELIST_HEIGHT_272
|
||||
elif minsize == 600:
|
||||
return ICON_SIZE_1080
|
||||
elif minsize >= 1080:
|
||||
return ICON_SIZE_1080
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
SCAN_DURATION_IN_S = 15
|
||||
|
||||
regexps_audio = [
|
||||
re.compile(r"00001108-(?P<Headset>.+)$"),
|
||||
re.compile(r"0000110b-(?P<AudioSink>.+)$"),
|
||||
]
|
||||
|
||||
re_connected = re.compile(r"Connected:(?P<Connected>.+)$")
|
||||
|
||||
re_paired = re.compile(r"Paired:(?P<Paired>.+)$")
|
||||
|
||||
Item_info_dev = ['Headset', 'AudioSink', 'Connected', 'Paired']
|
||||
|
||||
regexps_devinfo = [
|
||||
re.compile(r"00001108-(?P<Headset>.+)$"),
|
||||
re.compile(r"0000110b-(?P<AudioSink>.+)$"),
|
||||
re.compile(r"Connected:(?P<Connected>.+)$"),
|
||||
re.compile(r"Paired:(?P<Paired>.+)$"),
|
||||
]
|
||||
########################################
|
||||
#pactl (pulseaudio controller) wrapper
|
||||
########################################
|
||||
#for parse_sinks
|
||||
re_sink = re.compile(r"^Sink #(?P<Ident>.+)$")
|
||||
re_prop_sink = [
|
||||
re.compile(r"State:(?P<State>.+)$"),
|
||||
re.compile(r"Description:\s+(?P<Name>.+)$")
|
||||
]
|
||||
|
||||
#for parse_streams
|
||||
re_stream = re.compile(r"^Sink Input #(?P<Ident>.+)$")
|
||||
re_prop_stream = [
|
||||
re.compile(r"Sink:\s+(?P<Sink>.+)$"),
|
||||
re.compile(r"media\.name\s=\s(?P<Name>.+)$")
|
||||
]
|
||||
# id_str : ident of the stream, id_sink : ident of the sink
|
||||
def audiosink_set(id_str, id_sink):
|
||||
print("audiosink_set ")
|
||||
#print("id_str : %d", id_str)
|
||||
#print("id_sink : %d", id_sink)
|
||||
cmd = ["/usr/bin/pactl", "move-sink-input", id_str, id_sink]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
res = proc.stdout.read().decode('utf-8')
|
||||
return res
|
||||
|
||||
def scan_streams():
|
||||
cmd = ["/usr/bin/pactl", "list", "sink-inputs"]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
res = proc.stdout.read().decode('utf-8')
|
||||
return res
|
||||
|
||||
def parse_streams(streams):
|
||||
streams_lines = streams.split('\n')
|
||||
l_streams = []
|
||||
for line in streams_lines:
|
||||
line = line.strip()
|
||||
elt = re_stream.search(line)
|
||||
if elt is not None:
|
||||
l_streams.append(elt.groupdict())
|
||||
continue
|
||||
for reg in re_prop_stream:
|
||||
res = reg.search(line)
|
||||
if res is not None:
|
||||
l_streams[-1].update(res.groupdict())
|
||||
return l_streams
|
||||
|
||||
|
||||
def scan_sinks():
|
||||
cmd = ["/usr/bin/pactl", "list", "sinks"]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
res = proc.stdout.read().decode('utf-8')
|
||||
return res
|
||||
|
||||
def parse_sinks(sinks):
|
||||
sinks_lines=sinks.split('\n')
|
||||
l_sinks =[]
|
||||
for line in sinks_lines:
|
||||
line = line.strip()
|
||||
elt = re_sink.search(line)
|
||||
if elt is not None:
|
||||
l_sinks.append(elt.groupdict())
|
||||
continue
|
||||
for reg in re_prop_sink:
|
||||
res = reg.search(line)
|
||||
if res is not None:
|
||||
l_sinks[-1].update(res.groupdict())
|
||||
return l_sinks
|
||||
|
||||
|
||||
|
||||
def status_playback(self):
|
||||
sink_ident = []
|
||||
stream_ident = None
|
||||
|
||||
list_sinks = scan_sinks()
|
||||
sinks = parse_sinks(list_sinks)
|
||||
#print("refresh label_audio\n")
|
||||
#print(sinks)
|
||||
mess_bt = ""
|
||||
if sinks != []:
|
||||
for sk in sinks:
|
||||
for bt_dev_conn in self.list_dev_connect:
|
||||
if sk['Name'] == bt_dev_conn['name']:
|
||||
if mess_bt != "":
|
||||
mess_bt = mess_bt + "\n"
|
||||
mess_bt = mess_bt + "The audio BT device " + sk['Name'] + " is connected"
|
||||
sink_ident.append({'name': sk['Name'], 'ident': sk['Ident']})
|
||||
|
||||
if mess_bt == "":
|
||||
mess_bt = "Device not connected"
|
||||
|
||||
self.label_audio.set_markup("<span font='20' color='#000000'>%s</span>" % mess_bt)
|
||||
self.label_audio.set_justify(Gtk.Justification.LEFT)
|
||||
self.label_audio.set_line_wrap(True)
|
||||
return [stream_ident, sink_ident]
|
||||
|
||||
|
||||
def get_device_info(bl, macadr):
|
||||
#print("get_device_info")
|
||||
info_dev = bl.blctl_info(macadr)
|
||||
dict_info = {}
|
||||
for elt in Item_info_dev:
|
||||
dict_info[elt] = ''
|
||||
for reelt in regexps_devinfo:
|
||||
for elt in info_dev:
|
||||
result = reelt.search(elt)
|
||||
if result is not None:
|
||||
dict_info.update(result.groupdict())
|
||||
break
|
||||
return(dict_info)
|
||||
|
||||
|
||||
def list_devices(self, paired = False):
|
||||
#print("list_devices")
|
||||
if self.locked_devices == False:
|
||||
self.locked_devices = True
|
||||
self.bluetooth_liststore.clear()
|
||||
self.current_devs=[]
|
||||
i=0
|
||||
if paired == True:
|
||||
devs = self.bl.blctl_paired_devices()
|
||||
else:
|
||||
devs = self.bl.blctl_devices()
|
||||
for elt in devs:
|
||||
elt_info = get_device_info(self.bl, elt['mac_address'])
|
||||
#print("name===" , elt['name'].encode('utf-8').strip())
|
||||
if elt['name'] == "RSSI is nil":
|
||||
continue
|
||||
if elt['name'] == "TxPower is nil":
|
||||
continue
|
||||
#do not list device without real name
|
||||
if elt['mac_address'].replace(':','') != elt['name'].replace('-',''):
|
||||
i=i+1
|
||||
self.current_devs.append(elt['mac_address'])
|
||||
#print(elt_info)
|
||||
l_elt = []
|
||||
l_elt.append(i)
|
||||
l_elt.append(elt['name'])
|
||||
l_elt.append(elt_info['Connected'])
|
||||
if elt_info['Headset'] != '' or elt_info['AudioSink'] != '':
|
||||
l_elt.append('yes')
|
||||
else:
|
||||
l_elt.append('no')
|
||||
|
||||
if elt_info['Connected'] == " yes":
|
||||
if elt not in self.list_dev_connect:
|
||||
self.list_dev_connect.insert(0,elt)
|
||||
self.bl.set_prompt(elt['name'])
|
||||
self.bluetooth_liststore.append(l_elt)
|
||||
|
||||
self.locked_devices = False
|
||||
|
||||
|
||||
def device_connected(bl, macadr):
|
||||
info_dev=bl.blctl_info(macadr)
|
||||
if info_dev is not None:
|
||||
for elt in info_dev:
|
||||
result = re_connected.search(elt)
|
||||
if result is not None:
|
||||
l_info_dev = result.groupdict()
|
||||
if l_info_dev["Connected"] == " yes":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def device_paired(bl, macadr):
|
||||
info_dev=bl.blctl_info(macadr)
|
||||
if info_dev is not None:
|
||||
for elt in info_dev:
|
||||
result = re_paired.search(elt)
|
||||
if result is not None:
|
||||
l_info_dev = result.groupdict()
|
||||
if l_info_dev["Paired"] == " yes":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def device_audio(bl, macadr):
|
||||
info_dev=bl.blctl_info(macadr)
|
||||
for reelt in regexps_audio:
|
||||
for elt in info_dev:
|
||||
result = reelt.search(elt)
|
||||
if result is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def gtk_style():
|
||||
css = b"""
|
||||
|
||||
.widget .grid .label {
|
||||
background-color: rgba (31%, 32%, 32%, 0.9);
|
||||
}
|
||||
.textview {
|
||||
color: gray;
|
||||
}
|
||||
.label {
|
||||
color: black;
|
||||
}
|
||||
.switch {
|
||||
min-height: 44px;
|
||||
}
|
||||
"""
|
||||
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 BluetoothWindow(Gtk.Dialog):
|
||||
def __init__(self, parent):
|
||||
Gtk.Dialog.__init__(self, "Wifi", parent, 0)
|
||||
self.maximize()
|
||||
self.set_decorated(False)
|
||||
|
||||
gtk_style()
|
||||
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.treelist_height = get_treelist_height_from_screen_size(self.screen_width, self.screen_height)
|
||||
sizes = get_sizes_from_screen_size(self.screen_width, self.screen_height)
|
||||
self.font_size = sizes[SIZES_ID_FONT_SIZE]
|
||||
self.button_height = sizes[SIZES_ID_BUTTON_HEIGHT]
|
||||
|
||||
self.connect("button-release-event", self.on_page_press_event)
|
||||
mainvbox = self.get_content_area()
|
||||
|
||||
self.dev_selected = {'mac_address':'', 'name':''}
|
||||
self.audio_bt_sink = []
|
||||
self.list_dev_connect = []
|
||||
self.current_devs = []
|
||||
self.locked_devices = False
|
||||
self.scan_done = False
|
||||
self.previous_click_time=0
|
||||
|
||||
self.page_bluetooth = Gtk.VBox()
|
||||
self.page_bluetooth.set_border_width(15)
|
||||
|
||||
self.title = Gtk.Label()
|
||||
self.title.set_markup("<span font='%d' color='#00000000'>Connect bluetooth headset</span>" % (self.font_size+5))
|
||||
self.page_bluetooth.add(self.title)
|
||||
|
||||
self.ButtonBox = Gtk.HBox(homogeneous=True)
|
||||
|
||||
self.lb_button_scan = Gtk.Label()
|
||||
self.lb_button_scan.set_markup("<span font='%d'>start scan</span>" % self.font_size)
|
||||
self.button_scan = Gtk.Button()
|
||||
self.button_scan.set_property("height-request", self.button_height)
|
||||
self.button_scan.add(self.lb_button_scan)
|
||||
self.button_scan.connect("clicked", self.on_selection_scan_clicked)
|
||||
self.ButtonBox.add(self.button_scan)
|
||||
|
||||
self.lb_button_connect = Gtk.Label()
|
||||
self.lb_button_connect.set_markup("<span font='%d' color='#88888888'>connect</span>" % self.font_size)
|
||||
self.button_connect = Gtk.Button()
|
||||
self.button_connect.add(self.lb_button_connect)
|
||||
self.button_connect.connect("clicked", self.on_selection_connect_clicked)
|
||||
self.ButtonBox.add(self.button_connect)
|
||||
|
||||
self.page_bluetooth.add(self.ButtonBox)
|
||||
|
||||
self.progress_vbox = Gtk.VBox()
|
||||
self.scan_progress = Gtk.ProgressBar()
|
||||
self.scan_progress.set_fraction(0.0)
|
||||
self.progress_vbox.pack_start(self.scan_progress, False, False, 3)
|
||||
self.page_bluetooth.add(self.progress_vbox)
|
||||
|
||||
self.tree_list_vbox = Gtk.VBox(homogeneous=True)
|
||||
|
||||
self.bluetooth_liststore = Gtk.ListStore(int, str, str, str)
|
||||
self.bluetooth_treeview = Gtk.TreeView(self.bluetooth_liststore)
|
||||
|
||||
l_col = ["n°", "name", "connected", "Audio"]
|
||||
for i, column_title in enumerate(l_col):
|
||||
renderer = Gtk.CellRendererText()
|
||||
renderer.set_property('font', "%d" % self.font_size)
|
||||
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
|
||||
self.bluetooth_treeview.append_column(column)
|
||||
self.bluetooth_treeview.get_selection().connect("changed", self.on_changed)
|
||||
|
||||
self.scroll_treelist = Gtk.ScrolledWindow()
|
||||
self.scroll_treelist.set_vexpand(False)
|
||||
self.scroll_treelist.set_hexpand(False)
|
||||
self.scroll_treelist.set_property("min-content-height", self.treelist_height)
|
||||
self.scroll_treelist.add(self.bluetooth_treeview)
|
||||
self.tree_list_vbox.pack_start(self.scroll_treelist, True, True, 3)
|
||||
|
||||
self.page_bluetooth.add(self.tree_list_vbox)
|
||||
|
||||
self.label_audio = Gtk.Label()
|
||||
self.label_audio.set_markup("<span font='%d' color='#FFFFFFFF'> </span>" % self.font_size)
|
||||
self.label_audio.set_justify(Gtk.Justification.LEFT)
|
||||
self.label_audio.set_line_wrap(True)
|
||||
self.page_bluetooth.add(self.label_audio)
|
||||
|
||||
mainvbox.pack_start(self.page_bluetooth, False, True, 3)
|
||||
self.show_all()
|
||||
|
||||
# enable bluetooth
|
||||
os.system('su -c \"hciconfig hci0 up\"')
|
||||
#self.bluetooth_state = os.system('hciconfig hci0 up')
|
||||
self.bl = Bluetoothctl()
|
||||
|
||||
list_devices(self, paired=True)
|
||||
self.audio_bt_sink = status_playback(self)
|
||||
|
||||
|
||||
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)
|
||||
rgba = Gdk.RGBA(0.31, 0.32, 0.31, 0.8)
|
||||
dialog.override_background_color(0,rgba)
|
||||
|
||||
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 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 ("BluetoothWindow double click : exit")
|
||||
self.bl.close()
|
||||
self.destroy()
|
||||
else:
|
||||
#print ("simple click")
|
||||
self.previous_click_time = self.click_time
|
||||
|
||||
|
||||
def delayed_status_playback(self, user_data):
|
||||
self.audio_bt_sink = status_playback(self)
|
||||
return False
|
||||
|
||||
def progress_timeout(self, user_data):
|
||||
new_val=self.scan_progress.get_fraction() + 0.01
|
||||
if new_val > 1:
|
||||
self.scan_progress.set_fraction(0.0)
|
||||
self.bl.blctl_scan_off()
|
||||
self.lb_button_scan.set_markup("<span font='%d'>start scan</span>" % self.font_size)
|
||||
self.scan_done = True
|
||||
self.update_display()
|
||||
return False
|
||||
|
||||
self.scan_progress.set_fraction(new_val)
|
||||
self.scan_progress.set_text(str(new_val*100) + " % completed")
|
||||
return True
|
||||
|
||||
def on_changed(self, selection):
|
||||
(model, iter) = selection.get_selected()
|
||||
#print("on_changed")
|
||||
if iter is not None:
|
||||
self.audio_bt_sink = status_playback(self)
|
||||
#print(self.audio_bt_sink)
|
||||
self.dev_selected.update({'mac_address':self.current_devs[model[iter][0]-1], 'name':model[iter][1]})
|
||||
if model[iter][2] == " yes":
|
||||
self.lb_button_connect.set_markup("<span font='%d'>disconnect</span>" % self.font_size)
|
||||
else:
|
||||
if self.label_audio.get_text() == "Device not connected":
|
||||
self.lb_button_connect.set_markup("<span font='%d'>connect</span>" % self.font_size)
|
||||
else:
|
||||
self.lb_button_connect.set_markup("<span font='%d' color='#88888888'>connect</span>" % self.font_size)
|
||||
return True
|
||||
|
||||
def connect_process(self, dev):
|
||||
if device_connected(self.bl, dev['mac_address']):
|
||||
self.lb_button_connect.set_markup("<span font='%d'>disconnect</span>" % self.font_size)
|
||||
self.update_display()
|
||||
else:
|
||||
connect_res=self.bl.blctl_connect(dev['mac_address'])
|
||||
if connect_res == True:
|
||||
self.lb_button_connect.set_markup("<span font='%d' color='#88888888'>disconnect</span>" % self.font_size)
|
||||
self.update_display()
|
||||
# refresh status_playback after 2,5s because pulseaudio takes some time to update its status
|
||||
timer_update_dev = GLib.timeout_add(2500, self.delayed_status_playback, None)
|
||||
#In some cases, 2.5s is still not enough
|
||||
timer_update_dev = GLib.timeout_add(4000, self.delayed_status_playback, None)
|
||||
|
||||
def on_selection_connect_clicked(self, widget):
|
||||
if self.dev_selected['mac_address'] != '':
|
||||
device = self.dev_selected
|
||||
if self.lb_button_connect.get_text() == "connect":
|
||||
if self.label_audio.get_text() == "Device not connected":
|
||||
self.bl.set_prompt(device['name'])
|
||||
if device_paired(self.bl, device['mac_address']) == False:
|
||||
pairing_res=self.bl.blctl_pair(device['mac_address'])
|
||||
if pairing_res == 0:
|
||||
self.bl.blctl_session.send("no\n")
|
||||
else:
|
||||
if pairing_res == 1:
|
||||
sleep(5)
|
||||
self.connect_process(device)
|
||||
else:
|
||||
self.connect_process(device)
|
||||
else:
|
||||
print("[WARNING] A BT device is already connected :\ndisconnect it before connecting a new device\n")
|
||||
self.display_message("<span font='15' color='#000000'>A BT device is already connected :\nPlease disconnect it before connecting a new device\n</span>")
|
||||
else:
|
||||
connect_res=self.bl.blctl_disconnect(device['mac_address'])
|
||||
self.lb_button_connect.set_markup("<span font='%d' color='#88888888'>connect</span>" % self.font_size)
|
||||
self.update_display()
|
||||
else:
|
||||
print("[WARNING] Select the BT device to connect\n")
|
||||
self.display_message("<span font='15' color='#000000'>Please select a device in the list\n</span>")
|
||||
|
||||
def on_selection_scan_clicked(self, widget):
|
||||
if self.lb_button_scan.get_text() == "start scan":
|
||||
self.bl.blctl_scan_on()
|
||||
timer_scan = GLib.timeout_add(SCAN_DURATION_IN_S * 10, self.progress_timeout, None)
|
||||
self.lb_button_scan.set_markup("<span font='%d'>scan progress</span>"% self.font_size)
|
||||
|
||||
def update_display(self):
|
||||
if (self.scan_done == True):
|
||||
list_devices(self, False)
|
||||
else:
|
||||
list_devices(self, True)
|
||||
self.dev_selected.update({'mac_address':'', 'name':''})
|
||||
self.audio_bt_sink = status_playback(self)
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def create_subdialogwindow(parent):
|
||||
_window = BluetoothWindow(parent)
|
||||
_window.show_all()
|
||||
response = _window.run()
|
||||
_window.destroy()
|
||||
|
||||
|
||||
# -------------------------------------------------
|
||||
# -------------------------------------------------
|
||||
# test submodule
|
||||
class TestUIWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Test Launcher")
|
||||
create_subdialogwindow(self)
|
||||
self.show_all()
|
||||
|
||||
if __name__ == "__main__":
|
||||
win = TestUIWindow()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.show_all()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
script -qc "su -c 'hciconfig hci0 up || echo ko > /tmp/ble'"
|
||||
|
||||
if [ -e /tmp/ble ]; then
|
||||
rm -f /tmp/ble
|
||||
exit 1;
|
||||
else
|
||||
exit 0;
|
||||
fi
|
||||
@@ -0,0 +1,196 @@
|
||||
import time
|
||||
import pexpect
|
||||
import sys
|
||||
import re
|
||||
import pickle
|
||||
|
||||
##############################
|
||||
# bluetoothctl tool wrapper
|
||||
##############################
|
||||
|
||||
__all__ = ["wrapper_blctl"]
|
||||
|
||||
|
||||
device = re.compile(r"Device\s(?P<mac_address>([0-9 A-F][0-9 A-F]:){5}[0-9 A-F][0-9 A-F])(?P<name>.+)$")
|
||||
|
||||
re_device_notvalid = [
|
||||
re.compile(r"CHG"),
|
||||
re.compile(r"NEW"),
|
||||
re.compile(r"DEL")
|
||||
]
|
||||
|
||||
def read_prompt():
|
||||
try:
|
||||
f = open('/tmp/list_prompt', 'rb')
|
||||
except IOError as e:
|
||||
print("Cant not open the file : /tmp/list_prompt\n")
|
||||
return None
|
||||
else:
|
||||
s = pickle.load(f)
|
||||
f.close()
|
||||
return s
|
||||
|
||||
def write_prompt(prt):
|
||||
with open('/tmp/list_prompt', 'wb') as f:
|
||||
pickle.dump(prt,f)
|
||||
|
||||
|
||||
class blctl_error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class wrapper_blctl:
|
||||
|
||||
def __init__(self):
|
||||
self.blctl_session = pexpect.spawn("bluetoothctl", echo = False, maxread = 3000)
|
||||
|
||||
#no prompt expected because a BT device can be connected automatically
|
||||
prompt_expect = self.blctl_session.expect([pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
|
||||
str_out = str(self.blctl_session.before,"utf-8")
|
||||
l_out = str_out.split("\r\n")
|
||||
|
||||
self.prompt = read_prompt()
|
||||
if self.prompt == None:
|
||||
self.prompt= ["\[bluetooth\]", pexpect.EOF]
|
||||
#print(self.prompt)
|
||||
|
||||
#execute a bluetoothctl command and return the result as a list of lines
|
||||
#no status cmd expected
|
||||
def blctl_command(self, command, pause = 0):
|
||||
#print("blctl_command : " + command)
|
||||
self.blctl_session.send(command + "\n")
|
||||
time.sleep(pause)
|
||||
|
||||
prompt_expect = self.blctl_session.expect(self.prompt)
|
||||
|
||||
if (prompt_expect > (len(self.prompt) - 1) or (prompt_expect < 0)):
|
||||
raise blctl_error("The bluetoothctl command " + command + " failed")
|
||||
|
||||
str_output = str(self.blctl_session.before,"utf-8")
|
||||
output_array = str_output.split("\r\n")
|
||||
|
||||
return output_array
|
||||
|
||||
#execute a bluetoothctl command with status expected
|
||||
def blctl_command_with_status(self, command, status_expected, pause = 0):
|
||||
print("blctl_command_with_status : " + command + "\n")
|
||||
status = status_expected
|
||||
status.extend([pexpect.EOF])
|
||||
#print("prompt_status : %s\n", status)
|
||||
|
||||
self.blctl_session.send(command + "\n")
|
||||
time.sleep(pause)
|
||||
|
||||
res = self.blctl_session.expect(status)
|
||||
|
||||
return res
|
||||
|
||||
def close(self):
|
||||
write_prompt(self.prompt)
|
||||
self.blctl_session.close()
|
||||
|
||||
#build the list of bluetoothctl prompts
|
||||
def set_prompt(self, prompt):
|
||||
prpt = "\["+prompt+"\]"
|
||||
if prpt not in self.prompt:
|
||||
self.prompt.insert(0, prpt)
|
||||
|
||||
#bluetoothctl command : scan on
|
||||
def blctl_scan_on(self):
|
||||
try:
|
||||
cmd_res = self.blctl_command("scan on")
|
||||
except blctl_error as ex:
|
||||
print(ex)
|
||||
return None
|
||||
|
||||
#bluetoothctl command : scan off
|
||||
def blctl_scan_off(self):
|
||||
try:
|
||||
cmd_res = self.blctl_command("scan off")
|
||||
except blctl_error as ex:
|
||||
print(ex)
|
||||
return None
|
||||
|
||||
#make a dic (mac_address, name) from result of bluetoothctl command devices
|
||||
def parse_info(self, device_info):
|
||||
dev = {}
|
||||
info_isnot_valid = None
|
||||
for reg in re_device_notvalid:
|
||||
info_isnot_valid = reg.search(device_info)
|
||||
if info_isnot_valid is not None:
|
||||
break
|
||||
|
||||
if info_isnot_valid is None:
|
||||
result = device.search(device_info)
|
||||
if result is not None:
|
||||
dev = result.groupdict()
|
||||
name_tmp = dev['name'].strip()
|
||||
dev['name'] = name_tmp
|
||||
return dev
|
||||
|
||||
#bluetoothctl command : devices
|
||||
#return a list of dic {mac_address, name}
|
||||
def blctl_devices(self):
|
||||
try:
|
||||
cmd_res = self.blctl_command("devices")
|
||||
except blctl_error as ex:
|
||||
print(ex)
|
||||
return None
|
||||
else:
|
||||
list_devices = []
|
||||
for line in cmd_res:
|
||||
device = self.parse_info(line)
|
||||
if device:
|
||||
list_devices.append(device)
|
||||
|
||||
return list_devices
|
||||
|
||||
#bluetoothctl command : paired-devices
|
||||
#return a list of dic {mac_address, name}
|
||||
def blctl_paired_devices(self):
|
||||
try:
|
||||
cmd_res = self.blctl_command("paired-devices")
|
||||
except blctl_error as ex:
|
||||
print(ex)
|
||||
return None
|
||||
else:
|
||||
list_devices = []
|
||||
for line in cmd_res:
|
||||
device = self.parse_info(line)
|
||||
if device:
|
||||
list_devices.append(device)
|
||||
|
||||
return list_devices
|
||||
|
||||
#bluetoothctl command : info <mac_address>
|
||||
def blctl_info(self, mac_address):
|
||||
try:
|
||||
cmd_res = self.blctl_command("info " + mac_address)
|
||||
except blctl_error as ex:
|
||||
print(ex)
|
||||
return None
|
||||
else:
|
||||
return cmd_res
|
||||
|
||||
#bluetoothctl command : pair <mac_address>
|
||||
def blctl_pair(self, mac_address):
|
||||
cmd_res = self.blctl_command_with_status("pair " + mac_address, ["confirmation", "Pairing successful", "not available", "Failed to pair"], pause=4)
|
||||
return cmd_res
|
||||
|
||||
#bluetoothctl command : connect <mac_address>
|
||||
def blctl_connect(self, mac_address):
|
||||
cmd_res = self.blctl_command_with_status("connect " + mac_address, ["Failed to connect", "Connection successful"], pause=2)
|
||||
passed = True if cmd_res == 1 else False
|
||||
return passed
|
||||
|
||||
#bluetoothctl command : disconnect <mac_address>
|
||||
def blctl_disconnect(self, mac_address):
|
||||
cmd_res = self.blctl_command_with_status("disconnect " + mac_address, ["Failed to disconnect", "Successful disconnected"], pause=2)
|
||||
passed = True if cmd_res == 1 else False
|
||||
return passed
|
||||
|
||||
#bluetoothctl command : remove <mac_address>
|
||||
def blctl_remove(self, mac_address):
|
||||
cmd_res = self.blctl_command_with_status("remove " + mac_address, ["not available", "Failed to remove", "Device has been removed"], pause=3)
|
||||
passed = True if cmd_res == 2 else False
|
||||
return passed
|
||||
@@ -0,0 +1,38 @@
|
||||
SUMMARY = "Add support of camera preview on Demo Launcher"
|
||||
HOMEPAGE = "wiki.st.com"
|
||||
LICENSE = "BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9"
|
||||
|
||||
DEPENDS = "demo-launcher event-gtk-player wayland-utils"
|
||||
|
||||
PV = "2.0"
|
||||
|
||||
SRC_URI = " \
|
||||
file://launch_camera_preview.sh \
|
||||
file://stop_camera.sh \
|
||||
file://edge_InvertLuma.fs \
|
||||
file://ST1077_webcam_dark_blue.png \
|
||||
file://010-camera.yaml \
|
||||
file://check_camera_preview.sh \
|
||||
"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/application/camera/bin
|
||||
install -d ${D}${prefix}/local/demo/application/camera/pictures
|
||||
install -d ${D}${prefix}/local/demo/application/camera/shaders
|
||||
|
||||
# install yaml file
|
||||
install -m 0644 ${WORKDIR}/*.yaml ${D}${prefix}/local/demo/application/
|
||||
# install pictures
|
||||
install -m 0644 ${WORKDIR}/*.png ${D}${prefix}/local/demo/application/camera/pictures
|
||||
# script
|
||||
install -m 0755 ${WORKDIR}/*.sh ${D}${prefix}/local/demo/application/camera/bin
|
||||
# shaders
|
||||
install -m 0644 ${WORKDIR}/*.fs ${D}${prefix}/local/demo/application/camera/shaders
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/local/demo/application/"
|
||||
RDEPENDS:${PN} += "event-gtk-player demo-launcher"
|
||||
@@ -0,0 +1,17 @@
|
||||
Application:
|
||||
Name: Camera
|
||||
Description: preview
|
||||
Icon: application/camera/pictures/ST1077_webcam_dark_blue.png
|
||||
Board:
|
||||
List: all
|
||||
Type: script
|
||||
Script:
|
||||
Exist:
|
||||
Command: /usr/local/demo/application/camera/bin/check_camera_preview.sh
|
||||
Msg_false: Webcam or camera is not connected
|
||||
Start: application/camera/bin/launch_camera_preview.sh
|
||||
Action:
|
||||
button_release_event: script_management
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
is_dcmipp_present() {
|
||||
DCMIPP_PRESENT="NOTFOUND"
|
||||
# on disco board gc2145 or ov5640 camera can be present on csi connector
|
||||
for video in $(find /sys/class/video4linux -name "video*" -type l);
|
||||
do
|
||||
if [ "$(cat $video/name)" = "dcmipp_dump_capture" ]; then
|
||||
for sub in $(find /sys/class/video4linux -name "v4l-subdev*" -type l);
|
||||
do
|
||||
subdev_name=$(tr -d '\0' < $sub/name | awk '{print $1}')
|
||||
if [ "$subdev_name" = "gc2145" ] || [ "$subdev_name" = "ov5640" ]; then
|
||||
DCMIPP_PRESENT="FOUND"
|
||||
return
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
get_webcam_device() {
|
||||
WEBCAM_found="NOTFOUND"
|
||||
for video in $(find /sys/class/video4linux -name "video*" -type l | sort);
|
||||
do
|
||||
if [ ! "$(cat $video/name)" = "dcmipp_dump_capture" ]; then
|
||||
WEBCAM_found="FOUND"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# ------------------------------
|
||||
# main
|
||||
# ------------------------------
|
||||
|
||||
# camera detection
|
||||
# detect if we have a gc2145 or ov5640 plugged and associated to dcmipp
|
||||
is_dcmipp_present
|
||||
if [ "$DCMIPP_PRESENT" = "FOUND" ]; then
|
||||
exit 0
|
||||
fi
|
||||
get_webcam_device
|
||||
if [ "$WEBCAM_found" = "FOUND" ]; then
|
||||
exit 0
|
||||
fi
|
||||
exit 1
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Original shader from: https://www.shadertoy.com/view/MdGXDy
|
||||
*
|
||||
* Automatically converted by st-to-gstsh script
|
||||
* See: https://github.com/jolivain/gst-shadertoy
|
||||
*/
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
// gst-glshader uniforms
|
||||
uniform float time;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
uniform sampler2D tex;
|
||||
|
||||
// shadertoy globals
|
||||
float iGlobalTime = 0.0;
|
||||
float iTime = 0.0;
|
||||
vec3 iResolution = vec3(0.0);
|
||||
vec3 iMouse = vec3(0.0);
|
||||
vec4 iDate = vec4(0.0);
|
||||
|
||||
#define iChannel0 tex
|
||||
#define texture(t,c) texture2D(t,c)
|
||||
#if (__VERSION__ < 300)
|
||||
# define textureLod(s, uv, l) texture2D(s, uv)
|
||||
#endif
|
||||
|
||||
// Protect gst-glshader names
|
||||
#define time gstemu_time
|
||||
#define width gstemu_width
|
||||
#define height gstemu_height
|
||||
|
||||
// --------[ Original ShaderToy begins here ]---------- //
|
||||
const float gamma = 2.2;
|
||||
|
||||
float gamma2linear( float v )
|
||||
{
|
||||
return pow( v, gamma );
|
||||
}
|
||||
|
||||
float linear2gamma( float v )
|
||||
{
|
||||
return pow( v, 1./gamma );
|
||||
}
|
||||
|
||||
float min3( float a, float b, float c )
|
||||
{
|
||||
return min( min( a, b ), c );
|
||||
}
|
||||
|
||||
float max3( float a, float b, float c )
|
||||
{
|
||||
return max( max( a, b ), c );
|
||||
}
|
||||
|
||||
vec3 rgb2hsv(vec3 c)
|
||||
{
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
vec3 hsv2rgb(vec3 c)
|
||||
{
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
vec3 convertRGBtoHSL( vec3 col )
|
||||
{
|
||||
float red = col.r;
|
||||
float green = col.g;
|
||||
float blue = col.b;
|
||||
|
||||
float minc = min3( col.r, col.g, col.b );
|
||||
float maxc = max3( col.r, col.g, col.b );
|
||||
float delta = maxc - minc;
|
||||
|
||||
float lum = (minc + maxc) * 0.5;
|
||||
float sat = 0.0;
|
||||
float hue = 0.0;
|
||||
|
||||
if (lum > 0.0 && lum < 1.0) {
|
||||
float mul = (lum < 0.5) ? (lum) : (1.0-lum);
|
||||
sat = delta / (mul * 2.0);
|
||||
}
|
||||
|
||||
vec3 masks = vec3(
|
||||
(maxc == red && maxc != green) ? 1.0 : 0.0,
|
||||
(maxc == green && maxc != blue) ? 1.0 : 0.0,
|
||||
(maxc == blue && maxc != red) ? 1.0 : 0.0
|
||||
);
|
||||
|
||||
vec3 adds = vec3(
|
||||
((green - blue ) / delta),
|
||||
2.0 + ((blue - red ) / delta),
|
||||
4.0 + ((red - green) / delta)
|
||||
);
|
||||
|
||||
float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
|
||||
|
||||
hue += dot( adds, masks );
|
||||
hue *= deltaGtz;
|
||||
hue /= 6.0;
|
||||
|
||||
if (hue < 0.0)
|
||||
hue += 1.0;
|
||||
|
||||
return vec3( hue, sat, lum );
|
||||
}
|
||||
|
||||
vec3 convertHSLtoRGB( vec3 col )
|
||||
{
|
||||
const float onethird = 1.0 / 3.0;
|
||||
const float twothird = 2.0 / 3.0;
|
||||
const float rcpsixth = 6.0;
|
||||
|
||||
float hue = col.x;
|
||||
float sat = col.y;
|
||||
float lum = col.z;
|
||||
|
||||
vec3 xt = vec3(
|
||||
rcpsixth * (hue - twothird),
|
||||
0.0,
|
||||
rcpsixth * (1.0 - hue)
|
||||
);
|
||||
|
||||
if (hue < twothird) {
|
||||
xt.r = 0.0;
|
||||
xt.g = rcpsixth * (twothird - hue);
|
||||
xt.b = rcpsixth * (hue - onethird);
|
||||
}
|
||||
|
||||
if (hue < onethird) {
|
||||
xt.r = rcpsixth * (onethird - hue);
|
||||
xt.g = rcpsixth * hue;
|
||||
xt.b = 0.0;
|
||||
}
|
||||
|
||||
xt = min( xt, 1.0 );
|
||||
|
||||
float sat2 = 2.0 * sat;
|
||||
float satinv = 1.0 - sat;
|
||||
float luminv = 1.0 - lum;
|
||||
float lum2m1 = (2.0 * lum) - 1.0;
|
||||
vec3 ct = (sat2 * xt) + satinv;
|
||||
|
||||
vec3 rgb;
|
||||
if (lum >= 0.5)
|
||||
rgb = (luminv * ct) + lum2m1;
|
||||
else rgb = lum * ct;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
vec3 sample = texture( iChannel0, uv ).rgb;
|
||||
|
||||
vec3 s2 = convertRGBtoHSL( sample );
|
||||
|
||||
//s2.b = gamma2linear( s2.b );
|
||||
s2.b = ( s2.b * -1.0 ) + 1.0;
|
||||
//s2.b = linear2gamma( s2.b );
|
||||
|
||||
vec3 s3 = convertHSLtoRGB( s2 );
|
||||
fragColor = vec4(s3, 1.0);
|
||||
}
|
||||
// --------[ Original ShaderToy ends here ]---------- //
|
||||
|
||||
#undef time
|
||||
#undef width
|
||||
#undef height
|
||||
|
||||
void main(void)
|
||||
{
|
||||
iResolution = vec3(width, height, 0.0);
|
||||
iGlobalTime = time;
|
||||
iTime = time;
|
||||
iDate.w = time;
|
||||
|
||||
mainImage(gl_FragColor, gl_FragCoord.xy);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#!/bin/sh
|
||||
function print_debug() {
|
||||
echo "[exec]: $@"
|
||||
}
|
||||
|
||||
function pty_exec() {
|
||||
cmd=$1
|
||||
pty=$(tty > /dev/null 2>&1; echo $?)
|
||||
if [ $pty -eq 0 ]; then
|
||||
cmd=$(echo $cmd | sed "s#\"#'#g")
|
||||
event_cmd=$(echo /usr/local/demo/bin/touch-event-gtk-player -w $SCREEN_WIDTH -h $SCREEN_HEIGHT --graph \"$cmd\")
|
||||
eval $event_cmd > /dev/null 2>&1
|
||||
else
|
||||
# no pty
|
||||
echo "NO PTY"
|
||||
event_cmd=$(echo /usr/local/demo/bin/touch-event-gtk-player -w $SCREEN_WIDTH -h $SCREEN_HEIGHT --graph \'$cmd\')
|
||||
script -qc "$event_cmd" > /dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
is_dcmipp_present() {
|
||||
DCMIPP_SENSOR="NOTFOUND"
|
||||
# on disco board ov5640 camera can be present on csi connector
|
||||
for video in $(find /sys/class/video4linux -name "video*" -type l);
|
||||
do
|
||||
if [ "$(cat $video/name)" = "dcmipp_dump_capture" ]; then
|
||||
cd $video/device/
|
||||
mediadev=/dev/$(ls -d media*)
|
||||
cd -
|
||||
for sub in $(find /sys/class/video4linux -name "v4l-subdev*" -type l);
|
||||
do
|
||||
subdev_name=$(tr -d '\0' < $sub/name | awk '{print $1}')
|
||||
if [ "$subdev_name" = "gc2145" ] || [ "$subdev_name" = "ov5640" ]; then
|
||||
DCMIPP_SENSOR=$subdev_name
|
||||
V4L_DEVICE="device=/dev/$(basename $video)"
|
||||
sensorsubdev=$(tr -d '\0' < $sub/name)
|
||||
#bridge is connected to output of sensor (":0 [ENABLED" with media-ctl -p)
|
||||
bridgesubdev=$(media-ctl -d $mediadev -p -e "$sensorsubdev" | grep ":0 \[ENABLED" | awk -F\" '{print $2}')
|
||||
#interface is connected to input of postproc (":1 [ENABLED" with media-ctl -p)
|
||||
interfacesubdev=$(media-ctl -d $mediadev -p -e "dcmipp_dump_postproc" | grep ":1 \[ENABLED" | awk -F\" '{print $2}')
|
||||
if [ "$subdev_name" = "gc2145" ]; then
|
||||
sensorbuscode_constrain="BE"
|
||||
parallelbuscode="RGB565_2X8_BE"
|
||||
else
|
||||
sensorbuscode_constrain="LE"
|
||||
parallelbuscode="RGB565_2X8_LE"
|
||||
fi
|
||||
echo "media device: "$mediadev
|
||||
echo "video device: "$V4L_DEVICE
|
||||
echo "sensor subdev: " $sensorsubdev
|
||||
echo "bridge subdev: " $bridgesubdev
|
||||
echo "interface subdev: " $interfacesubdev
|
||||
|
||||
return
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
is_dcmi_present() {
|
||||
DCMI_SENSOR="NOTFOUND"
|
||||
# on disco board ov5640 camera can be present on // connector
|
||||
for video in $(find /sys/class/video4linux -name "video*" -type l);
|
||||
do
|
||||
if [ "$(cat $video/name)" = "stm32_dcmi" ]; then
|
||||
V4L_DEVICE="device=/dev/$(basename $video)"
|
||||
DCMI_SENSOR="$(basename $video)"
|
||||
echo "video DCMI device: "$V4L_DEVICE
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
get_webcam_device() {
|
||||
found="NOTFOUND"
|
||||
for video in $(find /sys/class/video4linux -name "video*" -type l | sort);
|
||||
do
|
||||
if [ "$(cat $video/name)" = "dcmipp_dump_capture" ]; then
|
||||
found="FOUND"
|
||||
else
|
||||
V4L_DEVICE="device=/dev/$(basename $video)"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# ------------------------------
|
||||
# main
|
||||
# ------------------------------
|
||||
|
||||
# graphic brackend detection
|
||||
if [ -f /etc/default/weston ] && $(grep "^OPTARGS" /etc/default/weston | grep -q "use-pixman" ) ;
|
||||
then
|
||||
echo "Without GPU"
|
||||
ADDONS="videoconvert ! queue !"
|
||||
else
|
||||
echo "With GPU"
|
||||
ADDONS=""
|
||||
fi
|
||||
|
||||
|
||||
# Detect size of screen
|
||||
SCREEN_WIDTH=$(wayland-info | grep logical_width | sed -r "s/logical_width: ([0-9]+),.*/\1/")
|
||||
SCREEN_HEIGHT=$(wayland-info | grep logical_width | sed -r "s/.*logical_height: ([0-9]+).*/\1/")
|
||||
|
||||
|
||||
# camera detection
|
||||
is_dcmipp_present
|
||||
if [ "$DCMIPP_SENSOR" != "NOTFOUND" ]; then
|
||||
WIDTH=640
|
||||
HEIGHT=480
|
||||
FPS=30
|
||||
|
||||
sensordev=$(media-ctl -d $mediadev -p -e "$sensorsubdev" | grep "node name" | awk -F\name '{print $2}')
|
||||
sensorbuscode=`v4l2-ctl --list-subdev-mbus-codes -d $sensordev | grep RGB565 | grep "$sensorbuscode_constrain" | awk -FMEDIA_BUS_FMT_ '{print $2}'| head -n 1`
|
||||
echo "sensor mbus-code: "$sensorbuscode
|
||||
print_debug media-ctl -d $mediadev --set-v4l2 "'$sensorsubdev':0[fmt:$sensorbuscode/${WIDTH}x${HEIGHT}@1/${FPS} field:none]"
|
||||
media-ctl -d $mediadev --set-v4l2 "'$sensorsubdev':0[fmt:$sensorbuscode/${WIDTH}x${HEIGHT}@1/${FPS} field:none]"
|
||||
print_debug media-ctl -d $mediadev --set-v4l2 "'$bridgesubdev':2[fmt:$sensorbuscode/${WIDTH}x${HEIGHT}]"
|
||||
media-ctl -d $mediadev --set-v4l2 "'$bridgesubdev':2[fmt:$sensorbuscode/${WIDTH}x${HEIGHT}]"
|
||||
print_debug media-ctl -d $mediadev --set-v4l2 "'$interfacesubdev':1[fmt:$parallelbuscode/${WIDTH}x${HEIGHT}]"
|
||||
media-ctl -d $mediadev --set-v4l2 "'$interfacesubdev':1[fmt:$parallelbuscode/${WIDTH}x${HEIGHT}]"
|
||||
print_debug media-ctl -d $mediadev --set-v4l2 "'dcmipp_dump_postproc':1[fmt:$parallelbuscode/${WIDTH}x${HEIGHT}]"
|
||||
media-ctl -d $mediadev --set-v4l2 "'dcmipp_dump_postproc':1[fmt:$parallelbuscode/${WIDTH}x${HEIGHT}]"
|
||||
V4L2_CAPS="video/x-raw, format=RGB16, width=$WIDTH, height=$HEIGHT"
|
||||
V4L_OPT=""
|
||||
|
||||
else
|
||||
is_dcmi_present
|
||||
if [ "$DCMI_SENSOR" != "NOTFOUND" ]; then
|
||||
COMPATIBLE_BOARD=$(cat /proc/device-tree/compatible | sed "s|st,|,|g" | cut -d ',' -f2)
|
||||
case $COMPATIBLE_BOARD in
|
||||
stm32mp15*)
|
||||
WIDTH=640
|
||||
HEIGHT=480
|
||||
;;
|
||||
*)
|
||||
WIDTH=640
|
||||
HEIGHT=480
|
||||
;;
|
||||
esac
|
||||
else
|
||||
get_webcam_device
|
||||
# suppose we have a webcam
|
||||
WIDTH=640
|
||||
HEIGHT=480
|
||||
fi
|
||||
|
||||
V4L2_CAPS="video/x-raw, width=$WIDTH, height=$HEIGHT"
|
||||
V4L_OPT="io-mode=4"
|
||||
v4l2-ctl --set-parm=30
|
||||
fi
|
||||
|
||||
|
||||
echo "Gstreamer graph:"
|
||||
GRAPH="v4l2src $V4L_DEVICE $V4L_OPT ! $V4L2_CAPS ! queue ! $ADDONS gtkwaylandsink name=gtkwsink"
|
||||
|
||||
echo " $GRAPH"
|
||||
pty_exec "$GRAPH"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
#killall gst-launch-1.0
|
||||
killall touch-event-gtk-player
|
||||
@@ -0,0 +1,44 @@
|
||||
SUMMARY = "Add support of netdata/hotspot wifi on Demo Launcher"
|
||||
HOMEPAGE = "wiki.st.com"
|
||||
LICENSE = "BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9"
|
||||
|
||||
DEPENDS = "demo-launcher demo-hotspot-wifi qrenc"
|
||||
|
||||
PV = "2.0"
|
||||
|
||||
SRC_URI = " \
|
||||
file://000-netdata.yaml \
|
||||
file://build_qrcode.sh \
|
||||
file://__init__.py \
|
||||
file://netdata.py \
|
||||
file://netdata-icon-192x192.png \
|
||||
file://hostapd \
|
||||
file://wifi_start.sh \
|
||||
file://wifi_stop.sh \
|
||||
file://get_wlan_name.sh \
|
||||
file://get_ethernet_ip.sh \
|
||||
"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/application/netdata/bin
|
||||
install -d ${D}${prefix}/local/demo/application/netdata/pictures
|
||||
|
||||
# install yaml file
|
||||
install -m 0644 ${WORKDIR}/*.yaml ${D}${prefix}/local/demo/application/
|
||||
# install bin
|
||||
install -m 0755 ${WORKDIR}/*.sh ${D}${prefix}/local/demo/application/netdata/bin
|
||||
# install pictures
|
||||
install -m 0644 ${WORKDIR}/*.png ${D}${prefix}/local/demo/application/netdata/pictures
|
||||
# python script
|
||||
install -m 0755 ${WORKDIR}/*.py ${D}${prefix}/local/demo/application/netdata/
|
||||
|
||||
# for wifi hotspot
|
||||
install -d ${D}${sysconfdir}/default
|
||||
install -m 0644 ${WORKDIR}/hostapd ${D}${sysconfdir}/default
|
||||
}
|
||||
RDEPENDS:${PN} += "python3-core python3-pygobject gtk+3 python3-threading demo-launcher demo-hotspot-wifi qrenc"
|
||||
FILES:${PN} += "${sysconfdir}/default ${prefix}/local/demo/application/"
|
||||
@@ -0,0 +1,14 @@
|
||||
Application:
|
||||
Name: netdata
|
||||
Description: perf monitor
|
||||
Icon: application/netdata/pictures/netdata-icon-192x192.png
|
||||
Type: python
|
||||
Board:
|
||||
List: all
|
||||
Python:
|
||||
Module: application.netdata.netdata
|
||||
Action:
|
||||
button_release_event: python_start
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
/usr/bin/qrencode -s 30 $1 $2 -m 1
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh -
|
||||
WLAN_INTERFACE=$(/usr/local/demo/application/netdata/bin/get_wlan_name.sh 2> /dev/null)
|
||||
|
||||
if [ -n "$WLAN_INTERFACE" ]; then
|
||||
LIST_ETH=$(/sbin/ip link | grep ^[1-9] | grep -v lo | grep -v "$WLAN_INTERFACE" | awk '{print $2;}' | sed "s/://")
|
||||
else
|
||||
LIST_ETH=$(/sbin/ip link | grep ^[1-9] | grep -v lo | awk '{print $2;}' | sed "s/://")
|
||||
fi
|
||||
|
||||
IP_ADDRESS=""
|
||||
for i in $LIST_ETH;
|
||||
do
|
||||
IP=$(/sbin/ip addr show $i | grep "inet " | awk '{print $2;}' | sed "s/\([0-9]*.[0-9]*.[0-9]*.[0-9]*\).*/\1/")
|
||||
if [ -n "$IP" ]; then
|
||||
IP_ADDRESS="$IP_ADDRESS http://$IP:19999"
|
||||
fi
|
||||
done
|
||||
echo $IP_ADDRESS
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh -
|
||||
/sbin/ip link show wlan0 | head -n 1 | awk '{print $2}' | tr '\n' ' ' | sed "s/: //"
|
||||
@@ -0,0 +1,2 @@
|
||||
HOSTAPD_SSID=STDemoNetwork
|
||||
HOSTAPD_PASSWD=stm32mp1
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,399 @@
|
||||
#!/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 os
|
||||
import socket
|
||||
import fcntl
|
||||
import struct
|
||||
import string
|
||||
import random
|
||||
import math
|
||||
import subprocess
|
||||
from time import sleep, time
|
||||
import threading
|
||||
|
||||
SIMULATE = 0
|
||||
|
||||
ETHERNET_PREFIX="end"
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
SUBMODULE_PATH = "application/netdata"
|
||||
DEMO_PATH = "/usr/local/demo"
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
WIFI_LINUX_INTERFACE_NAME = "wlan0"
|
||||
WIFI_HOTSPOT_IP="192.168.72.1"
|
||||
|
||||
WIFI_DEFAULT_SSID="STDemoNetwork"
|
||||
WIFI_DEFAULT_PASSWD="stm32mp1"
|
||||
|
||||
if SIMULATE > 0:
|
||||
WIFI_LINUX_INTERFACE_NAME = "wlp8s0"
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
ICON_SIZE_1080 = 260
|
||||
ICON_SIZE_720 = 160
|
||||
ICON_SIZE_480 = 160
|
||||
ICON_SIZE_272 = 48
|
||||
|
||||
# return format:
|
||||
# [ icon_size, font_size ]
|
||||
SIZES_ID_ICON_SIZE = 0
|
||||
SIZES_ID_FONT_SIZE = 1
|
||||
def get_sizes_from_screen_size(width, height):
|
||||
minsize = min(width, height)
|
||||
icon_size = None
|
||||
font_size = None
|
||||
if minsize == 720:
|
||||
icon_size = ICON_SIZE_720
|
||||
font_size = 25
|
||||
elif minsize == 480:
|
||||
icon_size = ICON_SIZE_480
|
||||
font_size = 20
|
||||
elif minsize == 272:
|
||||
icon_size = ICON_SIZE_272
|
||||
font_size = 10
|
||||
elif minsize == 600:
|
||||
icon_size = ICON_SIZE_720
|
||||
font_size = 15
|
||||
elif minsize >= 1080:
|
||||
icon_size = ICON_SIZE_1080
|
||||
font_size = 32
|
||||
return [icon_size, font_size]
|
||||
|
||||
def get_icon_size_from_screen_size(width, height):
|
||||
minsize = min(width, height)
|
||||
if minsize == 720:
|
||||
return ICON_SIZE_720
|
||||
elif minsize == 480:
|
||||
return ICON_SIZE_480
|
||||
elif minsize == 272:
|
||||
return ICON_SIZE_272
|
||||
elif minsize == 600:
|
||||
return ICON_SIZE_1080
|
||||
elif minsize >= 1080:
|
||||
return ICON_SIZE_1080
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Get the wlan interface name
|
||||
def get_wlan_interface_name():
|
||||
cmd = ["%s/application/netdata/bin/get_wlan_name.sh" % DEMO_PATH]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
res = proc.stdout.read().decode('utf-8')
|
||||
return res
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Get list of ip address
|
||||
def get_ip_address_list():
|
||||
cmd = ["%s/application/netdata/bin/get_ethernet_ip.sh" % DEMO_PATH]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
res = proc.stdout.read().decode('utf-8')
|
||||
return res
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Get the ip address of board
|
||||
def get_ip_address(ifname):
|
||||
ip = "NA"
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
ip = socket.inet_ntoa(fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8915, # SIOCGIFADDR
|
||||
struct.pack('256s', bytes(ifname[:15], 'utf-8'))
|
||||
)[20:24])
|
||||
except socket.error:
|
||||
pass
|
||||
return ip
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
def _load_image_wlan_eventBox(parent, filename, label_text1, label_text2, scale_w, scale_h):
|
||||
# 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='10' color='#FFFFFFFF'>%s\n</span>"
|
||||
"<span font='10' color='#FFFFFFFF'>%s</span>" % (label_text1, label_text2))
|
||||
#label.set_justify(Gtk.Justification.LEFT)
|
||||
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 id_generator(size=6, chars=string.ascii_lowercase + string.digits):
|
||||
return "".join(random.choice(chars) for _ in range(size))
|
||||
# -------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
class NetdataWebserver(Gtk.Dialog):
|
||||
def __init__(self, parent):
|
||||
Gtk.Dialog.__init__(self, "Wifi", parent, 0)
|
||||
|
||||
if SIMULATE > 0:
|
||||
self.screen_width = 800
|
||||
self.screen_height = 480
|
||||
self.set_default_size(self.screen_width, self.screen_height)
|
||||
else:
|
||||
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.icon_size = get_icon_size_from_screen_size(self.screen_width, self.screen_height)
|
||||
sizes = get_sizes_from_screen_size(self.screen_width, self.screen_height)
|
||||
self.font_size = sizes[SIZES_ID_FONT_SIZE]
|
||||
|
||||
self.set_decorated(False)
|
||||
rgba = Gdk.RGBA(0.31, 0.32, 0.31, 0.8)
|
||||
self.override_background_color(0,rgba)
|
||||
|
||||
mainvbox = self.get_content_area()
|
||||
|
||||
self.page_ip = Gtk.VBox(homogeneous=False, spacing=0)
|
||||
self.page_ip.set_border_width(10)
|
||||
self.set_border_width(10)
|
||||
|
||||
self.title = Gtk.Label()
|
||||
self.title.set_markup("<span font='%d' color='#FFFFFFFF'><b>Access information to netdata</b></span>" % (self.font_size+5))
|
||||
self.page_ip.add(self.title)
|
||||
self.label_eth = Gtk.Label()
|
||||
self.label_eth.set_markup("<span font='%d' color='#FFFFFFFF'>netdata over Ethernet:</span>" % self.font_size)
|
||||
self.label_eth.set_xalign (0.0)
|
||||
self.label_ip_ethernet = Gtk.Label()
|
||||
#self.label_ip_ethernet.set_xalign (0.0)
|
||||
self.label_wifi = Gtk.Label()
|
||||
self.label_wifi.set_markup("<span font='%d' color='#FFFFFFFF'>netdata over Wifi:</span>" % self.font_size)
|
||||
self.label_wifi.set_xalign (0.0)
|
||||
self.label_ip_wlan0 = Gtk.Label()
|
||||
#self.label_ip_wlan0.set_xalign (0.0)
|
||||
self.label_hotspot = Gtk.Label()
|
||||
self.label_hotspot.set_xalign (0.0)
|
||||
|
||||
self.previous_click_time=0
|
||||
self.wifi_ssid=WIFI_DEFAULT_SSID
|
||||
self.wifi_passwd=WIFI_DEFAULT_PASSWD
|
||||
|
||||
self.info_grid = Gtk.Grid()
|
||||
self.info_grid.set_column_spacing(2)
|
||||
self.info_grid.set_row_spacing(2)
|
||||
|
||||
self.info_grid.attach(self.label_eth, 0, 1, 1, 1)
|
||||
self.info_grid.attach(self.label_ip_ethernet, 1, 1, 1, 1)
|
||||
|
||||
if self.is_wifi_available():
|
||||
print ("wlan0 is available")
|
||||
self.hotspot_switch = Gtk.Switch()
|
||||
|
||||
# set wlan switch state on first execution
|
||||
ip_wlan0 = get_ip_address(get_wlan_interface_name())
|
||||
if ip_wlan0 == WIFI_HOTSPOT_IP:
|
||||
self.hotspot_switch.set_active(True)
|
||||
else:
|
||||
self.hotspot_switch.set_active(False)
|
||||
|
||||
self.hotspot_switch.connect("notify::active", self.on_switch_activated)
|
||||
self.info_grid.attach(self.label_wifi, 0, 2, 1, 1)
|
||||
self.info_grid.attach(self.hotspot_switch, 0, 3, 1, 1)
|
||||
self.info_grid.attach(self.label_hotspot, 1, 3, 1, 1)
|
||||
|
||||
else:
|
||||
print ("wlan0 interface not available")
|
||||
self.info_grid.attach(self.label_hotspot, 0, 3, 1, 1)
|
||||
|
||||
self.page_ip.add(self.info_grid)
|
||||
self.refresh_network_page()
|
||||
self.connect("button-release-event", self.on_page_press_event)
|
||||
|
||||
mainvbox.pack_start(self.page_ip, False, True, 3)
|
||||
self.show_all()
|
||||
|
||||
def is_wifi_available(self):
|
||||
interface_name = get_wlan_interface_name()
|
||||
if len(interface_name) > 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_wifi_config(self):
|
||||
filepath = "/etc/default/hostapd"
|
||||
if os.path.isfile(filepath):
|
||||
file = open(filepath, "r")
|
||||
i=0
|
||||
for line in file:
|
||||
if "HOSTAPD_SSID" in line:
|
||||
self.wifi_ssid = (line.split('=')[1]).rstrip('\r\n')
|
||||
i+=1
|
||||
if "HOSTAPD_PASSWD" in line:
|
||||
self.wifi_passwd=(line.split('=')[1]).rstrip('\r\n')
|
||||
i+=1
|
||||
file.close()
|
||||
if (i==2):
|
||||
print("[Wifi: use hostapd configuration: ssid=%s, passwd=%s]\n" %(self.wifi_ssid, self.wifi_passwd))
|
||||
else:
|
||||
self.wifi_ssid=WIFI_DEFAULT_SSID
|
||||
self.wifi_passwd=WIFI_DEFAULT_PASSWD
|
||||
print("[Wifi: use default configuration: ssid=%s, passwd=%s]\n" %(self.wifi_ssid, self.wifi_passwd))
|
||||
else:
|
||||
print("[Wifi: use default configuration: ssid=%s, passwd=%s]\n" %(self.wifi_ssid, self.wifi_passwd))
|
||||
|
||||
def set_random_wifi_config(self):
|
||||
self.wifi_ssid="ST-" + id_generator()
|
||||
#self.wifi_passwd=id_generator(6, string.ascii_lowercase)
|
||||
self.set_wifi_config(self.wifi_ssid, self.wifi_passwd)
|
||||
|
||||
def set_wifi_config(self, ssid, password):
|
||||
filepath = "/tmp/hostapd"
|
||||
file = open(filepath, "w")
|
||||
print ("[Wifi: set hostapd config: ssid=%s, passwd=%s]" %(ssid, password))
|
||||
file.write('HOSTAPD_SSID=%s\nHOSTAPD_PASSWD=%s\n' %(ssid, password))
|
||||
file.close()
|
||||
os.system('su -c \"cp /tmp/hostapd /etc/default/hostapd\"')
|
||||
|
||||
|
||||
def refresh_network_page(self):
|
||||
print("[Refresh network page]\n")
|
||||
|
||||
ip_list=get_ip_address_list().split()
|
||||
if len(ip_list) > 0:
|
||||
ip_ethernet = ip_list[0]
|
||||
ethernet_status = "<span font='%d' color='#FFFFFFFF'> %s</span>" % (self.font_size, ip_ethernet)
|
||||
else:
|
||||
ip_ethernet = get_ip_address('{}0'.format(ETHERNET_PREFIX))
|
||||
if ip_ethernet == "NA":
|
||||
ip_ethernet = get_ip_address('{}1'.format(ETHERNET_PREFIX))
|
||||
if ip_ethernet != "NA":
|
||||
ethernet_status = "<span font='%d' color='#FFFFFFFF'> http://%s:19999</span>" % (self.font_size, ip_ethernet)
|
||||
else:
|
||||
ethernet_status = "<span font='%d' color='#FF0000FF'> No Ethernet connection</span>" % self.font_size
|
||||
self.label_ip_ethernet.set_markup(ethernet_status)
|
||||
|
||||
if self.is_wifi_available():
|
||||
print ("wlan0 is available")
|
||||
ip_wlan0 = get_ip_address(get_wlan_interface_name())
|
||||
|
||||
print("Ip address of Wlan0 are: ", ip_wlan0)
|
||||
if ip_wlan0 == "NA":
|
||||
sleep(1)
|
||||
ip_wlan0 = get_ip_address(get_wlan_interface_name())
|
||||
print("Ip address of Wlan0 are: ", ip_wlan0)
|
||||
if ip_wlan0 == "NA":
|
||||
hotspot_status = "<span font='%d' color='#FF0000FF'> Wifi not started</span>" % self.font_size
|
||||
self.info_grid.remove_row(6)
|
||||
elif ip_wlan0 == WIFI_HOTSPOT_IP:
|
||||
self.get_wifi_config()
|
||||
hotspot_status = "<span font='%d' color='#00AA00FF'> Wifi hotspot started</span>" % self.font_size
|
||||
|
||||
wifi_qrcode_cmd = "WIFI:S:%s;T:WPA;P:%s;;" %(self.wifi_ssid, self.wifi_passwd)
|
||||
print("%s/bin/build_qrcode.sh" % os.path.join(DEMO_PATH,SUBMODULE_PATH), "-o /tmp/qr-code_wifi_access.png", wifi_qrcode_cmd)
|
||||
cmd = ["%s/bin/build_qrcode.sh" % os.path.join(DEMO_PATH,SUBMODULE_PATH), "-o /tmp/qr-code_wifi_access.png", wifi_qrcode_cmd]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
result = proc.stdout.read().decode('utf-8')
|
||||
|
||||
url_qrcode_cmd = "http://%s:19999" % ip_wlan0
|
||||
cmd2 = ["%s/bin/build_qrcode.sh" % os.path.join(DEMO_PATH,SUBMODULE_PATH), "-o /tmp/qr-code_netdata_url.png", url_qrcode_cmd]
|
||||
proc = subprocess.Popen(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
result = proc.stdout.read().decode('utf-8')
|
||||
|
||||
self.wifi_credential = _load_image_wlan_eventBox(self, "/tmp/qr-code_wifi_access.png", "ssid: %s" % self.wifi_ssid, "passwd: %s" % self.wifi_passwd, -1, self.icon_size)
|
||||
self.netdata_url = _load_image_wlan_eventBox(self, "/tmp/qr-code_netdata_url.png", "url: http://%s:19999" % ip_wlan0, "", -1, self.icon_size)
|
||||
self.info_grid.attach(self.wifi_credential, 0, 6, 1, 1)
|
||||
self.info_grid.attach(self.netdata_url, 1, 6, 1, 1)
|
||||
|
||||
self.show_all()
|
||||
else:
|
||||
hotspot_status = "<span font='%d' color='#FF0000FF'>Wifi started but not configured as hotspot</span>" % self.font_size
|
||||
self.info_grid.remove_row(6)
|
||||
|
||||
self.label_ip_wlan0.set_markup("<span font='%d' color='#FFFFFFFF'>NetData over Wifi: http://%s:19999</span>" % (self.font_size, ip_wlan0))
|
||||
self.info_grid.attach(self.label_ip_wlan0, 0, 6, 1, 1)
|
||||
self.show_all()
|
||||
else:
|
||||
print ("wlan0 interface not available")
|
||||
hotspot_status = "<span font='%d' color='#FF0000FF'> Wifi not available on board</span>" % self.font_size
|
||||
|
||||
self.label_hotspot.set_markup(hotspot_status)
|
||||
|
||||
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 : exit")
|
||||
self.destroy()
|
||||
else:
|
||||
#print ("simple click")
|
||||
self.previous_click_time = self.click_time
|
||||
|
||||
def on_switch_activated(self, switch, gparam):
|
||||
if switch.get_active():
|
||||
self.set_random_wifi_config()
|
||||
self.wifi_hotspot_start()
|
||||
else:
|
||||
self.wifi_hotspot_stop()
|
||||
self.refresh_network_page()
|
||||
|
||||
def wifi_hotspot_start(self):
|
||||
print('[DEBUG]: %s/application/netdata/bin/wifi_start.sh' % DEMO_PATH)
|
||||
os.system('%s/application/netdata/bin/wifi_start.sh' % DEMO_PATH)
|
||||
|
||||
|
||||
def wifi_hotspot_stop(self):
|
||||
print('[DEBUG]:%s/application/netdata/bin/wifi_start.sh\"' % DEMO_PATH)
|
||||
os.system('%s/application/netdata/bin/wifi_stop.sh' % DEMO_PATH)
|
||||
|
||||
def create_subdialogwindow(parent):
|
||||
_window = NetdataWebserver(parent)
|
||||
_window.show_all()
|
||||
response = _window.run()
|
||||
_window.destroy()
|
||||
|
||||
|
||||
# -------------------------------------------------
|
||||
# -------------------------------------------------
|
||||
# test submodule
|
||||
class TestUIWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Test Launcher")
|
||||
create_subdialogwindow(self)
|
||||
self.show_all()
|
||||
|
||||
if __name__ == "__main__":
|
||||
win = TestUIWindow()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.show_all()
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
script -qc 'su -c "/usr/local/demo/bin/st-hotspot-wifi-service.sh start"'
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
script -qc 'su -c "/usr/local/demo/bin/st-hotspot-wifi-service.sh stop"'
|
||||
@@ -0,0 +1,38 @@
|
||||
SUMMARY = "Add support of camera preview on Demo Launcher"
|
||||
HOMEPAGE = "wiki.st.com"
|
||||
LICENSE = "BSD-3-Clause"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9"
|
||||
|
||||
DEPENDS = "demo-launcher event-gtk-player wayland-utils"
|
||||
|
||||
PV = "2.0"
|
||||
|
||||
SRC_URI = " \
|
||||
file://Video_playback_logo.png \
|
||||
file://ST2297_visionv3.webm \
|
||||
file://ST19619_ST_Company_Video_16_9_EN_272p.webm \
|
||||
file://launch_video.sh \
|
||||
file://020-video.yaml \
|
||||
"
|
||||
|
||||
do_configure[noexec] = "1"
|
||||
do_compile[noexec] = "1"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${prefix}/local/demo/application/video/bin
|
||||
install -d ${D}${prefix}/local/demo/application/video/pictures
|
||||
install -d ${D}${prefix}/local/demo/media
|
||||
|
||||
# install yaml file
|
||||
install -m 0644 ${WORKDIR}/*.yaml ${D}${prefix}/local/demo/application/
|
||||
# install pictures
|
||||
install -m 0644 ${WORKDIR}/*.png ${D}${prefix}/local/demo/application/video/pictures
|
||||
# script
|
||||
install -m 0755 ${WORKDIR}/*.sh ${D}${prefix}/local/demo/application/video/bin
|
||||
# video
|
||||
install -m 0644 ${WORKDIR}/ST2297_visionv3.webm ${D}${prefix}/local/demo/media
|
||||
install -m 0644 ${WORKDIR}/ST19619_ST_Company_Video_16_9_EN_272p.webm ${D}${prefix}/local/demo/media
|
||||
}
|
||||
|
||||
FILES:${PN} += "${prefix}/local/demo/application/ ${prefix}/local/demo/media"
|
||||
RDEPENDS:${PN} += "demo-launcher event-gtk-player"
|
||||
@@ -0,0 +1,15 @@
|
||||
Application:
|
||||
Name: Video
|
||||
Description: playback
|
||||
Icon: application/video/pictures/Video_playback_logo.png
|
||||
Type: script
|
||||
Board:
|
||||
List: all
|
||||
Script:
|
||||
Start: application/video/bin/launch_video.sh
|
||||
Stop: application/video/bin/stop_video.sh
|
||||
Action:
|
||||
button_release_event: script_start
|
||||
button_press_event: highlight_eventBox
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
function pty_exec() {
|
||||
cmd=$1
|
||||
pty=$(tty > /dev/null 2>&1; echo $?)
|
||||
if [ $pty -eq 0 ]; then
|
||||
cmd=$(echo $cmd | sed "s#\"#'#g")
|
||||
event_cmd=$(echo /usr/local/demo/bin/touch-event-gtk-player -w $SCREEN_WIDTH -h $SCREEN_HEIGHT --graph \"$cmd\")
|
||||
eval $event_cmd > /dev/null 2>&1
|
||||
else
|
||||
# no pty
|
||||
echo "NO PTY"
|
||||
event_cmd=$(echo /usr/local/demo/bin/touch-event-gtk-player -w $SCREEN_WIDTH -h $SCREEN_HEIGHT --graph \"$cmd\")
|
||||
script -qc "$event_cmd" > /dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
# Detect if GPU are present or not
|
||||
gpu_presence=0
|
||||
if [ -f /etc/default/weston ] && $(grep "^OPTARGS" /etc/default/weston | grep -q "use-pixman" ) ;
|
||||
then
|
||||
echo "Without GPU"
|
||||
ADDONS="videoconvert ! video/x-raw,format=BGRx ! queue !"
|
||||
else
|
||||
echo "With GPU"
|
||||
gpu_presence=1
|
||||
ADDONS=""
|
||||
fi
|
||||
|
||||
# Detect size of screen
|
||||
SCREEN_WIDTH=$(wayland-info | grep logical_width | sed -r "s/logical_width: ([0-9]+),.*/\1/")
|
||||
SCREEN_HEIGHT=$(wayland-info | grep logical_width | sed -r "s/.*logical_height: ([0-9]+).*/\1/")
|
||||
|
||||
if [ $gpu_presence -eq 0 ] || [ $SCREEN_HEIGHT -lt 480 ];
|
||||
then
|
||||
VIDEO_FILE=/usr/local/demo/media/ST19619_ST_Company_Video_16_9_EN_272p.webm
|
||||
else
|
||||
VIDEO_FILE=/usr/local/demo/media/ST2297_visionv3.webm
|
||||
fi
|
||||
|
||||
echo "Gstreamer graph:"
|
||||
# WARNING: need to add a space before last ' to avoid that ' are taken by name and not by video-sink
|
||||
GRAPH="playbin3 uri=file://$VIDEO_FILE video-sink='$ADDONS gtkwaylandsink name=gtkwsink '"
|
||||
echo " $GRAPH"
|
||||
|
||||
pty_exec "$GRAPH"
|
||||
@@ -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()
|
||||
@@ -0,0 +1,22 @@
|
||||
SUMMARY = "GTK player with touch screen management"
|
||||
LICENSE = "GPL-2.0-or-later"
|
||||
LIC_FILES_CHKSUM = "file://COPYING;md5=801f80980d171dd6425610833a22dbe6"
|
||||
|
||||
SRC_URI = "git://github.com/STMicroelectronics/st-openstlinux-application.git;protocol=https;branch=main"
|
||||
|
||||
# Modify these as desired
|
||||
PV = "5.0+git${SRCPV}"
|
||||
SRCREV = "7c46618178db254520e017a5686a46b1beb413d0"
|
||||
|
||||
DEPENDS += "gstreamer1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gtk+3"
|
||||
|
||||
inherit meson pkgconfig
|
||||
|
||||
S = "${WORKDIR}/git/touch-event-gtk-player"
|
||||
|
||||
do_install () {
|
||||
install -d ${D}${prefix}/local/demo/bin
|
||||
install -m 0755 ${B}/touch-event-gtk-player ${D}${prefix}/local/demo/bin/
|
||||
}
|
||||
FILES:${PN} += "${prefix}/local/demo/bin"
|
||||
|
||||