diff --git a/packages/addons/service/fd628/changelog.txt b/packages/addons/service/fd628/changelog.txt index 32d81ca428..7e95b5bcd7 100644 --- a/packages/addons/service/fd628/changelog.txt +++ b/packages/addons/service/fd628/changelog.txt @@ -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 diff --git a/packages/addons/service/fd628/package.mk b/packages/addons/service/fd628/package.mk index af4cb2aa95..5b99d7f7f4 100644 --- a/packages/addons/service/fd628/package.mk +++ b/packages/addons/service/fd628/package.mk @@ -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() { diff --git a/packages/addons/service/fd628/sources/addon.xml b/packages/addons/service/fd628/sources/addon.xml index 431312422f..781a99bf3d 100644 --- a/packages/addons/service/fd628/sources/addon.xml +++ b/packages/addons/service/fd628/sources/addon.xml @@ -7,7 +7,7 @@ @@ -19,3 +19,4 @@ + diff --git a/packages/addons/service/fd628/sources/default.py b/packages/addons/service/fd628/sources/default.py deleted file mode 100644 index cefec180a2..0000000000 --- a/packages/addons/service/fd628/sources/default.py +++ /dev/null @@ -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 . -################################################################################ - -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 diff --git a/packages/addons/service/fd628/sources/resources/language/resource.language.en_gb/strings.po b/packages/addons/service/fd628/sources/resources/language/resource.language.en_gb/strings.po new file mode 100644 index 0000000000..2173018e15 --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/language/resource.language.en_gb/strings.po @@ -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 \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 diff --git a/packages/addons/service/fd628/sources/resources/lib/fd628dev.py b/packages/addons/service/fd628/sources/resources/lib/fd628dev.py new file mode 100644 index 0000000000..84bab02c2c --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/lib/fd628dev.py @@ -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 . +################################################################################ + +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 diff --git a/packages/addons/service/fd628/sources/resources/lib/fd628settings.py b/packages/addons/service/fd628/sources/resources/lib/fd628settings.py new file mode 100644 index 0000000000..2acac703b8 --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/lib/fd628settings.py @@ -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 . +################################################################################ + +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) diff --git a/packages/addons/service/fd628/sources/resources/lib/fd628states.py b/packages/addons/service/fd628/sources/resources/lib/fd628states.py new file mode 100644 index 0000000000..991b9e1f9d --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/lib/fd628states.py @@ -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 . +################################################################################ + +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)])] diff --git a/packages/addons/service/fd628/sources/resources/lib/fd628utils.py b/packages/addons/service/fd628/sources/resources/lib/fd628utils.py new file mode 100644 index 0000000000..7124073512 --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/lib/fd628utils.py @@ -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 . +################################################################################ + +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) diff --git a/packages/addons/service/fd628/sources/resources/lib/ioctl.py b/packages/addons/service/fd628/sources/resources/lib/ioctl.py new file mode 100644 index 0000000000..e368e16d35 --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/lib/ioctl.py @@ -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 diff --git a/packages/addons/service/fd628/sources/resources/lib/service.py b/packages/addons/service/fd628/sources/resources/lib/service.py new file mode 100644 index 0000000000..dbddbe8fa9 --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/lib/service.py @@ -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 . +################################################################################ + +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.') diff --git a/packages/addons/service/fd628/sources/resources/settings.xml b/packages/addons/service/fd628/sources/resources/settings.xml new file mode 100644 index 0000000000..614f0e65af --- /dev/null +++ b/packages/addons/service/fd628/sources/resources/settings.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/linux-drivers/amlogic/fd628-aml/package.mk b/packages/linux-drivers/amlogic/fd628-aml/package.mk index 2fc79a56cf..78613826d5 100644 --- a/packages/linux-drivers/amlogic/fd628-aml/package.mk +++ b/packages/linux-drivers/amlogic/fd628-aml/package.mk @@ -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" diff --git a/packages/linux-drivers/amlogic/fd628-aml/system.d/fd628.service b/packages/linux-drivers/amlogic/fd628-aml/system.d/fd628.service index 7f9ecb8fe0..63fbfb29b1 100644 --- a/packages/linux-drivers/amlogic/fd628-aml/system.d/fd628.service +++ b/packages/linux-drivers/amlogic/fd628-aml/system.d/fd628.service @@ -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 +