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
+