├── .github ├── FUNDING.yml └── stale.yml ├── LICENSE ├── README.md ├── create_detect_radio_module.sh ├── create_devicetree_armbian.sh ├── create_hb-rf-eth.sh ├── create_modules_dkms.sh ├── create_modules_raspberrypi.sh ├── create_pivccu3.sh ├── create_wait_sysfs_notify.sh ├── detect_radio_module ├── Makefile ├── hmframe.cpp ├── hmframe.h ├── main.cpp ├── radiomoduleconnector.cpp ├── radiomoduleconnector.h ├── radiomoduledetector.cpp ├── radiomoduledetector.h ├── radiomoduledetector_utils.h ├── streamparser.cpp └── streamparser.h ├── docs └── setup │ ├── armbian.md │ ├── otheros.md │ ├── raspberrypi.md │ └── wlan.md ├── dts ├── armbian │ ├── detect_board.inc │ ├── patch_dts.sh │ └── revert_dts.sh ├── lepotato.dts.include ├── nanopct4.dts.include ├── nanopim4.dts.include ├── odroidc2.dts.include ├── odroidc4.dts.include ├── pivccu-bananapi-m1.dts ├── pivccu-bananapi-pro.dts ├── pivccu-orangepi-h2plus.dts ├── pivccu-orangepi-h3.dts ├── pivccu-orangepi-h5.dts ├── pivccu-raspberrypi.dts ├── rock64.dts.include ├── rockpi4.dts.include ├── rockpro64.dts.include └── tinkerboard.dts.include ├── kernel ├── Makefile ├── devkey.inc ├── dummy_rx8130.c ├── dw_apb_raw_uart.c ├── eq3_char_loop.c ├── fake_hmrf.c ├── generic_raw_uart.c ├── generic_raw_uart.h ├── hb_rf_eth.c ├── hb_rf_usb.c ├── hb_rf_usb_2.c ├── hm.h ├── led_trigger_timer.c ├── meson_raw_uart.c ├── pl011_raw_uart.c ├── plat_eq3ccu2.c ├── rpi_rf_mod_led.c ├── rtc-rx8130.c └── stack_protector.include ├── package ├── detect-radio-module │ └── control ├── hb-rf-eth │ ├── conffiles │ ├── control │ ├── postinst │ ├── postrm │ ├── preinst │ ├── prerm │ └── templates ├── pivccu-devicetree-armbian │ ├── control │ ├── postinst │ ├── prerm │ └── templates ├── pivccu-modules-dkms │ ├── conffiles │ ├── control │ ├── postinst │ ├── postrm │ ├── prerm │ └── templates ├── pivccu-modules-raspberrypi │ ├── control │ ├── postinst │ ├── postrm │ ├── preinst │ ├── prerm │ └── templates ├── pivccu3 │ ├── conffiles │ ├── control │ ├── postinst │ ├── postrm │ ├── preinst │ ├── prerm │ └── templates └── wait-sysfs-notify │ └── control ├── pivccu ├── container3 │ ├── save-rega.tcl │ ├── set_hb_rf_eth_connection_dp.tcl │ ├── start-hook.sh │ └── wait_sysvar_creation.tcl ├── dkms │ ├── ensure_modules.sh │ └── pivccu-dkms.service ├── firmware3.patch ├── host3 │ ├── 99-pivccu.rules │ ├── default.config │ ├── detect_hardware.inc │ ├── lxc.config │ ├── monitor-hb-rf-eth.service │ ├── monitor_hb_rf_connection.sh │ ├── pivccu-attach.sh │ ├── pivccu-backup.sh │ ├── pivccu-info.sh │ ├── pivccu-startupfinished.service │ ├── pivccu.service │ ├── start_container.sh │ ├── stop_container.sh │ ├── wait_for_startup.sh │ └── wait_network_up.sh ├── rpi-modules │ ├── ensure_headers.sh │ └── pivccu-rpi-modules.service └── rtc │ ├── 40-rpi-rf-mod.rules │ ├── rpi-rf-mod_systohc.service │ └── rpi-rf-mod_systohc.timer └── wait_sysfs_notify ├── Makefile └── main.cpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: alexreinert 2 | ko_fi: alexreinert 3 | custom: ['https://www.amazon.de/gp/registry/wishlist/3NNUQIQO20AAP/ref=nav_wishlist_lists_1', 'https://www.paypal.com/donate/?cmd=_s-xclick&hosted_button_id=4PW43VJ2DZ7R2'] 4 | 5 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had recent activity. 14 | It will be closed if no further activity occurs. Thank you for your contributions. 15 | # Comment to post when closing a stale issue. Set to `false` to disable 16 | closeComment: false 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /create_detect_radio_module.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PKG_BUILD=7 3 | 4 | PKG_VERSION=1.0-$PKG_BUILD 5 | 6 | function throw { 7 | echo $1 8 | exit 1 9 | } 10 | 11 | function run { 12 | echo -n "$1 ... " 13 | shift 14 | ERR=`$* 2>&1` && RC=$? || RC=$? 15 | if [ $RC -eq 0 ]; then 16 | echo -e "\033[0;32mDone\033[0;0m" 17 | else 18 | echo -e "\033[1;91mFAILED\033[0;0m" 19 | echo "$ERR" 20 | exit 1 21 | fi 22 | } 23 | 24 | CURRENT_DIR=$(pwd) 25 | WORK_DIR=$(mktemp -d) 26 | 27 | cd $WORK_DIR 28 | 29 | SRC_DIR=$WORK_DIR/src 30 | mkdir -p $SRC_DIR 31 | 32 | cp -p $CURRENT_DIR/detect_radio_module/* $SRC_DIR 33 | 34 | function build_binaries { 35 | ARCH=$1 36 | 37 | cd $SRC_DIR 38 | run "make clean" make clean 39 | run "make ($ARCH)" make CXX=$ARCH_COMP 40 | } 41 | 42 | function build_package { 43 | TARGET_DIR=$WORK_DIR/detect-radio-module-$PKG_VERSION-$ARCH 44 | mkdir -p $TARGET_DIR/bin 45 | 46 | cp -p $SRC_DIR/detect_radio_module $TARGET_DIR/bin 47 | 48 | mkdir -p $TARGET_DIR/DEBIAN 49 | cp -p $CURRENT_DIR/package/detect-radio-module/* $TARGET_DIR/DEBIAN 50 | for file in $TARGET_DIR/DEBIAN/*; do 51 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 52 | sed -i "s/{PKG_ARCH}/$ARCH/g" $file 53 | done 54 | 55 | cd $WORK_DIR 56 | 57 | dpkg-deb --build -Zxz detect-radio-module-$PKG_VERSION-$ARCH || throw "Error on dpkg-deb" 58 | } 59 | 60 | declare -A architectures=(["armhf"]="arm-linux-gnueabihf-g++" ["arm64"]="aarch64-linux-gnu-g++" ["i386"]="i686-linux-gnu-g++" ["amd64"]="g++") 61 | for ARCH in "${!architectures[@]}" 62 | do 63 | ARCH_COMP=${architectures[$ARCH]} 64 | 65 | run "Build binaries for $ARCH" build_binaries $ARCH 66 | run "Build package for $ARCH" build_package $ARCH 67 | done 68 | 69 | cd $WORK_DIR 70 | 71 | run "Copy package to local directory" cp detect-radio-module-*.deb $CURRENT_DIR 72 | run "Cleanup temporary files" rm -rf $WORK_DIR 73 | 74 | -------------------------------------------------------------------------------- /create_devicetree_armbian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PKG_BUILD=37 3 | 4 | CURRENT_DIR=$(pwd) 5 | WORK_DIR=$(mktemp -d) 6 | 7 | PKG_VERSION=1.0.$PKG_BUILD 8 | 9 | TARGET_DIR=$WORK_DIR/pivccu-devicetree-armbian-$PKG_VERSION 10 | 11 | cd $WORK_DIR 12 | 13 | mkdir -p $TARGET_DIR/var/lib/piVCCU/dts 14 | 15 | cp $CURRENT_DIR/dts/armbian/* $TARGET_DIR/var/lib/piVCCU/dts 16 | cp $CURRENT_DIR/dts/*.dts.include $TARGET_DIR/var/lib/piVCCU/dts 17 | 18 | mkdir -p $TARGET_DIR/boot/overlay-user 19 | 20 | cd $CURRENT_DIR/dts 21 | for dts in $(find *.dts -type f); do 22 | dtc -@ -I dts -O dtb -W no-unit_address_vs_reg -o $TARGET_DIR/boot/overlay-user/${dts%.dts}.dtbo $dts 23 | done 24 | 25 | mkdir -p $TARGET_DIR/etc/apt/apt.conf.d 26 | 27 | cat <> $TARGET_DIR/etc/apt/apt.conf.d/99pivccu_patch_dts 28 | DPkg::Post-Invoke {"if [ -e /var/lib/piVCCU/dts/patch_dts.sh ]; then /var/lib/piVCCU/dts/patch_dts.sh; fi";}; 29 | EOF 30 | 31 | mkdir -p $TARGET_DIR/DEBIAN 32 | cp -p $CURRENT_DIR/package/pivccu-devicetree-armbian/* $TARGET_DIR/DEBIAN 33 | for file in $TARGET_DIR/DEBIAN/*; do 34 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 35 | done 36 | 37 | cd $WORK_DIR 38 | 39 | dpkg-deb --build -Zxz pivccu-devicetree-armbian-$PKG_VERSION 40 | 41 | cp pivccu-devicetree-armbian*.deb $CURRENT_DIR 42 | 43 | echo "Please clean-up the work dir temp folder $WORK_DIR, e.g. by doing rm -R $WORK_DIR" 44 | 45 | -------------------------------------------------------------------------------- /create_hb-rf-eth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PKG_BUILD=2 3 | 4 | PKG_VERSION=1.0.$PKG_BUILD 5 | 6 | CURRENT_DIR=$(pwd) 7 | WORK_DIR=$(mktemp -d) 8 | 9 | cd $WORK_DIR 10 | 11 | TARGET_DIR=$WORK_DIR/hb-rf-eth-$PKG_VERSION 12 | 13 | mkdir -p $TARGET_DIR/DEBIAN 14 | cp -p $CURRENT_DIR/package/hb-rf-eth/* $TARGET_DIR/DEBIAN 15 | for file in $TARGET_DIR/DEBIAN/*; do 16 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 17 | done 18 | 19 | cd $WORK_DIR 20 | 21 | dpkg-deb --build -Zxz hb-rf-eth-$PKG_VERSION 22 | 23 | cp hb-rf-eth-*.deb $CURRENT_DIR 24 | 25 | echo "Please clean-up the work dir temp folder $WORK_DIR, e.g. by doing rm -R $WORK_DIR" 26 | 27 | -------------------------------------------------------------------------------- /create_modules_dkms.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PKG_BUILD=85 3 | 4 | PKG_VERSION=1.0.$PKG_BUILD 5 | 6 | function throw { 7 | echo $1 8 | exit 1 9 | } 10 | 11 | function run { 12 | echo -n "$1 ... " 13 | shift 14 | ERR=`$* 2>&1` && RC=$? || RC=$? 15 | if [ $RC -eq 0 ]; then 16 | echo -e "\033[0;32mDone\033[0;0m" 17 | else 18 | echo -e "\033[1;91mFAILED\033[0;0m" 19 | echo "$ERR" 20 | exit 1 21 | fi 22 | } 23 | 24 | CURRENT_DIR=$(pwd) 25 | WORK_DIR=$(mktemp -d) 26 | TARGET_DIR=$WORK_DIR/pivccu-modules-dkms-$PKG_VERSION 27 | 28 | function create_package_dir { 29 | mkdir -p $TARGET_DIR/usr/src/pivccu-$PKG_VERSION || throw "Could not create temporary directory" 30 | } 31 | 32 | function create_dkms_config { 33 | DKMS_CONF_FILE=$TARGET_DIR/usr/src/pivccu-$PKG_VERSION/dkms.conf 34 | 35 | cat <> $DKMS_CONF_FILE 36 | PACKAGE_NAME="pivccu" 37 | PACKAGE_VERSION="$PKG_VERSION" 38 | 39 | MAKE="make ARCH=\`uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/arm.*/arm/ -e s/aarch64.*/arm64/\` all" 40 | CLEAN="make ARCH=\`uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/arm.*/arm/ -e s/aarch64.*/arm64/\` clean" 41 | 42 | AUTOINSTALL="yes" 43 | 44 | EOF 45 | 46 | index=0 47 | for file in $TARGET_DIR/usr/src/pivccu-$PKG_VERSION/*.c; do 48 | modname=$(basename "$file" .c) 49 | echo "BUILT_MODULE_NAME[$index]=\"$modname\"" >> $DKMS_CONF_FILE 50 | echo "DEST_MODULE_LOCATION[$index]=\"/kernel/drivers/pivccu\"" >> $DKMS_CONF_FILE 51 | index=$(expr $index + 1) 52 | done 53 | } 54 | 55 | function copy_files { 56 | cp $CURRENT_DIR/kernel/* $TARGET_DIR/usr/src/pivccu-$PKG_VERSION 57 | mkdir -p $TARGET_DIR/lib/systemd/system/ 58 | cp -p $CURRENT_DIR/pivccu/dkms/*.service $TARGET_DIR/lib/systemd/system/ 59 | cp -p $CURRENT_DIR/pivccu/rtc/*.service $TARGET_DIR/lib/systemd/system/ 60 | cp -p $CURRENT_DIR/pivccu/rtc/*.timer $TARGET_DIR/lib/systemd/system/ 61 | 62 | mkdir -p $TARGET_DIR/var/lib/piVCCU/dkms 63 | cp -p $CURRENT_DIR/pivccu/dkms/*.sh $TARGET_DIR/var/lib/piVCCU/dkms 64 | 65 | mkdir -p $TARGET_DIR/lib/udev/rules.d 66 | cp -p $CURRENT_DIR/pivccu/rtc/*.rules $TARGET_DIR/lib/udev/rules.d 67 | } 68 | 69 | function create_package_files { 70 | mkdir -p $TARGET_DIR/DEBIAN 71 | cp -p $CURRENT_DIR/package/pivccu-modules-dkms/* $TARGET_DIR/DEBIAN 72 | for file in $TARGET_DIR/DEBIAN/*; do 73 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 74 | done 75 | } 76 | 77 | cd $WORK_DIR 78 | 79 | run "Create package directory" create_package_dir 80 | run "Copy files" copy_files 81 | run "Create DKMS config file" create_dkms_config 82 | run "Create package meta files" create_package_files 83 | 84 | cd $WORK_DIR 85 | 86 | run "Create deb package" dpkg-deb --build -Zxz pivccu-modules-dkms-$PKG_VERSION 87 | run "Copy package to local directory" cp pivccu-modules-dkms-*.deb $CURRENT_DIR 88 | run "Cleanup temporary files" rm -rf $WORK_DIR 89 | 90 | -------------------------------------------------------------------------------- /create_modules_raspberrypi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PKG_BUILD=19 3 | 4 | PKG_VERSION=2.0-$PKG_BUILD 5 | 6 | CURRENT_DIR=$(pwd) 7 | WORK_DIR=$(mktemp -d) 8 | 9 | cd $WORK_DIR 10 | 11 | TARGET_DIR=$WORK_DIR/pivccu-modules-raspberrypi-$PKG_VERSION 12 | 13 | mkdir -p $TARGET_DIR/lib/systemd/system/ 14 | cp -p $CURRENT_DIR/pivccu/rpi-modules/pivccu-rpi-modules.service $TARGET_DIR/lib/systemd/system/ 15 | 16 | mkdir -p $TARGET_DIR/var/lib/piVCCU/rpi-modules 17 | cp -p $CURRENT_DIR/pivccu/rpi-modules/*.sh $TARGET_DIR/var/lib/piVCCU/rpi-modules 18 | 19 | mkdir -p $TARGET_DIR/var/lib/piVCCU/dtb/overlays 20 | 21 | cd $CURRENT_DIR/dts 22 | dtc -@ -I dts -O dtb -W no-unit_address_vs_reg -o $TARGET_DIR/var/lib/piVCCU/dtb/overlays/pivccu-raspberrypi.dtbo pivccu-raspberrypi.dts 23 | 24 | mkdir -p $TARGET_DIR/DEBIAN 25 | cp -p $CURRENT_DIR/package/pivccu-modules-raspberrypi/* $TARGET_DIR/DEBIAN 26 | for file in $TARGET_DIR/DEBIAN/*; do 27 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 28 | done 29 | 30 | cd $WORK_DIR 31 | 32 | dpkg-deb --build -Zxz pivccu-modules-raspberrypi-$PKG_VERSION 33 | 34 | cp pivccu-modules-raspberrypi-*.deb $CURRENT_DIR 35 | 36 | echo "Please clean-up the work dir temp folder $WORK_DIR, e.g. by doing rm -R $WORK_DIR" 37 | 38 | -------------------------------------------------------------------------------- /create_pivccu3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CCU_VERSION=3.81.5 4 | CCU_DOWNLOAD_SPLASH_URL="https://www.eq-3.de/service/downloads.html" 5 | CCU_DOWNLOAD_URL="https://www.eq-3.de/downloads/software/firmware/ccu3-firmware/ccu3-$CCU_VERSION.tgz" 6 | CCU_DOWNLOAD_URL="https://homematic-ip.com/sites/default/files/downloads/ccu3-$CCU_VERSION.tgz" 7 | 8 | PKG_BUILD=94 9 | 10 | function throw { 11 | echo $1 12 | exit 1 13 | } 14 | 15 | function run { 16 | echo -n "$1 ... " 17 | shift 18 | ERR=`$* 2>&1` && RC=$? || RC=$? 19 | if [ $RC -eq 0 ]; then 20 | echo -e "\033[0;32mDone\033[0;0m" 21 | else 22 | echo -e "\033[1;91mFAILED\033[0;0m" 23 | echo "$ERR" 24 | exit 1 25 | fi 26 | } 27 | 28 | CURRENT_DIR=$(pwd) 29 | WORK_DIR=$(mktemp -d) 30 | 31 | PKG_VERSION=$CCU_VERSION-$PKG_BUILD 32 | 33 | TARGET_DIR=$WORK_DIR/pivccu3-$PKG_VERSION 34 | CNT_ROOT=$TARGET_DIR/var/lib/piVCCU3 35 | CNT_ROOTFS=$CNT_ROOT/rootfs 36 | 37 | cd $WORK_DIR 38 | 39 | function download_ccu3_firmware { 40 | run "Get splash page" wget -O /dev/null --save-cookies=cookies.txt --keep-session-cookies $CCU_DOWNLOAD_SPLASH_URL 41 | run "Download package" wget -O ccu3.tar.gz --load-cookies=cookies.txt --referer=$CCU_DOWNLOAD_SPLASH_URL $CCU_DOWNLOAD_URL 42 | } 43 | run "Download CCU3 firmware" download_ccu3_firmware 44 | 45 | function extract_ccu3_firmware { 46 | run "Extract CCU3 firmware" tar xzf ccu3.tar.gz 47 | run "Extract root fs" gunzip rootfs.ext4.gz 48 | 49 | mkdir $WORK_DIR/image 50 | run "Mount root fs" fuse2fs -o ro,fakeroot rootfs.ext4 $WORK_DIR/image 51 | 52 | mkdir -p $CNT_ROOTFS 53 | 54 | run "Copy root fs files" cp -p -P -R $WORK_DIR/image/* $CNT_ROOTFS 55 | 56 | run "Umount root fs" umount $WORK_DIR/image 57 | } 58 | run "Extract CCU3 firmware" extract_ccu3_firmware 59 | 60 | cd $CNT_ROOTFS 61 | 62 | run "Patch CCU3 firmware" patch -E -l -p1 < $CURRENT_DIR/pivccu/firmware3.patch 63 | 64 | function patch_version { 65 | sed -i "s/@@@pivccu_version@@@/$PKG_VERSION/g" $CNT_ROOTFS/www/config/cp_maintenance.cgi || throw "Could not patch cp_maintenance.cgi" 66 | sed -i "s/@@@pivccu_version@@@/$PKG_VERSION/g" $CNT_ROOTFS/www/webui/webui.js || throw "Could not patch webui.js" 67 | } 68 | run "Patch version numbers" patch_version 69 | 70 | function add_hm_mod_rpi_pcb_firmware { 71 | mkdir -p $CNT_ROOTFS/firmware/HM-MOD-UART 72 | run "Download firmware" wget -q -O $CNT_ROOTFS/firmware/HM-MOD-UART/dualcopro_si1002_update_blhm.eq3 https://raw.githubusercontent.com/eq-3/occu/abc3d4c8ee7d0ba090407b6b4431aeca42aeb014/firmware/HM-MOD-UART/dualcopro_si1002_update_blhm.eq3 73 | run "Download fwmap" wget -q -O $CNT_ROOTFS/firmware/HM-MOD-UART/fwmap https://raw.githubusercontent.com/eq-3/occu/abc3d4c8ee7d0ba090407b6b4431aeca42aeb014/firmware/HM-MOD-UART/fwmap 74 | } 75 | run "Add HM-MOD-RPI-PCB firmware" add_hm_mod_rpi_pcb_firmware 76 | 77 | mkdir -p $CNT_ROOTFS/firmware/HmIP-RFUSB 78 | run "Add HmIP-RFUSB firmware" wget -q -P $CNT_ROOTFS/firmware/HmIP-RFUSB https://raw.githubusercontent.com/eq-3/occu/77f5f55eb456e9974355d645e2005a1d355063af/firmware/HmIP-RFUSB/dualcopro_update_blhmip-4.4.18.eq3 79 | 80 | mkdir -p $CNT_ROOTFS/etc/piVCCU3 81 | run "Add piVCCU container files" cp -p $CURRENT_DIR/pivccu/container3/* $CNT_ROOTFS/etc/piVCCU3 82 | 83 | mkdir -p $CNT_ROOT/userfs 84 | 85 | mkdir -p $TARGET_DIR/etc/piVCCU3 86 | run "Add lxc.config" cp -p $CURRENT_DIR/pivccu/host3/lxc.config $TARGET_DIR/etc/piVCCU3 87 | 88 | mkdir -p $TARGET_DIR/etc/default 89 | run "Add /etc/default/pivccu3" cp -p $CURRENT_DIR/pivccu/host3/default.config $TARGET_DIR/etc/default/pivccu3 90 | 91 | mkdir -p $TARGET_DIR/etc/udev/rules.d 92 | run "Add udev rules" cp -p $CURRENT_DIR/pivccu/host3/*.rules $TARGET_DIR/etc/udev/rules.d 93 | 94 | function copy_host_binaries { 95 | cp -p $CURRENT_DIR/pivccu/host3/*.sh $CNT_ROOT || throw "Could not copy .sh files" 96 | cp -p $CURRENT_DIR/pivccu/host3/*.inc $CNT_ROOT || throw "Could not copy .inc files" 97 | } 98 | run "Add piVCCU host binaries" copy_host_binaries 99 | 100 | mkdir -p $TARGET_DIR/lib/systemd/system/ 101 | run "Add systemd service files" cp -p $CURRENT_DIR/pivccu/host3/*.service $TARGET_DIR/lib/systemd/system/ 102 | 103 | mkdir -p $TARGET_DIR/DEBIAN 104 | cp -p $CURRENT_DIR/package/pivccu3/* $TARGET_DIR/DEBIAN 105 | for file in $TARGET_DIR/DEBIAN/*; do 106 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 107 | sed -i "s/{CCU_VERSION}/$CCU_VERSION/g" $file 108 | sed -i "s/{PKG_ARCH}/armhf/g" $file 109 | done 110 | 111 | cd $WORK_DIR 112 | 113 | run "Build armhf package" dpkg-deb --build -Zxz pivccu3-$PKG_VERSION 114 | 115 | run "Copy armhf package to local directory" cp pivccu3-$PKG_VERSION.deb $CURRENT_DIR/pivccu3-$PKG_VERSION-armhf.deb 116 | 117 | function add_openjdk { 118 | run "Download openjdk-11-jre.deb" wget -O openjdk-11-jre.deb https://archive.debian.org/debian/pool/main/o/openjdk-11/openjdk-11-jre_11.0.6+10-1~bpo9+1_armhf.deb 119 | run "Download openjdk-11-jre-headless.deb" wget -O openjdk-11-jre-headless.deb https://archive.debian.org/debian/pool/main/o/openjdk-11/openjdk-11-jre-headless_11.0.6+10-1~bpo9+1_armhf.deb 120 | 121 | run "Extract openjdk-11-jre.deb" dpkg-deb -x openjdk-11-jre.deb . 122 | run "Extract openjdk-11-jre-headless.deb" dpkg-deb -x openjdk-11-jre-headless.deb . 123 | 124 | run "Copy openjdk files" mv usr/lib/jvm/java-11-openjdk-armhf $CNT_ROOTFS/opt/openjdk 125 | run "Copy openjdk files" mv etc/java-11-openjdk $CNT_ROOTFS/etc 126 | run "Remove old jdk files" rm -f $CNT_ROOTFS/opt/java 127 | run "Create java symlink" ln -s /opt/openjdk $CNT_ROOTFS/opt/java 128 | } 129 | run "Add compatible openjdk package for arm64" add_openjdk 130 | 131 | rm -rf $TARGET_DIR/DEBIAN/* 132 | cp -p $CURRENT_DIR/package/pivccu3/* $TARGET_DIR/DEBIAN 133 | for file in $TARGET_DIR/DEBIAN/*; do 134 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 135 | sed -i "s/{CCU_VERSION}/$CCU_VERSION/g" $file 136 | sed -i "s/{PKG_ARCH}/arm64/g" $file 137 | done 138 | 139 | run "Build arm64 package" dpkg-deb --build -Zxz pivccu3-$PKG_VERSION 140 | 141 | run "Copy arm64 package to local directory" cp pivccu3-$PKG_VERSION.deb $CURRENT_DIR/pivccu3-$PKG_VERSION-arm64.deb 142 | 143 | run "Remove temporary files" rm -rf $WORK_DIR 144 | 145 | -------------------------------------------------------------------------------- /create_wait_sysfs_notify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PKG_BUILD=2 3 | 4 | PKG_VERSION=1.0-$PKG_BUILD 5 | 6 | CURRENT_DIR=$(pwd) 7 | WORK_DIR=$(mktemp -d) 8 | 9 | cd $WORK_DIR 10 | 11 | SRC_DIR=$WORK_DIR/src 12 | mkdir -p $SRC_DIR 13 | 14 | cp -p $CURRENT_DIR/wait_sysfs_notify/* $SRC_DIR 15 | 16 | declare -A architectures=(["armhf"]="arm-linux-gnueabihf-g++" ["arm64"]="aarch64-linux-gnu-g++" ["i386"]="i686-linux-gnu-g++" ["amd64"]="g++") 17 | for ARCH in "${!architectures[@]}" 18 | do 19 | ARCH_COMP=${architectures[$ARCH]} 20 | 21 | cd $SRC_DIR 22 | make clean 23 | make CXX=$ARCH_COMP 24 | 25 | TARGET_DIR=$WORK_DIR/wait-sysfs-notify-$PKG_VERSION-$ARCH 26 | mkdir -p $TARGET_DIR/bin 27 | 28 | cp -p $SRC_DIR/wait_sysfs_notify $TARGET_DIR/bin 29 | 30 | mkdir -p $TARGET_DIR/DEBIAN 31 | cp -p $CURRENT_DIR/package/wait-sysfs-notify/* $TARGET_DIR/DEBIAN 32 | for file in $TARGET_DIR/DEBIAN/*; do 33 | sed -i "s/{PKG_VERSION}/$PKG_VERSION/g" $file 34 | sed -i "s/{PKG_ARCH}/$ARCH/g" $file 35 | done 36 | 37 | cd $WORK_DIR 38 | 39 | dpkg-deb --build -Zxz wait-sysfs-notify-$PKG_VERSION-$ARCH 40 | done 41 | 42 | cp wait-sysfs-notify-*.deb $CURRENT_DIR 43 | 44 | echo "Please clean-up the work dir temp folder $WORK_DIR, e.g. by doing rm -R $WORK_DIR" 45 | 46 | -------------------------------------------------------------------------------- /detect_radio_module/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -pthread -static-libstdc++ 3 | OBJS = main.o hmframe.o streamparser.o radiomoduleconnector.o radiomoduledetector.o 4 | 5 | all: detect_radio_module 6 | 7 | detect_radio_module: $(OBJS) 8 | $(LINK.cc) $(OBJS) -o $@ 9 | 10 | clean: 11 | rm -f $(OBJS) detect_radio_module 12 | 13 | -------------------------------------------------------------------------------- /detect_radio_module/hmframe.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * hmframe.cpp is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH 3 | * 4 | * Copyright 2021 Alexander Reinert 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "hmframe.h" 20 | #include 21 | 22 | uint16_t HMFrame::crc(unsigned char *buffer, uint16_t len) 23 | { 24 | uint16_t crc = 0xd77f; 25 | int i; 26 | 27 | while (len--) 28 | { 29 | crc ^= *buffer++ << 8; 30 | for (i = 0; i < 8; i++) 31 | { 32 | if (crc & 0x8000) 33 | { 34 | crc <<= 1; 35 | crc ^= 0x8005; 36 | } 37 | else 38 | { 39 | crc <<= 1; 40 | } 41 | } 42 | } 43 | 44 | return crc; 45 | } 46 | 47 | bool HMFrame::TryParse(unsigned char *buffer, uint16_t len, HMFrame *frame) 48 | { 49 | uint16_t crc; 50 | 51 | if (len < 8) 52 | return false; 53 | 54 | if (buffer[0] != 0xfd) 55 | return false; 56 | 57 | frame->data_len = ((buffer[1] << 8) | buffer[2]) - 3; 58 | if (frame->data_len + 8 != len) 59 | return false; 60 | 61 | crc = (buffer[len - 2] << 8) | buffer[len - 1]; 62 | if (crc != HMFrame::crc(buffer, len - 2)) 63 | return false; 64 | 65 | frame->destination = buffer[3]; 66 | frame->counter = buffer[4]; 67 | frame->command = buffer[5]; 68 | frame->data = &buffer[6]; 69 | 70 | return true; 71 | } 72 | 73 | HMFrame::HMFrame() : data_len(0) 74 | { 75 | } 76 | 77 | uint16_t HMFrame::encode(unsigned char *buffer, uint16_t len, bool escaped) 78 | { 79 | uint16_t crc; 80 | 81 | if (data_len + 8 > len) 82 | return 0; 83 | 84 | buffer[0] = 0xfd; 85 | buffer[1] = ((data_len + 3) >> 8) & 0xff; 86 | buffer[2] = (data_len + 3) & 0xff; 87 | buffer[3] = destination; 88 | buffer[4] = counter; 89 | buffer[5] = command; 90 | if (data_len > 0) 91 | memcpy(&(buffer[6]), data, data_len); 92 | 93 | crc = HMFrame::crc(buffer, data_len + 6); 94 | buffer[data_len + 6] = (crc >> 8) & 0xff; 95 | buffer[data_len + 7] = crc & 0xff; 96 | 97 | uint16_t res = data_len + 8; 98 | 99 | if (escaped) 100 | { 101 | for (uint16_t i = 1; i < res; i++) 102 | { 103 | if (buffer[i] == 0xfc || buffer[i] == 0xfd) 104 | { 105 | memmove(buffer + i + 1, buffer + i, res - i); 106 | buffer[i++] = 0xfc; 107 | buffer[i] &= 0x7f; 108 | res++; 109 | } 110 | } 111 | } 112 | 113 | return res; 114 | } 115 | -------------------------------------------------------------------------------- /detect_radio_module/hmframe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hmframe.h is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH 3 | * 4 | * Copyright 2021 Alexander Reinert 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | class HMFrame 24 | { 25 | public: 26 | static bool TryParse(unsigned char *buffer, uint16_t len, HMFrame *frame); 27 | static uint16_t crc(unsigned char *buffer, uint16_t len); 28 | 29 | HMFrame(); 30 | uint8_t counter; 31 | uint8_t destination; 32 | uint8_t command; 33 | unsigned char *data; 34 | uint16_t data_len; 35 | 36 | uint16_t encode(unsigned char *buffer, uint16_t len, bool escaped); 37 | }; 38 | 39 | typedef enum 40 | { 41 | HM_DST_HMSYSTEM = 0x00, 42 | HM_DST_TRX = 0x01, 43 | HM_DST_HMIP = 0x02, 44 | HM_DST_LLMAC = 0x03, 45 | HM_DST_COMMON = 0xfe, 46 | } hm_dst_t; 47 | 48 | typedef enum 49 | { 50 | HM_CMD_HMSYSTEM_IDENTIFY = 0x00, 51 | HM_CMD_HMSYSTEM_GET_VERSION = 0x02, 52 | HM_CMD_HMSYSTEM_CHANGE_APP = 0x03, 53 | HM_CMD_HMSYSTEM_ACK = 0x04, 54 | HM_CMD_HMSYSTEM_GET_SERIAL = 0x0b, 55 | } hm_cmd_hmsystem_t; 56 | 57 | typedef enum 58 | { 59 | HM_CMD_TRX_GET_VERSION = 0x02, 60 | HM_CMD_TRX_ACK = 0x04, 61 | HM_CMD_TRX_GET_MCU_TYPE = 0x09, 62 | HM_CMD_TRX_GET_DEFAULT_RF_ADDR = 0x10, 63 | } hm_cmd_trx_t; 64 | 65 | typedef enum 66 | { 67 | HM_CMD_HMIP_GET_DEFAULT_RF_ADDR = 0x01, 68 | HM_CMD_HMIP_ACK = 0x06, 69 | } hm_cmd_hmip_t; 70 | 71 | typedef enum 72 | { 73 | HM_CMD_LLMAC_ACK = 0x01, 74 | HM_CMD_LLMAC_GET_SERIAL = 0x07, 75 | HM_CMD_LLMAC_GET_DEFAULT_RF_ADDR = 0x08, 76 | } hm_cmd_llmac_t; 77 | 78 | typedef enum 79 | { 80 | HM_CMD_COMMON_IDENTIFY = 0x01, 81 | HM_CMD_COMMON_START_BL = 0x02, 82 | HM_CMD_COMMON_START_APP = 0x03, 83 | HM_CMD_COMMON_GET_SGTIN = 0x04, 84 | HM_CMD_COMMON_ACK = 0x05, 85 | } hm_cmd_common_t; 86 | -------------------------------------------------------------------------------- /detect_radio_module/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Alexander Reinert 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "radiomoduleconnector.h" 26 | #include "radiomoduledetector.h" 27 | 28 | #define MAX_DEVICE_TYPE_LEN 64 29 | #define IOCTL_MAGIC 'u' 30 | #define IOCTL_IOCRESET_RADIO_MODULE _IO(IOCTL_MAGIC, 0x81) 31 | #define IOCTL_IOCGDEVINFO _IOW(IOCTL_MAGIC, 0x82, char[MAX_DEVICE_TYPE_LEN]) 32 | 33 | void handleFrame(unsigned char *buffer, uint16_t len); 34 | void readThreadProc(int fd, StreamParser *sp); 35 | void log(const char *text, ...); 36 | 37 | int _fd; 38 | 39 | bool debug = false; 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | if ((argc >= 2) && (strcmp(argv[1], "--debug") == 0)) 44 | { 45 | debug = true; 46 | } 47 | 48 | if (argc != (debug ? 3 : 2)) 49 | { 50 | printf("Usage: %s [--debug] \n", argv[0]); 51 | return -1; 52 | } 53 | 54 | char *path = argv[debug ? 2 : 1]; 55 | 56 | int fd = open(path, O_RDWR | O_NOCTTY | O_SYNC); 57 | if (fd < 0) 58 | { 59 | close(fd); 60 | printf("%s could not be opened\n", path); 61 | return -1; 62 | } 63 | 64 | unsigned char deviceType[MAX_DEVICE_TYPE_LEN]; 65 | if (!ioctl(fd, IOCTL_IOCGDEVINFO, deviceType)) 66 | { 67 | log("Raw UART device: %s", deviceType); 68 | } 69 | else 70 | { 71 | switch (errno) 72 | { 73 | case ENOTTY: 74 | // current generic_raw_uart kernel module does not support getting device type 75 | break; 76 | default: 77 | log("Raw UART device: unknown"); 78 | break; 79 | } 80 | } 81 | 82 | if (ioctl(fd, IOCTL_IOCRESET_RADIO_MODULE)) 83 | { 84 | switch (errno) 85 | { 86 | case EBUSY: 87 | close(fd); 88 | printf("Raw UART device is in use, aborting.\n"); 89 | return -1; 90 | case ENOTTY: 91 | log("Resetting radio module via current device is not supported."); 92 | break; 93 | case ENOSYS: 94 | log("Resetting radio module is not supported."); 95 | break; 96 | default: 97 | log("Reset of radio module failed (%d).", errno); 98 | break; 99 | } 100 | } 101 | else 102 | { 103 | log("Sucessfully resetted radio module."); 104 | } 105 | 106 | RadioModuleConnector connector(fd); 107 | connector.start(); 108 | 109 | RadioModuleDetector detector; 110 | detector.detectRadioModule(&connector); 111 | 112 | if (!ioctl(fd, IOCTL_IOCRESET_RADIO_MODULE)) 113 | log("Sucessfully resetted radio module."); 114 | 115 | close(fd); 116 | 117 | const char *moduleType; 118 | const char *sgtin = detector.getSGTIN(); 119 | 120 | switch (detector.getRadioModuleType()) 121 | { 122 | case RADIO_MODULE_HMIP_RFUSB: 123 | moduleType = (strstr(sgtin, "3014F5AC") == sgtin) ? "HMIP-RFUSB-TK" : "HMIP-RFUSB"; 124 | break; 125 | case RADIO_MODULE_HM_MOD_RPI_PCB: 126 | moduleType = "HM-MOD-RPI-PCB"; 127 | break; 128 | case RADIO_MODULE_RPI_RF_MOD: 129 | moduleType = "RPI-RF-MOD"; 130 | break; 131 | case RADIO_MODULE_NONE: 132 | printf("Error: Radio module was not detected\n"); 133 | return -1; 134 | case RADIO_MODULE_UNKNOWN: 135 | printf("Error: Radio module was found, but did not respond correctly (maybe bricked App in flashrom)\n"); 136 | return -1; 137 | default: 138 | printf("Error: Radio module was found, but type is unknown or not supported (0x%02X)\n", detector.getRadioModuleType()); 139 | return -1; 140 | } 141 | const uint8_t *firmwareVersion = detector.getFirmwareVersion(); 142 | printf("%s %s %s 0x%06X 0x%06X %d.%d.%d\n", moduleType, detector.getSerial(), sgtin, detector.getBidCosRadioMAC(), detector.getHmIPRadioMAC(), firmwareVersion[0], firmwareVersion[1], firmwareVersion[2]); 143 | return 0; 144 | } 145 | 146 | bool sem_wait_timeout(sem_t *sem, int timeout) 147 | { 148 | int s; 149 | struct timespec ts; 150 | clock_gettime(CLOCK_REALTIME, &ts); 151 | ts.tv_sec += timeout; 152 | 153 | while ((s = sem_timedwait(sem, &ts)) == -1 && errno == EINTR) 154 | { 155 | continue; 156 | } 157 | 158 | return s == 0; 159 | } 160 | 161 | std::string timestamp() 162 | { 163 | auto now_clock {std::chrono::system_clock::now()}; 164 | auto now_time {std::chrono::system_clock::to_time_t(now_clock)}; 165 | auto now_local {*std::localtime(&now_time)}; 166 | auto now_epoch {now_clock.time_since_epoch()}; 167 | auto msec {std::chrono::duration_cast(now_epoch).count() % 1000000}; 168 | 169 | std::ostringstream stream; 170 | stream << std::put_time (&now_local, "%T") << "." << std::setw(6) << std::setfill ('0') << msec; 171 | return stream.str(); 172 | } 173 | 174 | void log(const char *text, ...) 175 | { 176 | if (!debug) 177 | return; 178 | 179 | std::cout << timestamp() << " "; 180 | 181 | va_list args; 182 | va_start (args, text); 183 | vprintf (text, args); 184 | va_end (args); 185 | 186 | puts(""); 187 | } 188 | 189 | void log_frame(const char *text, unsigned char buffer[], uint16_t len) 190 | { 191 | if (!debug) 192 | return; 193 | 194 | std::cout << timestamp() << " "; 195 | fputs(text, stdout); 196 | for (int i = 0; i < len; i++) 197 | { 198 | printf(" %02x", buffer[i]); 199 | } 200 | puts(""); 201 | } 202 | -------------------------------------------------------------------------------- /detect_radio_module/radiomoduleconnector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Alexander Reinert 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include "radiomoduleconnector.h" 21 | #include "hmframe.h" 22 | 23 | static const char *TAG = "RadioModuleConnector"; 24 | 25 | void readThreadProc(int fd, StreamParser *sp) 26 | { 27 | int len; 28 | unsigned char buf[1]; 29 | 30 | while (true) 31 | { 32 | int len = read(fd, buf, 1); 33 | if (len > 0) 34 | { 35 | sp->append(buf[0]); 36 | } 37 | } 38 | } 39 | 40 | RadioModuleConnector::RadioModuleConnector(int fd) : _fd(fd) 41 | { 42 | 43 | using namespace std::placeholders; 44 | _streamParser = new StreamParser(false, std::bind(&RadioModuleConnector::_handleFrame, this, _1, _2)); 45 | 46 | struct termios tty; 47 | if (tcgetattr(_fd, &tty) == 0) 48 | { 49 | tty.c_cflag &= ~PARENB; 50 | tty.c_cflag &= ~CSTOPB; 51 | tty.c_cflag |= CS8; 52 | tty.c_cflag &= ~CRTSCTS; 53 | tty.c_cflag |= CREAD | CLOCAL; 54 | 55 | tty.c_lflag &= ~ICANON; 56 | tty.c_lflag &= ~ECHO; 57 | tty.c_lflag &= ~ECHOE; 58 | tty.c_lflag &= ~ECHONL; 59 | tty.c_lflag &= ~ISIG; 60 | tty.c_iflag &= ~(IXON | IXOFF | IXANY); 61 | tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); 62 | 63 | tty.c_oflag &= ~OPOST; 64 | tty.c_oflag &= ~ONLCR; 65 | 66 | tty.c_cc[VTIME] = 1; 67 | tty.c_cc[VMIN] = 0; 68 | 69 | cfsetispeed(&tty, B115200); 70 | cfsetospeed(&tty, B115200); 71 | tcsetattr(_fd, TCSANOW, &tty); 72 | } 73 | } 74 | 75 | void RadioModuleConnector::start() 76 | { 77 | _reader = new std::thread(readThreadProc, _fd, _streamParser); 78 | _reader->detach(); 79 | } 80 | 81 | void RadioModuleConnector::stop() 82 | { 83 | } 84 | 85 | void RadioModuleConnector::setFrameHandler(FrameHandler *frameHandler, bool decodeEscaped) 86 | { 87 | _frameHandler = frameHandler; 88 | _streamParser->setDecodeEscaped(decodeEscaped); 89 | } 90 | 91 | void RadioModuleConnector::sendFrame(unsigned char *buffer, uint16_t len) 92 | { 93 | write(_fd, buffer, len); 94 | fsync(_fd); 95 | } 96 | 97 | void RadioModuleConnector::_handleFrame(unsigned char *buffer, uint16_t len) 98 | { 99 | FrameHandler *frameHandler = _frameHandler; 100 | 101 | if (frameHandler) 102 | { 103 | frameHandler->handleFrame(buffer, len); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /detect_radio_module/radiomoduleconnector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Alexander Reinert 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "streamparser.h" 29 | 30 | class FrameHandler 31 | { 32 | public: 33 | virtual void handleFrame(unsigned char *buffer, uint16_t len) = 0; 34 | }; 35 | 36 | class RadioModuleConnector 37 | { 38 | private: 39 | StreamParser *_streamParser; 40 | FrameHandler *_frameHandler = NULL; 41 | std::thread *_reader = NULL; 42 | int _fd; 43 | 44 | void _handleFrame(unsigned char *buffer, uint16_t len); 45 | 46 | public: 47 | RadioModuleConnector(int fd); 48 | 49 | void start(); 50 | void stop(); 51 | 52 | void setFrameHandler(FrameHandler *handler, bool decodeEscaped); 53 | 54 | void sendFrame(unsigned char *buffer, uint16_t len); 55 | }; 56 | -------------------------------------------------------------------------------- /detect_radio_module/radiomoduledetector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * radiomoduleconnector.h is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH 3 | * 4 | * Copyright 2021 Alexander Reinert 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "radiomoduleconnector.h" 22 | #include "radiomoduledetector_utils.h" 23 | 24 | typedef enum 25 | { 26 | RADIO_MODULE_NONE = 0, 27 | RADIO_MODULE_HMIP_RFUSB = 1, 28 | RADIO_MODULE_HM_MOD_RPI_PCB = 3, 29 | RADIO_MODULE_RPI_RF_MOD = 4, 30 | RADIO_MODULE_UNKNOWN = 255, 31 | } radio_module_type_t; 32 | 33 | typedef enum 34 | { 35 | DETECT_STATE_START_BL = 0, 36 | DETECT_STATE_START_APP = 10, 37 | 38 | DETECT_STATE_GET_MCU_TYPE = 20, 39 | DETECT_STATE_GET_VERSION = 30, 40 | DETECT_STATE_GET_HMIP_RF_ADDRESS = 40, 41 | DETECT_STATE_GET_SGTIN = 50, 42 | DETECT_STATE_GET_BIDCOS_RF_ADDRESS = 60, 43 | DETECT_STATE_GET_SERIAL = 70, 44 | 45 | DETECT_STATE_LEGACY_GET_VERSION = 31, 46 | DETECT_STATE_LEGACY_GET_BIDCOS_RF_ADDRESS = 61, 47 | DETECT_STATE_LEGACY_GET_SERIAL = 71, 48 | 49 | DETECT_STATE_FINISHED = 255, 50 | } detect_radio_module_state_t; 51 | 52 | class RadioModuleDetector : private FrameHandler 53 | { 54 | private: 55 | void handleFrame(unsigned char *buffer, uint16_t len); 56 | void sendFrame(uint8_t counter, uint8_t destination, uint8_t command, unsigned char *data, uint data_len); 57 | 58 | char _serial[11] = {0}; 59 | uint32_t _bidCosRadioMAC = 0; 60 | uint32_t _hmIPRadioMAC = 0; 61 | char _sgtin[25] = {0}; 62 | uint8_t _firmwareVersion[3] = {0}; 63 | radio_module_type_t _radioModuleType = RADIO_MODULE_NONE; 64 | 65 | int _detectState; 66 | int _detectRetryCount; 67 | int _detectMsgCounter; 68 | SemaphoreHandle_t _detectWaitFrameDataSemaphore; 69 | RadioModuleConnector *_radioModuleConnector; 70 | 71 | public: 72 | void detectRadioModule(RadioModuleConnector *radioModuleConnector); 73 | const char *getSerial(); 74 | uint32_t getBidCosRadioMAC(); 75 | uint32_t getHmIPRadioMAC(); 76 | const char *getSGTIN(); 77 | const uint8_t *getFirmwareVersion(); 78 | radio_module_type_t getRadioModuleType(); 79 | }; 80 | -------------------------------------------------------------------------------- /detect_radio_module/radiomoduledetector_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Alexander Reinert 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #pragma once 20 | 21 | #define SemaphoreHandle_t sem_t 22 | 23 | bool sem_wait_timeout(sem_t *sem, int timeout); 24 | 25 | #define sem_take(__sem, __timeout) sem_wait_timeout(&__sem, __timeout) 26 | #define sem_give(__sem) sem_post(&__sem) 27 | #define sem_init(__sem) sem_init(&__sem, 1, 0); 28 | 29 | void log_frame(const char *text, unsigned char buffer[], uint16_t len); 30 | 31 | -------------------------------------------------------------------------------- /detect_radio_module/streamparser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * streamparser.cpp is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH 3 | * 4 | * Copyright 2021 Alexander Reinert 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "streamparser.h" 20 | #include 21 | 22 | StreamParser::StreamParser(bool decodeEscaped, std::function processor) : _bufferPos(0), _state(NO_DATA), _isEscaped(false), _decodeEscaped(decodeEscaped), _processor(processor) 23 | { 24 | } 25 | 26 | void StreamParser::append(unsigned char chr) 27 | { 28 | switch (chr) 29 | { 30 | case 0xfd: 31 | _bufferPos = 0; 32 | _isEscaped = false; 33 | _state = RECEIVE_LENGTH_HIGH_BYTE; 34 | break; 35 | 36 | case 0xfc: 37 | _isEscaped = true; 38 | if (_decodeEscaped) 39 | return; 40 | break; 41 | 42 | default: 43 | if (_isEscaped && _decodeEscaped) 44 | chr |= 0x80; 45 | 46 | switch (_state) 47 | { 48 | case NO_DATA: 49 | case FRAME_COMPLETE: 50 | return; // Do nothing until the first frame prefix occurs 51 | 52 | case RECEIVE_LENGTH_HIGH_BYTE: 53 | _frameLength = (_isEscaped ? chr | 0x80 : chr) << 8; 54 | _state = RECEIVE_LENGTH_LOW_BYTE; 55 | break; 56 | 57 | case RECEIVE_LENGTH_LOW_BYTE: 58 | _frameLength |= (_isEscaped ? chr | 0x80 : chr); 59 | _frameLength += 2; // handle crc as frame data 60 | _framePos = 0; 61 | _state = RECEIVE_FRAME_DATA; 62 | break; 63 | 64 | case RECEIVE_FRAME_DATA: 65 | _framePos++; 66 | _state = (_framePos == _frameLength) ? FRAME_COMPLETE : RECEIVE_FRAME_DATA; 67 | break; 68 | } 69 | _isEscaped = false; 70 | } 71 | 72 | _buffer[_bufferPos++] = chr; 73 | 74 | if (_bufferPos == sizeof(_buffer)) 75 | _state = FRAME_COMPLETE; 76 | 77 | if (_state == FRAME_COMPLETE) 78 | { 79 | _processor(_buffer, _bufferPos); 80 | _state = NO_DATA; 81 | } 82 | } 83 | 84 | void StreamParser::append(unsigned char *buffer, uint16_t len) 85 | { 86 | int i; 87 | for (i = 0; i < len; i++) 88 | { 89 | append(buffer[i]); 90 | } 91 | } 92 | 93 | void StreamParser::flush() 94 | { 95 | _state = NO_DATA; 96 | _bufferPos = 0; 97 | _isEscaped = false; 98 | } 99 | 100 | bool StreamParser::getDecodeEscaped() 101 | { 102 | return _decodeEscaped; 103 | } 104 | void StreamParser::setDecodeEscaped(bool decodeEscaped) 105 | { 106 | _decodeEscaped = decodeEscaped; 107 | } 108 | -------------------------------------------------------------------------------- /detect_radio_module/streamparser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * streamparser.h is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH 3 | * 4 | * Copyright 2021 Alexander Reinert 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | typedef enum 25 | { 26 | NO_DATA, 27 | RECEIVE_LENGTH_HIGH_BYTE, 28 | RECEIVE_LENGTH_LOW_BYTE, 29 | RECEIVE_FRAME_DATA, 30 | FRAME_COMPLETE 31 | } state_t; 32 | 33 | class StreamParser 34 | { 35 | private: 36 | unsigned char _buffer[2048]; 37 | uint16_t _bufferPos; 38 | uint16_t _framePos; 39 | uint16_t _frameLength; 40 | state_t _state; 41 | bool _isEscaped; 42 | bool _decodeEscaped; 43 | std::function _processor; 44 | 45 | public: 46 | StreamParser(bool decodeEscaped, std::function processor); 47 | 48 | void append(unsigned char chr); 49 | void append(unsigned char *buffer, uint16_t len); 50 | void flush(); 51 | 52 | bool getDecodeEscaped(); 53 | void setDecodeEscaped(bool decodeEscaped); 54 | }; 55 | -------------------------------------------------------------------------------- /docs/setup/armbian.md: -------------------------------------------------------------------------------- 1 | ### Prequisites 2 | 3 | * Armbian 4 | * At least kernel 4.14 (Mainline is prefered) 5 | * The HM-MOD-RPI-PCB and the RPI-RF-MOD are only working on supported platforms 6 | 7 | ### Installation 8 | 0. Create full backup of your SD card 9 | 1. Add the public key of the repository 10 | ```bash 11 | wget -q -O - https://apt.pivccu.de/piVCCU/public.key | sudo tee /usr/share/keyrings/pivccu.asc 12 | ``` 13 | 14 | 2. Add the package repository 15 | ```bash 16 | echo "deb [signed-by=/usr/share/keyrings/pivccu.asc] https://apt.pivccu.de/piVCCU stable main" | sudo tee /etc/apt/sources.list.d/pivccu.list 17 | sudo apt update 18 | ``` 19 | Instead of `stable` you can also use the `testing` tree, but be aware testing sometimes means not that stable. 20 | 21 | 3. Install the matching kernel headers 22 | ```bash 23 | sudo apt install build-essential bison flex libssl-dev 24 | sudo apt install `dpkg --get-selections | grep 'linux-image-' | grep '\sinstall' | sed -e 's/linux-image-\([a-z0-9-]\+\).*/linux-headers-\1/'` 25 | ``` 26 | 27 | 4. If you are using a HB-RF-ETH, install the neccessary support package 28 | ```bash 29 | sudo apt install hb-rf-eth 30 | ``` 31 | 32 | 5. Install the neccessary device tree patches (You can skip this step, if you do not use the HM-MOD-RPI-PCB or RPI-RF-MOD on GPIO header, for the HB-RF-USB(-2) and HB-RF-ETH this step is not neccessary) 33 | ```bash 34 | sudo apt install pivccu-devicetree-armbian 35 | ``` 36 | 37 | 6. Install the neccessary kernel modules 38 | ```bash 39 | sudo apt install pivccu-modules-dkms 40 | ``` 41 | 42 | 7. Add network bridge (if you are using wifi please refer to the debian documentation how to configure the network and the bridge) 43 | * Verify, that *eth0* is the name of your primary network interface: 44 | ```bash 45 | sudo nmcli connection show --active 46 | ``` 47 | 48 | * Update your config. (Replace *eth0* if necessary) 49 | ```bash 50 | sudo apt install bridge-utils 51 | sudo nmcli connection add ifname br0 type bridge con-name br0 52 | sudo nmcli connection add type bridge-slave ifname eth0 master br0 53 | ``` 54 | * You can use an static IP address, too: 55 | ```bash 56 | nmcli connection modify br0 ipv4.addresses "
/" ipv4.gateway "" ipv4.dns "," ipv4.method "manual" 57 | ``` 58 | Replace
, , , , with your settings. 59 | ist the subnet prefix (e.g. 24 for netmask 255.255.255.0) 60 | 61 | 8. Reboot the system 62 | ```bash 63 | sudo reboot 64 | ``` 65 | 66 | 9. Install CCU container 67 | ```bash 68 | sudo apt install pivccu3 69 | ``` 70 | 71 | 10. Start using your new virtualized CCU, you can get the IP of the container using 72 | ```bash 73 | sudo pivccu-info 74 | ``` 75 | 76 | -------------------------------------------------------------------------------- /docs/setup/otheros.md: -------------------------------------------------------------------------------- 1 | ### Prequisites 2 | 3 | * Debian or Ubuntu based distribution 4 | * armhf or arm64 architecture (no x64 at the moment!) 5 | * At least kernel 4.14 (Mainline is prefered) 6 | * HM-MOD-RPI-PCB is supported only on Armbian and on supported hardware platforms 7 | 8 | ### Installation 9 | 0. Create full backup of your SD card 10 | 1. Add the public key of the repository 11 | ```bash 12 | wget -q -O - https://apt.pivccu.de/piVCCU/public.key | sudo tee /usr/share/keyrings/pivccu.asc 13 | ``` 14 | 15 | 2. Add the package repository 16 | ```bash 17 | echo "deb [signed-by=/usr/share/keyrings/pivccu.asc] https://apt.pivccu.de/piVCCU stable main" | sudo tee /etc/apt/sources.list.d/pivccu.list 18 | sudo apt update 19 | ``` 20 | Instead of `stable` you can also use the `testing` tree, but be aware testing sometimes means not that stable. 21 | 22 | 3. Install the neccessary packages for building kernel modules 23 | ```bash 24 | sudo apt install build-essential bison flex libssl-dev 25 | ``` 26 | 27 | 4. Install the matching kernel headers, this highly depends on your distribution 28 | 29 | 5. Install the neccessary kernel modules 30 | ```bash 31 | sudo apt install pivccu-modules-dkms 32 | ``` 33 | 34 | 6. If you are using a HB-RF-ETH, install the neccessary support package 35 | ```bash 36 | sudo apt install hb-rf-eth 37 | ``` 38 | 39 | 7. Add network bridge (if you are using wifi please refer to the debian documentation how to configure the network and the bridge) 40 | * Verify, that *eth0* is the name of your primary network interface: 41 | ```bash 42 | sudo ip link show | cut -d' ' -f2 | cut -d: -f1 | grep -e '^e.*' 43 | ``` 44 | 45 | * Update your config. (Replace *eth0* if necessary) 46 | ```bash 47 | sudo apt install bridge-utils 48 | sudo bash -c 'cat << EOT > /etc/network/interfaces 49 | source-directory /etc/network/interfaces.d 50 | 51 | auto lo 52 | iface lo inet loopback 53 | 54 | iface eth0 inet manual 55 | 56 | auto br0 57 | iface br0 inet dhcp 58 | bridge_ports eth0 59 | EOT' 60 | ``` 61 | * You can use an static IP address, too. In that case use instead: 62 | ```bash 63 | sudo apt install bridge-utils 64 | sudo bash -c 'cat << EOT > /etc/network/interfaces 65 | source-directory /etc/network/interfaces.d 66 | 67 | auto lo 68 | iface lo inet loopback 69 | 70 | iface eth0 inet manual 71 | 72 | auto br0 73 | iface br0 inet static 74 | bridge_ports eth0 75 | address
76 | netmask 77 | gateway 78 | dns-nameservers 79 | EOT' 80 | ``` 81 | * To use Wireless LAN, please take a look [here](wlan.md) 82 | 83 | 8. Reboot the system 84 | ```bash 85 | sudo reboot 86 | ``` 87 | 88 | 9. Install CCU container 89 | ```bash 90 | sudo apt install pivccu3 91 | ``` 92 | 93 | 10. Start using your new virtualized CCU, you can get the IP of the container using 94 | ```bash 95 | sudo pivccu-info 96 | ``` 97 | 98 | -------------------------------------------------------------------------------- /docs/setup/raspberrypi.md: -------------------------------------------------------------------------------- 1 | ### Prequisites 2 | 3 | * Raspberry Pi 2B/3B/3B+/4B/5B 4 | * Raspberry Pi OS Bullseye or Bookworm (32 bit image or 64 bit image; the mixed mode 32 bit image with 64 bit kernel is not supported) 5 | 6 | ### Installation 7 | 0. Create full backup of your SD card 8 | 1. Add the public key of the repository 9 | ```bash 10 | wget -q -O - https://apt.pivccu.de/piVCCU/public.key | sudo tee /usr/share/keyrings/pivccu.asc 11 | ``` 12 | 13 | 2. Add the package repository 14 | ```bash 15 | echo "deb [signed-by=/usr/share/keyrings/pivccu.asc] https://apt.pivccu.de/piVCCU stable main" | sudo tee /etc/apt/sources.list.d/pivccu.list 16 | sudo apt update 17 | ``` 18 | Instead of `stable` you can also use the `testing` tree, but be aware testing sometimes means not that stable. 19 | 20 | 3. Install the neccessary kernel modules 21 | ```bash 22 | sudo apt install build-essential bison flex libssl-dev 23 | sudo apt install raspberrypi-kernel-headers pivccu-modules-dkms 24 | ``` 25 | 26 | 4. If you are using a HB-RF-ETH, install the neccessary support package 27 | ```bash 28 | sudo apt install hb-rf-eth 29 | ``` 30 | 31 | 5. Install the neccessary device tree patches (You can skip this step, if you do not use the HM-MOD-RPI-PCB or RPI-RF-MOD on GPIO header, for the HB-RF-USB(-2) and HB-RF-ETH this step is not neccessary) 32 | ```bash 33 | sudo apt install pivccu-modules-raspberrypi 34 | ``` 35 | 36 | 6. Enable UART GPIO pins (not required on Raspberry Pi 2) (You can skip this step, if you do not use the HM-MOD-RPI-PCB or RPI-RF-MOD on GPIO header, for the HB-RF-USB this step is not neccessary) 37 | * Option 1: Disabled bluetooth (prefered) 38 | ```bash 39 | sudo bash -c 'cat << EOT >> /boot/firmware/config.txt 40 | dtoverlay=pi3-disable-bt 41 | EOT' 42 | sudo systemctl disable hciuart.service 43 | ``` 44 | 45 | * Option 2: Bluetooth attached to mini uart 46 | ```bash 47 | sudo bash -c 'cat << EOT >> /boot/firmware/config.txt 48 | dtoverlay=pi3-miniuart-bt 49 | enable_uart=1 50 | force_turbo=1 51 | core_freq=250 52 | EOT' 53 | ``` 54 | 55 | 7. Disable serial console in command line (You can skip this step, if you do not use the HM-MOD-RPI-PCB or RPI-RF-MOD on GPIO header, for the HB-RF-USB this step is not neccessary) 56 | ```bash 57 | sudo sed -i /boot/firmware/cmdline.txt -e "s/console=serial0,[0-9]\+ //" 58 | sudo sed -i /boot/firmware/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //" 59 | ``` 60 | 61 | 8. Add network bridge (if you are using wifi please refer to the debian documentation how to configure the network and the bridge) 62 | * Verify, that *eth0* is the name of your primary network interface: 63 | ```bash 64 | sudo ip link show | cut -d' ' -f2 | cut -d: -f1 | grep -e '^e.*' 65 | ``` 66 | 67 | * Update your config. (Replace *eth0* if necessary) 68 | ```bash 69 | sudo apt remove dhcpcd5 70 | sudo apt install bridge-utils 71 | sudo bash -c 'cat << EOT > /etc/network/interfaces 72 | source-directory /etc/network/interfaces.d 73 | 74 | auto lo 75 | iface lo inet loopback 76 | 77 | iface eth0 inet manual 78 | 79 | auto br0 80 | iface br0 inet dhcp 81 | bridge_ports eth0 82 | EOT' 83 | ``` 84 | * You can use an static IP address, too. In that case use instead: 85 | ```bash 86 | sudo apt remove dhcpcd5 87 | sudo apt install bridge-utils 88 | sudo bash -c 'cat << EOT > /etc/network/interfaces 89 | source-directory /etc/network/interfaces.d 90 | 91 | auto lo 92 | iface lo inet loopback 93 | 94 | iface eth0 inet manual 95 | 96 | auto br0 97 | iface br0 inet static 98 | bridge_ports eth0 99 | address
100 | netmask 101 | gateway 102 | dns-nameservers 103 | EOT' 104 | ``` 105 | * To use Wireless LAN, please take a look [here](wlan.md) 106 | 107 | 9. Reboot the system 108 | ```bash 109 | sudo reboot 110 | ``` 111 | 112 | 10. Install CCU container 113 | ```bash 114 | sudo apt install pivccu3 115 | ``` 116 | 117 | 11. Start using your new virtualized CCU, you can get the IP of the container using 118 | ```bash 119 | sudo pivccu-info 120 | ``` 121 | 122 | ### Using rpi-update 123 | The stable kernel for the Raspberry Pi is distributed via apt. Normally you should use this kernel. But still there are some reasons to use rpi-update to install the latest (unstable) kernel. 124 | Since version 2.0.7 the pivccu-modules-raspberrypi does support kernels installed by rpi-update. Be aware, that piVCCU start after the reboot with a new kernel will take approx. 15 minutes. 125 | 126 | ### Migrating from custom kernel to original Raspbian kernel with custom modules and device tree overlay 127 | 0. Create full backup of your SD card 128 | 129 | 1. Upgrade to latest pivccu package 130 | ```bash 131 | sudo apt update 132 | sudo apt upgrade 133 | ``` 134 | 135 | 2. Verify, that at least Version 2.29.23-12 is installed 136 | ```bash 137 | sudo dpkg -s pivccu | grep 'Version' 138 | ``` 139 | 140 | 3. Install original Raspbian kernel and additional custom kernel modules 141 | ```bash 142 | sudo apt install pivccu-modules-raspberrypi raspberrypi-kernel 143 | ``` 144 | (In this step, the two packages should be get installed and the package raspberrypi-kernel-pivccu should be get removed) 145 | 146 | 4. Reboot the system 147 | ```bash 148 | sudo reboot 149 | ``` 150 | 151 | -------------------------------------------------------------------------------- /docs/setup/wlan.md: -------------------------------------------------------------------------------- 1 | WLAN is not as stable as a wired network connections, there are connections drops sometimes. Please consider using a wired network connection. 2 | 3 | For technical reasons, it is not possible to create a linux network bridge using a WLAN interface. 4 | Because of that, you need a bridge without a physical interface and to use port forwading to access the virtual CCU. To configure that, you need to do the following steps. Do *not* change the IP adresses 192.168.253.x in the commands. 5 | 6 | 1. Configure Interfaces 7 | ```bash 8 | sudo apt install bridge-utils 9 | sudo bash -c 'cat << EOT > /etc/network/interfaces 10 | source-directory /etc/network/interfaces.d 11 | 12 | auto lo 13 | iface lo inet loopback 14 | 15 | auto wlan0 16 | iface wlan0 inet dhcp 17 | wpa-ssid 18 | wpa-psk 19 | 20 | auto br0 21 | iface br0 inet static 22 | bridge_ports none 23 | bridge_fd 0 24 | address 192.168.253.1 25 | netmask 255.255.255.0 26 | EOT' 27 | ``` 28 | or via netplan (Ubuntu > 18.04): 29 | ```bash 30 | sudo apt install bridge-utils 31 | sudo bash -c 'cat << EOT > /etc/netplan/50-cloud-init.yaml 32 | network: 33 | ethernets: 34 | eth0: 35 | dhcp4: true 36 | optional: true 37 | version: 2 38 | wifis: 39 | wlan0: 40 | access-points: 41 | : 42 | password: 43 | dhcp4: true 44 | optional: true 45 | bridges: 46 | br0: 47 | addresses: [192.168.253.1/24] 48 | parameters: 49 | stp: false 50 | forward-delay: 0 51 | EOT' 52 | ``` 53 | 54 | 2. Configure (private) static IP for CCU (this needs to be done after each restore, too) 55 | (If you are using piVCCU3, please you the path /var/lib/piVCCU3 instead of /var/lib/piVCCU) 56 | ```bash 57 | sudo systemctl stop pivccu 58 | sudo bash -c 'cat << EOT > /var/lib/piVCCU/userfs/etc/config/netconfig 59 | HOSTNAME=homematic-ccu2 60 | MODE=MANUAL 61 | CURRENT_IP=192.168.253.2 62 | CURRENT_NETMASK=255.255.255.0 63 | CURRENT_GATEWAY=192.168.253.1 64 | CURRENT_NAMESERVER1=8.8.4.4 65 | CURRENT_NAMESERVER2=8.8.8.8 66 | IP=192.168.253.2 67 | NETMASK=255.255.255.0 68 | GATEWAY=192.168.253.1 69 | NAMESERVER1=8.8.4.4 70 | NAMESERVER2=8.8.8.8 71 | CRYPT=0 72 | EOT' 73 | ``` 74 | 75 | 3. Add IF UP Hook for port forwarding 76 | ```bash 77 | sudo bash -c 'cat << EOT > /etc/network/if-up.d/pivccu 78 | #!/bin/sh 79 | 80 | HOST_IF=wlan0 81 | BRIDGE=br0 82 | HOST_IP=192.168.253.1 83 | CCU_IP=192.168.253.2 84 | 85 | if [ "\$IFACE" = "\$BRIDGE" ]; then 86 | echo 1 > /proc/sys/net/ipv4/ip_forward 87 | iptables -A FORWARD -i \$IFACE -s \$HOST_IP/24 -m conntrack --ctstate NEW -j ACCEPT 88 | iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -o \$BRIDGE 89 | iptables -A POSTROUTING -t nat -j MASQUERADE -s \$HOST_IP/24 90 | 91 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 80 -j DNAT --to-destination \$CCU_IP:80 92 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 1999 -j DNAT --to-destination \$CCU_IP:1999 93 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 2000 -j DNAT --to-destination \$CCU_IP:2000 94 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 2001 -j DNAT --to-destination \$CCU_IP:2001 95 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 2002 -j DNAT --to-destination \$CCU_IP:2002 96 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 2010 -j DNAT --to-destination \$CCU_IP:2010 97 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 8181 -j DNAT --to-destination \$CCU_IP:8181 98 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 8183 -j DNAT --to-destination \$CCU_IP:8183 99 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 8700 -j DNAT --to-destination \$CCU_IP:8700 100 | iptables -t nat -A PREROUTING -p tcp -i \$HOST_IF --dport 8701 -j DNAT --to-destination \$CCU_IP:8701 101 | fi 102 | EOT' 103 | sudo chmod +x /etc/network/if-up.d/pivccu 104 | 105 | 4. On Systems like Ubuntu > 18.04 you need to tell netplan to use the if-up.d script with `/etc/networkd-dispatcher/routable.d/50-ifup-hooks`: 106 | ```bash 107 | #!/bin/sh 108 | 109 | for d in up post-up; do 110 | hookdir=/etc/network/if-${d}.d 111 | [ -e $hookdir ] && /bin/run-parts $hookdir 112 | done 113 | exit 0 114 | ``` 115 | 116 | 5. If you are using Docker on the same machine you need to knock out the intelligent bridge-detection and make it dumb, because Docker also uses bridges: 117 | ```bash 118 | sudo sed -i '/lxc.network.link/c\lxc.network.link \= br0' /etc/piVCCU3/lxc.config 119 | ``` 120 | **Note that this will probably need to be done again when the piVCCU package updates.** 121 | 122 | 6. Reboot 123 | 124 | -------------------------------------------------------------------------------- /dts/armbian/detect_board.inc: -------------------------------------------------------------------------------- 1 | if [ ! -z "$1" ]; then 2 | DEV_TREE_COMPATIBLE="$1" 3 | elif [ -e /proc/device-tree/compatible ]; then 4 | DEV_TREE_COMPATIBLE=$(strings /proc/device-tree/compatible) 5 | fi 6 | 7 | if [ ! -z "$DEV_TREE_COMPATIBLE" ]; then 8 | for str in $DEV_TREE_COMPATIBLE; do 9 | case $str in 10 | xunlong,orangepi-one|xunlong,orangepi-lite|xunlong,orangepi-plus|xunlong,orangepi-plus2e|xunlong,orangepi-2|xunlong,orangepi-pc|xunlong,orangepi-pc-plus) 11 | OVERLAY_MODE='overlay' 12 | OVERLAY_FILE='pivccu-orangepi-h3.dtbo' 13 | break 14 | ;; 15 | xunlong,orangepi-zero|xunlong,orangepi-r1) 16 | OVERLAY_MODE='overlay' 17 | OVERLAY_FILE='pivccu-orangepi-h2plus.dtbo' 18 | break 19 | ;; 20 | xunlong,orangepi-zero-plus) 21 | OVERLAY_MODE='overlay' 22 | OVERLAY_FILE='pivccu-orangepi-h5.dtbo' 23 | break 24 | ;; 25 | lemaker,bananapi) 26 | OVERLAY_MODE='overlay' 27 | OVERLAY_FILE='pivccu-bananapi-m1.dtbo' 28 | break; 29 | ;; 30 | lemaker,bananapro) 31 | OVERLAY_MODE='overlay' 32 | OVERLAY_FILE='pivccu-bananapi-pro.dtbo' 33 | break; 34 | ;; 35 | asus,rk3288-tinker|asus,rk3288-tinker-s) 36 | OVERLAY_MODE='patch' 37 | INCLUDE_FILE='/var/lib/piVCCU/dts/tinkerboard.dts.include' 38 | FDT_FILE='rk3288-tinker.dtb rk3288-tinker-s.dtb' 39 | break 40 | ;; 41 | pine64,rock64) 42 | OVERLAY_MODE='patch' 43 | INCLUDE_FILE='/var/lib/piVCCU/dts/rock64.dts.include' 44 | FDT_FILE='rockchip/rk3328-rock64.dtb' 45 | break 46 | ;; 47 | pine64,rockpro64) 48 | OVERLAY_MODE='patch' 49 | INCLUDE_FILE='/var/lib/piVCCU/dts/rockpro64.dts.include' 50 | FDT_FILE='rockchip/rk3399-rockpro64.dtb' 51 | break 52 | ;; 53 | hardkernel,odroid-c2) 54 | OVERLAY_MODE='patch' 55 | INCLUDE_FILE='/var/lib/piVCCU/dts/odroidc2.dts.include' 56 | FDT_FILE='amlogic/meson-gxbb-odroidc2.dtb' 57 | break 58 | ;; 59 | hardkernel,odroid-c4) 60 | OVERLAY_MODE='patch' 61 | INCLUDE_FILE='/var/lib/piVCCU/dts/odroidc4.dts.include' 62 | FDT_FILE='amlogic/meson-sm1-odroid-c4.dtb' 63 | break 64 | ;; 65 | libretech,cc|libretech,aml-s905x-cc) 66 | OVERLAY_MODE='patch' 67 | INCLUDE_FILE='/var/lib/piVCCU/dts/lepotato.dts.include' 68 | FDT_FILE='amlogic/meson-gxl-s905x-libretech-cc.dtb' 69 | break 70 | ;; 71 | friendlyelec,nanopc-t4|friendlyarm,nanopc-t4) 72 | OVERLAY_MODE='patch' 73 | INCLUDE_FILE='/var/lib/piVCCU/dts/nanopct4.dts.include' 74 | FDT_FILE='rockchip/rk3399-nanopc-t4.dtb' 75 | break 76 | ;; 77 | friendlyelec,nanopi-m4|friendlyarm,nanopi-m4) 78 | OVERLAY_MODE='patch' 79 | INCLUDE_FILE='/var/lib/piVCCU/dts/nanopim4.dts.include' 80 | FDT_FILE='rockchip/rk3399-nanopi-m4.dtb' 81 | break 82 | ;; 83 | radxa,rockpi4) 84 | OVERLAY_MODE='patch' 85 | INCLUDE_FILE='/var/lib/piVCCU/dts/rockpi4.dts.include' 86 | FDT_FILE='rockchip/rk3399-rock-pi-4.dtb' 87 | break 88 | ;; 89 | esac 90 | done 91 | fi 92 | 93 | case "$OVERLAY_MODE" in 94 | patch) 95 | CONFIG_FDT_FILE=`grep -e '^fdt_file=' /boot/armbianEnv.txt | cut -d= -f2` 96 | if [ ! -z "$CONFIG_FDT_FILE" ]; then 97 | FDT_FILE=$CONFIG_FDT_FILE 98 | fi 99 | 100 | CONFIG_FDT_FILE=`grep -e '^fdtfile=' /boot/armbianEnv.txt | cut -d= -f2` 101 | if [ ! -z "$CONFIG_FDT_FILE" ]; then 102 | FDT_FILE=$CONFIG_FDT_FILE 103 | fi 104 | 105 | if [ -z "$FDT_FILE" ]; then 106 | echo "piVCCU: Error! Current FDT could not be determined" 107 | exit 108 | fi 109 | 110 | if [ -z "$INCLUDE_FILE" ]; then 111 | echo "piVCCU: Error! Hardware platform is not supported" 112 | exit 113 | fi 114 | ;; 115 | 116 | overlay) 117 | if [ -z "$OVERLAY_FILE" ]; then 118 | echo "piVCCU: Error! Hardware platform is not supported" 119 | exit 120 | fi 121 | OVERLAY=`basename "$OVERLAY_FILE" .dtbo` 122 | ;; 123 | 124 | *) 125 | echo "piVCCU: Error! Hardware platform is not supported" 126 | exit 127 | ;; 128 | esac 129 | -------------------------------------------------------------------------------- /dts/armbian/patch_dts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $(dirname $0)/detect_board.inc 4 | 5 | case "$OVERLAY_MODE" in 6 | patch) 7 | TMP_DIR=`mktemp -d` 8 | for FILE in $FDT_FILE; do 9 | if [ -e /boot/dtb/$FILE ]; then 10 | dtc -I dtb -O dts -q -o $TMP_DIR/devicetree.dts /boot/dtb/$FILE 11 | 12 | if [ `grep -c -e 'compatible = "pivccu,' $TMP_DIR/devicetree.dts` -eq 0 ]; then 13 | echo "piVCCU: Patching DTB $FILE" 14 | cp /boot/dtb/$FILE /boot/dtb/$FILE.bak 15 | cat $INCLUDE_FILE >> $TMP_DIR/devicetree.dts 16 | dtc -I dts -O dtb -q -o $TMP_DIR/devicetree.dtb $TMP_DIR/devicetree.dts 17 | cp $TMP_DIR/devicetree.dtb /boot/dtb/$FILE 18 | else 19 | echo "piVCCU: DTB $FILE was already patched" 20 | fi 21 | 22 | rm $TMP_DIR/devicetree.dts 23 | fi 24 | done 25 | 26 | rm -rf $TMP_DIR 27 | ;; 28 | overlay) 29 | if [ `grep -c "^user_overlays=" /boot/armbianEnv.txt` -eq 0 ]; then 30 | echo "user_overlays=$OVERLAY" >> /boot/armbianEnv.txt 31 | elif [ `grep -c "^user_overlays=.*$OVERLAY.*" /boot/armbianEnv.txt` -eq 0 ]; then 32 | sed -i "s/^user_overlays=/user_overlays=$OVERLAY /" /boot/armbianEnv.txt 33 | fi 34 | ;; 35 | esac 36 | 37 | -------------------------------------------------------------------------------- /dts/armbian/revert_dts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source $(dirname $0)/detect_board.inc 3 | 4 | case "$OVERLAY_MODE" in 5 | patch) 6 | for FILE in $FDT_FILE; do 7 | if [ -e /boot/dtb/$FILE ]; then 8 | if [ -e /boot/dtb/$FILE.bak ]; then 9 | cp /boot/dtb/$FILE.bak /boot/dtb/$FILE 10 | else 11 | echo "piVCCU: Error! Could not find backup file of $FILE, cannot revert" 12 | exit 13 | fi 14 | fi 15 | done 16 | ;; 17 | overlay) 18 | sed -i "s/^\(user_overlays=.*\)$OVERLAY\(.*\)/\1\2/" /boot/armbianEnv.txt 19 | sed -i "/^user_overlays=\s*$/d" /boot/armbianEnv.txt 20 | ;; 21 | esac 22 | 23 | -------------------------------------------------------------------------------- /dts/lepotato.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | soc { 3 | bus@c8100000 { 4 | pinctrl@14 { 5 | pivccu_gpio_ao: bank@14 { 6 | }; 7 | pivccu_i2c_ao: i2c_ao { 8 | }; 9 | }; 10 | 11 | i2c@500 { 12 | status = "okay"; 13 | pinctrl-0 = <&pivccu_i2c_ao>; 14 | pinctrl-names = "default"; 15 | 16 | rpi_rf_mod_rtc: rx8130@32 { 17 | compatible = "epson,rx8130-legacy"; 18 | reg = <0x32>; 19 | status = "okay"; 20 | aux-voltage-chargeable = <1>; 21 | enable-external-capacitor; 22 | }; 23 | }; 24 | }; 25 | 26 | bus@c8834000 { 27 | pinctrl@4b0 { 28 | pivccu_gpio: bank@4b0 { 29 | }; 30 | pivccu_uart_a_pins: uart_a { 31 | }; 32 | }; 33 | }; 34 | 35 | bus@c1100000 { 36 | serial@84c0 { 37 | pinctrl-names = "default"; 38 | pinctrl-0 = <&pivccu_uart_a_pins>; 39 | status = "okay"; 40 | compatible = "pivccu,meson"; 41 | pivccu,reset-gpios = <&pivccu_gpio_ao 6 0>, <&pivccu_gpio 86 0>; 42 | pivccu,led-gpios = <&pivccu_gpio 81 0>, <&pivccu_gpio 82 0>, <&pivccu_gpio 83 0>; 43 | pivccu,rtc = <&rpi_rf_mod_rtc>; 44 | }; 45 | }; 46 | }; 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /dts/nanopct4.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | serial@ff1a0000 { 3 | compatible = "pivccu,dw_apb"; 4 | pinctrl-0 = <&pivccu_uart2b_xfer>; 5 | pivccu,reset-gpios = <&pivccu_gpio1 18 0>, <&pivccu_gpio4 6 0>; 6 | pivccu,led-gpios = <&pivccu_gpio4 7 0>, <&pivccu_gpio3 29 0>, <&pivccu_gpio3 30 0>; 7 | pivccu,rtc = <&rpi_rf_mod_rtc>; 8 | }; 9 | 10 | pinctrl { 11 | pivccu_gpio1: gpio1@ff730000 { 12 | }; 13 | pivccu_gpio3: gpio3@ff788000 { 14 | }; 15 | pivccu_gpio4: gpio4@ff790000 { 16 | }; 17 | uart2b { 18 | pivccu_uart2b_xfer: uart2b-xfer { 19 | }; 20 | }; 21 | }; 22 | 23 | i2c@ff120000 { 24 | status = "okay"; 25 | 26 | rpi_rf_mod_rtc: rx8130@32 { 27 | compatible = "epson,rx8130-legacy"; 28 | reg = <0x32>; 29 | status = "okay"; 30 | aux-voltage-chargeable = <1>; 31 | enable-external-capacitor; 32 | }; 33 | }; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /dts/nanopim4.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | serial@ff1a0000 { 3 | compatible = "pivccu,dw_apb"; 4 | pinctrl-0 = <&pivccu_uart2b_xfer>; 5 | pivccu,reset-gpios = <&pivccu_gpio1 18 0>, <&pivccu_gpio3 27 0>; 6 | pivccu,led-gpios = <&pivccu_gpio3 31 0>, <&pivccu_gpio3 29 0>, <&pivccu_gpio3 30 0>; 7 | pivccu,rtc = <&rpi_rf_mod_rtc>; 8 | }; 9 | 10 | pinctrl { 11 | pivccu_gpio1: gpio1@ff730000 { 12 | }; 13 | pivccu_gpio3: gpio3@ff788000 { 14 | }; 15 | uart2b { 16 | pivccu_uart2b_xfer: uart2b-xfer { 17 | }; 18 | }; 19 | }; 20 | 21 | i2c@ff120000 { 22 | status = "okay"; 23 | 24 | rpi_rf_mod_rtc: rx8130@32 { 25 | compatible = "epson,rx8130-legacy"; 26 | reg = <0x32>; 27 | status = "okay"; 28 | aux-voltage-chargeable = <1>; 29 | enable-external-capacitor; 30 | }; 31 | }; 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /dts/odroidc2.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | soc { 3 | bus@c8834000 { 4 | pinctrl@4b0 { 5 | pivccu_gpio: bank@4b0 { 6 | }; 7 | pivccu_uart_a_pins: uart_a { 8 | }; 9 | }; 10 | }; 11 | 12 | bus@c1100000 { 13 | serial@84c0 { 14 | pinctrl-names = "default"; 15 | pinctrl-0 = <&pivccu_uart_a_pins>; 16 | status = "okay"; 17 | compatible = "pivccu,meson"; 18 | pivccu,reset-gpios = <&pivccu_gpio 102 0>, <&pivccu_gpio 78 0>; 19 | pivccu,rtc = <&rpi_rf_mod_rtc>; 20 | }; 21 | 22 | i2c@8500 { 23 | status = "okay"; 24 | 25 | rpi_rf_mod_rtc: rx8130@32 { 26 | compatible = "epson,rx8130-legacy"; 27 | reg = <0x32>; 28 | status = "okay"; 29 | aux-voltage-chargeable = <1>; 30 | enable-external-capacitor; 31 | }; 32 | }; 33 | }; 34 | }; 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /dts/odroidc4.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | soc { 3 | bus@ff600000 { 4 | bus@34400 { 5 | pinctrl@40 { 6 | pivccu_gpio: bank@40 { 7 | }; 8 | pivccu_uart_a_pins: uart-a { 9 | }; 10 | }; 11 | }; 12 | }; 13 | 14 | bus@ffd00000 { 15 | serial@24000 { 16 | pinctrl-0 = <&pivccu_uart_a_pins>; 17 | pinctrl-names = "default"; 18 | status = "okay"; 19 | compatible = "pivccu,meson"; 20 | pivccu,reset-gpios = <&pivccu_gpio 81 0>, <&pivccu_gpio 84 0>; 21 | pivccu,rtc = <&rpi_rf_mod_rtc>; 22 | }; 23 | 24 | i2c@1d000 { 25 | status = "okay"; 26 | 27 | rpi_rf_mod_rtc: rx8130@32 { 28 | compatible = "epson,rx8130-legacy"; 29 | reg = <0x32>; 30 | status = "okay"; 31 | aux-voltage-chargeable = <1>; 32 | enable-external-capacitor; 33 | }; 34 | }; 35 | }; 36 | }; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /dts/pivccu-bananapi-m1.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "allwinner,sun7i-a20"; 6 | 7 | fragment@0 { 8 | target = <&uart3>; 9 | __overlay__ { 10 | status = "okay"; 11 | compatible = "pivccu,dw_apb"; 12 | pivccu,reset-gpios = <&pio 7 2 0>; 13 | pivccu,rtc = <&rpi_rf_mod_rtc>; 14 | }; 15 | }; 16 | 17 | fragment@1 { 18 | target = <&i2c2>; 19 | __overlay__ { 20 | #address-cells = <1>; 21 | #size-cells = <0>; 22 | status = "okay"; 23 | 24 | rpi_rf_mod_rtc: rx8130@32 { 25 | compatible = "epson,rx8130-legacy"; 26 | reg = <0x32>; 27 | status = "okay"; 28 | aux-voltage-chargeable = <1>; 29 | enable-external-capacitor; 30 | }; 31 | }; 32 | }; 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /dts/pivccu-bananapi-pro.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "allwinner,sun7i-a20"; 6 | 7 | fragment@0 { 8 | target = <&uart4>; 9 | __overlay__ { 10 | status = "okay"; 11 | compatible = "pivccu,dw_apb"; 12 | pivccu,reset-gpios = <&pio 8 3 0>, <&pio 1 7 0>; 13 | pivccu,led-gpios = <&pio 1 6 0>, <&pio 1 12 0>, <&pio 1 8 0>; 14 | pivccu,rtc = <&rpi_rf_mod_rtc>; 15 | }; 16 | }; 17 | 18 | fragment@1 { 19 | target = <&i2c2>; 20 | __overlay__ { 21 | #address-cells = <1>; 22 | #size-cells = <0>; 23 | status = "okay"; 24 | 25 | rpi_rf_mod_rtc: rx8130@32 { 26 | compatible = "epson,rx8130-legacy"; 27 | reg = <0x32>; 28 | status = "okay"; 29 | aux-voltage-chargeable = <1>; 30 | enable-external-capacitor; 31 | }; 32 | }; 33 | }; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /dts/pivccu-orangepi-h2plus.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "allwinner,sun8i-h2-plus"; 6 | 7 | fragment@0 { 8 | target = <&uart1>; 9 | __overlay__ { 10 | pinctrl-names = "default"; 11 | pinctrl-0 = <&uart1_pins>; 12 | status = "okay"; 13 | compatible = "pivccu,dw_apb"; 14 | pivccu,reset-gpios = <&pio 0 7 0>; 15 | pivccu,rtc = <&rpi_rf_mod_rtc>; 16 | }; 17 | }; 18 | 19 | fragment@1 { 20 | target = <&i2c0>; 21 | __overlay__ { 22 | #address-cells = <1>; 23 | #size-cells = <0>; 24 | status = "okay"; 25 | 26 | rpi_rf_mod_rtc: rx8130@32 { 27 | compatible = "epson,rx8130-legacy"; 28 | reg = <0x32>; 29 | status = "okay"; 30 | aux-voltage-chargeable = <1>; 31 | enable-external-capacitor; 32 | }; 33 | }; 34 | }; 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /dts/pivccu-orangepi-h3.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "allwinner,sun8i-h3"; 6 | 7 | fragment@0 { 8 | target = <&uart3>; 9 | __overlay__ { 10 | pinctrl-names = "default"; 11 | pinctrl-0 = <&uart3_pins>; 12 | status = "okay"; 13 | compatible = "pivccu,dw_apb"; 14 | pivccu,reset-gpios = <&pio 3 14 0>, <&pio 0 10 0>; 15 | pivccu,led-gpios = <&pio 6 9 0>, <&pio 6 6 0>, <&pio 6 7 0>; 16 | pivccu,rtc = <&rpi_rf_mod_rtc>; 17 | }; 18 | }; 19 | 20 | 21 | fragment@1 { 22 | target = <&i2c0>; 23 | __overlay__ { 24 | #address-cells = <1>; 25 | #size-cells = <0>; 26 | status = "okay"; 27 | 28 | rpi_rf_mod_rtc: rx8130@32 { 29 | compatible = "epson,rx8130-legacy"; 30 | reg = <0x32>; 31 | status = "okay"; 32 | aux-voltage-chargeable = <1>; 33 | enable-external-capacitor; 34 | }; 35 | }; 36 | }; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /dts/pivccu-orangepi-h5.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "allwinner,sun50i-h5"; 6 | 7 | fragment@0 { 8 | target = <&uart1>; 9 | __overlay__ { 10 | pinctrl-names = "default"; 11 | pinctrl-0 = <&uart1_pins>; 12 | status = "okay"; 13 | compatible = "pivccu,dw_apb"; 14 | pivccu,reset-gpios = <&pio 0 7 0>; 15 | pivccu,rtc = <&rpi_rf_mod_rtc>; 16 | }; 17 | }; 18 | 19 | fragment@1 { 20 | target = <&i2c0>; 21 | __overlay__ { 22 | #address-cells = <1>; 23 | #size-cells = <0>; 24 | status = "okay"; 25 | 26 | rpi_rf_mod_rtc: rx8130@32 { 27 | compatible = "epson,rx8130-legacy"; 28 | reg = <0x32>; 29 | status = "okay"; 30 | aux-voltage-chargeable = <1>; 31 | enable-external-capacitor; 32 | }; 33 | }; 34 | }; 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /dts/pivccu-raspberrypi.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "brcm,bcm2708"; 6 | 7 | fragment@0 { 8 | target = <&uart0>; 9 | __overlay__ { 10 | compatible = "pivccu,pl011"; 11 | status = "okay"; 12 | pivccu,reset-gpios = <&gpio 18 0>, <&gpio 19 0>; 13 | pivccu,led-gpios = <&gpio 16 0>, <&gpio 20 0>, <&gpio 21 0>; 14 | pivccu,rtc = <&rpi_rf_mod_rtc>; 15 | }; 16 | }; 17 | 18 | fragment@1 { 19 | target = <&i2c1>; 20 | __overlay__ { 21 | #address-cells = <1>; 22 | #size-cells = <0>; 23 | status = "okay"; 24 | 25 | rpi_rf_mod_rtc: rx8130@32 { 26 | compatible = "epson,rx8130-legacy"; 27 | reg = <0x32>; 28 | status = "okay"; 29 | aux-voltage-chargeable = <1>; 30 | enable-external-capacitor; 31 | }; 32 | }; 33 | }; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /dts/rock64.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | serial@ff130000 { 3 | compatible = "pivccu,dw_apb"; 4 | pivccu,reset-gpios = <&pivccu_gpio2 3 0>; 5 | pivccu,rtc = <&rpi_rf_mod_rtc>; 6 | }; 7 | 8 | pinctrl { 9 | pivccu_gpio2: gpio2@ff230000 { 10 | }; 11 | }; 12 | 13 | i2c@ff150000 { 14 | status = "okay"; 15 | 16 | rpi_rf_mod_rtc: rx8130@32 { 17 | compatible = "epson,rx8130-legacy"; 18 | reg = <0x32>; 19 | status = "okay"; 20 | aux-voltage-chargeable = <1>; 21 | enable-external-capacitor; 22 | }; 23 | }; 24 | 25 | chosen { 26 | stdout-path = ""; 27 | bootargs = ""; 28 | }; 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /dts/rockpi4.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | serial@ff1a0000 { 3 | compatible = "pivccu,dw_apb"; 4 | pivccu,reset-gpios = <&pivccu_gpio4 3 0>, <&pivccu_gpio4 5 0>; 5 | pivccu,led-gpios = <&pivccu_gpio4 4 0>, <&pivccu_gpio4 6 0>, <&pivccu_gpio4 7 0>; 6 | pinctrl-0 = <&pivccu_uart2c_xfer>; 7 | }; 8 | 9 | pinctrl { 10 | pivccu_gpio4: gpio4@ff790000 { 11 | }; 12 | uart2c { 13 | pivccu_uart2c_xfer: uart2c-xfer { 14 | }; 15 | }; 16 | }; 17 | 18 | i2c@ff160000 { 19 | status = "okay"; 20 | 21 | rx8130@32 { 22 | compatible = "epson,rx8130-legacy"; 23 | reg = <0x32>; 24 | status = "okay"; 25 | enable-external-capacitor; 26 | }; 27 | }; 28 | 29 | chosen { 30 | stdout-path = ""; 31 | bootargs = ""; 32 | }; 33 | 34 | i2s@ff890000 { 35 | status = "disabled"; 36 | }; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /dts/rockpro64.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | serial@ff1a0000 { 3 | compatible = "pivccu,dw_apb"; 4 | pinctrl-0 = <&pivccu_uart2c_xfer>; 5 | pivccu,reset-gpios = <&pivccu_gpio3 24 0>, <&pivccu_gpio3 26 0>; 6 | pivccu,led-gpios = <&pivccu_gpio3 30 0>, <&pivccu_gpio3 27 0>, <&pivccu_gpio3 31 0>; 7 | pivccu,rtc = <&rpi_rf_mod_rtc>; 8 | }; 9 | 10 | pinctrl { 11 | pivccu_gpio3: gpio3@ff788000 { 12 | }; 13 | uart2c { 14 | pivccu_uart2c_xfer: uart2c-xfer { 15 | }; 16 | }; 17 | }; 18 | 19 | i2c@ff3e0000 { 20 | status = "okay"; 21 | 22 | rpi_rf_mod_rtc: rx8130@32 { 23 | compatible = "epson,rx8130-legacy"; 24 | reg = <0x32>; 25 | status = "okay"; 26 | aux-voltage-chargeable = <1>; 27 | enable-external-capacitor; 28 | }; 29 | }; 30 | 31 | chosen { 32 | stdout-path = "mmc_cmdqueue=0"; 33 | bootargs = ""; 34 | }; 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /dts/tinkerboard.dts.include: -------------------------------------------------------------------------------- 1 | / { 2 | pinctrl { 3 | pivccu_gpio6: gpio6@ff7d0000 { 4 | }; 5 | pivccu_gpio7: gpio7@ff7e0000 { 6 | }; 7 | }; 8 | 9 | serial@ff190000 { 10 | compatible = "pivccu,dw_apb"; 11 | status = "okay"; 12 | pivccu,reset-gpios = <&pivccu_gpio6 0 0>, <&pivccu_gpio6 1 0>; 13 | pivccu,led-gpios = <&pivccu_gpio7 7 0>, <&pivccu_gpio6 3 0>, <&pivccu_gpio6 4 0>; 14 | pivccu,rtc = <&rpi_rf_mod_rtc>; 15 | }; 16 | 17 | i2c@ff140000 { 18 | status = "okay"; 19 | 20 | rpi_rf_mod_rtc: rx8130@32 { 21 | compatible = "epson,rx8130-legacy"; 22 | reg = <0x32>; 23 | status = "okay"; 24 | aux-voltage-chargeable = <1>; 25 | enable-external-capacitor; 26 | }; 27 | }; 28 | 29 | i2s@ff890000 { 30 | status = "disabled"; 31 | }; 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += eq3_char_loop.o 2 | obj-m += plat_eq3ccu2.o 3 | obj-m += generic_raw_uart.o 4 | obj-m += pl011_raw_uart.o 5 | obj-m += dw_apb_raw_uart.o 6 | obj-m += meson_raw_uart.o 7 | obj-m += fake_hmrf.o 8 | obj-m += rpi_rf_mod_led.o 9 | obj-m += dummy_rx8130.o 10 | obj-m += led_trigger_timer.o 11 | obj-m += hb_rf_usb.o 12 | obj-m += hb_rf_usb_2.o 13 | obj-m += hb_rf_eth.o 14 | obj-m += rtc-rx8130.o 15 | 16 | ifeq ($(KERNELRELEASE),) 17 | KERNELRELEASE := $(shell uname -r) 18 | endif 19 | 20 | ifeq ($(KERNEL_DIR),) 21 | KERNEL_DIR := /lib/modules/$(KERNELRELEASE)/build 22 | endif 23 | 24 | include $(KERNEL_DIR)/scripts/Kbuild.include 25 | ifeq ($(call cc-option-yn,-mstack-protector-guard=sysreg -mstack-protector-guard-reg=sp_el0 -mstack-protector-guard-offset=0),n) 26 | KBUILD_CFLAGS += -DPIVCCU_CC_HAS_NO_STACKPROTECTOR_SYSREG 27 | endif 28 | 29 | all: 30 | $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules 31 | 32 | clean: 33 | $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean 34 | 35 | -------------------------------------------------------------------------------- /kernel/dummy_rx8130.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "stack_protector.include" 6 | 7 | static int __init dummy_rx8130_init(void) 8 | { 9 | return 0; 10 | } 11 | 12 | static void __exit dummy_rx8130_exit(void) 13 | { 14 | } 15 | 16 | module_init(dummy_rx8130_init); 17 | module_exit(dummy_rx8130_exit); 18 | 19 | MODULE_AUTHOR("Alexander Reinert "); 20 | MODULE_DESCRIPTION("Dummy Module to trick the hss_led"); 21 | MODULE_VERSION("1.1"); 22 | MODULE_LICENSE("GPL"); 23 | MODULE_ALIAS("dummy_rx8130"); 24 | -------------------------------------------------------------------------------- /kernel/generic_raw_uart.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Copyright (c) 2025 by Alexander Reinert 3 | * Author: Alexander Reinert 4 | * Uses parts of bcm2835_raw_uart.c. (c) 2015 by eQ-3 Entwicklung GmbH 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | *---------------------------------------------------------------------------*/ 20 | #include 21 | 22 | #define BAUD 115200 23 | 24 | #define MAX_DEVICE_TYPE_LEN 64 25 | 26 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,4,0)) 27 | #define class_create(__owner, __class) class_create(__class) 28 | #define of_modalias_node(__node, __alias, __len) of_alias_from_compatible(__node, __alias, __len) 29 | #endif 30 | 31 | enum generic_raw_uart_rx_flags 32 | { 33 | GENERIC_RAW_UART_RX_STATE_NONE = 0, 34 | GENERIC_RAW_UART_RX_STATE_BREAK = 1, 35 | GENERIC_RAW_UART_RX_STATE_PARITY = 2, 36 | GENERIC_RAW_UART_RX_STATE_FRAME = 4, 37 | GENERIC_RAW_UART_RX_STATE_OVERRUN = 8, 38 | }; 39 | 40 | enum generic_raw_uart_led 41 | { 42 | GENERIC_RAW_UART_LED_RED = 0, 43 | GENERIC_RAW_UART_LED_GREEN = 1, 44 | GENERIC_RAW_UART_LED_BLUE = 2, 45 | }; 46 | 47 | struct generic_raw_uart 48 | { 49 | void *private; 50 | void *driver_data; 51 | int dev_number; 52 | }; 53 | 54 | struct raw_uart_driver 55 | { 56 | struct module *owner; 57 | 58 | int (*start_connection)(struct generic_raw_uart *raw_uart); 59 | void (*stop_connection)(struct generic_raw_uart *raw_uart); 60 | 61 | void (*init_tx)(struct generic_raw_uart *raw_uart); 62 | bool (*isready_for_tx)(struct generic_raw_uart *raw_uart); 63 | void (*tx_chars)(struct generic_raw_uart *raw_uart, unsigned char *chr, int index, int len); 64 | void (*stop_tx)(struct generic_raw_uart *raw_uart); 65 | 66 | int (*get_led_gpio_index)(struct generic_raw_uart *raw_uart, enum generic_raw_uart_led); 67 | int (*reset_radio_module)(struct generic_raw_uart *raw_uart); 68 | 69 | int tx_chunk_size; 70 | int tx_bulktransfer_size; 71 | 72 | int (*get_device_type)(struct generic_raw_uart *raw_uart, char *page); 73 | }; 74 | 75 | struct hb_usb_device_info 76 | { 77 | uint32_t vendorhash; 78 | uint32_t pkey[16]; 79 | bool enforce_verification; 80 | }; 81 | 82 | #define HB_DEV_KEY(...) __VA_ARGS__ 83 | #define HB_USB_DEVICE(_vend, _prod, _vendorhash, _enforce_verification, _pkey) \ 84 | USB_DEVICE((_vend), (_prod)), \ 85 | .driver_info = (kernel_ulong_t)&((struct hb_usb_device_info) { .vendorhash = (_vendorhash), .enforce_verification = _enforce_verification, .pkey = { HB_DEV_KEY _pkey } } ) 86 | 87 | extern struct generic_raw_uart *generic_raw_uart_probe(struct device *dev, struct raw_uart_driver *driver, void *driver_data); 88 | extern int generic_raw_uart_set_connection_state(struct generic_raw_uart *raw_uart, bool state); 89 | extern int generic_raw_uart_remove(struct generic_raw_uart *raw_uart); 90 | extern void generic_raw_uart_tx_queued(struct generic_raw_uart *raw_uart); 91 | extern void generic_raw_uart_handle_rx_char(struct generic_raw_uart *raw_uart, enum generic_raw_uart_rx_flags, unsigned char); 92 | extern void generic_raw_uart_rx_completed(struct generic_raw_uart *raw_uart); 93 | 94 | extern bool generic_raw_uart_verify_dkey(struct device *dev, unsigned char *dkey, int dkey_len, unsigned char *skey, uint32_t *pkey, int bytes); 95 | 96 | 97 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0)) 98 | #define module_raw_uart_driver(__module_name, __raw_uart_driver, __of_match) module_raw_uart_driver_int(__module_name, __raw_uart_driver, __of_match, ge611) 99 | #else 100 | #define module_raw_uart_driver(__module_name, __raw_uart_driver, __of_match) module_raw_uart_driver_int(__module_name, __raw_uart_driver, __of_match, le610) 101 | #endif 102 | 103 | #define module_raw_uart_driver_int(__module_name, __raw_uart_driver, __of_match, __remove_variant) \ 104 | static struct generic_raw_uart *__raw_uart_driver##_raw_uart; \ 105 | static int __##__raw_uart_driver##_probe(struct platform_device *pdev) \ 106 | { \ 107 | struct device *dev = &pdev->dev; \ 108 | int err = __raw_uart_driver##_probe(pdev); \ 109 | \ 110 | if (err) \ 111 | { \ 112 | dev_err(dev, "failed to initialize generic_raw_uart module"); \ 113 | return err; \ 114 | } \ 115 | \ 116 | __raw_uart_driver##_raw_uart = generic_raw_uart_probe(dev, &__raw_uart_driver, NULL); \ 117 | if (IS_ERR_OR_NULL(__raw_uart_driver##_raw_uart)) \ 118 | { \ 119 | dev_err(dev, "failed to initialize generic_raw_uart module"); \ 120 | return PTR_ERR(__raw_uart_driver##_raw_uart); \ 121 | } \ 122 | \ 123 | return 0; \ 124 | } \ 125 | \ 126 | static int __##__raw_uart_driver##_remove_le610(struct platform_device *pdev) \ 127 | { \ 128 | int err; \ 129 | struct device *dev = &pdev->dev; \ 130 | \ 131 | err = generic_raw_uart_remove(__raw_uart_driver##_raw_uart); \ 132 | if (err) \ 133 | { \ 134 | dev_err(dev, "failed to remove generic_raw_uart module"); \ 135 | return err; \ 136 | } \ 137 | \ 138 | return __raw_uart_driver##_remove(pdev); \ 139 | } \ 140 | \ 141 | static void __##__raw_uart_driver##_remove_ge611(struct platform_device *pdev) \ 142 | { \ 143 | __##__raw_uart_driver##_remove_le610(pdev); \ 144 | } \ 145 | \ 146 | static struct platform_driver __raw_uart_driver_platform_driver = { \ 147 | .probe = __##__raw_uart_driver##_probe, \ 148 | .remove = __##__raw_uart_driver##_remove_##__remove_variant, \ 149 | .driver = { \ 150 | .owner = THIS_MODULE, \ 151 | .name = __module_name, \ 152 | .of_match_table = __of_match, \ 153 | }, \ 154 | }; \ 155 | \ 156 | module_platform_driver(__raw_uart_driver_platform_driver); \ 157 | MODULE_DEVICE_TABLE(of, __of_match); 158 | -------------------------------------------------------------------------------- /kernel/hm.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Copyright (c) 2023 by Alexander Reinert 3 | * Author: Alexander Reinert 4 | * Uses parts of bcm2835_raw_uart.c. (c) 2015 by eQ-3 Entwicklung GmbH 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | *---------------------------------------------------------------------------*/ 20 | enum hm_dst 21 | { 22 | HM_DST_SYSTEM = 0x00, 23 | HM_DST_TRX = 0x01, 24 | HM_DST_HMIP = 0x02, 25 | HM_DST_LLMAC = 0x03, 26 | HM_DST_COMMON = 0xfe, 27 | }; 28 | 29 | enum hm_system_cmd 30 | { 31 | HM_SYSTEM_IDENTIFY = 0x00, 32 | HM_SYSTEM_START_APP = 0x03, 33 | }; 34 | 35 | enum hm_trx_cmd 36 | { 37 | HM_TRX_GET_VERSION = 0x02, 38 | HM_TRX_GET_DUTYCYCLE = 0x03, 39 | HM_TRX_SET_DCUTYCYCLE_LIMIT = 0x07, 40 | HM_TRX_GET_MCU_TYPE = 0x09, 41 | }; 42 | 43 | enum hm_llmac_cmd 44 | { 45 | HM_LLMAC_GET_TIMESTAMP = 0x02, 46 | HM_LLMAC_RFD_INIT = 0x06, 47 | HM_LLMAC_GET_SERIAL = 0x07, 48 | HM_LLMAC_GET_DEFAULT_RF_ADDR = 0x08, 49 | }; 50 | 51 | enum hm_common_cmd 52 | { 53 | HM_COMMON_IDENTIFY = 0x01, 54 | HM_COMMON_START_BL = 0x02, 55 | HM_COMMON_GET_SGTIN = 0x04, 56 | }; 57 | 58 | enum hm_hmip_cmd 59 | { 60 | HM_HMIP_SET_RADIO_ADDR = 0x00, 61 | HM_HMIP_GET_DEFAULT_RF_ADDR = 0x01, 62 | HM_HMIP_SEND = 0x03, 63 | HM_HMIP_ADD_LINK_PARTNER = 0x04, 64 | HM_HMIP_GET_SECURITY_COUNTER = 0x0a, 65 | HM_HMIP_SET_SECURITY_COUNTER = 0x08, 66 | HM_HMIP_SET_MAX_SENT_ATTEMPS = 0x0d, 67 | HM_HMIP_GET_LINK_PARTNER = 0x12, 68 | HM_HMIP_GET_NWKEY = 0x13, 69 | HM_HMIP_SET_NWKEY = 0x14, 70 | }; 71 | 72 | static uint16_t hm_crc(unsigned char *buf, size_t len) 73 | { 74 | uint16_t crc = 0xd77f; 75 | int i; 76 | 77 | while (len--) 78 | { 79 | crc ^= *buf++ << 8; 80 | for (i = 0; i < 8; i++) 81 | { 82 | if (crc & 0x8000) 83 | { 84 | crc <<= 1; 85 | crc ^= 0x8005; 86 | } 87 | else 88 | { 89 | crc <<= 1; 90 | } 91 | } 92 | } 93 | 94 | return crc; 95 | } 96 | 97 | struct hm_frame 98 | { 99 | uint8_t dst; 100 | uint8_t cnt; 101 | unsigned char *cmd; 102 | int cmdlen; 103 | }; 104 | 105 | static bool tryParseFrame(unsigned char *buf, size_t len, struct hm_frame *frame) 106 | { 107 | uint16_t crc; 108 | 109 | if (len < 8) 110 | return false; 111 | 112 | if (buf[0] != 0xfd) 113 | return false; 114 | 115 | frame->cmdlen = ((buf[1] << 8) | buf[2]) - 2; 116 | if (frame->cmdlen + 7 != len) 117 | return false; 118 | 119 | crc = (buf[len - 2] << 8) | buf[len - 1]; 120 | if (crc != hm_crc(buf, len - 2)) 121 | return false; 122 | 123 | frame->dst = buf[3]; 124 | frame->cnt = buf[4]; 125 | frame->cmd = &buf[5]; 126 | 127 | return true; 128 | } 129 | 130 | static size_t encodeFrame(unsigned char *buf, size_t len, struct hm_frame *frame) 131 | { 132 | uint16_t crc; 133 | 134 | if (frame->cmdlen + 7 > len) 135 | return -EMSGSIZE; 136 | 137 | buf[0] = 0xfd; 138 | buf[1] = ((frame->cmdlen + 2) >> 8) & 0xff; 139 | buf[2] = (frame->cmdlen + 2) & 0xff; 140 | buf[3] = frame->dst; 141 | buf[4] = frame->cnt; 142 | memcpy(&(buf[5]), frame->cmd, frame->cmdlen); 143 | 144 | crc = hm_crc(buf, frame->cmdlen + 5); 145 | buf[frame->cmdlen + 5] = (crc >> 8) & 0xff; 146 | buf[frame->cmdlen + 6] = crc & 0xff; 147 | 148 | return frame->cmdlen + 7; 149 | } 150 | 151 | static size_t encodeFrameBuffer(unsigned char *src, unsigned char *dst, size_t len) 152 | { 153 | size_t ret = 0; 154 | unsigned char cur; 155 | 156 | while (len--) 157 | { 158 | cur = *src++; 159 | if (cur == 0xfc || (cur == 0xfd && len == 1)) 160 | { 161 | *dst++ = 0xfc; 162 | ret++; 163 | cur &= 0x7f; 164 | } 165 | *dst++ = cur; 166 | ret++; 167 | } 168 | 169 | return ret; 170 | } 171 | 172 | static size_t decodeFrameBuffer(unsigned char *src, unsigned char *dst, size_t len) 173 | { 174 | size_t ret = 0; 175 | unsigned char cur; 176 | 177 | while (len--) 178 | { 179 | cur = *src++; 180 | if (cur == 0xfc) 181 | { 182 | cur = *src++ | 0x80; 183 | len--; 184 | } 185 | *dst++ = cur; 186 | 187 | ret++; 188 | } 189 | 190 | return ret; 191 | } 192 | -------------------------------------------------------------------------------- /kernel/led_trigger_timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LED Kernel Timer Trigger 3 | * 4 | * Copyright 2005-2006 Openedhand Ltd. 5 | * 6 | * Author: Richard Purdie 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | */ 13 | /* This version is a merge of the original linux kernel 14 | * LED Kernel Timer Trigger that could be compiled on kernel 4.14 as well 15 | * as on kernel 4.19 16 | */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "stack_protector.include" 26 | 27 | static ssize_t led_delay_on_show(struct device *dev, 28 | struct device_attribute *attr, char *buf) 29 | { 30 | struct led_classdev *led_cdev = dev_get_drvdata(dev); 31 | 32 | return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); 33 | } 34 | 35 | static ssize_t led_delay_on_store(struct device *dev, 36 | struct device_attribute *attr, const char *buf, size_t size) 37 | { 38 | struct led_classdev *led_cdev = dev_get_drvdata(dev); 39 | unsigned long state; 40 | ssize_t ret = -EINVAL; 41 | 42 | ret = kstrtoul(buf, 10, &state); 43 | if (ret) 44 | return ret; 45 | 46 | led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off); 47 | led_cdev->blink_delay_on = state; 48 | 49 | return size; 50 | } 51 | 52 | static ssize_t led_delay_off_show(struct device *dev, 53 | struct device_attribute *attr, char *buf) 54 | { 55 | struct led_classdev *led_cdev = dev_get_drvdata(dev); 56 | 57 | return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); 58 | } 59 | 60 | static ssize_t led_delay_off_store(struct device *dev, 61 | struct device_attribute *attr, const char *buf, size_t size) 62 | { 63 | struct led_classdev *led_cdev = dev_get_drvdata(dev); 64 | unsigned long state; 65 | ssize_t ret = -EINVAL; 66 | 67 | ret = kstrtoul(buf, 10, &state); 68 | if (ret) 69 | return ret; 70 | 71 | led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state); 72 | led_cdev->blink_delay_off = state; 73 | 74 | return size; 75 | } 76 | 77 | static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 78 | static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); 79 | 80 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)) 81 | static struct attribute *timer_trig_attrs[] = { 82 | &dev_attr_delay_on.attr, 83 | &dev_attr_delay_off.attr, 84 | NULL 85 | }; 86 | ATTRIBUTE_GROUPS(timer_trig); 87 | 88 | static int timer_trig_activate(struct led_classdev *led_cdev) 89 | { 90 | led_blink_set(led_cdev, &led_cdev->blink_delay_on, 91 | &led_cdev->blink_delay_off); 92 | 93 | return 0; 94 | } 95 | 96 | static void timer_trig_deactivate(struct led_classdev *led_cdev) 97 | { 98 | /* Stop blinking */ 99 | led_set_brightness(led_cdev, LED_OFF); 100 | } 101 | 102 | static struct led_trigger timer_led_trigger = { 103 | .name = "timer", 104 | .activate = timer_trig_activate, 105 | .deactivate = timer_trig_deactivate, 106 | .groups = timer_trig_groups, 107 | }; 108 | module_led_trigger(timer_led_trigger); 109 | #else 110 | static void timer_trig_activate(struct led_classdev *led_cdev) 111 | { 112 | int rc; 113 | 114 | led_cdev->trigger_data = NULL; 115 | 116 | rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); 117 | if (rc) 118 | return; 119 | rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); 120 | if (rc) 121 | goto err_out_delayon; 122 | 123 | led_blink_set(led_cdev, &led_cdev->blink_delay_on, 124 | &led_cdev->blink_delay_off); 125 | led_cdev->activated = true; 126 | 127 | return; 128 | 129 | err_out_delayon: 130 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); 131 | } 132 | 133 | static void timer_trig_deactivate(struct led_classdev *led_cdev) 134 | { 135 | if (led_cdev->activated) { 136 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); 137 | device_remove_file(led_cdev->dev, &dev_attr_delay_off); 138 | led_cdev->activated = false; 139 | } 140 | 141 | /* Stop blinking */ 142 | led_set_brightness(led_cdev, LED_OFF); 143 | } 144 | 145 | static struct led_trigger timer_led_trigger = { 146 | .name = "timer", 147 | .activate = timer_trig_activate, 148 | .deactivate = timer_trig_deactivate, 149 | }; 150 | 151 | static int __init timer_trig_init(void) 152 | { 153 | return led_trigger_register(&timer_led_trigger); 154 | } 155 | 156 | static void __exit timer_trig_exit(void) 157 | { 158 | led_trigger_unregister(&timer_led_trigger); 159 | } 160 | 161 | module_init(timer_trig_init); 162 | module_exit(timer_trig_exit); 163 | #endif 164 | 165 | MODULE_AUTHOR("Richard Purdie "); 166 | MODULE_DESCRIPTION("Timer LED trigger"); 167 | MODULE_LICENSE("GPL v2"); 168 | 169 | -------------------------------------------------------------------------------- /kernel/meson_raw_uart.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Copyright (c) 2025 by Alexander Reinert 3 | * Author: Alexander Reinert 4 | * Uses parts of bcm2835_raw_uart.c. (c) 2015 by eQ-3 Entwicklung GmbH 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | *---------------------------------------------------------------------------*/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "generic_raw_uart.h" 37 | 38 | #include "stack_protector.include" 39 | 40 | #define MODULE_NAME "meson_raw_uart" 41 | #define TX_CHUNK_SIZE 11 42 | 43 | #define MESON_WFIFO 0x00 44 | #define MESON_RFIFO 0x04 45 | #define MESON_CONTROL 0x08 46 | #define MESON_STATUS 0x0c 47 | #define MESON_MISC 0x10 48 | #define MESON_REG5 0x14 49 | 50 | #define MESON_TX_FULL BIT(21) 51 | #define MESON_RX_EMPTY BIT(20) 52 | 53 | #define MESON_RX_EN BIT(13) 54 | #define MESON_TX_EN BIT(12) 55 | 56 | #define MESON_TX_INT_EN BIT(28) 57 | #define MESON_RX_INT_EN BIT(27) 58 | 59 | #define MESON_TX_INT_TRESH 8 << 8 /* interrupt on less than 8 chars in tx fifo */ 60 | #define MESON_RX_INT_TRESH 1 /* interrupt on each char */ 61 | 62 | #define MESON_CLEAR_ERROR BIT(24) 63 | #define MESON_PARITY_ERR BIT(16) 64 | #define MESON_FRAME_ERR BIT(17) 65 | #define MESON_OVERRUN_ERR BIT(24) 66 | 67 | #define MESON_BUSY_MASK BIT(25) | BIT(26) 68 | 69 | #define MESON_RX_RST BIT(23) 70 | #define MESON_TX_RST BIT(22) 71 | 72 | static int meson_raw_uart_start_connection(struct generic_raw_uart *raw_uart); 73 | static void meson_raw_uart_stop_connection(struct generic_raw_uart *raw_uart); 74 | static void meson_raw_uart_stop_tx(struct generic_raw_uart *raw_uart); 75 | static bool meson_raw_uart_isready_for_tx(struct generic_raw_uart *raw_uart); 76 | static void meson_raw_uart_tx_chars(struct generic_raw_uart *raw_uart, unsigned char *chr, int index, int len); 77 | static void meson_raw_uart_init_tx(struct generic_raw_uart *raw_uart); 78 | static void meson_raw_uart_rx_chars(struct generic_raw_uart *raw_uart); 79 | static irqreturn_t meson_raw_uart_irq_handle(int irq, void *context); 80 | static int meson_raw_uart_probe(struct platform_device *pdev); 81 | static int meson_raw_uart_remove(struct platform_device *pdev); 82 | 83 | struct meson_port_s 84 | { 85 | struct clk *xtal_clk; 86 | struct clk *pclk_clk; 87 | struct clk *baud_clk; 88 | struct device *dev; 89 | struct reset_control *rst; 90 | unsigned long mapbase; 91 | void __iomem *membase; 92 | unsigned long irq; 93 | }; 94 | 95 | static struct meson_port_s *meson_port; 96 | 97 | static int meson_raw_uart_start_connection(struct generic_raw_uart *raw_uart) 98 | { 99 | int ret = 0; 100 | unsigned long val; 101 | unsigned long clkrate; 102 | 103 | // clear error 104 | val = readl(meson_port->membase + MESON_CONTROL); 105 | val |= MESON_CLEAR_ERROR | MESON_RX_RST | MESON_TX_RST; 106 | writel(val, meson_port->membase + MESON_CONTROL); 107 | val &= ~(MESON_CLEAR_ERROR | MESON_RX_RST | MESON_TX_RST); 108 | writel(val, meson_port->membase + MESON_CONTROL); 109 | 110 | val |= MESON_RX_EN | MESON_TX_EN; 111 | writel(val, meson_port->membase + MESON_CONTROL); 112 | 113 | // 8N1, two wire 114 | val &= ~(0x3f << 16); 115 | val |= BIT(15); 116 | writel(val, meson_port->membase + MESON_CONTROL); 117 | 118 | val |= MESON_RX_INT_EN; 119 | writel(val, meson_port->membase + MESON_CONTROL); 120 | 121 | // set RX and TX interrupt tresholds 122 | writel(MESON_RX_INT_TRESH | MESON_TX_INT_TRESH, meson_port->membase + MESON_MISC); 123 | 124 | // Baudrate 125 | clkrate = clk_get_rate(meson_port->baud_clk); 126 | if (clkrate == 24000000) 127 | { 128 | val = ((clkrate / 3) / BAUD) - 1; 129 | val |= BIT(24); 130 | } 131 | else 132 | { 133 | val = ((clkrate * 10 / (BAUD * 4) + 5) / 10) - 1; 134 | } 135 | val |= BIT(23); 136 | writel(val, meson_port->membase + MESON_REG5); 137 | 138 | /*Register interrupt handler*/ 139 | ret = request_irq(meson_port->irq, meson_raw_uart_irq_handle, 0, dev_name(meson_port->dev), (void *)raw_uart); 140 | if (ret) 141 | { 142 | dev_err(meson_port->dev, "irq could not be registered"); 143 | return ret; 144 | } 145 | 146 | return 0; 147 | } 148 | 149 | static void meson_raw_uart_stop_connection(struct generic_raw_uart *raw_uart) 150 | { 151 | writel(0, meson_port->membase + MESON_CONTROL); /*Disable UART*/ 152 | writel(0, meson_port->membase + MESON_MISC); /*Disable interrupts*/ 153 | 154 | free_irq(meson_port->irq, raw_uart); 155 | } 156 | 157 | static void meson_raw_uart_stop_tx(struct generic_raw_uart *raw_uart) 158 | { 159 | unsigned long control; 160 | 161 | control = readl(meson_port->membase + MESON_CONTROL); 162 | control &= ~MESON_TX_INT_EN; 163 | 164 | writel(control, meson_port->membase + MESON_CONTROL); 165 | } 166 | 167 | static bool meson_raw_uart_isready_for_tx(struct generic_raw_uart *raw_uart) 168 | { 169 | return !(readl(meson_port->membase + MESON_STATUS) & MESON_TX_FULL); 170 | } 171 | 172 | static void meson_raw_uart_tx_chars(struct generic_raw_uart *raw_uart, unsigned char *chr, int index, int len) 173 | { 174 | writel(chr[index], meson_port->membase + MESON_WFIFO); 175 | } 176 | 177 | static void meson_raw_uart_init_tx(struct generic_raw_uart *raw_uart) 178 | { 179 | unsigned long control; 180 | 181 | control = readl(meson_port->membase + MESON_CONTROL); 182 | control |= MESON_TX_INT_EN; 183 | 184 | writel(control, meson_port->membase + MESON_CONTROL); 185 | } 186 | 187 | static void meson_raw_uart_rx_chars(struct generic_raw_uart *raw_uart) 188 | { 189 | unsigned long status; 190 | unsigned long control; 191 | unsigned long data; 192 | enum generic_raw_uart_rx_flags flags = GENERIC_RAW_UART_RX_STATE_NONE; 193 | 194 | while (1) 195 | { 196 | status = readl(meson_port->membase + MESON_STATUS); 197 | 198 | if (status & MESON_RX_EMPTY) 199 | { 200 | break; 201 | } 202 | 203 | data = readl(meson_port->membase + MESON_RFIFO); 204 | 205 | /* Error handling */ 206 | if (status & MESON_PARITY_ERR) 207 | { 208 | flags |= GENERIC_RAW_UART_RX_STATE_PARITY; 209 | } 210 | if (status & MESON_FRAME_ERR) 211 | { 212 | flags |= GENERIC_RAW_UART_RX_STATE_FRAME; 213 | } 214 | if (status & MESON_OVERRUN_ERR) 215 | { 216 | flags |= GENERIC_RAW_UART_RX_STATE_OVERRUN; 217 | } 218 | 219 | if (flags != GENERIC_RAW_UART_RX_STATE_NONE) 220 | { 221 | control = readl(meson_port->membase + MESON_CONTROL); 222 | 223 | control |= MESON_CLEAR_ERROR; 224 | writel(control, meson_port->membase + MESON_CONTROL); 225 | 226 | control &= ~MESON_CLEAR_ERROR; 227 | writel(control, meson_port->membase + MESON_CONTROL); 228 | } 229 | 230 | generic_raw_uart_handle_rx_char(raw_uart, flags, (unsigned char)data); 231 | } 232 | 233 | generic_raw_uart_rx_completed(raw_uart); 234 | } 235 | 236 | static irqreturn_t meson_raw_uart_irq_handle(int irq, void *context) 237 | { 238 | struct generic_raw_uart *raw_uart = context; 239 | 240 | if (!(readl(meson_port->membase + MESON_STATUS) & MESON_RX_EMPTY)) 241 | { 242 | meson_raw_uart_rx_chars(raw_uart); 243 | } 244 | 245 | if (readl(meson_port->membase + MESON_CONTROL) & MESON_TX_INT_EN) 246 | { 247 | if (!(readl(meson_port->membase + MESON_STATUS) & MESON_TX_FULL)) 248 | { 249 | generic_raw_uart_tx_queued(raw_uart); 250 | } 251 | } 252 | 253 | return IRQ_HANDLED; 254 | } 255 | 256 | static struct raw_uart_driver meson_raw_uart = { 257 | .owner = THIS_MODULE, 258 | .start_connection = meson_raw_uart_start_connection, 259 | .stop_connection = meson_raw_uart_stop_connection, 260 | .init_tx = meson_raw_uart_init_tx, 261 | .isready_for_tx = meson_raw_uart_isready_for_tx, 262 | .tx_chars = meson_raw_uart_tx_chars, 263 | .stop_tx = meson_raw_uart_stop_tx, 264 | .tx_chunk_size = TX_CHUNK_SIZE, 265 | .tx_bulktransfer_size = 1, 266 | }; 267 | 268 | static inline struct clk *meson_raw_uart_probe_clk(struct device *dev, const char *id) 269 | { 270 | struct clk *clk = NULL; 271 | int ret; 272 | 273 | clk = devm_clk_get(dev, id); 274 | if (IS_ERR(clk)) 275 | return clk; 276 | 277 | ret = clk_prepare_enable(clk); 278 | if (ret) 279 | return ERR_PTR(ret); 280 | 281 | ret = devm_add_action(dev, (void (*)(void *))clk_disable_unprepare, clk); 282 | if (ret) 283 | clk_disable_unprepare(clk); 284 | 285 | return clk; 286 | } 287 | 288 | static int meson_raw_uart_probe(struct platform_device *pdev) 289 | { 290 | int err; 291 | struct device *dev = &pdev->dev; 292 | struct resource *ioresource; 293 | 294 | /* alloc private resources */ 295 | meson_port = kzalloc(sizeof(struct meson_port_s), GFP_KERNEL); 296 | if (!meson_port) 297 | { 298 | err = -ENOMEM; 299 | goto failed_inst_alloc; 300 | } 301 | 302 | /* Get mapbase and membase */ 303 | ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 304 | if (ioresource) 305 | { 306 | meson_port->mapbase = ioresource->start; 307 | meson_port->membase = ioremap(ioresource->start, resource_size(ioresource)); 308 | } 309 | else 310 | { 311 | dev_err(dev, "failed to get IO resource\n"); 312 | err = -ENOENT; 313 | goto failed_get_resource; 314 | } 315 | 316 | /* get irq */ 317 | meson_port->irq = platform_get_irq(pdev, 0); 318 | if (meson_port->irq <= 0) 319 | { 320 | dev_err(dev, "failed to get irq\n"); 321 | err = -ENOENT; 322 | goto failed_get_resource; 323 | } 324 | 325 | /* get clocks */ 326 | meson_port->pclk_clk = meson_raw_uart_probe_clk(dev, "pclk"); 327 | if (IS_ERR(meson_port->pclk_clk)) 328 | { 329 | dev_err(dev, "failed to get pclk clock\n"); 330 | err = PTR_ERR(meson_port->pclk_clk); 331 | goto failed_get_clock; 332 | } 333 | 334 | meson_port->xtal_clk = meson_raw_uart_probe_clk(dev, "xtal"); 335 | if (IS_ERR(meson_port->xtal_clk)) 336 | { 337 | dev_err(dev, "failed to get xtal clock\n"); 338 | err = PTR_ERR(meson_port->xtal_clk); 339 | goto failed_get_clock; 340 | } 341 | 342 | meson_port->baud_clk = meson_raw_uart_probe_clk(dev, "baud"); 343 | if (IS_ERR(meson_port->baud_clk)) 344 | { 345 | dev_err(dev, "failed to get baud clock\n"); 346 | err = PTR_ERR(meson_port->baud_clk); 347 | goto failed_get_clock; 348 | } 349 | 350 | /* get reset device */ 351 | meson_port->rst = devm_reset_control_get(dev, NULL); 352 | if (!IS_ERR(meson_port->rst)) 353 | { 354 | reset_control_deassert(meson_port->rst); 355 | } 356 | 357 | meson_port->dev = dev; 358 | 359 | dev_info(dev, "Initialized meson device; mapbase=0x%08lx; irq=%lu; clockrate=%lu", meson_port->mapbase, meson_port->irq, clk_get_rate(meson_port->baud_clk)); 360 | 361 | return 0; 362 | 363 | failed_get_clock: 364 | failed_get_resource: 365 | kfree(meson_port); 366 | failed_inst_alloc: 367 | return err; 368 | } 369 | 370 | static int meson_raw_uart_remove(struct platform_device *pdev) 371 | { 372 | kfree(meson_port); 373 | return 0; 374 | } 375 | 376 | static struct of_device_id meson_raw_uart_of_match[] = { 377 | {.compatible = "pivccu,meson"}, 378 | {/* sentinel */}, 379 | }; 380 | 381 | module_raw_uart_driver(MODULE_NAME, meson_raw_uart, meson_raw_uart_of_match); 382 | 383 | MODULE_ALIAS("platform:meson-raw-uart"); 384 | MODULE_LICENSE("GPL"); 385 | MODULE_VERSION("1.8"); 386 | MODULE_DESCRIPTION("MESON raw uart driver for communication of piVCCU with the HM-MOD-RPI-PCB and RPI-RF-MOD radio modules"); 387 | MODULE_AUTHOR("Alexander Reinert "); 388 | -------------------------------------------------------------------------------- /kernel/pl011_raw_uart.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Copyright (c) 2025 by Alexander Reinert 3 | * Author: Alexander Reinert 4 | * Uses parts of bcm2835_raw_uart.c. (c) 2015 by eQ-3 Entwicklung GmbH 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | *---------------------------------------------------------------------------*/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "generic_raw_uart.h" 37 | 38 | #include "stack_protector.include" 39 | 40 | #define MODULE_NAME "pl011_raw_uart" 41 | #define TX_CHUNK_SIZE 11 42 | 43 | static int pl011_raw_uart_start_connection(struct generic_raw_uart *raw_uart); 44 | static void pl011_raw_uart_stop_connection(struct generic_raw_uart *raw_uart); 45 | static void pl011_raw_uart_stop_tx(struct generic_raw_uart *raw_uart); 46 | static bool pl011_raw_uart_isready_for_tx(struct generic_raw_uart *raw_uart); 47 | static void pl011_raw_uart_tx_chars(struct generic_raw_uart *raw_uart, unsigned char *chr, int index, int len); 48 | static void pl011_raw_uart_init_tx(struct generic_raw_uart *raw_uart); 49 | static void pl011_raw_uart_rx_chars(struct generic_raw_uart *raw_uart); 50 | static irqreturn_t pl011_raw_uart_irq_handle(int irq, void *context); 51 | static int pl011_raw_uart_probe(struct platform_device *pdev); 52 | static int pl011_raw_uart_remove(struct platform_device *pdev); 53 | 54 | struct pl011_port_s 55 | { 56 | struct clk *clk; /*System clock assigned to the UART device*/ 57 | struct device *dev; /*System device*/ 58 | unsigned long mapbase; /*physical address of UART registers*/ 59 | void __iomem *membase; /*logical address of UART registers*/ 60 | unsigned long irq; /*interrupt number*/ 61 | }; 62 | 63 | static struct pl011_port_s *pl011_port; 64 | 65 | static int pl011_raw_uart_start_connection(struct generic_raw_uart *raw_uart) 66 | { 67 | int ret = 0; 68 | unsigned int bauddiv; 69 | unsigned long uart_cr; 70 | 71 | /* set baud rate */ 72 | bauddiv = DIV_ROUND_CLOSEST(clk_get_rate(pl011_port->clk) * 4, BAUD); 73 | writel(bauddiv & 0x3f, pl011_port->membase + UART011_FBRD); 74 | writel(bauddiv >> 6, pl011_port->membase + UART011_IBRD); 75 | 76 | /* Ensure interrupts from this UART are masked and cleared */ 77 | writel(0, pl011_port->membase + UART011_IMSC); 78 | writel(0x7ff, pl011_port->membase + UART011_ICR); 79 | 80 | /*Register interrupt handler*/ 81 | ret = request_irq(pl011_port->irq, pl011_raw_uart_irq_handle, IRQF_SHARED, dev_name(pl011_port->dev), raw_uart); 82 | if (ret) 83 | { 84 | dev_err(pl011_port->dev, "irq could not be registered"); 85 | return ret; 86 | } 87 | 88 | /* enable RX and TX, set RX FIFO threshold to lowest and TX FIFO threshold to mid */ 89 | /*If uart is enabled, wait until it is not busy*/ 90 | while ((readl(pl011_port->membase + UART011_CR) & UART01x_CR_UARTEN) && (readl(pl011_port->membase + UART01x_FR) & UART01x_FR_BUSY)) 91 | { 92 | schedule(); 93 | } 94 | 95 | uart_cr = readl(pl011_port->membase + UART011_CR); 96 | uart_cr &= ~(UART011_CR_OUT2 | UART011_CR_OUT1 | UART011_CR_DTR | UART01x_CR_IIRLP | UART01x_CR_SIREN); /*Set all RO bit to 0*/ 97 | 98 | /*Disable UART*/ 99 | uart_cr &= ~(UART01x_CR_UARTEN); 100 | writel(uart_cr, pl011_port->membase + UART011_CR); 101 | 102 | /*Flush fifo*/ 103 | writel(0, pl011_port->membase + UART011_LCRH); 104 | 105 | /*Set RX FIFO threshold to lowest and TX FIFO threshold to mid*/ 106 | writel(UART011_IFLS_RX1_8 | UART011_IFLS_TX2_8, pl011_port->membase + UART011_IFLS); 107 | 108 | /*enable RX and TX*/ 109 | uart_cr |= UART011_CR_RXE | UART011_CR_TXE; 110 | writel(uart_cr, pl011_port->membase + UART011_CR); 111 | 112 | /*Enable fifo and set to 8N1*/ 113 | writel(UART01x_LCRH_FEN | UART01x_LCRH_WLEN_8, pl011_port->membase + UART011_LCRH); 114 | 115 | /*Enable UART*/ 116 | uart_cr |= UART01x_CR_UARTEN; 117 | writel(uart_cr, pl011_port->membase + UART011_CR); 118 | 119 | /*Configure interrupts*/ 120 | writel(UART011_OEIM | UART011_BEIM | UART011_FEIM | UART011_RTIM | UART011_RXIM, pl011_port->membase + UART011_IMSC); 121 | 122 | return 0; 123 | } 124 | 125 | static void pl011_raw_uart_stop_connection(struct generic_raw_uart *raw_uart) 126 | { 127 | /*If uart is enabled, wait until it is not busy*/ 128 | while ((readl(pl011_port->membase + UART011_CR) & UART01x_CR_UARTEN) && (readl(pl011_port->membase + UART01x_FR) & UART01x_FR_BUSY)) 129 | { 130 | schedule(); 131 | } 132 | 133 | writel(0, pl011_port->membase + UART011_CR); /*Disable UART*/ 134 | 135 | writel(0, pl011_port->membase + UART011_IMSC); /*Disable interrupts*/ 136 | 137 | free_irq(pl011_port->irq, raw_uart); 138 | } 139 | 140 | static void pl011_raw_uart_stop_tx(struct generic_raw_uart *raw_uart) 141 | { 142 | unsigned long imsc; 143 | 144 | /*Diable TX interrupts*/ 145 | imsc = readl(pl011_port->membase + UART011_IMSC); 146 | imsc &= ~(UART011_DSRMIM | UART011_DCDMIM | UART011_RIMIM); /*Set all RO bit to 0*/ 147 | imsc &= ~(UART011_TXIM); /*disable TX interrupt*/ 148 | 149 | writel(imsc, pl011_port->membase + UART011_IMSC); 150 | } 151 | 152 | static bool pl011_raw_uart_isready_for_tx(struct generic_raw_uart *raw_uart) 153 | { 154 | return !(readl(pl011_port->membase + UART01x_FR) & UART01x_FR_TXFF); 155 | } 156 | 157 | static void pl011_raw_uart_tx_chars(struct generic_raw_uart *raw_uart, unsigned char *chr, int index, int len) 158 | { 159 | writel(chr[index], pl011_port->membase + UART01x_DR); 160 | } 161 | 162 | static void pl011_raw_uart_init_tx(struct generic_raw_uart *raw_uart) 163 | { 164 | unsigned long imsc; 165 | 166 | /*Clear TX interrupts*/ 167 | writel(UART011_TXIC, pl011_port->membase + UART011_ICR); 168 | 169 | /*Enable TX interrupts*/ 170 | imsc = readl(pl011_port->membase + UART011_IMSC); 171 | imsc &= ~(UART011_DSRMIM | UART011_DCDMIM | UART011_RIMIM); /*Set all RO bit to 0*/ 172 | imsc |= UART011_TXIM; /*enable TX interrupt*/ 173 | 174 | writel(imsc, pl011_port->membase + UART011_IMSC); 175 | } 176 | 177 | static void pl011_raw_uart_rx_chars(struct generic_raw_uart *raw_uart) 178 | { 179 | unsigned long status; 180 | unsigned long data; 181 | enum generic_raw_uart_rx_flags flags = GENERIC_RAW_UART_RX_STATE_NONE; 182 | 183 | while (1) 184 | { 185 | status = readl(pl011_port->membase + UART01x_FR); 186 | 187 | if (status & UART01x_FR_RXFE) 188 | { 189 | break; 190 | } 191 | 192 | data = readl(pl011_port->membase + UART01x_DR); 193 | 194 | /* Error handling */ 195 | if (data & UART011_DR_BE) 196 | { 197 | flags |= GENERIC_RAW_UART_RX_STATE_BREAK; 198 | } 199 | else 200 | { 201 | if (data & UART011_DR_PE) 202 | { 203 | flags |= GENERIC_RAW_UART_RX_STATE_PARITY; 204 | } 205 | if (data & UART011_DR_FE) 206 | { 207 | flags |= GENERIC_RAW_UART_RX_STATE_FRAME; 208 | } 209 | if (data & UART011_DR_OE) 210 | { 211 | flags |= GENERIC_RAW_UART_RX_STATE_OVERRUN; 212 | } 213 | } 214 | 215 | generic_raw_uart_handle_rx_char(raw_uart, flags, (unsigned char)data); 216 | } 217 | 218 | generic_raw_uart_rx_completed(raw_uart); 219 | } 220 | 221 | static irqreturn_t pl011_raw_uart_irq_handle(int irq, void *context) 222 | { 223 | struct generic_raw_uart *raw_uart = context; 224 | 225 | u32 istat; 226 | 227 | istat = readl(pl011_port->membase + UART011_MIS); 228 | smp_rmb(); 229 | 230 | /*Clear interrupts*/ 231 | smp_wmb(); 232 | 233 | writel(istat, pl011_port->membase + UART011_ICR); 234 | 235 | if (istat & (UART011_RXIS | UART011_RTIS)) 236 | { 237 | pl011_raw_uart_rx_chars(raw_uart); 238 | } 239 | 240 | if (istat & UART011_TXIS) 241 | { 242 | generic_raw_uart_tx_queued(raw_uart); 243 | } 244 | 245 | return IRQ_HANDLED; 246 | } 247 | 248 | static struct raw_uart_driver pl011_raw_uart = { 249 | .owner = THIS_MODULE, 250 | .start_connection = pl011_raw_uart_start_connection, 251 | .stop_connection = pl011_raw_uart_stop_connection, 252 | .init_tx = pl011_raw_uart_init_tx, 253 | .isready_for_tx = pl011_raw_uart_isready_for_tx, 254 | .tx_chars = pl011_raw_uart_tx_chars, 255 | .stop_tx = pl011_raw_uart_stop_tx, 256 | .tx_chunk_size = TX_CHUNK_SIZE, 257 | .tx_bulktransfer_size = 1, 258 | }; 259 | 260 | static int pl011_raw_uart_probe(struct platform_device *pdev) 261 | { 262 | int err; 263 | struct device *dev = &pdev->dev; 264 | struct resource *ioresource; 265 | 266 | /* alloc private resources */ 267 | pl011_port = kzalloc(sizeof(struct pl011_port_s), GFP_KERNEL); 268 | if (!pl011_port) 269 | { 270 | err = -ENOMEM; 271 | goto failed_inst_alloc; 272 | } 273 | 274 | /* Get mapbase and membase */ 275 | ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 276 | if (ioresource) 277 | { 278 | pl011_port->mapbase = ioresource->start; 279 | pl011_port->membase = ioremap(ioresource->start, resource_size(ioresource)); 280 | } 281 | else 282 | { 283 | dev_err(dev, "failed to get IO resource\n"); 284 | err = -ENOENT; 285 | goto failed_get_resource; 286 | } 287 | 288 | /* get irq */ 289 | pl011_port->irq = platform_get_irq(pdev, 0); 290 | if (pl011_port->irq <= 0) 291 | { 292 | dev_err(dev, "failed to get irq\n"); 293 | err = -ENOENT; 294 | goto failed_get_resource; 295 | } 296 | 297 | /* get clock */ 298 | pl011_port->clk = devm_clk_get(&pdev->dev, NULL); 299 | if (IS_ERR(pl011_port->clk)) 300 | { 301 | dev_err(dev, "failed to get clock\n"); 302 | err = PTR_ERR(pl011_port->clk); 303 | goto failed_get_clock; 304 | } 305 | clk_prepare_enable(pl011_port->clk); 306 | 307 | pl011_port->dev = dev; 308 | 309 | dev_info(dev, "Initialized pl011 device; mapbase=0x%08lx; irq=%lu; clockrate=%lu", pl011_port->mapbase, pl011_port->irq, clk_get_rate(pl011_port->clk)); 310 | 311 | return 0; 312 | failed_get_clock: 313 | failed_get_resource: 314 | kfree(pl011_port); 315 | failed_inst_alloc: 316 | return err; 317 | } 318 | 319 | static int pl011_raw_uart_remove(struct platform_device *pdev) 320 | { 321 | clk_disable_unprepare(pl011_port->clk); 322 | kfree(pl011_port); 323 | return 0; 324 | } 325 | 326 | static struct of_device_id pl011_raw_uart_of_match[] = { 327 | {.compatible = "pivccu,pl011"}, 328 | {/* sentinel */}, 329 | }; 330 | 331 | module_raw_uart_driver(MODULE_NAME, pl011_raw_uart, pl011_raw_uart_of_match); 332 | 333 | MODULE_ALIAS("platform:pl011-raw-uart"); 334 | MODULE_LICENSE("GPL"); 335 | MODULE_VERSION("1.11"); 336 | MODULE_DESCRIPTION("PL011 raw uart driver for communication of piVCCU with the HM-MOD-RPI-PCB and RPI-RF-MOD radio modules"); 337 | MODULE_AUTHOR("Alexander Reinert "); 338 | -------------------------------------------------------------------------------- /kernel/plat_eq3ccu2.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Copyright (c) 2020 by Alexander Reinert 3 | * Author: Alexander Reinert 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | *---------------------------------------------------------------------------*/ 19 | 20 | #include /*needed for priority messages in prink*/ 21 | #include /*needed for macros*/ 22 | #include /*needed for all modules*/ 23 | 24 | #include "stack_protector.include" 25 | 26 | static char *board_serial = ""; 27 | static char *radio_mac = ""; 28 | static char *board_extended_info = ""; 29 | static short eq3charloop_major = 0; 30 | static short uart_major = 0; 31 | static short hmip_major = 0; 32 | static short hmip_minor = 0; 33 | 34 | module_param(board_serial, charp, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 35 | MODULE_PARM_DESC(board_serial, "Board serial number, e.g. MEQ1234567"); 36 | module_param(radio_mac, charp, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 37 | MODULE_PARM_DESC(radio_mac, "Radio mac, e.g. 0x123456"); 38 | 39 | module_param(board_extended_info, charp, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 40 | MODULE_PARM_DESC(board_extended_info, "Extended board informations, e.g. firmware version"); 41 | 42 | module_param(eq3charloop_major, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 43 | MODULE_PARM_DESC(eq3charloop_major, "Device major number of eq3_char_loop"); 44 | module_param(uart_major, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 45 | MODULE_PARM_DESC(uart_major, "Device major number of raw uart"); 46 | 47 | module_param(hmip_major, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 48 | MODULE_PARM_DESC(hmip_major, "Device major number of HmIP device"); 49 | module_param(hmip_minor, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 50 | MODULE_PARM_DESC(hmip_minor, "Device minor number of HmIP device"); 51 | 52 | static int __init plat_eq3ccu2_init(void) 53 | { 54 | printk(KERN_INFO "Started plat_eq3ccu2\n"); 55 | return 0; 56 | } 57 | 58 | static void __exit plat_eq3ccu2_exit(void) 59 | { 60 | printk(KERN_INFO "Stopped plat_eq3ccu2\n"); 61 | } 62 | 63 | module_init(plat_eq3ccu2_init); 64 | module_exit(plat_eq3ccu2_exit); 65 | 66 | MODULE_LICENSE("GPL"); 67 | MODULE_VERSION("1.4"); 68 | MODULE_AUTHOR("Alexander Reinert "); 69 | MODULE_DESCRIPTION("plat_eq3ccu2 CCU2 emulation module"); 70 | -------------------------------------------------------------------------------- /kernel/rpi_rf_mod_led.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Copyright (c) 2020 by Alexander Reinert 3 | * Author: Alexander Reinert 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | *---------------------------------------------------------------------------*/ 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "stack_protector.include" 31 | 32 | static int red_gpio_pin = 0; 33 | static int green_gpio_pin = 0; 34 | static int blue_gpio_pin = 0; 35 | 36 | static struct rpi_rf_mod_led_led *red = 0; 37 | static struct rpi_rf_mod_led_led *green = 0; 38 | static struct rpi_rf_mod_led_led *blue = 0; 39 | 40 | struct rpi_rf_mod_led_led 41 | { 42 | struct led_classdev cdev; 43 | int gpio; 44 | enum led_brightness brightness; 45 | }; 46 | 47 | static void rpi_rf_mod_led_set_led_brightness(struct led_classdev *cdev, enum led_brightness b) 48 | { 49 | struct rpi_rf_mod_led_led *led = container_of(cdev, struct rpi_rf_mod_led_led, cdev); 50 | 51 | led->brightness = b; 52 | 53 | if (led->gpio != 0) 54 | { 55 | gpio_set_value(led->gpio, b == LED_OFF ? 0 : 1); 56 | } 57 | } 58 | 59 | static enum led_brightness rpi_rf_mod_led_get_led_brightness(struct led_classdev *cdev) 60 | { 61 | struct rpi_rf_mod_led_led *led = container_of(cdev, struct rpi_rf_mod_led_led, cdev); 62 | return led->brightness; 63 | } 64 | 65 | static struct rpi_rf_mod_led_led *rpi_rf_mod_led_createled(const char *name, bool initial) 66 | { 67 | struct rpi_rf_mod_led_led *led; 68 | 69 | led = kzalloc(sizeof(struct rpi_rf_mod_led_led), GFP_KERNEL); 70 | 71 | led->cdev.name = name; 72 | led->cdev.brightness_set = rpi_rf_mod_led_set_led_brightness; 73 | led->cdev.brightness_get = rpi_rf_mod_led_get_led_brightness; 74 | led->cdev.default_trigger = initial ? "default-on" : "none"; 75 | led->gpio = 0; 76 | led->brightness = initial ? LED_FULL : LED_OFF; 77 | 78 | led_classdev_register(NULL, &led->cdev); 79 | 80 | return led; 81 | } 82 | 83 | static void rpi_rf_mod_led_set_gpio_pin(struct rpi_rf_mod_led_led *led, int gpio) 84 | { 85 | if (led == 0) 86 | return; 87 | 88 | if (led->gpio != 0) 89 | { 90 | gpio_free(led->gpio); 91 | } 92 | 93 | if (gpio != 0 && gpio_is_valid(gpio)) 94 | { 95 | gpio_request(gpio, led->cdev.name); 96 | gpio_direction_output(gpio, false); 97 | gpio_set_value(gpio, led->brightness == LED_OFF ? 0 : 1); 98 | } 99 | else 100 | { 101 | gpio = 0; 102 | } 103 | 104 | led->gpio = gpio; 105 | } 106 | 107 | static void rpi_rf_mod_led_destroyled(struct rpi_rf_mod_led_led *led) 108 | { 109 | led_classdev_unregister(&led->cdev); 110 | 111 | if (led->gpio != 0) 112 | { 113 | gpio_free(led->gpio); 114 | } 115 | 116 | kfree(led); 117 | } 118 | 119 | static int __init rpi_rf_mod_led_init(void) 120 | { 121 | red = rpi_rf_mod_led_createled("rpi_rf_mod:red", true); 122 | green = rpi_rf_mod_led_createled("rpi_rf_mod:green", true); 123 | blue = rpi_rf_mod_led_createled("rpi_rf_mod:blue", false); 124 | 125 | rpi_rf_mod_led_set_gpio_pin(red, red_gpio_pin); 126 | rpi_rf_mod_led_set_gpio_pin(green, green_gpio_pin); 127 | rpi_rf_mod_led_set_gpio_pin(blue, blue_gpio_pin); 128 | 129 | return 0; 130 | } 131 | 132 | static void __exit rpi_rf_mod_led_exit(void) 133 | { 134 | rpi_rf_mod_led_destroyled(red); 135 | rpi_rf_mod_led_destroyled(green); 136 | rpi_rf_mod_led_destroyled(blue); 137 | } 138 | 139 | module_init(rpi_rf_mod_led_init); 140 | module_exit(rpi_rf_mod_led_exit); 141 | 142 | static int rpi_rf_mod_led_set_param(const char *val, const struct kernel_param *kp) 143 | { 144 | int gpio, ret; 145 | struct rpi_rf_mod_led_led *led; 146 | 147 | ret = kstrtoint(val, 10, &gpio); 148 | 149 | if (ret != 0) 150 | return -EINVAL; 151 | 152 | if (strcmp(kp->name, "red_gpio_pin") == 0) 153 | { 154 | red_gpio_pin = gpio; 155 | led = red; 156 | } 157 | else if (strcmp(kp->name, "green_gpio_pin") == 0) 158 | { 159 | green_gpio_pin = gpio; 160 | led = green; 161 | } 162 | else if (strcmp(kp->name, "blue_gpio_pin") == 0) 163 | { 164 | blue_gpio_pin = gpio; 165 | led = blue; 166 | } 167 | else 168 | { 169 | return -ENODEV; 170 | } 171 | 172 | rpi_rf_mod_led_set_gpio_pin(led, gpio); 173 | 174 | return 0; 175 | } 176 | 177 | static int rpi_rf_mod_led_get_param(char *buffer, const struct kernel_param *kp) 178 | { 179 | int value = 0; 180 | 181 | if (strcmp(kp->name, "red_gpio_pin") == 0) 182 | { 183 | value = red->gpio; 184 | } 185 | else if (strcmp(kp->name, "green_gpio_pin") == 0) 186 | { 187 | value = green->gpio; 188 | } 189 | else if (strcmp(kp->name, "blue_gpio_pin") == 0) 190 | { 191 | value = blue->gpio; 192 | } 193 | else 194 | { 195 | return -ENODEV; 196 | } 197 | 198 | return sprintf(buffer, "%d", value); 199 | } 200 | 201 | static const struct kernel_param_ops rpi_rf_mod_led_gpio_param_ops = { 202 | .set = rpi_rf_mod_led_set_param, 203 | .get = rpi_rf_mod_led_get_param, 204 | }; 205 | 206 | module_param_cb(red_gpio_pin, &rpi_rf_mod_led_gpio_param_ops, NULL, S_IRUGO | S_IWUSR); 207 | MODULE_PARM_DESC(red_gpio_pin, "GPIO Pin of red LED"); 208 | 209 | module_param_cb(green_gpio_pin, &rpi_rf_mod_led_gpio_param_ops, NULL, S_IRUGO | S_IWUSR); 210 | MODULE_PARM_DESC(green_gpio_pin, "GPIO Pin of green LED"); 211 | 212 | module_param_cb(blue_gpio_pin, &rpi_rf_mod_led_gpio_param_ops, NULL, S_IRUGO | S_IWUSR); 213 | MODULE_PARM_DESC(blue_gpio_pin, "GPIO Pin of blue LED"); 214 | 215 | MODULE_AUTHOR("Alexander Reinert "); 216 | MODULE_DESCRIPTION("GPIO LED driver for RPI-RF-MOD"); 217 | MODULE_VERSION("1.7"); 218 | MODULE_LICENSE("GPL"); 219 | MODULE_ALIAS("rpi_rf_mod_led"); 220 | -------------------------------------------------------------------------------- /kernel/stack_protector.include: -------------------------------------------------------------------------------- 1 | #ifdef CONFIG_ARM64 2 | #ifdef CONFIG_HAVE_STACKPROTECTOR 3 | #ifdef PIVCCU_CC_HAS_NO_STACKPROTECTOR_SYSREG 4 | unsigned long __stack_chk_guard; 5 | 6 | void __stack_chk_guard_setup(void) 7 | { 8 | __stack_chk_guard = current->stack_canary; 9 | } 10 | 11 | void __stack_chk_fail(void) 12 | { 13 | panic("stack-protector: Kernel stack is corrupted in: %pB", __builtin_return_address (0)); 14 | } 15 | #endif 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /package/detect-radio-module/control: -------------------------------------------------------------------------------- 1 | Package: detect-radio-module 2 | Version: {PKG_VERSION} 3 | Architecture: {PKG_ARCH} 4 | Maintainer: Alexander Reinert 5 | Section: misc 6 | Priority: extra 7 | Homepage: https://github.com/alexreinert/piVCCU 8 | Description: detect_radio_module 9 | This package contains a tool to identify Homematic radio modules 10 | 11 | -------------------------------------------------------------------------------- /package/hb-rf-eth/conffiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexreinert/piVCCU/b80aacfb75e9689d14d4e2c94380728816c6313e/package/hb-rf-eth/conffiles -------------------------------------------------------------------------------- /package/hb-rf-eth/control: -------------------------------------------------------------------------------- 1 | Package: hb-rf-eth 2 | Version: {PKG_VERSION} 3 | Architecture: all 4 | Maintainer: Alexander Reinert 5 | Depends: pivccu-modules-dkms (>= 1.0.39) 6 | Pre-Depends: perl, avahi-utils, debconf (>= 0.5) | debconf-2.0 7 | Section: misc 8 | Priority: extra 9 | Homepage: https://github.com/alexreinert/piVCCU 10 | Description: HB-RF-ETH meta package 11 | This package contains scripts to configure the HB-RF-ETH kernel module 12 | 13 | -------------------------------------------------------------------------------- /package/hb-rf-eth/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /usr/share/debconf/confmodule 4 | 5 | set -e 6 | 7 | case "$1" in 8 | configure|reconfigure|abort-upgrade) 9 | IP="" 10 | 11 | CHOICES="" 12 | declare -A DEVICES=() 13 | 14 | DEVICESRAW=`avahi-browse -p -t -r -k _raw-uart._udp | grep -e "^=" | awk '{split($0,a,";"); print a[4],a[8]}'` 15 | IFS=$'\n'; for line in $DEVICESRAW; do 16 | DEVNAME=`echo "$line" | awk '{print $1}'` 17 | DEVIP=`echo "$line" | awk '{print $2}'` 18 | 19 | if [ ! -z "$CHOICES" ]; then 20 | CHOICES="$CHOICES, $DEVNAME ($DEVIP)" 21 | else 22 | CHOICES="$DEVNAME ($DEVIP)" 23 | fi 24 | DEVICES["$DEVNAME"]="$DEVIP" 25 | done 26 | 27 | COUNT="${#DEVICES[@]}" 28 | if [ $COUNT -eq 1 ]; then 29 | IP=${DEVICES[${!DEVICES[@]}]} 30 | db_fset hb_rf_eth/used_module seen false 31 | db_subst hb_rf_eth/used_module ip $IP 32 | db_input high hb_rf_eth/used_module || true 33 | db_go 34 | elif [ $COUNT -ge 2 ]; then 35 | db_fset hb_rf_eth/modules seen false 36 | db_subst hb_rf_eth/modules choices $CHOICES 37 | db_input high hb_rf_eth/modules || true 38 | db_go 39 | db_get hb_rf_eth/modules 40 | 41 | DEVNAME=`echo "$RET" | awk '{print $1}'` 42 | if [ ! -z "$DEVNAME" ]; then 43 | IP=${DEVICES["$DEVNAME"]} 44 | fi 45 | fi 46 | 47 | if [ -z "$IP" ]; then 48 | db_fset hb_rf_eth/warn_no_module_found seen false 49 | db_input critical hb_rf_eth/warn_no_module_found || true 50 | db_go 51 | else 52 | echo "HB_RF_ETH_ADDRESS=\"$IP\"" > /etc/default/hb_rf_eth 53 | fi 54 | 55 | db_stop 56 | ;; 57 | 58 | abort-remove|abort-deconfigure) 59 | ;; 60 | 61 | esac 62 | 63 | -------------------------------------------------------------------------------- /package/hb-rf-eth/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . /usr/share/debconf/confmodule 3 | 4 | set -e 5 | 6 | case "$1" in 7 | purge) 8 | db_purge 9 | rm -f /etc/default/hb_rf_eth 10 | ;; 11 | 12 | remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 13 | ;; 14 | esac 15 | 16 | -------------------------------------------------------------------------------- /package/hb-rf-eth/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /usr/share/debconf/confmodule 4 | 5 | case "$1" in 6 | install|upgrade) 7 | ;; 8 | 9 | abort-upgrade) 10 | ;; 11 | esac 12 | 13 | -------------------------------------------------------------------------------- /package/hb-rf-eth/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | case "$1" in 6 | remove|upgrade|deconfigure) 7 | ;; 8 | 9 | failed-upgrade) 10 | ;; 11 | esac 12 | -------------------------------------------------------------------------------- /package/hb-rf-eth/templates: -------------------------------------------------------------------------------- 1 | Template: hb_rf_eth/warn_no_module_found 2 | Type: error 3 | Description: ERROR: No HB-RF-ETH module could be detected in your network. 4 | Description-DE: ERROR: Es konnte kein HB-RF-ETH Modul im Netzwerk gefunden werden. 5 | 6 | Template: hb_rf_eth/modules 7 | Type: select 8 | Description: Which HB-RF-ETH module should be used? 9 | Description-DE: Welches HB-RF-ETH Modul soll verwendet werden? 10 | Choices: ${choices} 11 | 12 | Template: hb_rf_eth/used_module 13 | Type: note 14 | Description: The HB-RF-ETH module with IP ${ip} will be used. 15 | Description-DE: Es wird das HB-RF-ETH Modul mit der IP Adresse ${ip} verwendet. 16 | 17 | -------------------------------------------------------------------------------- /package/pivccu-devicetree-armbian/control: -------------------------------------------------------------------------------- 1 | Package: pivccu-devicetree-armbian 2 | Version: {PKG_VERSION} 3 | Architecture: all 4 | Maintainer: Alexander Reinert 5 | Pre-Depends: binutils 6 | Provides: pivccu-devicetree 7 | Section: misc 8 | Priority: extra 9 | Homepage: https://github.com/alexreinert/piVCCU 10 | Description: piVCCU DeviceTree files for armbian 11 | This package contains piVCCU DeviceTree files for armbian 12 | 13 | -------------------------------------------------------------------------------- /package/pivccu-devicetree-armbian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . /usr/share/debconf/confmodule 3 | 4 | set -e 5 | 6 | case "$1" in 7 | configure) 8 | if [ ! -e /pivccu.createimage ]; then 9 | /var/lib/piVCCU/dts/patch_dts.sh 10 | fi 11 | 12 | if [ ! -e /pivccu.createimage ]; then 13 | db_fset pivccu/reboot_required seen false 14 | db_input medium pivccu/reboot_required || true 15 | db_go 16 | fi 17 | ;; 18 | 19 | abort-upgrade|abort-remove|abort-deconfigure) 20 | ;; 21 | esac 22 | 23 | -------------------------------------------------------------------------------- /package/pivccu-devicetree-armbian/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | case "$1" in 6 | remove|upgrade|deconfigure) 7 | /var/lib/piVCCU/dts/revert_dts.sh 8 | ;; 9 | 10 | failed-upgrade) 11 | ;; 12 | esac 13 | 14 | -------------------------------------------------------------------------------- /package/pivccu-devicetree-armbian/templates: -------------------------------------------------------------------------------- 1 | Template: pivccu/reboot_required 2 | Type: error 3 | Description: WARNING: A reboot is required to enable the modules. 4 | Description-DE: WARNUNG: Ein Neustart ist erforderlich um die Module zu aktivieren. 5 | -------------------------------------------------------------------------------- /package/pivccu-modules-dkms/conffiles: -------------------------------------------------------------------------------- 1 | /lib/systemd/system/pivccu-dkms.service 2 | -------------------------------------------------------------------------------- /package/pivccu-modules-dkms/control: -------------------------------------------------------------------------------- 1 | Package: pivccu-modules-dkms 2 | Version: {PKG_VERSION} 3 | Architecture: all 4 | Maintainer: Alexander Reinert 5 | Provides: pivccu-kernel-modules 6 | Pre-Depends: dkms, build-essential, bison, flex, debconf (>= 0.5) | debconf-2.0 7 | Conflicts: pivccu 8 | Section: kernel 9 | Priority: extra 10 | Homepage: https://github.com/alexreinert/piVCCU 11 | Description: DKMS package for kernel modules needed for Homematic 12 | This package contains the a DKMS package for kernel needed for Homematic. 13 | 14 | -------------------------------------------------------------------------------- /package/pivccu-modules-dkms/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . /usr/share/debconf/confmodule 3 | 4 | function throw { 5 | echo $1 6 | exit 1 7 | } 8 | 9 | function run { 10 | echo -n "$1 ... " 11 | shift 12 | ERR=`$* 2>&1` && RC=$? || RC=$? 13 | if [ $RC -eq 0 ]; then 14 | echo -e "\033[0;32mDone\033[0;0m" 15 | else 16 | echo -e "\033[1;91mFAILED\033[0;0m" 17 | echo "$ERR" 18 | exit 1 19 | fi 20 | } 21 | 22 | function ensure_raspberry_non_mixed_kernel { 23 | if [ "`dpkg --print-architecture`" == "armhf" ]; then 24 | for file in /boot/firmware/config.txt /boot/config.txt 25 | do 26 | if [ -e $file ]; then 27 | grep -q "^arm_64bit=" $file 28 | if [ $? -ne 0 ]; then 29 | [ -n "$(tail -1 $file)" ] && echo >> $file 30 | echo "arm_64bit=0" >> $file 31 | fi 32 | fi 33 | done 34 | fi 35 | } 36 | 37 | case "$1" in 38 | configure) 39 | if [ ! -e /pivccu.createimage ]; then 40 | if [ -e /proc/device-tree/model ]; then 41 | grep -q "Raspberry Pi" /proc/device-tree/model 42 | if [ $? -eq 0 ]; then 43 | run "Ensure non mixed processor architecure" ensure_raspberry_non_mixed_kernel 44 | fi 45 | fi 46 | 47 | (run "Create kernel modules" . /var/lib/piVCCU/dkms/ensure_modules.sh) || true 48 | fi 49 | 50 | run "Enable DKMS service" systemctl enable pivccu-dkms.service 51 | 52 | if [ ! -e /pivccu.createimage ]; then 53 | db_fset pivccu/reboot_required seen false 54 | db_input medium pivccu/reboot_required || true 55 | db_go 56 | fi 57 | ;; 58 | 59 | abort-upgrade|abort-remove|abort-deconfigure) 60 | ;; 61 | esac 62 | -------------------------------------------------------------------------------- /package/pivccu-modules-dkms/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . /usr/share/debconf/confmodule 3 | 4 | function throw { 5 | echo $1 6 | exit 1 7 | } 8 | 9 | function run { 10 | echo -n "$1 ... " 11 | shift 12 | ERR=`$* 2>&1` && RC=$? || RC=$? 13 | if [ $RC -eq 0 ]; then 14 | echo -e "\033[0;32mDone\033[0;0m" 15 | else 16 | echo -e "\033[1;91mFAILED\033[0;0m" 17 | echo "$ERR" 18 | exit 1 19 | fi 20 | } 21 | 22 | case "$1" in 23 | purge) 24 | run "Cleanup debconf database" db_purge 25 | ;; 26 | 27 | remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 28 | ;; 29 | esac 30 | 31 | -------------------------------------------------------------------------------- /package/pivccu-modules-dkms/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function throw { 4 | echo $1 5 | exit 1 6 | } 7 | 8 | function run { 9 | echo -n "$1 ... " 10 | shift 11 | ERR=`$* 2>&1` && RC=$? || RC=$? 12 | if [ $RC -eq 0 ]; then 13 | echo -e "\033[0;32mDone\033[0;0m" 14 | else 15 | echo -e "\033[1;91mFAILED\033[0;0m" 16 | echo "$ERR" 17 | exit 1 18 | fi 19 | } 20 | 21 | DKMS_VERSION={PKG_VERSION} 22 | 23 | case "$1" in 24 | remove|upgrade|deconfigure) 25 | run "Disabled DKMS service" systemctl disable pivccu-dkms.service 26 | 27 | if [ "$(dkms status -m pivccu -v $DKMS_VERSION)" ]; then 28 | run "Remove obsolete kernel modules" dkms remove -m pivccu -v $DKMS_VERSION --all 29 | fi 30 | ;; 31 | 32 | failed-upgrade) 33 | ;; 34 | esac 35 | -------------------------------------------------------------------------------- /package/pivccu-modules-dkms/templates: -------------------------------------------------------------------------------- 1 | Template: pivccu/reboot_required 2 | Type: error 3 | Description: WARNING: A reboot is required to enable the modules. 4 | Description-DE: WARNUNG: Ein Neustart ist erforderlich um die Module zu aktivieren. 5 | -------------------------------------------------------------------------------- /package/pivccu-modules-raspberrypi/control: -------------------------------------------------------------------------------- 1 | Package: pivccu-modules-raspberrypi 2 | Version: {PKG_VERSION} 3 | Architecture: all 4 | Maintainer: Alexander Reinert 5 | Depends: raspberrypi-kernel-headers | linux-headers-raspi, pivccu-modules-dkms, bc 6 | Pre-Depends: debconf (>= 0.5) | debconf-2.0 7 | Section: kernel 8 | Priority: extra 9 | Homepage: https://github.com/alexreinert/piVCCU 10 | Description: Raspberry Pi kernel modules needed for Homematic 11 | This package contains the Raspberry Pi kernel needed for Homematic. 12 | 13 | -------------------------------------------------------------------------------- /package/pivccu-modules-raspberrypi/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . /usr/share/debconf/confmodule 3 | 4 | set -e 5 | 6 | case "$1" in 7 | configure) 8 | if [ -f /usr/share/rpikernelhack/overlays/pivccu-raspberrypi.dtbo ]; then 9 | rm -f /var/lib/piVCCU/dtb/overlays/pivccu-raspberrypi.dtbo 10 | dpkg-divert --package rpikernelhack --remove --rename /var/lib/piVCCU/dtb/overlays/pivccu-raspberrypi.dtbo 11 | sync 12 | fi 13 | 14 | sed -i /var/lib/piVCCU/dtb/config.txt -e '/dtoverlay=pivccu-raspberrypi/d' 15 | [ -n "$(tail -1 /var/lib/piVCCU/dtb/config.txt)" ] && echo >> /var/lib/piVCCU/dtb/config.txt 16 | echo "dtoverlay=pivccu-raspberrypi" >> /var/lib/piVCCU/dtb/config.txt 17 | 18 | umount /var/lib/piVCCU/dtb 19 | 20 | systemctl enable pivccu-rpi-modules.service 21 | 22 | if [ ! -e /pivccu.createimage ]; then 23 | db_fset pivccu/reboot_required seen false 24 | db_input medium pivccu/reboot_required || true 25 | db_go 26 | fi 27 | ;; 28 | 29 | abort-upgrade|abort-remove|abort-deconfigure) 30 | ;; 31 | esac 32 | 33 | -------------------------------------------------------------------------------- /package/pivccu-modules-raspberrypi/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . /usr/share/debconf/confmodule 3 | 4 | set -e 5 | 6 | case "$1" in 7 | remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 8 | sed -i /var/lib/piVCCU/dtb/config.txt -e '/dtoverlay=pivccu-raspberrypi/d' 9 | umount /var/lib/piVCCU/dtb 10 | ;; 11 | 12 | purge) 13 | db_purge 14 | ;; 15 | esac 16 | 17 | -------------------------------------------------------------------------------- /package/pivccu-modules-raspberrypi/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | case "$1" in 6 | install|upgrade) 7 | mkdir -p /var/lib/piVCCU/dtb 8 | if [[ -d /boot/firmware/overlays ]]; then 9 | mount --bind /boot/firmware /var/lib/piVCCU/dtb 10 | elif [[ -d /boot/overlays ]]; then 11 | mount --bind /boot /var/lib/piVCCU/dtb 12 | fi 13 | 14 | mkdir -p /usr/share/rpikernelhack/overlays 15 | dpkg-divert --package rpikernelhack --divert /usr/share/rpikernelhack/overlays/pivccu-raspberrypi.dtbo /var/lib/piVCCU/dtb/overlays/pivccu-raspberrypi.dtbo 16 | ;; 17 | 18 | abort-upgrade) 19 | ;; 20 | esac 21 | 22 | -------------------------------------------------------------------------------- /package/pivccu-modules-raspberrypi/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | case "$1" in 6 | remove|upgrade|deconfigure) 7 | systemctl disable pivccu-rpi-modules.service 8 | 9 | mkdir -p /var/lib/piVCCU/dtb 10 | if [[ -d /boot/firmware/overlays ]]; then 11 | mount --bind /boot/firmware /var/lib/piVCCU/dtb 12 | elif [[ -d /boot/overlays ]]; then 13 | mount --bind /boot /var/lib/piVCCU/dtb 14 | fi 15 | ;; 16 | 17 | failed-upgrade) 18 | ;; 19 | esac 20 | -------------------------------------------------------------------------------- /package/pivccu-modules-raspberrypi/templates: -------------------------------------------------------------------------------- 1 | Template: pivccu/reboot_required 2 | Type: error 3 | Description: WARNING: A reboot is required to enable the modules. 4 | Description-DE: WARNUNG: Ein Neustart ist erforderlich um die Module zu aktivieren. 5 | -------------------------------------------------------------------------------- /package/pivccu3/conffiles: -------------------------------------------------------------------------------- 1 | /etc/default/pivccu3 2 | /etc/piVCCU3/lxc.config 3 | /lib/systemd/system/pivccu.service 4 | -------------------------------------------------------------------------------- /package/pivccu3/control: -------------------------------------------------------------------------------- 1 | Package: pivccu3 2 | Version: {PKG_VERSION} 3 | Architecture: {PKG_ARCH} 4 | Maintainer: Alexander Reinert 5 | Pre-Depends: pivccu-modules-dkms (>= 1.0.10), detect-radio-module, wait-sysfs-notify, perl, lxc, bridge-utils, net-tools, systemd, debconf (>= 0.5) | debconf-2.0 6 | Conflicts: pivccu, pivccu-modules-dkms (>= 2.0.0) 7 | Section: misc 8 | Priority: extra 9 | Homepage: https://github.com/alexreinert/piVCCU 10 | Description: piVCCU - Homematic CCU LXC container 11 | This package contains piVCCU - a Homematic CCU LXC container 12 | 13 | -------------------------------------------------------------------------------- /package/pivccu3/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | CONFIGFILE=/etc/default/pivccu3 3 | 4 | . /usr/share/debconf/confmodule 5 | 6 | function throw { 7 | echo $1 8 | exit 1 9 | } 10 | 11 | function run { 12 | echo -n "$1 ... " 13 | shift 14 | ERR=`$* 2>&1` && RC=$? || RC=$? 15 | if [ $RC -eq 0 ]; then 16 | echo -e "\033[0;32mDone\033[0;0m" 17 | else 18 | echo -e "\033[1;91mFAILED\033[0;0m" 19 | echo "$ERR" 20 | exit 1 21 | fi 22 | } 23 | 24 | function add_symlinks { 25 | if [ ! -e /usr/sbin/pivccu-attach ]; then 26 | run "Create pivccu-attach symlink" ln -s /var/lib/piVCCU3/pivccu-attach.sh /usr/sbin/pivccu-attach 27 | fi 28 | if [ ! -e /usr/sbin/pivccu-info ]; then 29 | run "Create pivccu-info symlink" ln -s /var/lib/piVCCU3/pivccu-info.sh /usr/sbin/pivccu-info 30 | fi 31 | if [ ! -e /usr/sbin/pivccu-backup ]; then 32 | run "Create pivccu-backup symlink" ln -s /var/lib/piVCCU3/pivccu-backup.sh /usr/sbin/pivccu-backup 33 | fi 34 | } 35 | 36 | function enable_services { 37 | run "Enable pivccu.service" systemctl enable pivccu.service 38 | run "Enable pivccu-startupfinished.service" systemctl enable pivccu-startupfinished.service 39 | run "Enable monitor-hb-rf-eth.service" systemctl enable monitor-hb-rf-eth.service 40 | } 41 | 42 | function update_apt_repo { 43 | wget -q -O - https://apt.pivccu.de/piVCCU/public.key | sudo tee /usr/share/keyrings/pivccu.asc > /dev/null || throw "Error downloading piVCCU APT key" 44 | for file in /etc/apt/sources.list /etc/apt/sources.list.d/*.list 45 | do 46 | if [ -f $file ]; then 47 | for repo in https://www.debmatic.de/debmatic https://www.pivccu.de/piVCCU 48 | do 49 | sed -i "s|deb $repo |deb [signed-by=/usr/share/keyrings/pivccu.asc] https://apt.pivccu.de/piVCCU |g" $file || throw "Error updating repo $repo in $file" 50 | done 51 | fi 52 | done 53 | apt-key --keyring /etc/apt/trusted.gpg del "2EE7 5239 FB96 1829 848D 0AA0 5412 30BA 05C3 8BC4" || throw "Could not remove old APT key" 54 | } 55 | 56 | case "$1" in 57 | configure|reconfigure|abort-upgrade) 58 | run "Reload udev rules" udevadm control --reload-rules && udevadm trigger 59 | 60 | run "Create symlinks" add_symlinks 61 | 62 | if [ "$1" = "reconfigure" ] || [ "${DEBCONF_RECONFIGURE}" = "1" ]; then 63 | db_fset pivccu/rf_mode seen false 64 | db_input high pivccu/rf_mode || true 65 | elif [ -e /pivccu.createimage ]; then 66 | db_set pivccu/rf_mode "Normal" 67 | elif [ ! -z "$2" ]; then 68 | db_get pivccu/rf_mode 69 | if [ -z "$RET" ]; then 70 | db_set pivccu/rf_mode "Normal" 71 | fi 72 | else 73 | db_input high pivccu/rf_mode || true 74 | fi 75 | 76 | db_go || true 77 | 78 | db_get pivccu/rf_mode 79 | 80 | case "$RET" in 81 | "Fake") 82 | PIVCCU_RF_MODE="Fake" 83 | ;; 84 | *) 85 | PIVCCU_RF_MODE="Normal" 86 | ;; 87 | esac 88 | 89 | grep -Eq '^ *PIVCCU_RF_MODE=' $CONFIGFILE || echo "PIVCCU_RF_MODE=" >> $CONFIGFILE 90 | sed -i $CONFIGFILE -e "s/^ *PIVCCU_RF_MODE=.*/PIVCCU_RF_MODE=\"$PIVCCU_RF_MODE\"/" 91 | 92 | if [ ! -e /pivccu.createimage ]; then 93 | if [ -z "$2" ]; then 94 | if [ "$PIVCCU_RF_MODE" != "Fake" ]; then 95 | run "Dectect radio hardware" . /var/lib/piVCCU3/detect_hardware.inc 96 | if [ ! -e /sys/devices/virtual/raw-uart ]; then 97 | db_input critical pivccu/warn_raw_uart_not_found || true 98 | elif [ -z "$HM_HMRF_DEV" ] && [ -z "$HM_HMIP_DEV" ]; then 99 | if [ -f /proc/device-tree/model ] && [ `grep -c "Raspberry Pi 3" /proc/device-tree/model` == 1 ]; then 100 | if ! cmp -s /proc/device-tree/aliases/uart0 /proc/device-tree/aliases/serial0; then 101 | db_input critical pivccu/warn_gpio_uart_not_assigned || true 102 | fi 103 | fi 104 | 105 | db_input critical pivccu/warn_no_radio_module_found || true 106 | fi 107 | fi 108 | 109 | BRIDGE=`brctl show | sed -n 2p | awk '{print $1}'` 110 | if [ -z "$BRIDGE" ]; then 111 | db_input critical pivccu/warn_no_bridge_found || true 112 | fi 113 | 114 | db_go 115 | fi 116 | 117 | if [ "$1" = "reconfigure" ] || [ "${DEBCONF_RECONFIGURE}" = "1" ]; then 118 | CHOICES="" 119 | declare -A DEVICES=() 120 | 121 | for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do 122 | syspath="${sysdevpath%/dev}" 123 | 124 | devname="$(udevadm info -q name -p $syspath)" 125 | [[ "$devname" == "bus/"* ]] && continue 126 | 127 | declare -A UDEV_PROPERTIES=() 128 | while IFS='=' read -r a b; do UDEV_PROPERTIES["$a"]="$b"; done < <(udevadm info -q property -p $syspath) 129 | 130 | [[ -z "${UDEV_PROPERTIES[ID_SERIAL]}" ]] && continue 131 | 132 | [[ "${UDEV_PROPERTIES[DEVTYPE]}" == "disk" ]] && continue 133 | 134 | [[ "${UDEV_PROPERTIES[ID_VENDOR_ID]}:${UDEV_PROPERTIES[ID_MODEL_ID]}" == "1b1f:c020" ]] && continue 135 | 136 | if [ ! -z "$CHOICES" ]; then 137 | CHOICES="$CHOICES, /dev/$devname (${UDEV_PROPERTIES[ID_SERIAL]})" 138 | else 139 | CHOICES="/dev/$devname (${UDEV_PROPERTIES[ID_SERIAL]})" 140 | fi 141 | DEVICES["/dev/$devname"]=$syspath 142 | done 143 | 144 | db_fset pivccu/usbdevices seen false 145 | db_subst pivccu/usbdevices choices $CHOICES 146 | db_input high pivccu/usbdevices || true 147 | db_go 148 | 149 | db_get pivccu/usbdevices 150 | 151 | IFS="," 152 | SELECTED=($RET) 153 | 154 | NEWDEVCONFIG="" 155 | 156 | for dev in "${SELECTED[@]}" 157 | do 158 | dev=`echo "$dev" | awk '{print $1}'` 159 | syspath="${DEVICES[$dev]}" 160 | 161 | if [ -z "$syspath" ]; then 162 | continue 163 | fi 164 | 165 | declare -A UDEV_PROPERTIES=() 166 | while IFS='=' read -r a b; do UDEV_PROPERTIES["$a"]="$b"; done < <(udevadm info -q property -p $syspath) 167 | 168 | DEVCONFIG="${UDEV_PROPERTIES[ID_VENDOR_ID]};${UDEV_PROPERTIES[ID_MODEL_ID]};${UDEV_PROPERTIES[ID_SERIAL_SHORT]};${UDEV_PROPERTIES[ID_USB_INTERFACE_NUM]};${UDEV_PROPERTIES[ID_PART_ENTRY_UUID]}" 169 | if [ -z "$NEWDEVCONFIG" ]; then 170 | NEWDEVCONFIG="$DEVCONFIG" 171 | else 172 | NEWDEVCONFIG="$NEWDEVCONFIG,$DEVCONFIG" 173 | fi 174 | done 175 | 176 | grep -Eq '^ *PIVCCU_USB_DEVICES=' $CONFIGFILE || echo "PIVCCU_USB_DEVICES=" >> $CONFIGFILE 177 | sed -i $CONFIGFILE -e "s/^ *PIVCCU_USB_DEVICES=.*/PIVCCU_USB_DEVICES=\"$NEWDEVCONFIG\"/" 178 | fi 179 | fi 180 | 181 | db_stop 182 | 183 | run "Enable services" enable_services 184 | 185 | run "Update APT repository config" update_apt_repo 186 | 187 | if [ ! -e /pivccu.createimage ]; then 188 | (run "Start piVCCU" systemctl start pivccu.service) || true 189 | fi 190 | ;; 191 | 192 | abort-remove|abort-deconfigure) 193 | ;; 194 | 195 | esac 196 | 197 | -------------------------------------------------------------------------------- /package/pivccu3/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . /usr/share/debconf/confmodule 3 | 4 | function throw { 5 | echo $1 6 | exit 1 7 | } 8 | 9 | function run { 10 | echo -n "$1 ... " 11 | shift 12 | ERR=`$* 2>&1` && RC=$? || RC=$? 13 | if [ $RC -eq 0 ]; then 14 | echo -e "\033[0;32mDone\033[0;0m" 15 | else 16 | echo -e "\033[1;91mFAILED\033[0;0m" 17 | echo "$ERR" 18 | exit 1 19 | fi 20 | } 21 | 22 | case "$1" in 23 | purge) 24 | run "Cleanup confdb" db_purge 25 | run "Remove /etc/default/pivccu3" rm -f /etc/default/pivccu3 26 | run "Remove /etc/piVCCU" rm -rf /etc/piVCCU 27 | run "Remove obsolete container root fs" rm -rf /var/lib/piVCCU3/rootfs 28 | run "Remove obsolete container user fs" rm -rf /var/lib/piVCCU3/userfs 29 | ;; 30 | 31 | remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 32 | ;; 33 | esac 34 | 35 | -------------------------------------------------------------------------------- /package/pivccu3/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /usr/share/debconf/confmodule 4 | 5 | function throw { 6 | echo $1 7 | exit 1 8 | } 9 | 10 | function run { 11 | echo -n "$1 ... " 12 | shift 13 | ERR=`$* 2>&1` && RC=$? || RC=$? 14 | if [ $RC -eq 0 ]; then 15 | echo -e "\033[0;32mDone\033[0;0m" 16 | else 17 | echo -e "\033[1;91mFAILED\033[0;0m" 18 | echo "$ERR" 19 | exit 1 20 | fi 21 | } 22 | 23 | case "$1" in 24 | install|upgrade) 25 | if [ ! -z "$2" ]; then 26 | OLD_CCU_VERSION=`echo "$2" | sed 's/\([0-9]\+\.[0-9]\+\.[0-9]\+\)-[0-9]\+/\1/g'` 27 | 28 | if [ "{CCU_VERSION}" != "$OLD_CCU_VERSION" ]; then 29 | db_fset pivccu/has_backup seen false 30 | db_input critical pivccu/has_backup || true 31 | db_go 32 | 33 | db_get pivccu/has_backup 34 | if [ "$RET" = "false" ]; then 35 | db_input critical pivccu/err_no_backup || true 36 | db_go 37 | exit 2 38 | fi 39 | fi 40 | fi 41 | 42 | run "Clear container root" rm -rf /var/lib/piVCCU3/rootfs/* 43 | ;; 44 | 45 | abort-upgrade) 46 | ;; 47 | esac 48 | 49 | -------------------------------------------------------------------------------- /package/pivccu3/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function throw { 4 | echo $1 5 | exit 1 6 | } 7 | 8 | function run { 9 | echo -n "$1 ... " 10 | shift 11 | ERR=`$* 2>&1` && RC=$? || RC=$? 12 | if [ $RC -eq 0 ]; then 13 | echo -e "\033[0;32mDone\033[0;0m" 14 | else 15 | echo -e "\033[1;91mFAILED\033[0;0m" 16 | echo "$ERR" 17 | exit 1 18 | fi 19 | } 20 | 21 | function disable_services { 22 | run "Disable monitor-hb-rf-eth.service" systemctl disable monitor-hb-rf-eth.service 23 | run "Disable pivccu-startupfinished.service" systemctl disable pivccu-startupfinished.service 24 | run "Disable pivccu.service" systemctl disable pivccu.service 25 | } 26 | 27 | function remove_symlinks { 28 | run "Remove pivccu-attach" rm -f /usr/sbin/pivccu-attach 29 | run "Remove pivccu-info" rm -f /usr/sbin/pivccu-info 30 | run "Remove pivccu-backup" rm -f /usr/sbin/pivccu-backup 31 | } 32 | 33 | case "$1" in 34 | remove|upgrade|deconfigure) 35 | run "Stop piVCCU" systemctl stop pivccu.service 36 | run "Disable services" disable_services 37 | run "Remove symlinks" remove_symlinks 38 | ;; 39 | 40 | failed-upgrade) 41 | ;; 42 | esac 43 | -------------------------------------------------------------------------------- /package/pivccu3/templates: -------------------------------------------------------------------------------- 1 | Template: pivccu/has_backup 2 | Type: boolean 3 | Description: 4 | A new CCU firmware version is to be installed. 5 | . 6 | It is recommended that you create a backup before installing a new CCU firmware version. 7 | . 8 | Do you have a backup? 9 | Description-DE: 10 | Eine neue CCU Firmware Version soll installiert werden. 11 | . 12 | Es wird empfohlen ein Backup zu erstellen, bevor eine neue CCU Firmware Version installiert wird. 13 | . 14 | Haben Sie ein Backup? 15 | 16 | Template: pivccu/err_no_backup 17 | Type: error 18 | Description: The installation will be canceled. 19 | Description-DE: Die Installation wird abgebrochen. 20 | 21 | Template: pivccu/warn_gpio_uart_not_assigned 22 | Type: error 23 | Description: WARNING: Hardware UART is not assigned to GPIO pins. This is only required, if the radio module is connected to the GPIO header. 24 | Description-DE: WARNUNG: Der Hardware UART ist nicht den GPIO Pins zugewiesen. Dies ist nur notwendig, wenn das Funkmodul per GPIO Header angeschlossen ist. 25 | 26 | Template: pivccu/warn_raw_uart_not_found 27 | Type: error 28 | Description: WARNING: Could not locate raw uart interface. Are the kernel modules and the device tree overlays installed and did you reboot after installation of them? 29 | Description-DE: WARNUNG: Das raw uart Interface konnte nicht gefunden werden. Sind die Kernel Module und die Device Tree Overlays installiert und haben Sie einen Neustart nach der Installation von diesen durchgeführt? 30 | 31 | Template: pivccu/warn_no_radio_module_found 32 | Type: error 33 | Description: WARNING: No radio module was not detected. 34 | Description-DE: WARNUNG: Es wurde kein Funkmodul gefunden. 35 | 36 | Template: pivccu/warn_no_bridge_found 37 | Type: error 38 | Description: WARNING: No Network bridge could be detected. 39 | Description-DE: WARNUNG: Die Netzwerk Bridge konnte nicht gefunden werden. 40 | 41 | Template: pivccu/rf_mode 42 | Type: select 43 | Description: Which radio module should be used? 44 | Description-DE: Welches Funkmodul soll verwendet werden? 45 | Choices: Normal, Fake 46 | Choices-EN: HM-MOD-RPI-PCB/RPI-RF-MOD/HmIP-RFUSB (Only on supported platforms), Fake radio module emulation 47 | Choices-DE: HM-MOD-RPI-PCB/RPI-RF-MOD/HmIP-RFUSB (Nur auf unterstützten Platformen), Softwareemulation des Funkmoduls 48 | 49 | Template: pivccu/usbdevices 50 | Type: multiselect 51 | Description: Which USB devices should be available inside the CCU? 52 | Description-DE: Welche USB Geräte sollen innerhalb der CCU verfügbar sein? 53 | Choices: ${choices} 54 | -------------------------------------------------------------------------------- /package/wait-sysfs-notify/control: -------------------------------------------------------------------------------- 1 | Package: wait-sysfs-notify 2 | Version: {PKG_VERSION} 3 | Architecture: {PKG_ARCH} 4 | Maintainer: Alexander Reinert 5 | Section: misc 6 | Priority: extra 7 | Homepage: https://github.com/alexreinert/piVCCU 8 | Description: wait_sysfs_notify 9 | This package contains a tool to wait for a sysfs_notify on a sysfs entry 10 | 11 | -------------------------------------------------------------------------------- /pivccu/container3/save-rega.tcl: -------------------------------------------------------------------------------- 1 | #!/bin/tclsh 2 | load tclrega.so 3 | rega_script {system.Save();} 4 | 5 | -------------------------------------------------------------------------------- /pivccu/container3/set_hb_rf_eth_connection_dp.tcl: -------------------------------------------------------------------------------- 1 | #!/bin/tclsh 2 | 3 | load tclrpc.so 4 | load tclrega.so 5 | 6 | if { $argc < 1 } { 7 | exit 1 8 | } 9 | 10 | set state [lindex $argv 0] 11 | 12 | set script " 13 | object alObj = null; 14 | string sSysVarId; 15 | foreach(sSysVarId, dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()) { 16 | object oSysVar = dom.GetObject(sSysVarId); 17 | if((alObj == null) && ((oSysVar.Name() == \"HB-RF-ETH Connection\") || (oSysVar.Name() == \"HB_RF_ETH_Connection\"))) { 18 | alObj=oSysVar; 19 | } 20 | } 21 | 22 | if(alObj == null) { 23 | alObj = dom.CreateObject(OT_ALARMDP); 24 | if(alObj != null) { 25 | alObj.Name(\"HB-RF-ETH Connection\"); 26 | alObj.ValueType(ivtBinary); 27 | alObj.ValueSubType(istAlarm); 28 | alObj.DPInfo(\"\${hb_eth_connection_description}\"); 29 | alObj.ValueName0(\"\${hb_eth_connection_connected}\"); 30 | alObj.ValueName1(\"\${hb_eth_connection_disconnected}\"); 31 | alObj.ValueUnit(\"\"); 32 | alObj.AlType(atSystem); 33 | alObj.AlArm(true); 34 | alObj.AlSetBinaryCondition(); 35 | alObj.State(false); 36 | dom.GetObject(ID_SYSTEM_VARIABLES).Add(alObj.ID()); 37 | dom.RTUpdate(1); 38 | } 39 | } 40 | 41 | if(alObj != null) { 42 | alObj.State($state); 43 | } 44 | " 45 | 46 | rega_script $script 47 | 48 | -------------------------------------------------------------------------------- /pivccu/container3/start-hook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . /var/pivccu/conf 4 | 5 | find /var/* -maxdepth 0 ! -name pivccu -exec rm -rf {} \; 6 | rm -rf /tmp/* 7 | 8 | rm -f /dev/eq3loop 9 | rm -f /dev/mmd_bidcos 10 | rm -f /dev/mmd_hmip 11 | rm -f /dev/raw-uart 12 | 13 | mknod -m 666 /dev/eq3loop c $HM_EQ3LOOP_MAJOR 0 14 | mknod -m 666 /dev/mmd_hmip c $HM_HMIP_MAJOR $HM_HMIP_MINOR 15 | mknod -m 666 /dev/mmd_bidcos c $HM_EQ3LOOP_MAJOR 2 16 | mknod -m 666 /dev/raw-uart c $HM_RAW_UART_MAJOR $HM_RAW_UART_MINOR 17 | 18 | mkdir -p /dev/net 19 | if [ ! -e /dev/net/tun ]; then 20 | mknod -m 666 /dev/net/tun c 10 200 21 | fi 22 | 23 | if [ ! -e /dev/ptmx ]; then 24 | mknod -m 666 /dev/ptmx c 5 2 25 | fi 26 | 27 | if [ -e /var/pivccu/create-devs ]; then 28 | /bin/sh /var/pivccu/create-devs 29 | fi 30 | if [ -e /var/pivccu/create-mounts ]; then 31 | /bin/sh /var/pivccu/create-mounts 32 | fi 33 | 34 | mkdir -p /var/status 35 | 36 | if [ "0$HAS_USB" -eq 1 ]; then 37 | touch /var/status/hasUSB 38 | touch /var/status/hasSD 39 | mkdir -p /media/usb0/measurement 40 | if [ -d /media/usb0/measurement ]; then 41 | touch /var/status/USBinitialised 42 | touch /var/status/SDinitialised 43 | fi 44 | fi 45 | 46 | HM_HMIP_DEVNODE="/dev/raw-uart" 47 | HM_HMRF_DEVNODE="/dev/raw-uart" 48 | if [ "$HM_HMIP_DEV" == "HMIP-RFUSB-TK" ]; then 49 | HM_HMIP_DEVNODE="/dev/mmd_hmip" 50 | fi 51 | 52 | cat > /var/hm_mode << EOF 53 | HM_HOST='rpi3' 54 | HM_MODE='NORMAL' 55 | HM_LED_GREEN='' 56 | HM_LED_GREEN_MODE1='none' 57 | HM_LED_GREEN_MODE2='none' 58 | HM_LED_RED='' 59 | HM_LED_RED_MODE1='none' 60 | HM_LED_RED_MODE2='none' 61 | HM_LED_YELLOW='' 62 | HM_LED_YELLOW_MODE1='none' 63 | HM_LED_YELLOW_MODE2='none' 64 | HM_HOST_GPIO_UART='/dev/raw-uart' 65 | HM_HOST_GPIO_RESET='' 66 | HM_RTC='' 67 | HM_HMIP_DEV='$HM_HMIP_DEV' 68 | HM_HMIP_DEVNODE='$HM_HMIP_DEVNODE' 69 | HM_HMIP_SERIAL='$HM_HMIP_SERIAL' 70 | HM_HMIP_VERSION='$HM_HMIP_VERSION' 71 | HM_HMIP_SGTIN='$HM_HMIP_SGTIN' 72 | HM_HMIP_ADDRESS='$HM_HMIP_ADDRESS' 73 | HM_HMIP_ADDRESS_ACTIVE='$HM_HMIP_ADDRESS' 74 | HM_HMIP_DEVTYPE='$HM_HMIP_DEVTYPE' 75 | HM_HMRF_DEV='$HM_HMRF_DEV' 76 | HM_HMRF_DEVNODE='$HM_HMRF_DEVNODE' 77 | HM_HMRF_SERIAL='$HM_HMRF_SERIAL' 78 | HM_HMRF_VERSION='$HM_HMRF_VERSION' 79 | HM_HMRF_ADDRESS='$HM_HMRF_ADDRESS' 80 | HM_HMRF_ADDRESS_ACTIVE='$HM_HMRF_ADDRESS' 81 | HM_HMRF_DEVTYPE='$HM_HMRF_DEVTYPE' 82 | EOF 83 | 84 | if [[ -n "${HM_HMIP_SERIAL}" ]]; then 85 | echo -n "${HM_HMIP_SERIAL}" > /var/board_serial 86 | else 87 | echo -n "${HM_HMRF_SERIAL}" > /var/board_serial 88 | fi 89 | 90 | if [[ -n "${HM_HMIP_SGTIN}" ]]; then 91 | echo -n "${HM_HMIP_SGTIN}" > /var/board_sgtin 92 | fi 93 | 94 | echo -n "${HM_HMRF_SERIAL}" > /var/rf_board_serial 95 | echo -n "${HM_HMRF_ADDRESS}" > /var/rf_address 96 | echo -n "${HM_HMRF_VERSION}" > /var/rf_firmware_version 97 | echo -n "${HM_HMIP_SERIAL}" > /var/hmip_board_serial 98 | echo -n "${HM_HMIP_VERSION}" > /var/hmip_firmware_version 99 | echo -n "${HM_HMIP_ADDRESS}" > /var/hmip_address 100 | echo -n "${HM_HMIP_SGTIN}" > /var/hmip_board_sgtin 101 | 102 | -------------------------------------------------------------------------------- /pivccu/container3/wait_sysvar_creation.tcl: -------------------------------------------------------------------------------- 1 | #!/bin/tclsh 2 | 3 | load tclrpc.so 4 | load tclrega.so 5 | 6 | set script " 7 | boolean are_sv_created = false; 8 | string sv_id; 9 | 10 | foreach (sv_id, dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()) { 11 | if ((sv_id == 40) || (sv_id == 41) || (sv_id == ID_PRESENT)) { 12 | are_sv_created = true; 13 | } 14 | } 15 | " 16 | 17 | for {set i 0} {$i < 60} {incr i} { 18 | array set result [rega_script $script] 19 | set ise_are_sv_created $result(are_sv_created) 20 | 21 | if {$ise_are_sv_created} { 22 | break 23 | } 24 | 25 | exec sleep 5 26 | } 27 | 28 | -------------------------------------------------------------------------------- /pivccu/dkms/ensure_modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function throw { 3 | echo $1 4 | exit 1 5 | } 6 | 7 | function run { 8 | echo -n "$1 ... " 9 | shift 10 | ERR=`$* 2>&1` && RC=$? || RC=$? 11 | if [ $RC -eq 0 ]; then 12 | echo -e "\033[0;32mDone\033[0;0m" 13 | else 14 | echo -e "\033[1;91mFAILED\033[0;0m" 15 | echo "$ERR" 16 | exit 1 17 | fi 18 | } 19 | 20 | KERNEL_VER=`uname -r` 21 | 22 | function check_for_headers { 23 | if [ ! -e /usr/src/linux-headers-$KERNEL_VER ]; then 24 | throw "No headers found for current active kernel $KERNEL_VER" 25 | fi 26 | } 27 | 28 | function prepare_headers { 29 | cd /usr/src/linux-headers-$KERNEL_VER 30 | if [ ! -x scripts/recordmcount ]; then 31 | if [ `grep -c "^source \"net/wireguard/Kconfig\"" net/Kconfig` -gt 0 ]; then 32 | mkdir -p net/wireguard 33 | touch net/wireguard/Kconfig 34 | touch net/wireguard/Makefile 35 | fi 36 | 37 | make scripts 38 | 39 | if [ ! -x scripts/recordmcount ]; then 40 | make EXTRAVERSION="-`uname -r | cut -d- -f2-`" prepare0 41 | cd /usr/src/linux-headers-$KERNEL_VER/scripts 42 | make recordmcount 43 | fi 44 | fi 45 | } 46 | 47 | function reload_udev { 48 | if [ -e /etc/default/hb_rf_eth ]; then 49 | . /etc/default/hb_rf_eth 50 | fi 51 | if [ -z "$HB_RF_ETH_ADDRESS" ]; then 52 | for i in {1..12}; do 53 | if [ -e /dev/raw-uart ]; then 54 | break 55 | fi 56 | udevadm settle -t 5 -E /dev/raw-uart || true 57 | udevadm trigger -c add || true 58 | udevadm trigger || true 59 | sleep 5 60 | done 61 | fi 62 | } 63 | 64 | modinfo generic_raw_uart &> /dev/null && RC=$? || RC=$? 65 | if [ ! $RC -eq 0 ]; then 66 | PKG_VER=`dpkg -s pivccu-modules-dkms | grep '^Version: ' | cut -d' ' -f2` 67 | 68 | DKMS_STATUS=`dkms status -m pivccu -v $PKG_VER -k $KERNEL_VER` 69 | if [ ! -z "$DKMS_STATUS" ]; then 70 | run "Remove DKMS package" dkms remove -m pivccu -v $PKG_VER -k `uname -r` 71 | fi 72 | 73 | run "Check kernel headers" check_for_headers 74 | 75 | run "Prepare kernel headers" prepare_headers 76 | 77 | run "Install DKMS package" dkms install -m pivccu -v $PKG_VER -k $KERNEL_VER 78 | 79 | run "Try to load fresh build modules" modprobe generic_raw_uart 80 | 81 | run "Reload udev" reload_udev 82 | fi 83 | 84 | -------------------------------------------------------------------------------- /pivccu/dkms/pivccu-dkms.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=piVCCU DKMS Modules 3 | Before=pivccu.service 4 | Before=debmatic.service 5 | 6 | [Service] 7 | ExecStart=/var/lib/piVCCU/dkms/ensure_modules.sh 8 | Type=oneshot 9 | TimeoutSec=600s 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | RequiredBy=pivccu.service 14 | WantedBy=debmatic.service 15 | -------------------------------------------------------------------------------- /pivccu/host3/99-pivccu.rules: -------------------------------------------------------------------------------- 1 | ATTRS{idVendor}=="1b1f" ATTRS{idProduct}=="c020", ENV{ID_MM_DEVICE_IGNORE}="1" 2 | ATTRS{idVendor}=="1b1f" ATTRS{idProduct}=="c00f", ENV{ID_MM_DEVICE_IGNORE}="1" 3 | ATTRS{idVendor}=="0403" ATTRS{idProduct}=="6f70", ENV{ID_MM_DEVICE_IGNORE}="1" 4 | 5 | -------------------------------------------------------------------------------- /pivccu/host3/default.config: -------------------------------------------------------------------------------- 1 | PIVCCU_HMRF_MODE= 2 | PIVCCU_HMIP_MODE= 3 | PIVCCU_USB_DEVICES= 4 | -------------------------------------------------------------------------------- /pivccu/host3/detect_hardware.inc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -e /etc/default/pivccu3 ]; then 4 | . /etc/default/pivccu3 5 | fi 6 | 7 | if [ -e /sys/devices/virtual/eq3loop ]; then 8 | HM_EQ3LOOP_MAJOR=`cat /sys/devices/virtual/eq3loop/eq3loop/dev | cut -d: -f1` 9 | fi 10 | 11 | if [ -z "$PIVCCU_FAKE_SERIAL" ]; then 12 | PIVCCU_FAKE_SERIAL=`shuf -i 1-9999999 -n 1` 13 | PIVCCU_FAKE_SERIAL=`printf "FKE%07d" $PIVCCU_FAKE_SERIAL` 14 | echo "PIVCCU_FAKE_SERIAL=\"$PIVCCU_FAKE_SERIAL\"" >> /etc/default/pivccu3 15 | fi 16 | 17 | if [ -z "$PIVCCU_FAKE_RADIO_MAC" ]; then 18 | PIVCCU_FAKE_RADIO_MAC=`shuf -i 16711680-16777214 -n 1` 19 | PIVCCU_FAKE_RADIO_MAC=`printf "0x%06x" $PIVCCU_FAKE_RADIO_MAC` 20 | echo "PIVCCU_FAKE_RADIO_MAC=\"$PIVCCU_FAKE_RADIO_MAC\"" >> /etc/default/pivccu3 21 | fi 22 | 23 | HM_RAW_UART_MAJOR=1 24 | HM_RAW_UART_MINOR=3 25 | HM_HMIP_MAJOR=1 26 | HM_HMIP_MINOR=3 27 | 28 | case "$PIVCCU_RF_MODE" in 29 | "Fake") 30 | modprobe -q fake_hmrf 31 | if [ -e /sys/module/fake_hmrf ]; then 32 | HM_RAW_UART_MAJOR=`cat /sys/devices/virtual/fake-hmrf/fake-hmrf/dev | cut -d: -f1` 33 | HM_RAW_UART_MINOR=`cat /sys/devices/virtual/fake-hmrf/fake-hmrf/dev | cut -d: -f2` 34 | echo -n "$PIVCCU_FAKE_SERIAL" > /sys/module/fake_hmrf/parameters/board_serial 35 | echo -n "$PIVCCU_FAKE_RADIO_MAC" > /sys/module/fake_hmrf/parameters/radio_mac 36 | fi 37 | 38 | HM_HMIP_DEV="HM-MOD-RPI-PCB" 39 | HM_HMIP_DEVNODE="/dev/fake_hmrf" 40 | HM_HMIP_SERIAL="$PIVCCU_FAKE_SERIAL" 41 | HM_HMIP_VERSION=`grep "^CCU2 " /var/lib/piVCCU3/rootfs/firmware/fwmap | awk -F ' ' '{print $3}'` 42 | HM_HMIP_SGTIN="3014F711A061A7D5699D" 43 | HM_HMIP_ADDRESS="$PIVCCU_FAKE_RADIO_MAC" 44 | HM_HMIP_DEVTYPE="FAKE" 45 | HM_HMRF_DEV="$HM_HMIP_DEV" 46 | HM_HMRF_DEVNODE="$HM_HMIP_DEVNODE" 47 | HM_HMRF_SERIAL="$HM_HMIP_SERIAL" 48 | HM_HMRF_VERSION="$HM_HMIP_VERSION" 49 | HM_HMRF_ADDRESS="$PIVCCU_FAKE_RADIO_MAC" 50 | HM_HMRF_DEVTYPE="$HM_HMIP_DEVTYPE" 51 | HM_HMIP_MAJOR="$HM_EQ3LOOP_MAJOR" 52 | HM_HMIP_MINOR=1 53 | ;; 54 | 55 | *) 56 | if [ -e /etc/default/hb_rf_eth ]; then 57 | . /etc/default/hb_rf_eth 58 | fi 59 | 60 | if [ ! -z "$HB_RF_ETH_ADDRESS" ]; then 61 | if [ ! -e /sys/module/hb_rf_eth/parameters/connect ]; then 62 | modprobe -q hb_rf_eth 63 | 64 | /var/lib/piVCCU3/wait_network_up.sh 65 | 66 | for try in {0..30}; do 67 | if [ -e /sys/module/hb_rf_eth/parameters/connect ]; then 68 | break 69 | fi 70 | sleep 1 71 | done 72 | fi 73 | 74 | if [ -e /sys/module/hb_rf_eth/parameters/connect ]; then 75 | for try in {0..30}; do 76 | if [ -e /sys/class/hb-rf-eth/hb-rf-eth/connect ]; then 77 | echo "$HB_RF_ETH_ADDRESS" > /sys/class/hb-rf-eth/hb-rf-eth/connect && break 78 | else 79 | echo "$HB_RF_ETH_ADDRESS" > /sys/module/hb_rf_eth/parameters/connect && break 80 | fi 81 | sleep 2 82 | done 83 | fi 84 | fi 85 | 86 | for syspath in $(find /sys/bus/usb/devices/); do 87 | if [ ! -e $syspath/idVendor ]; then 88 | continue 89 | fi 90 | 91 | USBID="`cat $syspath/idVendor`:`cat $syspath/idProduct`" 92 | 93 | case "$USBID" in 94 | "0403:6f70") 95 | KMOD="hb_rf_usb" 96 | ;; 97 | "10c4:8c07" | "1b1f:c020") 98 | KMOD="hb_rf_usb_2" 99 | ;; 100 | *) 101 | continue 102 | ;; 103 | esac 104 | 105 | if [ $(lsmod | grep -w $KMOD | wc -l) -eq 0 ]; then 106 | modprobe -q $KMOD 107 | 108 | for try in {0..30}; do 109 | lsmod | grep -q -w $KMOD && RC=$? || RC=$? 110 | if [ $RC -eq 0 ]; then 111 | break 112 | fi 113 | sleep 1 114 | done 115 | fi 116 | 117 | for try in {0..30}; do 118 | if [ $(find $syspath/ -mindepth 2 -name driver | wc -l) -ne 0 ]; then 119 | break 120 | fi 121 | sleep 1 122 | done 123 | done 124 | 125 | for dev_no in {0..5} 126 | do 127 | if [ $dev_no -eq 0 ]; then 128 | UART_DEV="raw-uart" 129 | else 130 | UART_DEV="raw-uart$dev_no" 131 | fi 132 | 133 | if [ -e "/sys/class/raw-uart/$UART_DEV" ]; then 134 | if [ ! -e "/dev/$UART_DEV" ]; then 135 | mknod "/dev/$UART_DEV" c `cat /sys/class/raw-uart/$UART_DEV/dev | tr ':' ' '` 136 | fi 137 | 138 | MODULE_INFO=`detect_radio_module /dev/$UART_DEV` && RC=$? || RC=$? 139 | if [ $RC -eq 0 ]; then 140 | DEV_TYPE=`echo $MODULE_INFO | cut -d' ' -f1` 141 | DEV_SERIAL=`echo $MODULE_INFO | cut -d' ' -f2` 142 | 143 | HM_HMIP_DEV="$DEV_TYPE" 144 | HM_HMIP_DEVNODE="/dev/$UART_DEV" 145 | HM_HMIP_SERIAL="$DEV_SERIAL" 146 | HM_HMIP_VERSION=`echo $MODULE_INFO | cut -d' ' -f6` 147 | HM_HMIP_SGTIN=`echo $MODULE_INFO | cut -d' ' -f3` 148 | HM_HMIP_ADDRESS=`echo $MODULE_INFO | cut -d' ' -f5` 149 | if [ -e "/sys/class/raw-uart/$UART_DEV/device_type" ]; then 150 | HM_HMIP_DEVTYPE=`cat /sys/class/raw-uart/$UART_DEV/device_type` 151 | fi 152 | 153 | if [ "$DEV_TYPE" == "HMIP-RFUSB-TK" ]; then 154 | HM_HMRF_DEV="HM-MOD-RPI-PCB" 155 | HM_HMRF_DEVNODE="/dev/fake_hmrf" 156 | HM_HMRF_SERIAL="$PIVCCU_FAKE_SERIAL" 157 | HM_HMRF_VERSION=`grep "^CCU2 " /var/lib/piVCCU3/rootfs/firmware/fwmap | awk -F ' ' '{print $3}'` 158 | HM_HMRF_ADDRESS="$PIVCCU_FAKE_RADIO_MAC" 159 | HM_HMRF_DEVTYPE="FAKE" 160 | 161 | modprobe -q fake_hmrf 162 | if [ -e /sys/module/fake_hmrf ]; then 163 | echo -n "$PIVCCU_FAKE_SERIAL" > /sys/module/fake_hmrf/parameters/board_serial 164 | echo -n "$PIVCCU_FAKE_RADIO_MAC" > /sys/module/fake_hmrf/parameters/radio_mac 165 | HM_RAW_UART_MAJOR=`cat /sys/devices/virtual/fake-hmrf/fake-hmrf/dev | cut -d: -f1` 166 | HM_RAW_UART_MINOR=`cat /sys/devices/virtual/fake-hmrf/fake-hmrf/dev | cut -d: -f2` 167 | fi 168 | HM_HMIP_MAJOR=`cat /sys/class/raw-uart/$UART_DEV/dev | cut -d: -f1` 169 | HM_HMIP_MINOR=`cat /sys/class/raw-uart/$UART_DEV/dev | cut -d: -f2` 170 | else 171 | HM_HMRF_DEV="$HM_HMIP_DEV" 172 | HM_HMRF_DEVNODE="$HM_HMIP_DEVNODE" 173 | HM_HMRF_SERIAL="$HM_HMIP_SERIAL" 174 | HM_HMRF_VERSION="$HM_HMIP_VERSION" 175 | HM_HMRF_ADDRESS=`echo $MODULE_INFO | cut -d' ' -f4` 176 | HM_HMRF_DEVTYPE="$HM_HMIP_DEVTYPE" 177 | 178 | HM_RAW_UART_MAJOR=`cat /sys/class/raw-uart/$UART_DEV/dev | cut -d: -f1` 179 | HM_RAW_UART_MINOR=`cat /sys/class/raw-uart/$UART_DEV/dev | cut -d: -f2` 180 | HM_HMIP_MAJOR="$HM_EQ3LOOP_MAJOR" 181 | HM_HMIP_MINOR=1 182 | fi 183 | 184 | break 185 | fi 186 | fi 187 | done 188 | ;; 189 | esac 190 | 191 | BRIDGE=`brctl show | grep -v "lxcbr0" | grep -v "^\s" | sed -n 2p | awk '{print $1}'` 192 | MAIN_INTERFACE=`route | grep 'default' | awk '{print $5" "$8}' | sort | awk '{print $2}' | uniq | head -n 1` 193 | HOST_MAC=`cat /sys/class/net/$MAIN_INTERFACE/address` 194 | MAC=`echo $HOST_MAC | md5sum | sed 's/\(.\)\(..\)\(..\)\(..\)\(..\)\(..\).*/\1a:\2:\3:\4:\5:\6/'` 195 | 196 | -------------------------------------------------------------------------------- /pivccu/host3/lxc.config: -------------------------------------------------------------------------------- 1 | lxc.utsname = piVCCU 2 | 3 | lxc.hook.start = /etc/piVCCU3/start-hook.sh 4 | 5 | lxc.rootfs = /var/lib/piVCCU3/rootfs 6 | lxc.rootfs.options = ro 7 | 8 | lxc.mount.auto = proc sys:rw cgroup 9 | lxc.mount.entry = devpts dev/pts devpts defaults,newinstance 0 0 10 | 11 | lxc.mount.entry = tmpfs tmp tmpfs defaults,mode=1777 0 0 12 | lxc.mount.entry = /tmp/pivccu-var var none defaults,bind 0 0 13 | lxc.mount.entry = /tmp/pivccu-media media none defaults,bind 0 0 14 | lxc.mount.entry = tmpfs run tmpfs defaults,mode=0755,nosuid,nodev 0 0 15 | lxc.mount.entry = tmpfs dev/shm tmpfs defaults,nosuid,nodev,noexec,mode=1777,size=16M,create=dir 0 0 16 | 17 | lxc.mount.entry = /var/lib/piVCCU3/userfs usr/local/ none defaults,bind 0 0 18 | 19 | lxc.network.type = veth 20 | lxc.network.flags = up 21 | lxc.network.link = 22 | lxc.network.hwaddr = 23 | lxc.network.veth.pair = vethpivccu 24 | 25 | lxc.cgroup.devices.deny = a 26 | lxc.cgroup.devices.allow = c 1:3 rwm 27 | lxc.cgroup.devices.allow = c 1:5 rwm 28 | lxc.cgroup.devices.allow = c 1:8 rwm 29 | lxc.cgroup.devices.allow = c 1:9 rwm 30 | lxc.cgroup.devices.allow = c 5:0 rwm 31 | lxc.cgroup.devices.allow = c 5:1 rwm 32 | lxc.cgroup.devices.allow = c 5:2 rwm 33 | lxc.cgroup.devices.allow = c 10:200 rwm 34 | lxc.cgroup.devices.allow = c 136:* rwm 35 | lxc.cgroup.devices.allow = c :0 rwm 36 | lxc.cgroup.devices.allow = c :1 rwm 37 | lxc.cgroup.devices.allow = c :2 rwm 38 | lxc.cgroup.devices.allow = c : rwm 39 | lxc.cgroup.devices.allow = c : rwm 40 | 41 | lxc.aa_profile = unconfined 42 | 43 | lxc.pts = 1024 44 | -------------------------------------------------------------------------------- /pivccu/host3/monitor-hb-rf-eth.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Monitor HB-RF-ETH 3 | PartOf=pivccu.service 4 | After=pivccu.service 5 | ConditionPathExists=/sys/class/hb-rf-eth/hb-rf-eth/is_connected 6 | 7 | [Service] 8 | Type=simple 9 | ExecStart=/var/lib/piVCCU3/monitor_hb_rf_connection.sh 10 | Restart=on-abnormal 11 | RestartSec=5s 12 | 13 | [Install] 14 | WantedBy=pivccu.service 15 | 16 | -------------------------------------------------------------------------------- /pivccu/host3/monitor_hb_rf_connection.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo -n "Waiting for CCU startup " 4 | while true; do 5 | if [ -e /tmp/pivccu-var/status/startupFinished ] && [ `/usr/bin/lxc-info --lxcpath /var/lib/piVCCU3/ --name lxc --state --no-humanize` == "RUNNING" ]; then 6 | echo " Done." 7 | break 8 | fi 9 | echo -n "." 10 | sleep 1 11 | done 12 | 13 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3/ --name lxc -- /etc/piVCCU3/wait_sysvar_creation.tcl || true 14 | 15 | STATE=`cat /sys/class/hb-rf-eth/hb-rf-eth/is_connected` 16 | 17 | while true; do 18 | if [ "$STATE" -eq "1" ]; then 19 | echo "HB-RF-ETH is (re-)connected" 20 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3/ --name lxc -- /etc/piVCCU3/set_hb_rf_eth_connection_dp.tcl false || true 21 | else 22 | echo "HB-RF-ETH is not connected anymore" 23 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3/ --name lxc -- /etc/piVCCU3/set_hb_rf_eth_connection_dp.tcl true || true 24 | fi 25 | 26 | STATE=`wait_sysfs_notify /sys/class/hb-rf-eth/hb-rf-eth/is_connected` 27 | if [ $? != 0 ]; then 28 | exit 29 | fi 30 | done 31 | 32 | -------------------------------------------------------------------------------- /pivccu/host3/pivccu-attach.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $EUID != 0 ]; then 3 | echo "Please run as root" 4 | exit 1 5 | fi 6 | 7 | if [ `/usr/bin/lxc-info --lxcpath /var/lib/piVCCU3/ --name lxc --state --no-humanize` == "STOPPED" ]; then 8 | echo "piVCCU is not running, cannot attach." 9 | exit 1 10 | fi 11 | 12 | if [ $# -eq 0 ]; then 13 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3 --name lxc 14 | else 15 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3 --name lxc -- $@ 16 | fi 17 | 18 | -------------------------------------------------------------------------------- /pivccu/host3/pivccu-backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ $EUID != 0 ]; then 6 | echo "Please run as root" 7 | exit 8 | fi 9 | 10 | if [ $# -ne 1 ] || [ ! -d "$1" ]; then 11 | echo "pivccu-backup " 12 | exit 1 13 | fi 14 | 15 | CURDIR=`pwd` 16 | 17 | BACKUPPATH="$1/pivccu3_`dpkg -s pivccu3 | grep '^Version: ' | cut -d' ' -f2`_`date '+%Y-%m-%d_%H-%M-%S'`.sbk" 18 | BACKUPPATH=`realpath $BACKUPPATH` 19 | 20 | if [ `/usr/bin/lxc-info --lxcpath /var/lib/piVCCU3/ --name lxc --state --no-humanize` != "STOPPED" ]; then 21 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3/ --name lxc -- /etc/piVCCU3/save-rega.tcl 22 | fi 23 | 24 | TMPDIR=`mktemp -d` 25 | 26 | mkdir -p $TMPDIR/root 27 | mount --bind /var/lib/piVCCU3/rootfs $TMPDIR/root 28 | mount --bind /var/lib/piVCCU3/userfs $TMPDIR/root/usr/local 29 | 30 | cd $TMPDIR/root 31 | tar czf $TMPDIR/usr_local.tar.gz usr/local 32 | 33 | /usr/sbin/chroot $TMPDIR/root crypttool -s -t 1 < $TMPDIR/usr_local.tar.gz > $TMPDIR/signature 34 | /usr/sbin/chroot $TMPDIR/root crypttool -g -t 1 > $TMPDIR/key_index 35 | 36 | cp $TMPDIR/root/boot/VERSION $TMPDIR/firmware_version 37 | 38 | cd $TMPDIR 39 | umount $TMPDIR/root/usr/local 40 | umount $TMPDIR/root 41 | 42 | tar cf $BACKUPPATH usr_local.tar.gz signature firmware_version key_index 43 | 44 | cd $CURDIR 45 | rm -rf $TMPDIR 46 | 47 | echo "Backup written to $BACKUPPATH" 48 | -------------------------------------------------------------------------------- /pivccu/host3/pivccu-info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "piVCCU version: `dpkg -s pivccu3 | grep '^Version: ' | cut -d' ' -f2`" 3 | 4 | if [ $EUID != 0 ]; then 5 | echo "Please run as root" 6 | exit 1 7 | fi 8 | 9 | . /etc/default/pivccu3 10 | 11 | if [ -e /etc/os-release ]; then 12 | PRETTY_NAME=$(grep '^PRETTY_NAME=' /etc/os-release | cut -d '=' -f2 | sed 's/^\"//' | sed 's/\"$//') 13 | fi 14 | if [ -z "$PRETTY_NAME" ]; then 15 | PRETTY_NAME="Unknown" 16 | fi 17 | echo "OS: $PRETTY_NAME" 18 | echo "Kernel: `uname -r -m`" 19 | 20 | modprobe -q generic_raw_uart && RC=$? || RC=$? 21 | if [ $RC -eq 0 ]; then 22 | MODULE_STATE="Available" 23 | else 24 | MODULE_STATE="Not available" 25 | fi 26 | echo "Kernel modules: $MODULE_STATE" 27 | 28 | if [ "`/usr/bin/lxc-info --lxcpath /var/lib/piVCCU3/ --name lxc --state --no-humanize`" == "STOPPED" ]; then 29 | . /var/lib/piVCCU3/detect_hardware.inc 30 | else 31 | if [ -e /tmp/pivccu-var/pivccu/conf ]; then 32 | . /tmp/pivccu-var/pivccu/conf 33 | fi 34 | fi 35 | 36 | if [ "$(echo /sys/class/raw-uart/raw-uart*)" != "/sys/class/raw-uart/raw-uart*" ]; then 37 | RAW_UART_STATE="Available" 38 | else 39 | RAW_UART_STATE="Not available" 40 | fi 41 | echo "Raw UART dev: $RAW_UART_STATE" 42 | 43 | if [ -f /proc/device-tree/model ] && [ `grep -c "Raspberry Pi" /proc/device-tree/model` == 1 ] && [ `grep -c "Raspberry Pi 2" /proc/device-tree/model` == 0 ]; then 44 | if cmp -s /proc/device-tree/aliases/uart0 /proc/device-tree/aliases/serial0; then 45 | UART_STATE="Assigned to GPIO pins" 46 | else 47 | UART_STATE="Not assigned to GPIO pins" 48 | fi 49 | echo "Rasp.Pi UART: $UART_STATE" 50 | fi 51 | 52 | if [ -z "$HM_HMRF_DEV" ]; then 53 | echo "HMRF Hardware: unknown" 54 | elif [ "$HM_HMRF_DEVTYPE" == "FAKE" ]; then 55 | echo "HMRF Hardware: Emulated" 56 | else 57 | echo "HMRF Hardware: $HM_HMRF_DEV" 58 | 59 | if [ ! -z "$HM_HMRF_DEVTYPE" ]; then 60 | echo " Connected via: $HM_HMRF_DEVTYPE ($HM_HMRF_DEVNODE)" 61 | fi 62 | 63 | if [ -z "$HM_HMRF_SERIAL" ]; then 64 | HM_HMRF_SERIAL='unknown' 65 | fi 66 | echo " Board serial: $HM_HMRF_SERIAL" 67 | 68 | if [ -z "$HM_HMRF_ADDRESS" ]; then 69 | HM_HMRF_ADDRESS='unknown' 70 | fi 71 | echo " Radio MAC: $HM_HMRF_ADDRESS" 72 | fi 73 | 74 | if [ -z "$HM_HMIP_DEV" ]; then 75 | echo "HMIP Hardware: unknown" 76 | elif [ "$HM_HMIP_DEVTYPE" == "FAKE" ]; then 77 | echo "HMIP Hardware: Emulated" 78 | else 79 | echo "HMIP Hardware: $HM_HMIP_DEV" 80 | 81 | if [ ! -z "$HM_HMIP_DEVTYPE" ]; then 82 | echo " Connected via: $HM_HMIP_DEVTYPE ($HM_HMIP_DEVNODE)" 83 | fi 84 | 85 | if [ -z "$HM_HMIP_SGTIN" ]; then 86 | HM_HMIP_SGTIN='unknown' 87 | fi 88 | echo " SGTIN: $HM_HMIP_SGTIN" 89 | 90 | if [ -z "$HM_HMIP_ADDRESS" ]; then 91 | HM_HMIP_ADDRESS='unknown' 92 | fi 93 | echo " Radio MAC: $HM_HMIP_ADDRESS" 94 | fi 95 | 96 | /usr/bin/lxc-info --lxcpath /var/lib/piVCCU3/ --name lxc --ips --pid --stats --state 97 | 98 | -------------------------------------------------------------------------------- /pivccu/host3/pivccu-startupfinished.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=piVCCU startup finished 3 | PartOf=pivccu.service 4 | After=pivccu.service 5 | 6 | [Service] 7 | Type=oneshot 8 | RemainAfterExit=yes 9 | ExecStart=/var/lib/piVCCU3/wait_for_startup.sh 10 | 11 | [Install] 12 | WantedBy=pivccu.service 13 | -------------------------------------------------------------------------------- /pivccu/host3/pivccu.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=piVCCU 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/var/lib/piVCCU3/start_container.sh 7 | ExecStop=/var/lib/piVCCU3/stop_container.sh 8 | Type=forking 9 | PIDFile=/var/run/pivccu3.pid 10 | TimeoutSec=300s 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | 15 | -------------------------------------------------------------------------------- /pivccu/host3/start_container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . /etc/default/pivccu3 4 | 5 | modprobe ip_tables || true 6 | modprobe ip6_tables || true 7 | 8 | modprobe eq3_char_loop && RC=$? || RC=$? 9 | if [ $RC -ne 0 ]; then 10 | logger -t piVCCU3 -p user.err -s "Could not load required kernel module eq3_char_loop." 1>&2 11 | exit 12 | fi 13 | 14 | . /var/lib/piVCCU3/detect_hardware.inc 15 | 16 | if [ -z "$HM_HMRF_DEV" ]; then 17 | logger -t piVCCU3 -p user.warn -s "HMRF hardware was not detected" 1>&2 18 | fi 19 | 20 | if [ -z "$HM_HMIP_DEV" ]; then 21 | logger -t piVCCU3 -p user.warn -s "HMIP hardware was not detected" 1>&2 22 | fi 23 | 24 | RED_PIN=0 25 | GREEN_PIN=0 26 | BLUE_PIN=0 27 | 28 | if [ "$HM_HMIP_DEV" == "RPI-RF-MOD" ]; then 29 | modprobe dummy_rx8130 || true 30 | 31 | if [ -e "/sys/module/generic_raw_uart/parameters/red_gpio_pin" ]; then 32 | RED_PIN=`cat /sys/module/generic_raw_uart/parameters/red_gpio_pin` 33 | GREEN_PIN=`cat /sys/module/generic_raw_uart/parameters/green_gpio_pin` 34 | BLUE_PIN=`cat /sys/module/generic_raw_uart/parameters/blue_gpio_pin` 35 | fi 36 | if [ -e "/sys/class/raw-uart/$UART_DEV/red_gpio_pin" ]; then 37 | RED_PIN=`cat /sys/class/raw-uart/$UART_DEV/red_gpio_pin` 38 | GREEN_PIN=`cat /sys/class/raw-uart/$UART_DEV/green_gpio_pin` 39 | BLUE_PIN=`cat /sys/class/raw-uart/$UART_DEV/blue_gpio_pin` 40 | fi 41 | fi 42 | 43 | modprobe ledtrig-timer || modprobe led_trigger_timer || true 44 | modprobe ledtrig-default-on || true 45 | modprobe rpi_rf_mod_led red_gpio_pin=$RED_PIN green_gpio_pin=$GREEN_PIN blue_gpio_pin=$BLUE_PIN || true 46 | 47 | mkdir -p /var/lib/piVCCU3/lxc 48 | 49 | if [ -z "$BRIDGE" ]; then 50 | logger -t piVCCU3 -p user.warning -s "No network bridge could be detected." 1>&2 51 | fi 52 | 53 | rm -rf /tmp/pivccu-media 54 | mkdir -p /tmp/pivccu-media 55 | 56 | rm -rf /tmp/pivccu-var 57 | mkdir -p /tmp/pivccu-var/pivccu 58 | 59 | CONFIG_FILE=/var/lib/piVCCU3/lxc/config 60 | cat /etc/piVCCU3/lxc.config > $CONFIG_FILE 61 | 62 | sed -i $CONFIG_FILE -e "s//$MAC/" 63 | sed -i $CONFIG_FILE -e "s//$BRIDGE/" 64 | sed -i $CONFIG_FILE -e "s//$HM_EQ3LOOP_MAJOR/" 65 | sed -i $CONFIG_FILE -e "s//$HM_RAW_UART_MAJOR/" 66 | sed -i $CONFIG_FILE -e "s//$HM_RAW_UART_MINOR/" 67 | sed -i $CONFIG_FILE -e "s//$HM_HMIP_MAJOR/" 68 | sed -i $CONFIG_FILE -e "s//$HM_HMIP_MINOR/" 69 | 70 | command -v lxc-update-config > /dev/null && lxc-update-config -c $CONFIG_FILE 71 | 72 | cat > /tmp/pivccu-var/pivccu/conf << EOF 73 | HM_RAW_UART_MAJOR='$HM_RAW_UART_MAJOR' 74 | HM_RAW_UART_MINOR='$HM_RAW_UART_MINOR' 75 | HM_HMIP_MAJOR='$HM_HMIP_MAJOR' 76 | HM_HMIP_MINOR='$HM_HMIP_MINOR' 77 | HM_EQ3LOOP_MAJOR='$HM_EQ3LOOP_MAJOR' 78 | HM_HMIP_DEV='$HM_HMIP_DEV' 79 | HM_HMIP_DEVNODE='$HM_HMIP_DEVNODE' 80 | HM_HMIP_SERIAL='$HM_HMIP_SERIAL' 81 | HM_HMIP_VERSION='$HM_HMIP_VERSION' 82 | HM_HMIP_SGTIN='$HM_HMIP_SGTIN' 83 | HM_HMIP_ADDRESS='$HM_HMIP_ADDRESS' 84 | HM_HMIP_DEVTYPE='$HM_HMIP_DEVTYPE' 85 | HM_HMRF_DEV='$HM_HMRF_DEV' 86 | HM_HMRF_DEVNODE='$HM_HMRF_DEVNODE' 87 | HM_HMRF_SERIAL='$HM_HMRF_SERIAL' 88 | HM_HMRF_VERSION='$HM_HMRF_VERSION' 89 | HM_HMRF_ADDRESS='$HM_HMRF_ADDRESS' 90 | HM_HMRF_DEVTYPE='$HM_HMRF_DEVTYPE' 91 | EOF 92 | 93 | OIFS=$IFS 94 | IFS=, 95 | declare -a devices=($PIVCCU_USB_DEVICES) 96 | IFS=$OIFS 97 | 98 | USBDISKINDEX=1 99 | 100 | for dev in ${devices[@]}; do 101 | IFS=";" read vendor_id model_id serial_short usb_interface_num part_entry_uuid <<< "$dev" 102 | 103 | FOUND=0 104 | for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do 105 | syspath="${sysdevpath%/dev}" 106 | 107 | declare -A UDEV_PROPERTIES=() 108 | while IFS='=' read -r a b; do UDEV_PROPERTIES["$a"]="$b"; done < <(udevadm info -q property -p $syspath) 109 | 110 | [[ "${UDEV_PROPERTIES[ID_VENDOR_ID]}" != "$vendor_id" ]] && continue 111 | [[ "${UDEV_PROPERTIES[ID_MODEL_ID]}" != "$model_id" ]] && continue 112 | [[ "${UDEV_PROPERTIES[ID_SERIAL_SHORT]}" != "$serial_short" ]] && continue 113 | [[ "${UDEV_PROPERTIES[ID_USB_INTERFACE_NUM]}" != "$usb_interface_num" ]] && continue 114 | [[ "${UDEV_PROPERTIES[ID_PART_ENTRY_UUID]}" != "$part_entry_uuid" ]] && continue 115 | 116 | FOUND=1 117 | 118 | if [ "${UDEV_PROPERTIES[DEVTYPE]}" == "partition" ]; then 119 | DEVTYPE="b" 120 | echo "mount -t ${UDEV_PROPERTIES[ID_FS_TYPE]} -o noexec,nodev,noatime,nodiratime ${UDEV_PROPERTIES[DEVNAME]} /media/usb$USBDISKINDEX" >> /tmp/pivccu-var/pivccu/create-mounts 121 | mkdir -p /tmp/pivccu-media/usb$USBDISKINDEX 122 | if [ ! -e /tmp/pivccu-media/usb0 ]; then 123 | ln -s /media/usb$USBDISKINDEX /tmp/pivccu-media/usb0 124 | fi 125 | mkdir -p /tmp/pivccu-var/status 126 | echo "HAS_USB=1" >> /tmp/pivccu-var/pivccu/conf 127 | let "USBDISKINDEX++" 128 | else 129 | DEVTYPE="c" 130 | fi 131 | 132 | echo "lxc.cgroup.devices.allow = $DEVTYPE ${UDEV_PROPERTIES[MAJOR]}:${UDEV_PROPERTIES[MINOR]} rwm" >> $CONFIG_FILE 133 | 134 | echo "rm -f ${UDEV_PROPERTIES[DEVNAME]}" >> /tmp/pivccu-var/pivccu/create-devs 135 | echo "mknod -m 666 ${UDEV_PROPERTIES[DEVNAME]} $DEVTYPE ${UDEV_PROPERTIES[MAJOR]} ${UDEV_PROPERTIES[MINOR]}" >> /tmp/pivccu-var/pivccu/create-devs 136 | 137 | for alias in ${UDEV_PROPERTIES[DEVLINKS]}; do 138 | aliasdir=`dirname $alias` 139 | echo "mkdir -p $aliasdir" >> /tmp/pivccu-var/pivccu/create-devs 140 | echo "rm -f $alias" >> /tmp/pivccu-var/pivccu/create-devs 141 | echo "ln -s ${UDEV_PROPERTIES[DEVNAME]} $alias" >> /tmp/pivccu-var/pivccu/create-devs 142 | done 143 | done 144 | 145 | (($FOUND)) && continue 146 | logger -t piVCCU3 -p user.warning -s "Could not find configured USB device $vendor_id:$model_id ($serial_short)." 1>&2 147 | done 148 | 149 | PIVCCU_VERSION=$(dpkg -s pivccu3 | grep '^Version: ' | cut -d' ' -f2) 150 | 151 | if [ -e /etc/os-release ]; then 152 | OS_ID=$(grep '^ID=' /etc/os-release | cut -d '=' -f2) 153 | VERSION_CODENAME=$(grep '^VERSION_CODENAME=' /etc/os-release | cut -d '=' -f2) 154 | if [ -z "$VERSION_CODENAME" ]; then 155 | VERSION_CODENAME=$(grep '^VERSION_ID=' /etc/os-release | cut -d '=' -f2) 156 | fi 157 | else 158 | OS_ID=unknown 159 | VERSION_CODENAME=unknown 160 | fi 161 | 162 | OS_ARCH=$(uname -m) 163 | 164 | if [ -e /etc/armbian-release ]; then 165 | BOARD_TYPE=$(grep '^BOARD=' /etc/armbian-release | cut -d '=' -f2) 166 | ARMBIAN_CODENAME=$(grep '^DISTRIBUTION_CODENAME=' /etc/armbian-release | cut -d '=' -f2) 167 | if [ -n "$ARMBIAN_CODENAME" ]; then 168 | VERSION_CODENAME=$ARMBIAN_CODENAME 169 | fi 170 | OS_ID=armbian 171 | elif [ -e /sys/firmware/devicetree/base/compatible ]; then 172 | BOARD_TYPE=$(strings /sys/firmware/devicetree/base/compatible | tr '\n' ':' | tr ',' '_') 173 | else 174 | BOARD_TYPE=unknown 175 | fi 176 | 177 | OS_RELEASE=${OS_ID}_${VERSION_CODENAME} 178 | 179 | wget -O /dev/null -q --timeout=5 "https://www.pivccu.de/latestVersion?version=$PIVCCU_VERSION&product=HM-CCU3&serial=$HM_HMIP_SERIAL&os=$OS_RELEASE&board=$BOARD_TYPE" || true 180 | 181 | sysctl -w kernel.sched_rt_runtime_us=-1 182 | 183 | if [ -x /etc/piVCCU3/pre-start.sh ]; then 184 | /etc/piVCCU3/pre-start.sh 185 | fi 186 | 187 | if [ -e /proc/sys/abi/cp15_barrier ]; then 188 | echo 2 > /proc/sys/abi/cp15_barrier 189 | fi 190 | if [ -e /proc/sys/abi/setend ]; then 191 | echo 2 > /proc/sys/abi/setend 192 | fi 193 | 194 | /usr/bin/lxc-start --lxcpath /var/lib/piVCCU3 --name lxc --pidfile /var/run/pivccu3.pid --daemon 195 | 196 | if [ -x /etc/piVCCU3/post-start.sh ]; then 197 | /etc/piVCCU3/post-start.sh 198 | fi 199 | 200 | -------------------------------------------------------------------------------- /pivccu/host3/stop_container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -e /etc/piVCCU3/pre-stop.sh ]; then 4 | /etc/piVCCU3/pre-stop.sh 5 | fi 6 | 7 | # stop container 8 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3/ --name lxc -- /etc/piVCCU3/save-rega.tcl || true 9 | /usr/bin/lxc-attach --lxcpath /var/lib/piVCCU3/ --name lxc -- poweroff || true 10 | /usr/bin/lxc-wait --lxcpath /var/lib/piVCCU3/ --name lxc --state STOPPED --timeout 300 || /usr/bin/lxc-stop --lxcpath /var/lib/piVCCU3/ --name lxc 11 | 12 | if [ -e /etc/piVCCU3/post-stop.sh ]; then 13 | /etc/piVCCU3/post-stop.sh 14 | fi 15 | 16 | rm -rf /tmp/pivccu-media 17 | rm -rf /tmp/pivccu-var 18 | 19 | # unload kernel modules 20 | rmmod eq3_char_loop || true 21 | rmmod fake_hmrf || true 22 | rmmod dummy_rx8130 || true 23 | rmmod rpi_rf_mod_led || true 24 | rmmod hb_rf_eth || true 25 | 26 | -------------------------------------------------------------------------------- /pivccu/host3/wait_for_startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo -n "Waiting for CCU startup " 3 | sleep 5 4 | while true; do 5 | if [ -e /tmp/pivccu-var/status/startupFinished ] && [ `/usr/bin/lxc-info --lxcpath /var/lib/piVCCU3/ --name lxc --state --no-humanize` == "RUNNING" ]; then 6 | echo " Done." 7 | break 8 | fi 9 | echo -n "." 10 | sleep 1 11 | done 12 | -------------------------------------------------------------------------------- /pivccu/host3/wait_network_up.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | INTERFACES=`ifquery --list --exclude lo --allow auto | xargs` 3 | 4 | if [ -n "$INTERFACES" ]; then 5 | exit 0 6 | fi 7 | 8 | while ! ifquery --state $INTERFACES >/dev/null; do 9 | sleep 1 10 | done 11 | 12 | for i in $INTERFACES; do 13 | while [ -e /run/network/ifup-$i.pid ]; do 14 | sleep 0.2 15 | done 16 | done 17 | 18 | -------------------------------------------------------------------------------- /pivccu/rpi-modules/ensure_headers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | FW_REPO="https://raw.githubusercontent.com/Hexxeh/rpi-firmware/" 3 | KERNEL_REPO="https://github.com/raspberrypi/linux/" 4 | 5 | ACTIVE_KERNEL=`uname -r` 6 | MODULE_DIR="/lib/modules/$ACTIVE_KERNEL" 7 | 8 | modinfo generic_raw_uart &> /dev/null && RC=$? || RC=$? 9 | if [ $RC -eq 0 ]; then 10 | exit 11 | fi 12 | 13 | if [ -e $MODULE_DIR/build ]; then 14 | exit 15 | fi 16 | 17 | set -e 18 | 19 | if [ -f /boot/.firmware_revision ]; then 20 | FW_HASH=`cat /boot/.firmware_revision` 21 | KERNEL_GIT_HASH=`wget -O - -q $FW_REPO$FW_HASH/git_hash` 22 | KERNEL_GIT_VERSION=`wget -O - -q $FW_REPO$FW_HASH/uname_string7 | cut -d' ' -f3` 23 | 24 | if [ "$KERNEL_GIT_VERSION" != "$ACTIVE_KERNEL" ]; then 25 | echo "/boot/.firmware_revision does not match active kernel version." 26 | exit 1 27 | fi 28 | 29 | echo "Downloading kernel sources from GIT" 30 | wget -O $MODULE_DIR/linux.tar.gz -q $KERNEL_REPO/archive/$KERNEL_GIT_HASH.tar.gz 31 | 32 | echo "Unpacking kernel sources" 33 | cd $MODULE_DIR 34 | tar -xzf $MODULE_DIR/linux.tar.gz 35 | rm $MODULE_DIR/linux.tar.gz 36 | mv $MODULE_DIR/linux-$KERNEL_GIT_HASH $MODULE_DIR/source 37 | ln -sf $MODULE_DIR/source $MODULE_DIR/build 38 | 39 | echo "Configuring kernel sources" 40 | cd $MODULE_DIR/source 41 | KERNEL=kernel7 42 | modprobe configs &> /dev/null 43 | zcat /proc/config.gz > $MODULE_DIR/source/.config 44 | make modules_prepare 45 | else 46 | echo "Could not determine kernel source." 47 | exit 1 48 | fi 49 | 50 | -------------------------------------------------------------------------------- /pivccu/rpi-modules/pivccu-rpi-modules.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=piVCCU RPi Kernel loader 3 | Before=pivccu-dkms.service 4 | Wants=network-online.target 5 | After=network-online.target 6 | 7 | [Service] 8 | ExecStart=/var/lib/piVCCU/rpi-modules/ensure_headers.sh 9 | Type=oneshot 10 | TimeoutSec=600s 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | 15 | -------------------------------------------------------------------------------- /pivccu/rtc/40-rpi-rf-mod.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEM=="rtc", DRIVERS=="rtc-rx8130", SYMLINK+="rtc", OPTIONS+="link_priority=-50", ACTION=="add", RUN+="/usr/bin/logger -t rtc-rx8130 Detected RX8130 RTC at $root/$name, updating system time", RUN+="/sbin/hwclock --rtc $root/$name --hctosys" 2 | -------------------------------------------------------------------------------- /pivccu/rtc/rpi-rf-mod_systohc.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | ConditionCapability=CAP_SYS_TIME 3 | ConditionVirtualization=!container 4 | ConditionPathExists=/dev/rtc 5 | After=systemd-timesyncd.service 6 | 7 | [Service] 8 | Type=oneshot 9 | CapabilityBoundingSet=CAP_SYS_TIME 10 | PrivateTmp=yes 11 | ProtectSystem=full 12 | ProtectHome=yes 13 | DeviceAllow=/dev/rtc rw 14 | DevicePolicy=closed 15 | ExecStart=/sbin/hwclock -f /dev/rtc --systohc 16 | 17 | -------------------------------------------------------------------------------- /pivccu/rtc/rpi-rf-mod_systohc.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | 3 | [Timer] 4 | OnUnitActiveSec=1h 5 | OnBootSec=5m 6 | 7 | [Install] 8 | WantedBy=timers.target 9 | -------------------------------------------------------------------------------- /wait_sysfs_notify/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -static-libstdc++ 3 | OBJS = main.o 4 | 5 | all: wait_sysfs_notify 6 | 7 | wait_sysfs_notify: $(OBJS) 8 | $(LINK.cc) $(OBJS) -o $@ 9 | 10 | clean: 11 | rm -f $(OBJS) wait_sysfs_notify 12 | 13 | -------------------------------------------------------------------------------- /wait_sysfs_notify/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | if (argc != 2) 14 | { 15 | printf("Usage: %s \n", argv[0]); 16 | return -1; 17 | } 18 | 19 | int fd = open(argv[1], O_RDONLY); 20 | if (fd < 0) 21 | { 22 | close(fd); 23 | printf("%s could not be opened\n", argv[1]); 24 | return -1; 25 | } 26 | 27 | char buffer[1024]; 28 | if (read(fd, buffer, sizeof(buffer)) == -1) 29 | { 30 | printf("%s could is not readable\n", argv[1]); 31 | return -1; 32 | } 33 | 34 | struct pollfd fds = { .fd = fd, .events = POLLPRI|POLLERR, .revents = 0 }; 35 | 36 | if (poll(&fds, 1, -1) <= 0) 37 | { 38 | return -1; 39 | } 40 | 41 | if (lseek(fd, 0, SEEK_SET) == -1) 42 | { 43 | return -1; 44 | } 45 | 46 | int cnt = read(fd, buffer, sizeof(buffer) - 1); 47 | if (cnt <= 0) 48 | { 49 | return -1; 50 | } 51 | 52 | close(fd); 53 | 54 | buffer[cnt] = 0; 55 | printf("%s", buffer); 56 | 57 | return 0; 58 | } 59 | 60 | --------------------------------------------------------------------------------