Merge pull request #2481 from arthur-liberman/patch-1

Improvements to the service.fd628 add-on
This commit is contained in:
Radostan Riedel 2018-03-20 08:46:14 +01:00 committed by GitHub
commit c8ebf53216
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 867 additions and 113 deletions

View File

@ -1,2 +1,13 @@
110
- Rewrite add-on from scratch
- Add support for APPS, SETUP, CVBS (X92) and POWER (A1 Max) indicators.
- Add a configuration dialog:
* Adjust display brightness.
* Storage access indication.
* Advanced hardware configuration of the display.
- Fix crash if aml_fd628 module is not loaded (led_on, led_off files don't exist)
- Fix disable add-on from Kodi UI.
- Turn off indicators when add-on is disabled.
100
- Initial add-on

View File

@ -17,7 +17,7 @@
################################################################################
PKG_NAME="fd628"
PKG_VERSION="1.0"
PKG_VERSION="1.1"
PKG_REV="100"
PKG_ARCH="any"
PKG_LICENSE="GPL"
@ -31,7 +31,7 @@ PKG_TOOLCHAIN="manual"
PKG_IS_ADDON="yes"
PKG_ADDON_NAME="service.fd628"
PKG_ADDON_PROJECTS="S905"
PKG_ADDON_PROJECTS="S905 S912"
PKG_ADDON_TYPE="xbmc.service"
make_target() {

View File

@ -7,7 +7,7 @@
<import addon="xbmc.python" version="2.1.0"/>
</requires>
<extension point="xbmc.service"
library="default.py"
library="resources/lib/service.py"
start="startup">
</extension>
<extension point="xbmc.addon.metadata">
@ -19,3 +19,4 @@
</assets>
</extension>
</addon>

View File

@ -1,104 +0,0 @@
################################################################################
# This file is part of LibreELEC - https://libreelec.tv
# Copyright (C) 2018-present Team LibreELEC
#
# LibreELEC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import datetime
import xbmcgui
import xbmcaddon
import threading
import time
import sys
import os
import subprocess
addon = xbmcaddon.Addon(id='service.fd628')
class clockThreadClass(threading.Thread):
def run(self):
self.shutdown = False
while not self.shutdown:
vfdon = '/sys/class/leds/fd628_dev/led_on'
vfdoff = '/sys/class/leds/fd628_dev/led_off'
ledon = []
ledoff = []
play = pause = lanstate = lan = wifistate = wifi = ""
sd_state = sd = usb_state = usb = ''
play = xbmc.getCondVisibility('Player.Playing')
pause = xbmc.getCondVisibility('Player.Paused')
if ( os.path.isfile('/sys/class/amhdmitx/amhdmitx0/hpd_state')):
hpd_state = file('/sys/class/amhdmitx/amhdmitx0/hpd_state', "rb")
hpdstate = hpd_state.read()
p = subprocess.Popen('blkid /dev/sd*', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
usb_state += line
retval = p.wait()
p = subprocess.Popen('blkid /dev/mmcblk* | grep " UUID"', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
sd_state += line
retval = p.wait()
if ( os.path.isfile('/sys/class/net/eth0/operstate')):
lanstate = file('/sys/class/net/eth0/operstate', 'rb')
lan = lanstate.read()
if ( os.path.isfile('/sys/class/net/wlan0/operstate')):
wifistate = file('/sys/class/net/wlan0/operstate', 'rb')
wifi = wifistate.read()
if len(usb_state) > 0 :
ledon.append('usb')
else:
ledoff.append('usb')
if len(sd_state) > 0 :
ledon.append('sd')
else:
ledoff.append('sd')
if (hpdstate == '1'):
ledon.append('hdmi')
else:
ledoff.append('hdmi')
if (lan.find('up')>=0 or lan.find('unknown')>=0):
ledon.append('eth')
else:
ledoff.append('eth')
if (wifi.find('up')>=0):
ledon.append('wifi')
else:
ledoff.append('wifi')
if pause == True:
ledon.append('pause')
else:
ledoff.append('pause')
if play == True:
ledon.append('play')
else:
ledoff.append('play')
for i in ledon:
vfd = file(vfdon, "wb")
vfd.write(i)
vfd.flush()
for j in ledoff:
vfd = file(vfdoff, "wb")
vfd.write(j)
vfd.flush()
time.sleep(0.5)
class ClockDialog:
def __init__(self):
self.clockThread = clockThreadClass()
self.clockThread.start()
dialog = ClockDialog()
del dialog
del addon

View File

@ -0,0 +1,136 @@
# Kodi Media Center language file
# Addon Name: FD628 Display
# Addon id: service.fd628
# Addon Provider: Team LibreELEC
msgid ""
msgstr ""
"Project-Id-Version: XBMC-Addons\n"
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
"POT-Creation-Date: 2018-02-12 17:48+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en_GB\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
# Kodi Settings
msgctxt "#30000"
msgid "General"
msgstr ""
msgctxt "#30001"
msgid "Turn on display"
msgstr ""
msgctxt "#30002"
msgid "Display brightness"
msgstr ""
msgctxt "#30003"
msgid "Advanced settings"
msgstr ""
msgctxt "#30004"
msgid "Display type"
msgstr ""
msgctxt "#30026"
msgid "Common anode display (transposed ram)"
msgstr ""
msgctxt "#30013"
msgid "Enable storage access (RW) indicator"
msgstr ""
msgctxt "#30014"
msgid "Select which icon is to be used as the access indicator"
msgstr ""
msgctxt "#30028"
msgid "Clock colon (:) always on"
msgstr ""
msgctxt "#30015"
msgid "play"
msgstr ""
msgctxt "#30016"
msgid "pause"
msgstr ""
msgctxt "#30017"
msgid "hdmi"
msgstr ""
msgctxt "#30018"
msgid "cvbs"
msgstr ""
msgctxt "#30019"
msgid "eth"
msgstr ""
msgctxt "#30020"
msgid "wifi"
msgstr ""
msgctxt "#30021"
msgid "setup"
msgstr ""
msgctxt "#30022"
msgid "apps"
msgstr ""
msgctxt "#30023"
msgid "usb"
msgstr ""
msgctxt "#30024"
msgid "sd"
msgstr ""
msgctxt "#30025"
msgid "alarm"
msgstr ""
msgctxt "#30027"
msgid "power"
msgstr ""
msgctxt "#30012"
msgid "Reorder character indexes"
msgstr ""
msgctxt "#30005"
msgid "Index 0"
msgstr ""
msgctxt "#30006"
msgid "Index 1"
msgstr ""
msgctxt "#30007"
msgid "Index 2"
msgstr ""
msgctxt "#30008"
msgid "Index 3"
msgstr ""
msgctxt "#30009"
msgid "Index 4"
msgstr ""
msgctxt "#30010"
msgid "Index 5"
msgstr ""
msgctxt "#30011"
msgid "Index 6"
msgstr ""
# Max index 30028

View File

@ -0,0 +1,93 @@
################################################################################
# This file is part of LibreELEC - https://libreelec.tv
# Copyright (C) 2018-present Team LibreELEC
#
# LibreELEC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import os
import struct
from fd628utils import *
_led_cmd = '/sys/class/leds/fd628_dev/led_cmd'
class fd628Dev:
def __init__(self):
import ioctl
import ctypes
size = ctypes.sizeof(ctypes.c_int(0))
self._FD628_IOC_MAGIC = ord('M')
self._FD628_IOC_SMODE = ioctl.IOW(self._FD628_IOC_MAGIC, 1, size)
self._FD628_IOC_GMODE = ioctl.IOR(self._FD628_IOC_MAGIC, 2, size)
self._FD628_IOC_SBRIGHT = ioctl.IOW(self._FD628_IOC_MAGIC, 3, size)
self._FD628_IOC_GBRIGHT = ioctl.IOR(self._FD628_IOC_MAGIC, 4, size)
self._FD628_IOC_POWER = ioctl.IOW(self._FD628_IOC_MAGIC, 5, size)
self._FD628_IOC_GVER = ioctl.IOR(self._FD628_IOC_MAGIC, 6, size)
self._FD628_IOC_STATUS_LED = ioctl.IOW(self._FD628_IOC_MAGIC, 7, size)
self._FD628_IOC_GDISPLAY_TYPE = ioctl.IOR(self._FD628_IOC_MAGIC, 8, size)
self._FD628_IOC_SDISPLAY_TYPE = ioctl.IOW(self._FD628_IOC_MAGIC, 9, size)
self._FD628_IOC_SCHARS_ORDER = ioctl.IOW(self._FD628_IOC_MAGIC, 10, 7)
self._FD628_IOC_USE_DTB_CONFIG = ioctl.IOW(self._FD628_IOC_MAGIC, 11, size)
self._FD628_IOC_MAXNR = 12
def enableDisplay(self, value):
self.__writeFD628(self._FD628_IOC_POWER, int(value))
def getBrightness(self):
return self.__readFD628(self._FD628_IOC_GBRIGHT)
def setBrightness(self, value):
self.__writeFD628(self._FD628_IOC_SBRIGHT, value)
def getDisplayType(self):
return self.__readFD628(self._FD628_IOC_GDISPLAY_TYPE)
def setDisplayType(self, value):
self.__writeFD628(self._FD628_IOC_SDISPLAY_TYPE, value)
def setCharacterOrder(self, value):
pack = struct.pack('BBBBBBB', value[0], value[1], value[2], value[3], value[4], value[5], value[6])
self.__writeFD628(self._FD628_IOC_SCHARS_ORDER, pack, True)
def useDtbConfig(self):
self.__writeFD628(self._FD628_IOC_USE_DTB_CONFIG, 0)
def __readFD628(self, cmd, isBuf = False):
import ioctl
ret = None
if (ioctl.DIR(cmd) == ioctl.READ and self.__writeFD628(cmd, 0)):
with open(_led_cmd, "rb") as vfd:
ret = vfd.read()
if (ret == ''):
ret = None
if (not isBuf and ret != None):
ret = int(ret, 0)
kodiLog('fd628Dev.__readFD628: value = {0}'.format(str(ret)))
return ret
def __writeFD628(self, cmd, value, isBuf = False):
ret = False
if (os.path.isfile(_led_cmd)):
if isBuf:
value = ''.join([struct.pack('I', cmd), value])
else:
value = struct.pack('Ii', cmd, value)
kodiLog('fd628Dev.__writeFD628: value = {0}'.format(repr(value)))
try:
with open(_led_cmd, "wb") as vfd:
vfd.write(value)
ret = True
except Exception as inst:
kodiLogError(inst)
return ret

View File

@ -0,0 +1,110 @@
################################################################################
# This file is part of LibreELEC - https://libreelec.tv
# Copyright (C) 2018-present Team LibreELEC
#
# LibreELEC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import xbmcaddon
addon = xbmcaddon.Addon(id='service.fd628')
def getSetting(id):
return addon.getSetting(id)
def getSettingBool(id):
value = getSetting(id).lower()
if (value == 'true'):
value = True
else:
value = False
return value
def getSettingInt(id):
return int(getSetting(id))
def getSettingNumber(id):
return float(getSetting(id))
class fd628Settings:
def __init__(self):
self.readValues()
def isDisplayOn(self):
return self._displayOn
def isAdvancedSettings(self):
return self._displayAdvanced
def getBrightness(self):
return self._displayBrightness
def getDisplayType(self):
return self._displayType
def isCommonAnode(self):
return self._commonAnode
def getDisplay(self):
value = self.getDisplayType()
if (self.isCommonAnode()):
value = value + (1 << 16)
return value
def getCharacterIndex(self, i):
return self._characterIndexes[i]
def getCharacterIndexes(self):
return self._characterIndexes
def isStorageIndicator(self):
return self._storageIndicator
def getStorageIndicatorIcon(self):
return self._storageIndicatorIcon
def isColonOn(self):
return self._colonOn
def readValues(self):
self._displayAdvanced = False
self._displayOn = getSettingBool('display.on')
if (self._displayOn):
self._displayBrightness = getSettingInt('display.brightness')
self._storageIndicator = getSettingBool('display.storage.indicator')
self._storageIndicatorIcon = getSetting('display.storage.indicator.icon')
self._colonOn = getSettingBool('display.colon.on')
self._displayAdvanced = getSettingBool('display.advanced')
if (self._displayAdvanced):
self._displayType = getSettingInt('display.type')
self._commonAnode = getSettingBool('display.common.anode')
self._characterIndexes = []
for i in range(7):
self._characterIndexes.append(getSettingInt('display.char.index{0}'.format(i)))
else:
self.__initDefaultValues()
else:
self.__initDefaultValues()
def __initDefaultValues(self):
if not (self._displayOn):
self._displayBrightness = 7
self._storageIndicator = False
self._storageIndicatorIcon = ''
self._colonOn = False
self._displayAdvanced = False
if not (self._displayAdvanced):
self._displayType = 0
self._commonAnode = False
self._characterIndexes = range(0, 7)

View File

@ -0,0 +1,202 @@
################################################################################
# This file is part of LibreELEC - https://libreelec.tv
# Copyright (C) 2018-present Team LibreELEC
#
# LibreELEC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import xbmc
import os
from fd628utils import *
class fd628State(object):
def __init__(self, ledName):
self._value = False
self._hasChanged = False
self._ledName = ledName
def _getStr(self, className):
return '{0} ({1})'.format(className, self._ledName)
def update(self):
raise NotImplementedError
def getValue(self):
return self._value
def hasChanged(self):
return self._hasChanged
def getLedName(self):
return self._ledName
def _update(self, value):
if (value != self._value):
self._hasChanged = True
self._value = value
else:
self._hasChanged = False
class fd628IconIndicator(fd628State):
def __init__(self, on, ledName):
super(fd628IconIndicator, self).__init__(ledName)
self._on = on
def __str__(self):
return self._getStr('fd628IconIndicator')
def turnOn(self):
self._on = True
def turnOff(self):
self._on = False
def toggle(self):
self._on = not self._on
def update(self):
self._update(self._on)
class fd628CondVisibility(fd628State):
def __init__(self, ledName, cmd):
super(fd628CondVisibility, self).__init__(ledName)
self._cmd = cmd
def __str__(self):
return self._getStr('fd628CondVisibility')
def update(self):
value = xbmc.getCondVisibility(self._cmd)
self._update(value)
class fd628FileContains(fd628State):
def __init__(self, ledName, path, strings):
super(fd628FileContains, self).__init__(ledName)
self._path = path
self._strings = strings
def __str__(self):
return self._getStr('fd628FileContains')
def update(self):
if (os.path.isfile(self._path)):
with open(self._path, 'rb') as state:
content = state.read()
value = self.__checkContent(content)
self._update(value)
else:
self._update(False)
def __checkContent(self, content):
ret = False
for s in self._strings:
if (s in content):
ret = True
break
return ret
class fd628WindowChecker(fd628State):
def __init__(self, ledName, windows):
super(fd628WindowChecker, self).__init__(ledName)
self._windows = windows
def __str__(self):
return self._getStr('fd628WindowChecker')
def update(self):
value = False
for id in self._windows:
if (xbmc.getCondVisibility('Window.IsVisible({0})'.format(id))):
value = True
break
self._update(value)
class fd628ExtStorageChecker(fd628State):
def __init__(self, ledName, path):
super(fd628ExtStorageChecker, self).__init__(ledName)
self._path = path
def __str__(self):
return self._getStr('fd628ExtStorageChecker')
def update(self):
value = False
for folder, subs, files in os.walk('/dev/disk/by-uuid'):
for filename in files:
path = os.path.realpath(os.path.join(folder, filename))
if (path.startswith(self._path)):
value = True
break
self._update(value)
class fd628ExtStorageCount(fd628State):
def __init__(self, ledName, drives, type):
super(fd628ExtStorageCount, self).__init__(ledName)
if (drives == None): # Monitor all drives
self._drives = None
drives = self.__getAllDrives()
else: # Monitor listed drives
self._drives = drives
drives = self.__getSelectedDrives()
self._driveStats = {key: self.__readStatus(key) for key in drives}
kodiLogNotice('fd628ExtStorageCount.__init__: Drive stats ' + str(self._driveStats))
self._read = False
self._write = False
if (type == 'r'):
self._read = True
elif (type == 'w'):
self._write = True
elif (type == 'rw'):
self._read = True
self._write = True
else:
raise Exception('\'type\' must be \'r\', \'w\' or \'rw\'.')
def update(self):
value = False
if (self._drives == None):
drives = self.__getAllDrives()
else:
drives = self.__getSelectedDrives()
for drive in drives:
if (not drive in self._driveStats):
self._driveStats[drive] = None
kodiLogNotice('fd628ExtStorageCount.update: New drive found \'{0}\''.format(drive))
for path, stats in self._driveStats.iteritems():
newStats = self.__readStatus(path)
if (stats != None and newStats != None):
if (self._read):
value = value or stats[0] != newStats[0]
if (self._write):
value = value or stats[1] != newStats[1]
self._driveStats[path] = newStats
self._update(value)
def __readStatus(self, path):
path = os.path.join('/sys/block', path, 'stat')
if (os.path.isfile(path)):
with open(path, 'rb') as status:
values = status.read().split()
return (values[2], values[6])
else:
return None
def __getAllDrives(self):
drives = []
for folder, subs, files in os.walk('/sys/block'):
drives = [sub for sub in subs if (not sub.startswith('loop'))]
return drives
def __getSelectedDrives(self):
return [drive for drive in self.__getAllDrives() if ([d for d in self._drives if drive.startswith(d)])]

View File

@ -0,0 +1,34 @@
################################################################################
# This file is part of LibreELEC - https://libreelec.tv
# Copyright (C) 2018-present Team LibreELEC
#
# LibreELEC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import xbmc
import xbmcaddon
addonName = xbmcaddon.Addon(id='service.fd628').getAddonInfo('name')
def kodiLog(message, level = xbmc.LOGDEBUG):
xbmc.log('{0} -> {1}'.format(addonName, str(message)), level)
def kodiLogError(message):
kodiLog(message, xbmc.LOGERROR)
def kodiLogWarning(message):
kodiLog(message, xbmc.LOGWARNING)
def kodiLogNotice(message):
kodiLog(message, xbmc.LOGNOTICE)

View File

@ -0,0 +1,89 @@
#!/usr/bin/python
"""
Author: SpliFF
License: Public Domain
Python ioctl constants and functions module
Mostly follows specifications in asm-generic/ioctl.h from linux 2.5.36
Notable differences:
* no architecture dependant stuff
* size parameters are all passed as bytes, not types (ie pass 4, not int)
!! WARNING EXPERIMENTAL SOFTWARE !!
Make sure the values returned by these functions are properly tested before using fcntl on anything remotely valuable!
"""
NRBITS = 8
TYPEBITS = 8
# may be arch dependent
SIZEBITS = 14
DIRBITS = 2
NRMASK = (1 << NRBITS) - 1
TYPEMASK = (1 << TYPEBITS) - 1
SIZEMASK = (1 << SIZEBITS) - 1
DIRMASK = (1 << DIRBITS) - 1
NRSHIFT = 0
TYPESHIFT = NRSHIFT + NRBITS
SIZESHIFT = TYPESHIFT + TYPEBITS
DIRSHIFT = SIZESHIFT + SIZEBITS
# may be arch dependent
NONE = 0x0
WRITE = 0x1
READ = 0x2
# for the drivers/sound files...
IN = WRITE << DIRSHIFT
OUT = READ << DIRSHIFT
INOUT = (WRITE | READ) << DIRSHIFT
IOCSIZE_MASK = SIZEMASK << SIZESHIFT
IOCSIZE_SHIFT = SIZESHIFT
# used to create numbers ...
def IO( _type, nr):
return IOC(NONE, _type, nr, 0)
def IOC(direction, _type, nr, size):
return (direction << DIRSHIFT) | (_type << TYPESHIFT) | (nr << NRSHIFT) | (size << SIZESHIFT)
def IOR( _type, nr, size):
return IOC(READ, _type, nr, size)
def IOW(_type, nr, size):
return IOC(WRITE, _type, nr, size)
def IOWR(_type, nr, size):
return IOC(READ|WRITE, _type, nr, size)
def IOR_BAD(_type, nr, size):
return IOC(READ, _type, nr, size)
def IOW_BAD(_type, nr, size):
return IOC(WRITE, _type, nr, size)
def IOWR_BAD(_type, nr, size):
return IOC(READ|WRITE, _type, nr, size)
# used to decode ioctl numbers..
def DIR(nr):
return (nr >> DIRSHIFT) & DIRMASK
def TYPE(nr):
return (nr >> TYPESHIFT) & TYPEMASK
def NR(nr):
return (nr >> NRSHIFT) & NRMASK
def SIZE(nr):
return (nr >> SIZESHIFT) & SIZEMASK

View File

@ -0,0 +1,158 @@
################################################################################
# This file is part of LibreELEC - https://libreelec.tv
# Copyright (C) 2018-present Team LibreELEC
#
# LibreELEC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import xbmcaddon
import threading
import os
import fd628states
import fd628dev
import fd628settings
from fd628utils import *
addon = xbmcaddon.Addon(id='service.fd628')
class fd628Monitor(xbmc.Monitor):
def __init__(self):
super(fd628Monitor, self).__init__()
self._settingsChangedCallback = None
def setSettingsChangedCallback(self, callbackObject):
self._settingsChangedCallback = callbackObject
def onSettingsChanged(self):
kodiLog('Enter fd628Monitor.onSettingsChanged')
if (self._settingsChangedCallback != None):
self._settingsChangedCallback.onSettingsChanged()
class fd628Addon():
def __init__(self, monitor):
self._fd628 = fd628dev.fd628Dev()
self._states = []
self._monitor = monitor
self._monitor.setSettingsChangedCallback(self)
self._settings = fd628settings.fd628Settings()
self._vfdon = '/sys/class/leds/fd628_dev/led_on'
self._vfdoff = '/sys/class/leds/fd628_dev/led_off'
self._rlock = threading.RLock()
def run(self):
firstLoop = True
while not self._monitor.abortRequested():
if self._monitor.waitForAbort(0.5):
break
if (not os.path.isfile(self._vfdon) or not os.path.isfile(self._vfdoff)):
firstLoop = True
continue
if (firstLoop):
self.onSettingsChanged()
firstLoop = False
self.__updateIndicators()
self.__cleanUp()
def __updateIndicators(self):
ledon = []
ledoff = []
if (self._rlock.acquire()):
for state in self._states:
state.update()
if (state.hasChanged()):
if (state.getValue()):
ledon.append(state.getLedName())
else:
ledoff.append(state.getLedName())
self.__writeFile(self._vfdon, ledon)
self.__writeFile(self._vfdoff, ledoff)
self._rlock.release()
def __cleanUp(self):
self.__turnOffIndicators()
self._monitor = None
def __turnOffIndicators(self):
if (self._rlock.acquire()):
ledoff = [state.getLedName() for state in self._states]
self.__writeFile(self._vfdoff, ledoff)
self._rlock.release()
def __writeFile(self, path, values):
if (os.path.isfile(path)):
with open(path, "wb") as vfd:
for j in values:
vfd.write(j)
vfd.flush()
def onSettingsChanged(self):
kodiLog('Enter fd628Addon.onSettingsChanged')
self._settings.readValues()
if (self._rlock.acquire()):
self.__createStates()
self._fd628.enableDisplay(self._settings.isDisplayOn())
if (self._settings.isDisplayOn()):
self._fd628.setBrightness(self._settings.getBrightness())
if (self._settings.isAdvancedSettings()):
self._fd628.setDisplayType(self._settings.getDisplay())
self._fd628.setCharacterOrder(self._settings.getCharacterIndexes())
else:
self._fd628.useDtbConfig()
if (self._colonIcon != None and self._settings.isColonOn()):
self._colonIcon.turnOn()
self.__updateIndicators()
self._rlock.release()
kodiLog('isDisplayOn = {0}'.format(self._settings.isDisplayOn()))
kodiLog('getBrightness = {0}'.format(self._settings.getBrightness()))
kodiLog('isAdvancedSettings = {0}'.format(self._settings.isAdvancedSettings()))
kodiLog('getDisplayType = {0}'.format(self._settings.getDisplayType()))
kodiLog('isCommonAnode = {0}'.format(self._settings.isCommonAnode()))
kodiLog('getCharacterIndexex = {0}'.format(self._settings.getCharacterIndexes()))
def __createStates(self):
settingsWindows = ['settings', 'systeminfo', 'systemsettings', 'servicesettings', 'pvrsettings', \
'playersettings', 'mediasettings', 'interfacesettings', 'profiles', 'skinsettings', 'videossettings', \
'musicsettings', 'appearancesettings', 'picturessettings', 'weathersettings', 'gamesettings', \
'service-LibreELEC-Settings-mainWindow.xml', 'service-LibreELEC-Settings-wizard.xml', \
'service-LibreELEC-Settings-getPasskey.xml']
appsWindows = ['addonbrowser', 'addonsettings', 'addoninformation', 'addon', 'programs']
states = []
states.append(fd628states.fd628IconIndicator(True, 'power'))
states.append(fd628states.fd628CondVisibility('play', 'Player.Playing'))
states.append(fd628states.fd628CondVisibility('pause', 'Player.Paused'))
states.append(fd628states.fd628FileContains('hdmi', '/sys/class/amhdmitx/amhdmitx0/hpd_state', ['1']))
states.append(fd628states.fd628FileContains('cvbs', '/sys/class/display/mode', ['cvbs']))
states.append(fd628states.fd628FileContains('eth', '/sys/class/net/eth0/operstate', ['up', 'unknown']))
states.append(fd628states.fd628FileContains('wifi', '/sys/class/net/wlan0/operstate', ['up']))
states.append(fd628states.fd628WindowChecker('setup', settingsWindows))
states.append(fd628states.fd628WindowChecker('apps', appsWindows))
states.append(fd628states.fd628ExtStorageChecker('usb', '/dev/sd'))
states.append(fd628states.fd628ExtStorageChecker('sd', '/dev/mmcblk'))
self._colonIcon = fd628states.fd628IconIndicator(False, 'colon')
states.append(self._colonIcon)
if (self._settings.isStorageIndicator()):
for state in states:
if (state.getLedName() == self._settings.getStorageIndicatorIcon()):
states.remove(state)
break
states.append(fd628states.fd628ExtStorageCount(self._settings.getStorageIndicatorIcon(), None, 'rw'))
kodiLog('Active states: ' + str([str(state) for state in states]))
self.__turnOffIndicators()
self._states = states
monitor = fd628Monitor()
fd628 = fd628Addon(monitor)
kodiLog('Service start.')
fd628.run()
kodiLog('Service stop.')

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>
<category label="30000">
<setting label="30001" type="bool" id="display.on" default="true" />
<setting label="30002" type="slider" id="display.brightness" default="7" range="0,7" option="int" visible="eq(-1,true)" />
<setting label="30013" type="bool" id="display.storage.indicator" default="false" visible="eq(-2,true)" />
<setting label="30014" type="labelenum" id="display.storage.indicator.icon" lvalues="30025|30015|30016|30017|30018|30019|30020|30021|30022|30023|30024|30027" default="30025" visible="eq(-3,true) + eq(-1,true)" subsetting="true" />
<setting label="30028" type="bool" id="display.colon.on" default="false" visible="eq(-4,true)" />
<setting label="30003" type="bool" id="display.advanced" default="false" visible="eq(-5,true)" />
<setting label="30004" type="enum" id="display.type" values="0|1|2|3|4|5|6" default="1" visible="eq(-6,true) + eq(-1,true)" subsetting="true" />
<setting label="30026" type="bool" id="display.common.anode" default="false" visible="eq(-7,true) + eq(-2,true)" subsetting="true" />
<setting type="lsep" label="30012" visible="eq(-8,true) + eq(-3,true)" />
<setting label="30005" type="enum" id="display.char.index0" values="0|1|2|3|4|5|6" default="0" visible="eq(-9 ,true) + eq(-4,true)" subsetting="true" />
<setting label="30006" type="enum" id="display.char.index1" values="0|1|2|3|4|5|6" default="1" visible="eq(-10,true) + eq(-5,true)" subsetting="true" />
<setting label="30007" type="enum" id="display.char.index2" values="0|1|2|3|4|5|6" default="2" visible="eq(-11,true) + eq(-6,true)" subsetting="true" />
<setting label="30008" type="enum" id="display.char.index3" values="0|1|2|3|4|5|6" default="3" visible="eq(-12,true) + eq(-7,true)" subsetting="true" />
<setting label="30009" type="enum" id="display.char.index4" values="0|1|2|3|4|5|6" default="4" visible="eq(-13,true) + eq(-8,true)" subsetting="true" />
<setting label="30010" type="enum" id="display.char.index5" values="0|1|2|3|4|5|6" default="5" visible="false" subsetting="true" />
<setting label="30011" type="enum" id="display.char.index6" values="0|1|2|3|4|5|6" default="6" visible="false" subsetting="true" />
</category>
</settings>

View File

@ -17,11 +17,11 @@
################################################################################
PKG_NAME="fd628-aml"
PKG_VERSION="6993a86"
PKG_SHA256="5eb30d485d23c9be427528b3604d564565194f759281677c2b1b66419e6edc15"
PKG_VERSION="4c4cc6e"
PKG_SHA256="c52780595c1e72cbe153011a54f6f3b946e9c77d5e13f4dd48ad70cce7905a43"
PKG_ARCH="arm aarch64"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/tanixbox/tx3mini_linux_fd628"
PKG_SITE="https://github.com/arthur-liberman/linux_fd628"
PKG_URL="https://github.com/arthur-liberman/linux_fd628/archive/$PKG_VERSION.tar.gz"
PKG_SOURCE_DIR="linux_fd628-$PKG_VERSION*"
PKG_DEPENDS_TARGET="toolchain linux"

View File

@ -1,12 +1,15 @@
[Unit]
Description=Amlogic FD628 Service
ConditionPathExists=/proc/device-tree/fd628_dev
ConditionPathExists=/proc/device-tree/le-vfd/
ConditionPathExists=/storage/.config/vfd.conf
[Service]
Type=oneshot
ExecStart=/usr/sbin/modprobe aml_fd628
ExecStart=/usr/sbin/FD628Service
EnvironmentFile=/storage/.config/vfd.conf
ExecStart=/bin/sh -c '[ `cat /proc/device-tree/le-vfd/compatible` = "le,vfd" ] && /sbin/modprobe aml_fd628 vfd_gpio_clk=${vfd_gpio_clk} vfd_gpio_dat=${vfd_gpio_dat} vfd_gpio_stb=${vfd_gpio_stb} vfd_chars=${vfd_chars} vfd_dot_bits=${vfd_dot_bits} vfd_display_type=${vfd_display_type}
ExecStart=/bin/sh -c '[ `cat /proc/device-tree/le-vfd/compatible` = "le,vfd" ] && /usr/sbin/FD628Service
RemainAfterExit=yes
[Install]
WantedBy=basic.target