added my Recipes

This commit is contained in:
2024-07-11 14:16:35 +02:00
parent 38bc4f53ac
commit 09b621d929
7118 changed files with 525762 additions and 3 deletions

View File

@@ -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 "

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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__ */

View File

@@ -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

View File

@@ -0,0 +1,2 @@
#!/bin/sh
script -qc "/usr/local/demo/bin/ai_char_reco_launcher /usr/local/demo/bin/apps_launcher_example.sh"

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,17 @@
Application:
Name: 3D Cam
Description: GPU &amp; 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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
#!/bin/sh
/usr/local/demo/bin/weston-st-egl-cube-tex -f

View File

@@ -0,0 +1,4 @@
#!/bin/sh
/usr/local/demo/bin/weston-st-egl-cube-tex -f -a

View File

@@ -0,0 +1,4 @@
#!/bin/sh
/usr/local/demo/bin/weston-st-egl-cube-tex --video=/usr/local/demo/media/ST2297_visionv3.webm -f

View File

@@ -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

View File

@@ -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/"

View File

@@ -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

View File

@@ -0,0 +1 @@
#print('Importing bluetooth __init__')

View File

@@ -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 = ["", "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()

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -0,0 +1,4 @@
#!/bin/sh
#killall gst-launch-1.0
killall touch-event-gtk-player

View File

@@ -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/"

View File

@@ -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

View File

@@ -0,0 +1,2 @@
#!/bin/sh
/usr/bin/qrencode -s 30 $1 $2 -m 1

View File

@@ -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

View File

@@ -0,0 +1,2 @@
#!/bin/sh -
/sbin/ip link show wlan0 | head -n 1 | awk '{print $2}' | tr '\n' ' ' | sed "s/: //"

View File

@@ -0,0 +1,2 @@
HOSTAPD_SSID=STDemoNetwork
HOSTAPD_PASSWD=stm32mp1

View File

@@ -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()

View File

@@ -0,0 +1,3 @@
#!/bin/sh
script -qc 'su -c "/usr/local/demo/bin/st-hotspot-wifi-service.sh start"'

View File

@@ -0,0 +1,3 @@
#!/bin/sh
script -qc 'su -c "/usr/local/demo/bin/st-hotspot-wifi-service.sh stop"'

View File

@@ -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"

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -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"

View File

@@ -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 "

View File

@@ -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&#174; Cortex&#174;-A7</span>

View File

@@ -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&#174; Cortex&#174;-A7</span>|<span font='10' color='#FFFFFFFF'>+</span>|<span font='10' color='#FFFFFFFF'>Copro Arm&#174; Cortex&#174;-M4</span>

View 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)

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -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

View 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"

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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 "

View File

@@ -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.

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View 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()

View 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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"

Some files were not shown because too many files have changed in this diff Show More