Compare commits

...

523 commits

Author SHA1 Message Date
Ruledo
11d6d3deda Update foxbuntu-builder.sh
Moved pico repo
2025-05-14 00:32:15 -07:00
noon92
6f16acfae1
Merge pull request #411 from femtofox/noon2
Combined meshtastic wifi sync and avahi daemon service managers into a single function
2025-04-25 21:06:49 +03:00
nagumii
df8cb48983 Combined meshtastic wifi sync and avahi daemon service managers into a single function 2025-04-25 21:06:26 +03:00
noon92
64eaf03236
Merge pull request #410 from femtofox/noon2
Add avahi-daemon toggle to networking menu
2025-04-25 16:00:27 +03:00
nagumii
2a3f96ed70 Add avahi-daemon toggle to networking menu 2025-04-25 16:00:02 +03:00
noon92
3d053a5c6f
Merge pull request #409 from femtofox/main
Update noon2
2025-04-25 15:28:30 +03:00
noon92
08de3d0cb8
Merge pull request #408 from femtofox/noon2
Prettify runounce output
2025-04-25 15:28:00 +03:00
noon92
7e52f44f3c
Merge pull request #404 from jeremy-asher/add-tun-module-dependency
add tun module dependency
2025-04-21 20:28:23 +03:00
Jeremy Asher
419f203f57 add tun module dependency
This adds `NET_CORE` which is a dependency for `TUN`.
2025-04-18 11:21:40 -07:00
Tom
ccdb98a113
Update README.md 2025-03-24 00:35:38 +00:00
nagumii
2b1ffd0d90 Prettify runounce output 2025-03-15 19:51:40 +02:00
Tom
6c3b0da71f
Update README.md 2025-03-15 00:35:04 +00:00
noon92
1fd343fadf
Merge pull request #391 from femtofox/noon2
Increment foxbuntu release
2025-03-14 18:08:25 +02:00
nagumii
a4b8ba374d Increment foxbuntu release 2025-03-14 18:08:10 +02:00
noon92
9242ab9bc7
Merge pull request #390 from femtofox/noon2
Fix meshtastic install/upgrade in menus
2025-03-14 17:18:06 +02:00
nagumii
673cd7e268 Fix meshtastic install/upgrade in menus 2025-03-14 17:17:27 +02:00
noon92
0540668e19
Merge pull request #389 from femtofox/noon2
Fix software install/upgrade exit status false reports
2025-03-14 17:14:56 +02:00
nagumii
357d6fe77a Fix software install/upgrade exit status false reports 2025-03-14 17:14:01 +02:00
Tom
dbcbba4402
Merge pull request #387 from Jorropo/patch-1
fix tindie 404 link in README.md
2025-03-13 14:45:49 +00:00
Jorropo
253d10b8bf
fix tindie 404 link in README.md 2025-03-13 15:43:41 +01:00
noon92
c20eaa469c
Merge pull request #386 from femtofox/noon2
Fix "run software" command in software menu, re-enable for Contact and Control
2025-03-08 18:34:19 +02:00
nagumii
6b3245b554 Update contact_client.sh 2025-03-08 18:33:40 +02:00
nagumii
3997de8c87 Fix "run software" command in software menu, re-enable for Contact and Control 2025-03-08 18:33:01 +02:00
noon92
b7bc76a9ac
Merge pull request #385 from femtofox/main
Update noon2 from main
2025-03-08 18:30:46 +02:00
noon92
9a2fbb40b8
Merge pull request #384 from femtofox/noon2
try prevent daily updates
2025-03-08 16:48:39 +02:00
nagumii
5120cba1a6 try prevent daily updates 2025-03-08 16:47:59 +02:00
noon92
1eaab50281
Merge pull request #383 from femtofox/settings_overhaul_control
Prevent conflicts between Control for Meshtastic and running BBS applications
2025-03-05 23:59:47 +02:00
nagumii
7d34cd9b61 Prevent conflicts between Control for Meshtastic and running BBS applications 2025-03-05 23:58:41 +02:00
nagumii
6c6a7218a8 add pip install of control for meshtastic requirements to chroot 2025-03-05 22:51:23 +02:00
noon92
cfbce79724
Merge pull request #382 from femtofox/settings_overhaul_control
+x for control software package
2025-03-05 22:37:06 +02:00
nagumii
f8e2355e79 +x for control software package 2025-03-05 22:36:40 +02:00
noon92
52f92ffdb8
Merge pull request #381 from femtofox/settings_overhaul_control
Revamp settings menu to take advantage of Control by @pdxlocations
2025-03-05 20:28:40 +02:00
nagumii
978d58d649 Add control package to software menu 2025-03-05 20:26:38 +02:00
nagumii
fc7f187937 Add control download to chroot 2025-03-05 20:07:56 +02:00
nagumii
436856abcd Revamp settings menu to take advantage of Control by pdxlocations 2025-03-05 20:04:37 +02:00
noon92
89d10194bb
Merge pull request #380 from femtofox/noon2
Fix wifi toggle on button press
2025-03-04 12:46:42 +02:00
nagumii
242a145bdb Fix wifi toggle on button press 2025-03-04 12:44:48 +02:00
noon92
cb92aa7b18
Merge pull request #379 from femtofox/main
update noon2
2025-03-03 19:38:13 +02:00
noon92
c4a703c172
Update femto-config 2025-03-03 19:37:22 +02:00
noon92
e464fc7507
Update femtofox-config.txt 2025-03-03 19:32:28 +02:00
noon92
0466655eff
Merge pull request #378 from femtofox/noon2
Add meshtastic i2c support to menus and usb-config
2025-03-03 19:31:15 +02:00
noon92
95bf58eb48
Merge branch 'main' into noon2 2025-03-03 19:31:09 +02:00
nagumii
8e4895320e Add meshtastic i2c support to menus. 2025-03-03 19:30:46 +02:00
Ruledo
f5a903cfe6 Foxbuntu Build Script Documentation
This is how we build the releases.
2025-03-03 00:16:12 -08:00
noon92
17ea7f770d
Merge pull request #374 from femtofox/noon2
Add TUN as kernel module
2025-03-02 00:14:02 +02:00
nagumii
97ba36396b Add Tun 2025-03-01 23:56:44 +02:00
noon92
cc66ac4e34
Merge pull request #372 from femtofox/noon2
Minor fix for system info > OS info
2025-02-27 13:35:01 +02:00
nagumii
81309bf271 Minor fix for system info > OS info 2025-02-27 13:34:45 +02:00
noon92
563160d522
Merge pull request #371 from femtofox/noon2
Increment foxbuntu version
2025-02-26 20:07:47 +02:00
nagumii
e74b48af6b Increment foxbuntu version 2025-02-26 20:07:15 +02:00
noon92
dbaebb6b23
Merge pull request #370 from femtofox/noon2
Add retry to usb-config-tool software installation
2025-02-26 19:17:24 +02:00
nagumii
b04080efb5 Prevent Boot Complete LED boot code until USB-config is done 2025-02-26 19:17:00 +02:00
nagumii
dd420e146e Add retry to usb-config-tool software installation
Will retry up to 5 times
2025-02-26 19:16:12 +02:00
noon92
fb33c3af1d
Merge pull request #369 from femtofox/noon2
Fix usb-config config first boot check
2025-02-26 18:09:16 +02:00
nagumii
94ae7aaa1b Update femto-usb-config-tool.sh 2025-02-26 16:41:17 +02:00
noon92
7c36111d6c
Merge pull request #368 from femtofox/noon2
Add software installation to femto-config.txt example file
2025-02-26 16:37:14 +02:00
nagumii
3fe7984082 Update femtofox-config.txt 2025-02-26 16:36:55 +02:00
noon92
753d216999
Merge pull request #367 from femtofox/noon2
Add software install via USB config tool
2025-02-26 16:16:20 +02:00
nagumii
119b4ef039 Update femtofox-config.txt 2025-02-26 16:16:07 +02:00
nagumii
5c7e392c95 Add software install via USB config tool 2025-02-26 16:08:40 +02:00
Ruledo
73788c1b84 Build on any OS
Good luck.
2025-02-25 00:12:36 -08:00
noon92
5d2394b0b0
Merge pull request #366 from femtofox/noon2
Add new meshing-around dependencies
2025-02-24 22:46:56 +02:00
nagumii
581236ad7b Add new meshing-around dependencies 2025-02-24 22:46:26 +02:00
noon92
70ce2d8eb7
Merge pull request #365 from femtofox/noon2
Fix meshtastic_cli support
2025-02-23 15:52:40 +02:00
nagumii
0cdd6f7125 Fix meshtastic_cli support 2025-02-23 15:52:25 +02:00
noon92
5a80480095
Merge pull request #364 from femtofox/noon2
Add meshtastic_cli to usb config tool
2025-02-23 14:37:50 +02:00
nagumii
4550289068 Add meshtastic_cli to usb config tool 2025-02-23 14:37:33 +02:00
noon92
5e018368a0
Update README.md 2025-02-22 20:01:06 +02:00
noon92
cd52e21cd5
Merge pull request #361 from femtofox/noon2
Fix small pinouts issues
2025-02-20 00:33:10 +02:00
nagumii
ff37008b0f Fix small pinouts issues 2025-02-20 00:32:41 +02:00
noon92
b86f52c830
Merge pull request #359 from femtofox/noon2
Missing " in runonce
2025-02-19 20:39:19 +02:00
nagumii
80fa90e120 Missing " in runonce 2025-02-19 20:39:02 +02:00
noon92
89a302d024
Merge pull request #358 from femtofox/noon2
Fix typo in lora settings menu
2025-02-19 14:35:06 +02:00
nagumii
21519c0345 Fix typo in lora settings menu 2025-02-19 14:34:42 +02:00
noon92
8b4e251b5c
Merge pull request #357 from femtofox/noon2
Default routes auto update more reliably (thanks @Ruledo)
2025-02-19 14:18:20 +02:00
nagumii
9db705447e disable ttyd in chroot and re-enable on first boot 2025-02-19 14:14:38 +02:00
nagumii
01b65a6424 Update femto-runonce.sh 2025-02-19 13:50:27 +02:00
nagumii
a980af7e47 add back ssh keygen 2025-02-19 13:49:53 +02:00
nagumii
883d57a3e7 Network failover 2025-02-19 13:24:32 +02:00
Tom
0850c60fd1
Update README.md 2025-02-19 02:50:51 +00:00
Tom
3a06244174
Update README.md 2025-02-19 01:21:49 +00:00
noon92
064a8b726c
Merge pull request #353 from femtofox/noon2
add jq and rsync to apt installs in chroot
2025-02-19 01:03:58 +02:00
nagumii
9aabaad7d5 add jq and rsync to apt installs in chroot 2025-02-19 01:03:08 +02:00
noon92
8fa643408a
Merge pull request #352 from femtofox/main
Update from main
2025-02-19 01:01:29 +02:00
noon92
f205eebb05
Merge pull request #346 from joshbowyer/patch-10
Update femtofox.chroot
2025-02-19 01:00:54 +02:00
noon92
d7bdf64a2f
Merge pull request #351 from femtofox/noon2
Only generate new ttyd ssl keys if hostname actually changed
2025-02-19 01:00:39 +02:00
nagumii
368adf0641 Only generate new ttyd ssl keys if hostname actually changed 2025-02-19 01:00:04 +02:00
Tom
9019527e95
Update README.md 2025-02-18 22:51:35 +00:00
noon92
f2e8ad0491
Merge pull request #350 from femtofox/noon2
Revamp meshtastic settings ingest
2025-02-18 22:27:21 +02:00
nagumii
ee461842ec Revamp settings ingest 2025-02-18 21:16:33 +02:00
nagumii
3fc3c50f9a Continue refining lora settings menu 2025-02-17 22:35:40 +02:00
noon92
a5eef81248
Merge pull request #347 from femtofox/noon2
Revert runonce swapfile
2025-02-17 19:43:27 +02:00
nagumii
aaaa7d9e87 Revert runonce swapfile
"oops"
2025-02-17 19:43:09 +02:00
joshbowyer
8f0d52117e
Update femtofox.chroot
Add vim and mtd-utils to apt install in chroot
2025-02-17 11:33:47 -06:00
nagumii
57954fe236 Update femto-set-time.sh 2025-02-17 17:37:12 +02:00
nagumii
2c2edf0516 Update femto-set-time.sh 2025-02-17 17:31:10 +02:00
noon92
6481653ad8
Merge pull request #345 from femtofox/noon2
Fix set-time dialog
2025-02-17 15:04:35 +02:00
nagumii
f9977f68a2 Fix set-time dialog 2025-02-17 15:04:15 +02:00
noon92
c212a3db80
Merge pull request #344 from femtofox/noon2
Enable Meshtastic webserver on port 443
2025-02-17 12:49:33 +02:00
nagumii
793aa33869 Enable Meshtastic webserver on port 443 2025-02-17 12:48:04 +02:00
noon92
90651c52c9
Merge pull request #343 from femtofox/noon2
Major improvements to LoRa configuration menus
2025-02-16 23:19:51 +02:00
nagumii
5db521a409 Update femto-meshtasticd-lora-dialogs.sh 2025-02-16 23:19:18 +02:00
nagumii
0d71573975 Continued work on lora settings menu 2025-02-16 17:38:03 +02:00
nagumii
ef7a938f76 Fix compatibility with install wizard 2025-02-16 15:04:05 +02:00
nagumii
7c73c1ed16 Merge branch 'noon2' of https://github.com/femtofox/femtofox into noon2 2025-02-16 14:57:00 +02:00
nagumii
1e6aa868e0 Major improvements to LoRa configuration menus 2025-02-16 14:56:57 +02:00
noon92
39ef5b7856
Merge pull request #342 from femtofox/noon2
Change femto-runonce service to self-disable after first boot
2025-02-16 11:29:03 +02:00
noon92
f3fff87fca
Merge branch 'main' into noon2 2025-02-16 11:28:43 +02:00
nagumii
95d20fb8ba Change femto-runonce service to self-disable after first boot 2025-02-16 11:27:58 +02:00
Tom
4cbc597b1f
Update README.md 2025-02-16 01:56:51 +00:00
noon92
5348b1482c
Merge pull request #341 from femtofox/noon2
Fix typo in legacy admin menu
2025-02-16 00:02:13 +02:00
nagumii
d09b299875 Fix typo in legacy admin menu 2025-02-16 00:01:56 +02:00
noon92
2a6fc16e4e
Merge pull request #340 from femtofox/noon2
Massive overhaul of LoRa settings menus
2025-02-15 23:02:05 +02:00
nagumii
0e0316d362 Update femto-meshtasticd-lora-dialogs.sh 2025-02-15 22:55:34 +02:00
nagumii
e585c88882 Update .dialogrc 2025-02-15 22:41:51 +02:00
nagumii
083110a264 Overhaul of LoRa settings menus 2025-02-15 22:41:44 +02:00
noon92
fc023f695f
Merge pull request #338 from femtofox/noon2
Prettify the service status utility
2025-02-14 20:06:19 +02:00
nagumii
6d1b7ecc5b Prettify the service status utility 2025-02-14 20:05:59 +02:00
noon92
031e056c0e
Merge pull request #337 from femtofox/noon2
Fix Foxbuntu version display method
2025-02-14 18:31:12 +02:00
nagumii
1ea75dd079 Fix Foxbuntu version display method 2025-02-14 18:02:21 +02:00
noon92
29d9625cfa
Merge pull request #336 from femtofox/noon2
Fix typo in #330
2025-02-14 15:55:20 +02:00
nagumii
828f27992e Fix small issue with #330 2025-02-14 15:54:56 +02:00
noon92
86de5cd0ab
Merge pull request #335 from femtofox/noon2
Temporarily remove "Run software" from software manager package menu due to bug #326
2025-02-14 14:15:10 +02:00
nagumii
d52e26def2 Final touches 2025-02-14 14:13:30 +02:00
nagumii
35128e204e Temporarily remove "Run software" from software manager package menu due to bug #326 2025-02-14 13:57:12 +02:00
noon92
ed65be5879
Merge pull request #334 from femtofox/noon2
Improve installation usability by allowing pip installs to display live on screen
2025-02-14 13:43:55 +02:00
nagumii
01da3ccd36 Improve installation usability by allowing pip installs to display live on screen 2025-02-14 13:43:28 +02:00
noon92
1270ba504d
Merge pull request #333 from femtofox/noon2
Improve UX for blacklisting function in kernel modification manager
2025-02-14 13:27:58 +02:00
nagumii
104c8cf656 spit and polish 2025-02-14 13:20:24 +02:00
nagumii
d7b822c7b1 Improve UX for blacklisting function in kernel modification manager 2025-02-14 11:23:24 +02:00
noon92
39444ad634
Merge pull request #332 from femtofox/noon2
Increment Foxbuntu release to 1.0
2025-02-14 10:38:27 +02:00
nagumii
af8bdab446 Increment Foxbuntu release to 1.0 2025-02-14 10:37:59 +02:00
nagumii
97d10e8a35 Tidy up runonce 2025-02-14 10:36:08 +02:00
noon92
784e5e5f44
Merge pull request #331 from femtofox/main
Update noon2
2025-02-14 10:34:03 +02:00
noon92
4852b4057c
Merge pull request #330 from femtofox/noon2
Prevent login prompt from appearing until boot is complete
2025-02-14 10:19:16 +02:00
nagumii
989ffdbfd7 Prevent login prompt from appearing until boot is complete
Written by @Ruledo
2025-02-14 10:18:41 +02:00
noon92
bf58b66b3e
Merge pull request #329 from femtofox/OSC
wrong arg in getting private key in femto-config
2025-02-14 10:00:50 +02:00
Ruledo
a7ace1c758 wrong arg in getting private key in femto-config
Just a typo in the menu
2025-02-13 16:06:44 -08:00
Ruledo
822485e6aa
Merge pull request #328 from femtofox/OSC
Fixed compiler.  Removed apt cleanout from build.
2025-02-13 15:20:44 -08:00
Ruledo
b74db8055f Merge branch 'OSC' of https://github.com/femtofox/femtofox into OSC 2025-02-13 14:21:57 -08:00
Ruledo
9ad001f5e1 Backup and restore libc_nonshared.a and correct paths
libgcc wasn't playing nice after build.sh got a hold of it.
This preserves the compiler.
2025-02-13 14:21:48 -08:00
Ruledo
74af9894d9 backing up libc_nonshared.a before build.
cp /usr/lib/arm-linux-gnueabihf/libc_nonshared.a /usr/lib/arm-linux-gnueabihf/libc_nonshared.a.keep
Because build.sh kills it and we need it.
2025-02-13 14:03:24 -08:00
noon92
9882d3e0d0
Merge pull request #323 from femtofox/OSC
Watchclock Dog checks if meshtasticd is running
2025-02-13 23:30:39 +02:00
noon92
4f7c392ae6
Change sleep time to 30 2025-02-13 23:30:19 +02:00
noon92
f9bb77b26e
Merge pull request #325 from femtofox/noon2
Revamp of kernel module menu, adding blacklist and better UI
2025-02-13 22:26:47 +02:00
nagumii
70196d7134 Revamp of kernel module menu, adding blacklist and better UI 2025-02-13 21:41:16 +02:00
noon92
abac1e33cb
Merge pull request #320 from femtofox/eth0_test
Use eth0 mac address for meshtasticd
2025-02-13 15:02:11 +02:00
noon92
6600f73d12
Merge pull request #324 from femtofox/noon2
Revamp kernel module manager
2025-02-13 13:46:20 +02:00
nagumii
3cb06aeb91 Revamp kernel module manager 2025-02-13 13:45:58 +02:00
noon92
f689b8ba20
Update femto-kernel-modules.sh 2025-02-13 13:44:36 +02:00
nagumii
7ed3a99ee4 Revamp kernel module manager 2025-02-13 13:42:53 +02:00
nagumii
0ce3fb1535 remove debug line 2025-02-12 22:15:37 +02:00
nagumii
e0fa55a4d1 Merge branch 'eth0_test' of https://github.com/femtofox/femtofox into eth0_test 2025-02-12 22:09:05 +02:00
nagumii
7bf723d62d fix a couple service Afters 2025-02-12 22:09:01 +02:00
Ruledo
ed80e931de Watchclock Dog checks if meshtasticd is running
While loop checks if meshtasticd is running and if not nopes out until next loop.
2025-02-12 11:38:41 -08:00
nagumii
298c545cfa Update femto-runonce.sh 2025-02-12 21:36:20 +02:00
noon92
db6574790a
Merge pull request #322 from femtofox/main
Merge main to eth0
2025-02-12 21:32:45 +02:00
nagumii
60f2432c69 Update femtofox.chroot 2025-02-12 21:09:20 +02:00
noon92
bcd8ec366f
Merge pull request #321 from femtofox/noon2
Fix ssl keygen for ttyd package
2025-02-12 20:08:17 +02:00
nagumii
85f959b1a3 Fix ssl keygen for ttyd package 2025-02-12 20:07:45 +02:00
nagumii
d2d2fd9cbe Update override.conf 2025-02-12 19:22:59 +02:00
nagumii
e337ed62ae Switch source of meshtasticd mac address to eth0 2025-02-12 18:42:37 +02:00
nagumii
d83944862a Clean up license display 2025-02-12 17:54:55 +02:00
noon92
c51ffabb57
Merge pull request #319 from femtofox/main
merge main to noon2
2025-02-12 17:48:53 +02:00
nagumii
83e5891645 Update femto-software.sh 2025-02-12 17:48:06 +02:00
nagumii
eb914176b8 Update femto_package_template.sh 2025-02-12 16:46:23 +02:00
nagumii
d80265fd7c maintainer helptext fix 2025-02-12 16:44:21 +02:00
noon92
01f090316d
Merge pull request #318 from femtofox/noon2
Small refactor of software packages
2025-02-12 16:32:31 +02:00
nagumii
c14624fca9 More changes to packages 2025-02-12 16:31:56 +02:00
nagumii
1486a39675 package manager modifications 2025-02-12 14:01:01 +02:00
noon92
142fe6f29f
Update femto-config 2025-02-11 23:18:57 +02:00
noon92
39e5973cc7
Merge pull request #316 from femtofox/noon2
Add Meshtastic wifi sync management menu in networking
2025-02-11 23:17:59 +02:00
nagumii
987d56955c Add Meshtastic wifi sync management menu in networking 2025-02-11 23:17:33 +02:00
noon92
140b770317
Merge pull request #315 from femtofox/noon2
Fix new service descriptions
2025-02-11 21:08:33 +02:00
nagumii
875b7e3f08 Fix new service descriptions 2025-02-11 21:06:52 +02:00
noon92
d8c28c1263
Merge pull request #314 from femtofox/noon2
Tidy up runonce
2025-02-11 15:13:59 +02:00
nagumii
abae18a4bd Tidy up runonce 2025-02-11 15:13:30 +02:00
noon92
4147676af4
Merge pull request #313 from femtofox/noon2
Move all femto services to /etc/systemd/system
2025-02-10 23:57:02 +02:00
nagumii
8168aa5628 Add software license name to software description 2025-02-10 23:55:44 +02:00
nagumii
a79f0750b0 Move all femto services to /etc/systemd/system 2025-02-10 23:37:38 +02:00
noon92
009b158182
Merge pull request #310 from femtofox/OSC
wifi mesh control and watchclock-dog
2025-02-10 23:10:32 +02:00
noon92
1bfb13a35c
Merge pull request #311 from pdxlocations/escape-escape
Double escape special chars in override.conf
2025-02-10 23:10:20 +02:00
pdxlocations
f591a19481 double escape special chars 2025-02-10 13:02:02 -08:00
noon92
96060c8804
Merge pull request #302 from femtofox/sfc-alias
Add SFC alias to bash_aliases at firstrun
2025-02-10 22:44:23 +02:00
noon92
8a8193a87b
Update femto-wifi-mesh-control.service 2025-02-10 22:40:01 +02:00
noon92
9f46e22725
Update femto-watchclock-dog.service 2025-02-10 22:31:55 +02:00
Ruledo
abd6995d95 femto-wifi-mesh-control and femto-watchclock-dog
enable services in chroot
2025-02-10 11:35:57 -08:00
Ruledo
0b64bbefa7 Missed +x
oops.
2025-02-10 11:31:21 -08:00
Ruledo
5876ced494 wifi mesh control and watchclock-dog
Renamed wifi-mesh-control and now checks for meshtasticd to be running.
Also removed wants from service to prevent starting meshtasticd.
Added femto-watchclock-dog that checks for large time changes and restarts meshtasticd if detected to prevent a state where meshtasticd is running but not responsive on api port.
2025-02-10 11:26:55 -08:00
noon92
5d1518bd91
Update femto-runonce.sh 2025-02-10 20:39:18 +02:00
Tom
4926254b40
Revert 00-header 2025-02-10 18:28:42 +00:00
noon92
fd52c30427
Merge pull request #308 from femtofox/noon
Check if meshtasticd service is running before trying to interact with it, and offer to launch the service if not
2025-02-10 18:15:56 +02:00
nagumii
4f16844e83 Check if meshtasticd service is running before trying to modify settings 2025-02-10 18:13:39 +02:00
nagumii
8898c1137d Update femto-config 2025-02-10 01:14:46 +02:00
noon92
e0a5ab1f4b
Merge pull request #305 from femtofox/noon
Fix small niggling error in sysinfo cpu
2025-02-10 01:13:35 +02:00
nagumii
3ad68460f0 Fix small niggling error in sysinfo cpu 2025-02-10 01:12:48 +02:00
nagumii
4316bd2c88 Create rv1106-luckfox-pico-ultra-ipc.dtsi 2025-02-09 19:03:39 +02:00
noon92
ef17960a7c
Merge pull request #303 from femtofox/revert-294-OSC
This was merged accidentally
2025-02-09 18:58:40 +02:00
noon92
7d5b8be309
Revert "time-monitor service to restart meshtasticd" 2025-02-09 18:58:21 +02:00
Tom
48f4bec539
Update 00-header 2025-02-09 00:43:04 +00:00
Tom
9799a4709f
Add SFC alias to bash_aliases at firstrun
because 14 extra characters is too much.
2025-02-09 00:30:16 +00:00
noon92
33dd9f1d0e
Merge pull request #301 from femtofox/main
Update noon from main
2025-02-09 00:36:57 +02:00
noon92
1ee196aaa6
Merge pull request #300 from femtofox/noon
Update femto-utils.sh
2025-02-09 00:36:32 +02:00
noon92
50a0936849
Merge pull request #299 from femtofox/new_working
Further improve granularity
2025-02-09 00:34:24 +02:00
nagumii
99dcac2b66 Create rv1106-luckfox-pico-ultra-ipc.dtsi 2025-02-09 00:33:22 +02:00
noon92
986210021f
Merge branch 'main' into new_working 2025-02-09 00:31:07 +02:00
noon92
f6b5767b28
Merge pull request #298 from femtofox/revert-295-OSC
Revert "Update new_working from OSC"
2025-02-09 00:27:05 +02:00
noon92
a995399774
Revert "Update new_working from OSC" 2025-02-09 00:26:55 +02:00
nagumii
2746e23523 Update femto-utils.sh 2025-02-09 00:26:12 +02:00
noon92
a71d4bd1dd
Merge pull request #296 from femtofox/noon
Improve granularity of service status utility in femto-utils.sh
2025-02-08 19:23:22 +02:00
nagumii
412065a195 Improve granularity of service status utility in femto-utils.sh 2025-02-08 19:23:04 +02:00
nagumii
b543a11898 Improve service state utility in femto-utils.sh 2025-02-08 19:05:19 +02:00
nagumii
3b520405ff Fix femto-utils.sh help text 2025-02-08 18:00:13 +02:00
nagumii
8879717914 Merge branch 'new_working' of https://github.com/femtofox/femtofox into new_working 2025-02-08 14:48:43 +02:00
noon92
d1374f6242
Merge pull request #295 from femtofox/OSC
Update from OSC
2025-02-08 14:47:44 +02:00
Ruledo
bad1ddc204 time-monitor service to restart meshtasticd
Currently set to detect a 1 week change in time.
2025-02-07 20:26:41 -08:00
nagumii
d8cc314662 License button should only show for installed packages 2025-02-08 04:02:06 +02:00
noon92
34755aeeb5
Merge pull request #293 from femtofox/new_working
add ttyd license to /opt/ttyd
2025-02-08 03:01:42 +02:00
nagumii
921634eeb2 add ttyd license to /opt/ttyd 2025-02-08 03:00:27 +02:00
noon92
29318c8a4d
Merge pull request #292 from femtofox/new_working
ttyd.sh +x
2025-02-08 02:38:55 +02:00
nagumii
6c2a010189 +x 2025-02-08 02:38:09 +02:00
noon92
fe8d049fb4
Merge pull request #291 from femtofox/new_working
Revamp software menu system and improve package manager
2025-02-08 02:24:59 +02:00
nagumii
db764c4612 Revamp software menu system and improve package manager 2025-02-08 02:23:38 +02:00
noon92
2f4f085620
Merge pull request #290 from femtofox/new_working
Update LICENSE
2025-02-08 02:22:50 +02:00
nagumii
5212649d94 Delete ttyd.sh 2025-02-08 02:22:28 +02:00
nagumii
82a980498b undo 2025-02-08 02:21:33 +02:00
nagumii
f907dfad5f add pip install -r requirements.txt to meshing_around, tc2_bbs, contact 2025-02-08 02:16:22 +02:00
nagumii
efd5adc63e Add license button to package installer 2025-02-08 00:54:25 +02:00
nagumii
e0cc5ddc6c Update femto-software.sh 2025-02-07 22:02:44 +02:00
nagumii
038da36ccd Refactor of parts of package manager, move ttyd to package manager, move check-service-status to utils 2025-02-07 21:51:38 +02:00
nagumii
af9b7b42bd Merge branch 'new_working' of https://github.com/femtofox/femtofox into new_working 2025-02-07 17:15:35 +02:00
nagumii
07e387f1e0 Change Foxbuntu license to GPL3 2025-02-07 17:03:16 +02:00
noon92
0672889f8e
Update LICENSE
This changes the Foxbuntu license to GPL3
2025-02-07 16:40:17 +02:00
noon92
52964d23c8
Merge pull request #286 from joshbowyer/patch-9
Create rv1106-luckfox-pico-ultra-ipc.dtsi
2025-02-07 16:39:11 +02:00
noon92
05c7cbcfc3
Merge pull request #289 from femtofox/new_working
Show install status of package in software menu
2025-02-07 16:38:46 +02:00
nagumii
f4167e20d3 Show install status of package in software menu 2025-02-07 12:41:13 +02:00
noon92
521b8d6e37
Merge pull request #288 from femtofox/new_working
Improve wizard and set-time UX
2025-02-07 01:00:11 +02:00
nagumii
f5a7303046 Improve wizard and set-time UX 2025-02-07 00:59:38 +02:00
joshbowyer
7ab27dabbd
Create rv1106-luckfox-pico-ultra-ipc.dtsi
Fix SPI pin conflict for Ultra W
2025-02-06 12:46:17 -06:00
noon92
33306b89d0
Merge pull request #285 from femtofox/new_working
Disable daily unattended upgrade that somehow got enabled
2025-02-06 18:07:53 +02:00
nagumii
a66a97e2a9 Disable daily unattended upgrade that somehow got disabled 2025-02-06 18:07:18 +02:00
noon92
d206776998
Merge pull request #284 from femtofox/new_working
Tidy up install wizard
2025-02-06 15:11:37 +02:00
nagumii
e0cb49db40 Tidy up install wizard 2025-02-06 15:10:34 +02:00
noon92
2c8643b3f8
Merge pull request #283 from femtofox/new_working
Change menu colors a bit to make clearer in web terminal
2025-02-06 15:10:12 +02:00
nagumii
ca22939701 Update .dialogrc 2025-02-06 14:44:06 +02:00
nagumii
c799f55703 Change menu colors a bit to make clearer in web terminal 2025-02-06 14:41:17 +02:00
noon92
c47bc537a0
Merge pull request #282 from femtofox/new_working
Update web terminal help text in menu
2025-02-06 13:48:39 +02:00
nagumii
801ae57549 Update web terminal help text in menu 2025-02-06 13:48:21 +02:00
noon92
4eac49ea52
Merge pull request #281 from femtofox/new_working
Increment foxbuntu version
2025-02-06 13:44:29 +02:00
nagumii
c193fad672 Increment foxbuntu version 2025-02-06 13:44:01 +02:00
noon92
ea571110c9
Merge pull request #280 from femtofox/new_working
Generate ttyd SSL encryption on first boot and whenever hostname changes
2025-02-06 13:01:06 +02:00
nagumii
afb44c0b11 Generate ttyd SSL encryption on first boot and whenever hostname changes 2025-02-06 12:59:13 +02:00
noon92
eb7ee5817a
Merge pull request #279 from femtofox/new_working
move ttyd to /opt/ttyd
2025-02-05 21:49:20 +02:00
nagumii
95f55550d1 move ttyd to /opt/ttyd 2025-02-05 21:48:59 +02:00
noon92
1230e5ebba
Merge pull request #278 from femtofox/new_working
Fix adding meshtastic repo
2025-02-05 16:48:20 +02:00
nagumii
15b5381d77 Fix adding meshtastic repo 2025-02-05 16:47:44 +02:00
noon92
696bc5f7e3
Merge pull request #277 from femtofox/new_working
Update femtofox.chroot
2025-02-05 16:27:10 +02:00
nagumii
cc6c5ae564 Update femtofox.chroot 2025-02-05 16:26:41 +02:00
noon92
78601990f2
Merge pull request #276 from femtofox/new_working
Transition to official release of meshtasticd
2025-02-05 15:55:38 +02:00
nagumii
61e46d57ed Transition to official releases of meshtasticd 2025-02-05 15:54:24 +02:00
noon92
ce7a81059d
Merge pull request #275 from femtofox/new_working
Generate new SSH encryption keys on first boot
2025-02-05 15:00:32 +02:00
nagumii
2457b426d9 Fix ssh encryption 2025-02-05 14:59:52 +02:00
noon92
55717f583a
Merge pull request #274 from femtofox/new_working
Add web-terminal and add public and private key settings to install wizard
2025-02-04 20:57:58 +02:00
nagumii
97730e6cf3 Add public and private key settings to setup wizard 2025-02-04 20:55:03 +02:00
nagumii
9012d9f6e5 Add ttyd service management to menu 2025-02-04 20:01:02 +02:00
nagumii
60f8b583b7 fix ttyd service filename 2025-02-04 18:10:38 +02:00
nagumii
42ead87e50 Update ttyd.service.service 2025-02-04 16:25:59 +02:00
nagumii
995732a7ce add ttyd service 2025-02-04 16:19:47 +02:00
nagumii
61532c87b2 add ttyd service 2025-02-04 14:31:08 +02:00
nagumii
2e0aede20e add ttyd 2025-02-04 14:30:00 +02:00
nagumii
079bfc3803 Merge branch 'new_working' of https://github.com/femtofox/femtofox into new_working 2025-02-04 14:00:45 +02:00
nagumii
b04ea9bcce improve set-time, pinout 2025-02-04 14:00:44 +02:00
noon92
ff7aff14d8
Merge pull request #273 from femtofox/main
update new_working
2025-02-04 13:58:05 +02:00
Tom
a4657e9582
Update README.md 2025-02-04 10:57:58 +00:00
noon92
216d10b19d
Merge branch 'docs-update' into main 2025-02-04 12:53:31 +02:00
noon92
91b0160259
Update usb_config.md 2025-02-04 12:53:15 +02:00
noon92
da13fa5dde usb_config.md updated from https://stackedit.io/ 2025-02-03 16:16:35 +02:00
noon92
e0c4d6718c usb_config.md updated from https://stackedit.io/ 2025-02-03 16:15:04 +02:00
noon92
9260ffaf07 usb_config.md updated from https://stackedit.io/ 2025-02-03 16:10:25 +02:00
noon92
08ab057bae usb_config.md updated from https://stackedit.io/ 2025-02-03 16:08:39 +02:00
noon92
d32bc35bb8 usb_config.md updated from https://stackedit.io/ 2025-02-03 16:07:03 +02:00
noon92
c548b4f78d usb_config.md updated from https://stackedit.io/ 2025-02-03 16:05:28 +02:00
noon92
39460086d2 usb_config.md updated from https://stackedit.io/ 2025-02-03 16:03:52 +02:00
noon92
fcf612de65 usb_config.md updated from https://stackedit.io/ 2025-02-03 16:02:13 +02:00
noon92
46d49d5ac2 usb_config.md updated from https://stackedit.io/ 2025-02-03 16:00:38 +02:00
Tom
121dcd6e4f
Merge pull request #270 from femtofox/main
update
2025-02-03 01:15:46 +00:00
Tom
a6d38269d6
Update README.md 2025-02-03 01:11:09 +00:00
Tom
9870a91996
Update README.md 2025-02-03 00:19:46 +00:00
Tom
85e526af6c
Delete usb_config.md 2025-02-03 00:02:22 +00:00
Tom
ef76f85fdd
Delete supported_hardware.md 2025-02-02 23:31:36 +00:00
Tom
d93c531b2c
Delete foxbuntu_install.md 2025-02-02 23:31:26 +00:00
Tom
b8ac2f0a71
Delete Getting_started.md 2025-02-02 23:26:17 +00:00
Tom
679506e326
Update README.md 2025-02-02 23:10:45 +00:00
Tom
51206de9d0
Update foxbuntu_install.md 2025-02-02 22:49:51 +00:00
noon92
9a8163d303
Merge pull request #269 from femtofox/new_working
Add apt package listing to package description
2025-02-02 16:03:23 +02:00
nagumii
00797704bd Add apt package listing to package description 2025-02-02 16:02:30 +02:00
noon92
9c24fa12c5
Merge pull request #268 from femtofox/new_working
Refactor data supply and ingestion for UIs
2025-02-02 16:02:02 +02:00
nagumii
db2c49a268 Add helptext support to menus 2025-02-01 23:01:00 +02:00
nagumii
9c24f93fe2 Fix color in internet connectivity test 2025-02-01 19:16:37 +02:00
nagumii
37f98473a3 Add complete system info back in 2025-02-01 18:17:05 +02:00
nagumii
c55c0bd00e Continued refactor 2025-02-01 18:04:05 +02:00
nagumii
051c42e7b6 Refactor femto scripts to provide data in more easily utilized fashion 2025-02-01 17:30:18 +02:00
nagumii
1a1133d7b1 Begin refactor of method data is supplied by scripts and displayed by menus 2025-02-01 00:59:13 +02:00
nagumii
2b6b6f6847 Try remove luckfox-config load 2025-01-31 15:10:58 +02:00
Ruledo
11487d6bab
Merge pull request #267 from femtofox/OSC
Disabled unattended-upgrades and apt periodic updates
2025-01-30 22:58:04 -08:00
Ruledo
62e1d7f849 Disabled unattened-upgrades and apt periodic updates
Disabled service and changed apt setting.
2025-01-30 22:53:26 -08:00
noon92
2549819a88
Merge pull request #266 from femtofox/new_working
increment foxbuntu version
2025-01-30 14:21:18 +02:00
nagumii
44ef16e14f increment foxbuntu version 2025-01-30 14:21:01 +02:00
noon92
7dce5f3df7
Merge pull request #265 from femtofox/new_working
Add Samba file sharing support (disabled by default)
2025-01-30 14:18:59 +02:00
nagumii
7bac1c22d6 Complete samba? 2025-01-30 14:17:43 +02:00
nagumii
8521180d78 allow samba (and meshing around) initialization from menu 2025-01-30 13:51:18 +02:00
nagumii
03dddff716 Updated run once messages 2025-01-30 11:29:07 +02:00
nagumii
8c5b94da52 Complete samba support. Pretty please? 2025-01-30 00:09:42 +02:00
nagumii
464551d0bb Switch smb.conf to git source 2025-01-29 22:17:32 +02:00
nagumii
cfe2e19e40 Fix activation command helptext 2025-01-29 20:38:16 +02:00
nagumii
e2d6cb8ac7 This time it's GOTTA be the last one, right? ...right? 2025-01-29 20:01:02 +02:00
nagumii
90a58d9f8d Add a bit of extra echo to runonce 2025-01-29 19:08:02 +02:00
nagumii
c8e5fbd8db Final commit for Samba? One can hope. 2025-01-29 18:51:25 +02:00
nagumii
93f086d66c +x 2025-01-29 18:13:46 +02:00
nagumii
a1e1009fb3 Add samba to chroot 2025-01-29 17:42:16 +02:00
nagumii
ab8342fc93 Merge branch 'new_working' of https://github.com/femtofox/femtofox into new_working 2025-01-29 15:13:13 +02:00
nagumii
6534d4a3a0 Add Samba file sharing support, and improve software menu
Software menu is now entirely dynamically generated from the contents of /usr/local/bin/packages. To add a new software package, simply create a package file in that directory.
2025-01-29 15:12:53 +02:00
noon92
245fed036f
Merge pull request #264 from femtofox/main
Update new_working
2025-01-29 14:06:23 +02:00
Tom
c57e2cfd0c README.md updated from https://stackedit.io/ 2025-01-28 23:00:48 +00:00
nagumii
0f83ec0555 Improve runonce text. 2025-01-28 18:09:43 +02:00
noon92
84a23449fe
Merge pull request #262 from femtofox/new_working
Menus now remember previous selections
2025-01-28 12:44:54 +02:00
nagumii
a5696fc1fc improve menu UX 2025-01-28 12:43:31 +02:00
Tom
a1e06971bb Getting_started.md updated from https://stackedit.io/ 2025-01-28 10:30:25 +00:00
Tom
97d0c518c4 Getting_started.md updated from https://stackedit.io/ 2025-01-28 10:29:42 +00:00
Tom
30c625ff59 Getting_started.md updated from https://stackedit.io/ 2025-01-28 10:28:10 +00:00
Tom
e1cf427cd3 Getting_started.md updated from https://stackedit.io/ 2025-01-28 10:26:38 +00:00
Tom
30db0cc9f2 Getting_started.md created from https://stackedit.io/ 2025-01-28 10:25:04 +00:00
nagumii
332524772d Cleanup 2025-01-28 01:51:12 +02:00
noon92
1ab06664a5
Merge pull request #261 from femtofox/new_working
Fix bug with meshtastic node info in menus
2025-01-28 01:09:28 +02:00
nagumii
9f34793e13 Fix bug with meshtastic node info in menus 2025-01-28 01:08:46 +02:00
noon92
760ed554a7
Merge pull request #260 from femtofox/new_working
Improve menus, especially system info
2025-01-28 00:54:46 +02:00
nagumii
03e4af59ab Improve menus, especially system info 2025-01-28 00:54:17 +02:00
noon92
661b08f897
Merge pull request #259 from femtofox/new_working
Remove rtc from runonce
2025-01-27 15:53:30 +02:00
nagumii
1663ffd0d9 Remove rtc from runonce 2025-01-27 15:53:12 +02:00
noon92
5929ce9392
Merge pull request #257 from femtofox/new_working
Clean up menus a bit
2025-01-26 19:36:10 +02:00
nagumii
cd58c7a957 Add unmount to end of USB-config script 2025-01-26 19:35:50 +02:00
nagumii
e5ff39dac3 Clean up menus 2025-01-25 18:18:02 +02:00
nagumii
89ce3549d9 clean up pinout a bit 2025-01-25 03:18:46 +02:00
noon92
0df1d26291 README.eyJicmFuY2giOiJtYWluIiwib3duZXIiOiJmZW10b2ZveCIsInBhdGgiOiJSRUFETUUubWQiLCJwcm92aWRlcklkIjoiZ2l0aHViIiwicmVwbyI6ImZlbXRvZm94Iiwic3ViIjoiNDA4MDc5NzAiLCJ0ZW1wbGF0ZUlkIjoicGxhaW5UZXh0In0.publish created from https://stackedit.io/ 2025-01-25 02:35:55 +02:00
noon92
c1fd5f1d5e README.md updated from https://stackedit.io/ 2025-01-25 02:35:10 +02:00
noon92
4ba7c84c7b usb_config.md updated from https://stackedit.io/ 2025-01-25 02:35:00 +02:00
noon92
7ace373a30 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:31:04 +02:00
noon92
332e3201c7 usb_config.eyJicmFuY2giOiJtYWluIiwib3duZXIiOiJmZW10b2ZveCIsInBhdGgiOiJ1c2JfY29uZmlnLm1kIiwicHJvdmlkZXJJZCI6ImdpdGh1YiIsInJlcG8iOiJmZW10b2ZveCIsInN1YiI6IjQwODA3OTcwIiwidGVtcGxhdGVJZCI6InBsYWluVGV4dCJ9.publish created from https://stackedit.io/ 2025-01-25 02:29:49 +02:00
noon92
9fe40c9a2e usb_config.md updated from https://stackedit.io/ 2025-01-25 02:29:41 +02:00
noon92
fb66a595f7 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:28:49 +02:00
noon92
fdfad96b30 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:28:47 +02:00
noon92
6916a0070b usb_config.md updated from https://stackedit.io/ 2025-01-25 02:28:17 +02:00
noon92
cdab771f07 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:26:46 +02:00
noon92
83c961abac usb_config.md updated from https://stackedit.io/ 2025-01-25 02:25:14 +02:00
noon92
797571d2b6 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:23:42 +02:00
noon92
b0d009555c usb_config.md updated from https://stackedit.io/ 2025-01-25 02:22:09 +02:00
noon92
47fc702fbc usb_config.md updated from https://stackedit.io/ 2025-01-25 02:20:36 +02:00
noon92
da9f61fd38 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:18:28 +02:00
noon92
59f7e85ed7 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:16:56 +02:00
noon92
660e88bfbd usb_config.md updated from https://stackedit.io/ 2025-01-25 02:15:24 +02:00
noon92
3631878567 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:13:51 +02:00
noon92
0ee7a0547f usb_config.md updated from https://stackedit.io/ 2025-01-25 02:12:19 +02:00
noon92
33628f2c69 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:11:30 +02:00
noon92
63a7b9d3ea usb_config.md updated from https://stackedit.io/ 2025-01-25 02:10:47 +02:00
noon92
eb94549de2 usb_config.md updated from https://stackedit.io/ 2025-01-25 02:10:29 +02:00
noon92
23b961251e usb_config.md updated from https://stackedit.io/ 2025-01-25 02:10:18 +02:00
noon92
0dce97035a
Merge pull request #256 from femtofox/new_working
remove debug flag
2025-01-24 23:07:19 +02:00
nagumii
3c82bb83d3 remove debug flag 2025-01-24 23:06:52 +02:00
noon92
614a23f68a
Merge pull request #255 from femtofox/new_working
Bug fixes for new firstboot flag.
2025-01-24 23:03:35 +02:00
nagumii
50fe958cf3 Update femto-runonce.sh 2025-01-24 22:54:56 +02:00
nagumii
b308e4d603 Update femto-runonce.sh 2025-01-24 22:44:56 +02:00
nagumii
bde2c9b59a Update femto-runonce.sh 2025-01-24 22:35:16 +02:00
nagumii
a1015ed361 Update femto.conf 2025-01-24 22:33:47 +02:00
nagumii
b1fc816bae add debug 2025-01-24 22:32:34 +02:00
nagumii
25ab04811c test 2025-01-24 22:18:54 +02:00
noon92
fe0de2a02c
Merge pull request #254 from femtofox/new_working
remove commenting #
2025-01-24 21:51:45 +02:00
nagumii
957a70b8fa remove commenting # 2025-01-24 21:51:26 +02:00
noon92
3b9f990bda
Merge pull request #253 from femtofox/new_working
Change true to false :\
2025-01-24 21:37:34 +02:00
nagumii
3613730c97 Change true to false :\ 2025-01-24 21:37:17 +02:00
noon92
4e2cecd20f
Merge pull request #252 from femtofox/new_working
make pulse run in background
2025-01-24 21:18:17 +02:00
nagumii
464710740e make pulse run in background 2025-01-24 21:17:45 +02:00
noon92
e617434dc5
Merge pull request #251 from femtofox/new_working
Add LED heartbeat during first boot
2025-01-24 21:11:56 +02:00
nagumii
94148e2181 Add LED heartbeat during first boot 2025-01-24 21:11:28 +02:00
noon92
ce4d9531ca
Merge pull request #250 from femtofox/new_working
change false to true :/
2025-01-24 21:04:24 +02:00
nagumii
a805798fcf change false to true :/ 2025-01-24 21:04:03 +02:00
noon92
230e09c80e
Merge pull request #249 from femtofox/new_working
"oops"
2025-01-24 20:41:53 +02:00
nagumii
30f3c9ccbf "oops" 2025-01-24 20:41:32 +02:00
noon92
2f45ecc263
Merge pull request #248 from femtofox/new_working
Move firstboot flag to /etc/femto.conf
2025-01-24 20:39:48 +02:00
nagumii
5362eb1144 Move firstboot flag to /etc/femto.conf 2025-01-24 20:39:21 +02:00
noon92
c8bb1f3900 supported_hardware.eyJicmFuY2giOiJtYWluIiwib3duZXIiOiJmZW10b2ZveCIsInBhdGgiOiJzdXBwb3J0ZWRfaGFyZHdhcmUubWQiLCJwcm92aWRlcklkIjoiZ2l0aHViIiwicmVwbyI6ImZlbXRvZm94Iiwic3ViIjoiNDA4MDc5NzAiLCJ0ZW1wbGF0ZUlkIjoicGxhaW5UZXh0In0.publish created from https://stackedit.io/ 2025-01-24 18:34:07 +02:00
noon92
fb1cb8ff3d foxbuntu_install.eyJicmFuY2giOiJtYWluIiwib3duZXIiOiJmZW10b2ZveCIsInBhdGgiOiJmb3hidW50dV9pbnN0YWxsLm1kIiwicHJvdmlkZXJJZCI6ImdpdGh1YiIsInJlcG8iOiJmZW10b2ZveCIsInN1YiI6IjQwODA3OTcwIiwidGVtcGxhdGVJZCI6InBsYWluVGV4dCJ9.publish created from https://stackedit.io/ 2025-01-24 18:34:06 +02:00
noon92
c943d09ef6
Delete usb_config.eyJicmFuY2giOiJtYWluIiwib3duZXIiOiJmZW10b2ZveCIsInBhdGgiOiJ1c2JfY29uZmlnLm1kIiwicHJvdmlkZXJJZCI6ImdpdGh1YiIsInJlcG8iOiJmZW10b2ZveCIsInN1YiI6IjQwODA3OTcwIiwidGVtcGxhdGVJZCI6InBsYWluVGV4dCJ9.publish 2025-01-24 18:33:52 +02:00
noon92
d4d646127d supported_hardware.md updated from https://stackedit.io/ 2025-01-24 18:33:35 +02:00
noon92
2e0bfb5c82 supported_hardware.md updated from https://stackedit.io/ 2025-01-24 18:33:33 +02:00
noon92
e4d4c980d5 foxbuntu_install.md updated from https://stackedit.io/ 2025-01-24 18:33:16 +02:00
noon92
d17c7c0597 foxbuntu_install.md updated from https://stackedit.io/ 2025-01-24 18:33:14 +02:00
noon92
34857a313f foxbuntu_install.md updated from https://stackedit.io/ 2025-01-24 18:32:34 +02:00
noon92
f0df3a3a34 foxbuntu_install.md updated from https://stackedit.io/ 2025-01-24 18:31:00 +02:00
noon92
128c04f9d6 foxbuntu_install.md updated from https://stackedit.io/ 2025-01-24 18:29:28 +02:00
noon92
d5ea815bcc foxbuntu_install.md updated from https://stackedit.io/ 2025-01-24 18:27:55 +02:00
noon92
da72cd58cd usb_config.md updated from https://stackedit.io/ 2025-01-24 18:26:23 +02:00
noon92
35dffcf34d usb_config.md updated from https://stackedit.io/ 2025-01-24 18:26:11 +02:00
noon92
6307d9829c usb_config.md updated from https://stackedit.io/ 2025-01-24 18:25:45 +02:00
noon92
72ab418802 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:25:01 +02:00
noon92
b9c7b29fc8 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:24:31 +02:00
noon92
a1c3209ab5 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:24:10 +02:00
noon92
b95b8eede0 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:23:38 +02:00
noon92
ebda6b1306 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:22:36 +02:00
noon92
87faac225e usb_config.md updated from https://stackedit.io/ 2025-01-24 18:21:54 +02:00
noon92
2ae64a7073 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:21:43 +02:00
noon92
8753ae4ce2 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:20:11 +02:00
noon92
9d85471050 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:18:38 +02:00
noon92
8a86d894e9 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:17:06 +02:00
noon92
e99ce3ec8f usb_config.md updated from https://stackedit.io/ 2025-01-24 18:16:36 +02:00
noon92
3aa25ccb7e usb_config.md updated from https://stackedit.io/ 2025-01-24 18:16:05 +02:00
noon92
88f18c2d1e usb_config.md updated from https://stackedit.io/ 2025-01-24 18:15:21 +02:00
noon92
178f32b10a usb_config.md updated from https://stackedit.io/ 2025-01-24 18:13:31 +02:00
noon92
f0edb171f8 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:12:22 +02:00
noon92
cd54fa4fba usb_config.md updated from https://stackedit.io/ 2025-01-24 18:11:11 +02:00
noon92
5bf9d4c500 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:10:58 +02:00
noon92
c433a7ce7f usb_config.md updated from https://stackedit.io/ 2025-01-24 18:09:19 +02:00
noon92
a615b73b7e usb_config.md updated from https://stackedit.io/ 2025-01-24 18:08:02 +02:00
noon92
3cc1fa0c6d usb_config.md updated from https://stackedit.io/ 2025-01-24 18:07:55 +02:00
noon92
c321fa5d0f usb_config.eyJicmFuY2giOiJtYWluIiwib3duZXIiOiJmZW10b2ZveCIsInBhdGgiOiJ1c2JfY29uZmlnLm1kIiwicHJvdmlkZXJJZCI6ImdpdGh1YiIsInJlcG8iOiJmZW10b2ZveCIsInN1YiI6IjQwODA3OTcwIiwidGVtcGxhdGVJZCI6InBsYWluVGV4dCJ9.publish created from https://stackedit.io/ 2025-01-24 18:07:54 +02:00
holocron.so
c541b8c514 Update usb_config.md 2025-01-24 16:07:13 +00:00
noon92
5d136e5c24 usb_config.md updated from https://stackedit.io/ 2025-01-24 18:07:08 +02:00
holocron.so
f2c8bb3a48 Update usb_config.md 2025-01-24 15:59:48 +00:00
holocron.so
5437a1e7df Update usb_config.md 2025-01-24 15:59:18 +00:00
holocron.so
4630a501ef Update usb_config.md 2025-01-24 15:57:41 +00:00
holocron.so
3efade35ca Update usb_config.md 2025-01-24 15:57:11 +00:00
holocron.so
7b8604ad37 Update usb_config.md 2025-01-24 15:56:41 +00:00
holocron.so
53d8e77a07 Update usb_config.md 2025-01-24 15:54:28 +00:00
holocron.so
1c05d98fa3 Update usb_config.md 2025-01-24 15:53:58 +00:00
holocron.so
cbbc66bb3a Update foxbuntu_install.md 2025-01-24 15:52:15 +00:00
holocron.so
5907cfcbe6 Update usb_config.md 2025-01-24 15:51:14 +00:00
holocron.so
f6752c875b Update usb_config.md 2025-01-24 15:50:44 +00:00
holocron.so
4832cffb27 Update usb_config.md 2025-01-24 15:49:10 +00:00
holocron.so
9c42f42632 Update usb_config.md 2025-01-24 15:48:40 +00:00
holocron.so
e34f284937 Update foxbuntu_install.md 2025-01-24 15:48:10 +00:00
holocron-so[bot]
2d5baf3ec0 Update usb_config.md 2025-01-24 15:12:18 +00:00
holocron-so[bot]
f06456c724 Update usb_config.md 2025-01-24 15:11:29 +00:00
holocron-so[bot]
55c13c934d Update usb_config.md 2025-01-24 15:11:23 +00:00
noon92
c6ec052fd7
Update usb_config.md 2025-01-24 16:59:02 +02:00
noon92
d14ba4ba3d
Update foxbuntu_install.md 2025-01-24 16:47:05 +02:00
noon92
597f947595
Merge pull request #247 from femtofox/new_working
Fix bugs in time and time-zone setting utility
2025-01-24 16:24:41 +02:00
nagumii
ca696c6019 Fix bugs in time and time-zone setting utility 2025-01-24 16:24:23 +02:00
noon92
b7fe8c1a8b
Merge pull request #246 from femtofox/new_working
Increment foxbuntu version
2025-01-24 09:33:20 +02:00
nagumii
605d04d9b0 Increment foxbuntu version 2025-01-24 09:33:07 +02:00
noon92
df35e2b3b6
Merge pull request #245 from femtofox/new_working
Add activity led state to sysinfo
2025-01-23 23:33:42 +02:00
nagumii
6063c73a8b Add activity led state to sysinfo 2025-01-23 23:33:26 +02:00
noon92
6d1f786e8e
Merge pull request #244 from femtofox/new_working
Move all meshtastic security settings to their own menu
2025-01-23 22:18:52 +02:00
nagumii
c686787560 changes 2025-01-23 22:17:55 +02:00
noon92
145276bf17
Merge pull request #243 from femtofox/new_working
fix typo in femtofox-config.txt
2025-01-23 21:41:26 +02:00
nagumii
f925b54a02 fix typo in femtofox-config.txt 2025-01-23 21:40:28 +02:00
noon92
e1c7630371
Merge pull request #237 from femtofox/Nestpebble-patch-1
Update repo address
2025-01-23 21:37:45 +02:00
noon92
7acd287677
Merge pull request #242 from femtofox/new_working
Add activity LED setting, with menu and usbconfig support
2025-01-23 21:37:02 +02:00
nagumii
0fb912f3b0 Create femto.conf. firstboot parameter is not yet in use.
@Ruledo
2025-01-23 21:02:22 +02:00
nagumii
18cfe45cff Update femtofox-config.txt 2025-01-23 20:58:48 +02:00
nagumii
9d1becc89f Add activity LED setting, with menu and usbconfig support 2025-01-23 20:57:35 +02:00
Tom
a7c167550c
Merge pull request #241 from femtofox/main
update branch to match main
2025-01-23 16:57:49 +00:00
noon92
303380ee23
Merge pull request #240 from femtofox/new_working
fix typo
2025-01-23 18:40:03 +02:00
nagumii
cb47c32e5e fix typo 2025-01-23 18:37:46 +02:00
noon92
5856a0245b
Merge pull request #239 from femtofox/new_working
Added setting meshtastic public and private keys to menus and usb-config-tool
2025-01-23 18:36:40 +02:00
nagumii
bd729fa3fd Added public and private key settings to usb config tool 2025-01-23 18:35:30 +02:00
Tom
362f75f414
update repo address 2025-01-23 00:38:41 +00:00
Tom
8b3c7954a3
Update femtofox-config.txt 2025-01-23 00:38:01 +00:00
Tom
e59d803231
update repo address 2025-01-23 00:36:48 +00:00
nagumii
9b1010f982 Add public/private key support to meshtasticd menu and interface script 2025-01-22 22:16:03 +02:00
noon92
540b861c7f
Merge pull request #236 from femtofox/new_working
Improve meshtasticd menus
2025-01-22 19:28:41 +02:00
nagumii
da65263ad7 Improve meshtasticd menus 2025-01-22 19:28:16 +02:00
noon92
d5b8497c09
Merge pull request #235 from femtofox/new_working
Add colors to first boot and usbconfig script's outputs to improve console readability
2025-01-21 20:45:49 +02:00
nagumii
dda9449d54 Add colors to first boot and usbconfig script's outputs to improve console readability 2025-01-21 20:45:01 +02:00
noon92
1b1f668c46
Merge pull request #234 from femtofox/new_working
Increment Foxbuntu release
2025-01-21 19:59:11 +02:00
nagumii
3c8f701d3a Increment Foxbuntu release 2025-01-21 19:58:54 +02:00
noon92
ac761a52f2
Merge pull request #233 from femtofox/new_working
increase set-time attempts from 1 to 5 before fail
2025-01-21 18:32:05 +02:00
nagumii
d8212de844 increase set-time attempts from 1 to 5 before fail 2025-01-21 18:31:34 +02:00
noon92
fa9717c3dc
Merge pull request #232 from femtofox/new_working
Fix time-setting script issues
2025-01-21 13:48:35 +02:00
nagumii
7de4dfe39a Merge branch 'new_working' of https://github.com/femtofox/foxbuntu into new_working 2025-01-21 13:47:39 +02:00
nagumii
f640845f6c move time-setting to function 2025-01-21 13:37:44 +02:00
nagumii
34e70f3a9f Prevent time menu from showing during usb-config 2025-01-21 13:14:26 +02:00
noon92
bf3dd91089
Merge pull request #231 from femtofox/main
Update new-working
2025-01-21 13:13:55 +02:00
Ruledo
d1beafba43
Merge pull request #226 from femtofox/OSC
Run once and usb tool moved from rc.local to services.
2025-01-20 15:35:52 -08:00
Ruledo
1de218d573 Merge branch 'main' into OSC 2025-01-20 15:34:06 -08:00
nagumii
ce7b9607af Improve process priority setting for meshtasticd service override 2025-01-20 23:03:03 +02:00
nagumii
c27760d4ec Disable LED to prevent boot codes from showing during first boot 2025-01-20 22:50:39 +02:00
noon92
1b3deefb79
Merge pull request #230 from femtofox/new_working
Remove redundant notification screen from timezone set
2025-01-20 22:47:07 +02:00
nagumii
60a4f0657b Remove redundant notification screen from timezone set 2025-01-20 22:46:28 +02:00
noon92
31bebd3197
Merge pull request #229 from femtofox/new_working
Remove errant exit
2025-01-20 19:00:52 +02:00
nagumii
3c4a62a57d Remove errant exit 2025-01-20 18:58:31 +02:00
noon92
6820d751c9
Merge pull request #228 from femtofox/new_working
Remove debug echo from femto-config
2025-01-20 18:55:59 +02:00
nagumii
3ea190d02d Remove debug echo from femto-config 2025-01-20 18:55:29 +02:00
noon92
3c4816cb2d
Merge pull request #227 from femtofox/new_working
Complete meshtasticd service management menu
2025-01-20 18:53:58 +02:00
nagumii
110d5f1a4d Forgot to merge this and had to rewrite -_- 2025-01-20 18:53:12 +02:00
nagumii
73150d882f Reorder lines in meshtasticd service override 2025-01-20 18:32:15 +02:00
nagumii
fae26cc178 Move meshtasticd -h argument to service override 2025-01-20 17:39:19 +02:00
nagumii
86bdb71578 Finishing touches 2025-01-20 17:38:35 +02:00
Ruledo
19123a00e5 put back button service
I accidentally removed this earlier.
2025-01-20 04:06:54 -08:00
Ruledo
71f3ee6b42 fixed run once check for usb tool
Check if run once flag exists, if so exit silently.
2025-01-20 03:00:31 -08:00
Ruledo
83a95e5c69 run once and usb service fixes
I forgot to +x rc local and as a result found some issues
2025-01-20 00:46:48 -08:00
Ruledo
2e8a3f7136 Do not run usb tool on first boot.
Checks for first boot flag and exits gracefully.
2025-01-19 23:16:12 -08:00
Ruledo
eba5b4c217 Should be successful exit
Change to successful exit for run once when it has already been run once and on boot screen.
2025-01-19 23:01:31 -08:00
Ruledo
27652fecb1 Nicer console output for runonce
Switched from tty to journal and console for output.
2025-01-19 22:38:32 -08:00
Ruledo
1f211d7cf9 Fixed permissions
Missed these.
2025-01-19 21:44:27 -08:00
Ruledo
ba690b2250 Enable new services
Chroot changes to enable new services
2025-01-19 20:17:45 -08:00
Ruledo
c7c627f0d9 Re-engineered rc.local
Moved femto-runonce to a service
Moved femto-usb-config-tool to a service
re-added override for meshtasticd to execute after rc-local
small fix in femto-network-config ro removed uneeded steps (same as I did in wifi config)
added a step in runonce that if no user logged in and already has been been run once, exit and do not run menu.
2025-01-19 19:17:26 -08:00
Ruledo
14e6c36c7b Fixed bad permission
+x
2025-01-19 19:09:53 -08:00
noon92
92b2ab51b8
Merge pull request #223 from femtofox/new_working
Simplified and improved meshtastic menu
2025-01-19 23:55:42 +02:00
nagumii
20ab007734 Simplified and improved meshtastic menu 2025-01-19 23:55:25 +02:00
noon92
4b66e0fde4
Merge pull request #222 from femtofox/new_working
Workaround for meshtastic API incommunicado issue
2025-01-19 18:21:25 +02:00
nagumii
e4a237abb9 Workaround for meshtastic API incommunicado issue 2025-01-19 18:20:58 +02:00
noon92
13791d142b
Merge pull request #221 from femtofox/revert-220-OSC
Revert "Override for meshtasticd boot order."
2025-01-19 15:09:43 +02:00
noon92
2c038a4172
Revert "Override for meshtasticd boot order." 2025-01-19 15:09:33 +02:00
Ruledo
5be5b60d5d
Merge pull request #218 from joshbowyer/patch-8
Update wifi-mesh-control.service
2025-01-19 03:04:05 -08:00
Ruledo
0155b308d7
Merge pull request #220 from femtofox/OSC
Override for meshtasticd boot order.
2025-01-19 03:03:29 -08:00
Ruledo
26e4297064 Override for meshtasticd boot order.
meshtasticd api wouldn't respond when started too early.  Thx @noon92 for pushing this across the finish line.
2025-01-19 03:02:53 -08:00
Ruledo
35c84443c3
Merge pull request #219 from femtofox/OSC
Added DTS files for pico ultra and ultra-w (UNTESTED)
2025-01-19 02:27:22 -08:00
Ruledo
ce520837b6 Merge branch 'main' into OSC 2025-01-19 02:21:59 -08:00
joshbowyer
3bc3d6d008
Update wifi-mesh-control.service
Add Requires so wifi-mesh-control wont start until meshtasticd is fully up. Also removed After directive for network.target as meshtasticd service file already has this. Meshtasticd should be up before this service runs.
2025-01-18 15:01:28 -06:00
Ruledo
9ddd462585 Added DTS files for Luckfox Pico U
I have not tested this.
A full sdk install would be needed and the correct board selected.
2025-01-16 20:47:07 -08:00
Ruledo
2452798c6c Merge branch 'main' into OSC 2025-01-16 17:30:01 -08:00
Ruledo
95a7d5be6b Merge branch 'OSC' of https://github.com/femtofox/foxbuntu into OSC 2025-01-16 17:29:29 -08:00
Ruledo
8dcc88e961 Change the way wifi mesh control gets the state of the interface
ip link was reporting the interface as down when wifi was disconnected so switched to operstate to get authoritative interface state.
2025-01-16 01:43:55 -08:00
Ruledo
b2c3af1887 Fixed getting interface state
ip link was reporting interface as down when wifi was not connected.
2025-01-16 01:36:40 -08:00
76 changed files with 5686 additions and 5191 deletions

685
LICENSE
View file

@ -1,3 +1,10 @@
Femtofox is comprised of two projects, with two different licenses:
1. Femtofox - the hardware, which is licensed "CC BY-NC-ND - noncommercial". Summary: you may copy and share and modify the hardware files, but cannot sell them without license from Femtofox, and must give attribution to Femtofox.
2. Foxbuntu - refers to the modifications to Ubuntu made as part of the Femtofox project, which is licensed GNU GPLv3. Summary: you may use, modify and distribute (including for commercial purposes) Foxbuntu, but must give attribution to Femtofox and distribute this license with your project. Any modified version must remain open source.
See below for the full license texts.
Hardware (Femtofox) license:
Summary:
Attribution — You must give appropriate credit , provide a link to the license, and indicate if changes were made . You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
NonCommercial — You may not use the material for commercial purposes .
@ -408,3 +415,681 @@ the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
Software (Foxbuntu) license:
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

102
README.md
View file

@ -1,82 +1,74 @@
<img src="assets/images/KSE_side_shot.png" width="750">
# Femtofox &nbsp;&nbsp;&nbsp;<sub><sub>The tiny, low power Linux Meshtastic node
### &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Click here for the Femtofox store](https://www.etsy.com/listing/1861858340/femtofox-pro-v1-kit-compact-arm-linux)
**Femtofox is a Linux-based mesh development platform - a Raspberry Pi sized computer with onboard LoRa radio, capable of being run with only 0.3w, making it *ideal* for solar powered nodes.**
The Luckfox Pico Mini is the postage stamp sized heart of the Femtofox - a compact and power efficient Linux board, running a customized version of Ubuntu. Femtofox is an expansion of the Luckfox's capabilities, utilizing a custom PCB with a 30db LoRa radio (over 6x the transmit power of a RAK Wisblock or Heltec V3) to create a power efficient, tiny and highly capable Meshtastic Linux node.
The Luckfox Pico Mini is the postage stamp sized heart of the Femtofox - a compact and power efficient Linux board, running Foxbuntu, our own customized version of Ubuntu. Femtofox is an expansion of the Luckfox's capabilities, utilizing a custom PCB with a 30db LoRa radio (over 6x the transmit power of a RAK Wisblock or Heltec V3) to create a power efficient, tiny and highly capable Meshtastic Linux node.
- [Features](#features)
- Specifications - coming soon
- [Supported hardware](./supported_hardware.md)
- [Installation guide](./foxbuntu_install.md)
- How to order - coming soon
- DIY instructions - coming soon
- [Networking](#networking)
- [USB configuration tool](./usb_config.md)
Find out more in the sections below, or in the [Wiki](https://github.com/femtofox/femtofox/wiki).
- [Features](#features) and [Specifications](#Specification)
- [Supported hardware](https://github.com/femtofox/femtofox/wiki/Supported-Hardware)
- [Installation guide](https://github.com/femtofox/femtofox/wiki/Getting-Started)
- How to order
- [Etsy (USA)](https://www.etsy.com/listing/1861858340/femtofox-pro-v1-kit-compact-arm-linux)
- [Tindie (UK)](https://www.tindie.com/products/nomdetom/femtofox-pro-v1-kit-linux-meshtastic-node/)
- [Etsy (UK)](https://www.etsy.com/uk/listing/1866094154/femtofox-pro-v1-kit-linux-meshtastic)
- [DIY instructions](https://github.com/femtofox/Femtofox_Community_Hardware)
- [USB configuration tool](https://github.com/femtofox/femtofox/wiki/USB-Configuration-Tool)
- [Building your own Foxbuntu image](https://github.com/femtofox/femtofox/wiki/Building-Foxbuntu-%28WSL%29)
### Features
* Tiny size (63x54mm for the Kitchen Sink Edition, 65x30mm for the Smol Edition). Roughly equivalent to a standard Raspberry Pi hat and Pi Zero respectively.
* Power efficiency (~0.27-0.4w average, depending on radio and mesh congestion)
* Tiny size (63x54mm for Femtofox, 65x30mm for the Smol Edition). Equivalent to a standard Raspberry Pi hat and Pi Zero respectively.
* Power efficient (~0.27-0.4w average, depending on radio and mesh congestion)
* Full Linux CLI (Ubuntu) via our pre-built Foxbuntu image
* Meshtastic native client support via SPI
* USB host support - attach USB peripherals (see [supported hardware](supported_hardware.md))
* USB wifi support (see [supported hardware](supported_hardware.md))
* RTC support for timekeeping (see [supported hardware](supported_hardware.md))
* USB host support - attach USB peripherals
* USB wifi support
* RTC support for timekeeping
### Specification
| Feature | Specification |
| ------------ | ------------------------------------------------------- |
| Processor | Rockchip RV1103, Cortex A7 \@1.1GHz |
| Memory | 64MB DDR2 |
| OS | Foxbuntu (based on Ubuntu 22.04.5 LTS Jammy) |
| Connectivity | USB 2.0 Host/Device |
| Network | RJ45 Ethernet with filtering<br> |
| | WiFi ready |
| GPIO | 17x GPIO pins (of which 8 are required for Lora module) |
| IO | 2x I2C JST PH |
| | 1x UART JST PH |
| Debug | 1x CH340 USB to serial adapter (Pro only) |
| Mesh | 30dB LoRa Radio 868-915MHz |
| Storage | Micro-SD slot |
| Power | 3.3-5V.dc via JST PH or USB-C |
| Dimensions | 63 x 54 x 19mm |
**Accomplished:**
- [x] Meshtastic native client controlling a LoRa radio (see [supported hardware](supported_hardware.md))
- [x] WIFI over USB (see [supported hardware](supported_hardware.md))
- [x] Ethernet over USB (see [supported hardware](supported_hardware.md))
- [x] Meshtastic native client controlling a LoRa radio (see [supported hardware](https://github.com/femtofox/femtofox/wiki/Supported-Hardware))
- [x] WIFI over USB (see [supported hardware](https://github.com/femtofox/femtofox/wiki/Supported-Hardware))
- [x] Ethernet over pins (see *Networking* below and wiring diagram at bottom of page)
- [x] UART communications with Meshtastic nodes (2 pin pairs) such as RAK Wisblock
- [x] USB serial communications with Meshtastic nodes (see [supported hardware](supported_hardware.md))
- [x] USB serial communications with Meshtastic nodes (see [supported hardware](https://github.com/femtofox/femtofox/wiki/Supported-Hardware))
- [x] USB mass storage
- [x] Real time clock (RTC) support (see [supported hardware](supported_hardware.md))
- [x] Real time clock (RTC) support (see [supported hardware](https://github.com/femtofox/femtofox/wiki/Supported-Hardware))
- [x] Activity LED disabled. User LED will blink for 5 seconds when boot is complete
- [x] Short pressing the "BOOT" button toggles wifi, 2-5 second press triggers reboot, 5+ second press shuts system down
- [x] Ability to reconfigure wifi via USB flash drive
- [x] Meshtasticd to run LoRa radio over SPI (accomplished, updated image and instructions coming soon)
- [x] Allow editing of config files by plugging in thumb drive
- [x] Ability to activate or deactivate WIFI via Meshtastic admin
The preconfigured images will reboot every 24 hours. If the internal clock is accurate, this will be at 3am. Reboot timing is set in `crontab`. To keep accurate time, an RTC module can be installed (see [supported hardware](supported_hardware.md)) or internet connectivity can be utilized for NTP via [Chrony](https://chrony-project.org/).
### [Supported hardware - click here](supported_hardware.md)
### Networking
There are four methods to get online:
1. Ethernet over USB - most adapters should be supported, but I've only tested the RTL8152 chipset.
2. USB wifi (see [supported hardware](supported_hardware.md)).
3. Preconfigured Ubuntu images: ethernet via the castellated pins at the bottom of the board. See pinout at the bottom of this readme.
4. RDNIS via usb - [see this guide](https://web.archive.org/web/20241006173648/https://wiki.luckfox.com/Luckfox-Pico/Luckfox-Pico-Network-Sharing-1/). Note that in the preconfigured images USB is set to host mode, so you'll have to switch back to peripheral with `sudo luckfox-config`. This is not really recommended, but can be used in a pinch.
### [Installation guide](foxbuntu_install.md)
### Pinout:
|Pin #|Pin ID |Function |Luckfox |Pin #|Pin ID |Function |
|-----|-------|--------------|--------|-----|-------|--------------|
|1 |VBus |5V in/out | |22 |1V8 |1.8V out |
|2 |GND | | |21 |GND | |
|3 |3V3 |3.3V out | |20 |4C1 |1v8 IO, SARADC|
|4/42 |1B2 |Debug UART2-TX| |19 |4C0 |1v8 IO, SARADC|
|5/43 |1B3 |Debug UART2-RX| |18/4 |0A4 |3v3 IO |
|6/48 |1C0 |CS0, IO | |17/55|1C7 |IRQ, IO |
|7/49 |1C1 |CLK, IO | |16/54|1C6 |BUSY, IO |
|8/50 |1C2 |MOSI, IO | |15/59|1D3 |i2c SCL |
|9/51 |1C3 |MISO, IO | |14/58|1D2 |i2c SDA |
|10/52|1C4 |UART4-TX | |13/57|1D1 |UART3-RX, NRST|
|11/53|1C5 |UART4-RX | |12/56|1D0 |UART3-TX, RXEN|
Pin ID explanation: **1C6** = GPIO bank **1**, group **C**, pin **6**.
In Meshtasticd's config.yaml we use GPIO bank 1, and subtract 32 from the pin number.
![pinout](assets/images/luckfox_pinout.png)
![pinout](assets/images/luckfox_pico_mini_original_wiring_diagram.jpg)
> [!NOTE]
> The information on this page is given without warranty or guarantee. Links to vendors of products are for informational purposes only.
> Meshtastic® is a registered trademark of Meshtastic LLC. Meshtastic software components are released under various licenses, see GitHub for details. No warranty is provided - use at your own risk.
<!--stackedit_data:
eyJoaXN0b3J5IjpbMTAyOTUxODA1MywtODA3NjYxMjY1XX0=
eyJoaXN0b3J5IjpbMTE3Mjg3OTE0N119
-->

View file

@ -1,46 +1,66 @@
## femtofox-config.txt
## Help: https://github.com/noon92/femtofox/usbconfig.md
## Help: https://github.com/femtofox/femtofox/blob/main/usb_config.md
## To set a setting, uncomment a line by removing its preceeding `#`
## All settings are optional - remove any you don't want to set.
### Foxbuntu settings
## Localization settings. CaSe SeNsItIvE
## List of timezones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#wifi_country="US"
#timezone="UTC"
## Wifi settings / wpa_supplicant. CaSe SeNsItIvE
#wifi_ssid="wifi network name"
#wifi_psk="password"
#wifi_country="US"
## Localization settings. CaSe SeNsItIvE
## List of timezones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#timezone="UTC"
## Activity LED setting. CaSe SeNsItIvE
## Options are "enable" and "disable"
#act_led="disable"
### Software installation
## Software package names are filenames (without .sh suffix) in /usr/local/bin/packages
## Multiple packages can be installed by separating them with commas
#software_install="packageA,packageB"
### Meshtastic settings
## Multiple meshtastic_cli lines can be added. This is important, as the Meshtastic CLI requires that different settings categories (such as device and lora) be handled in separate commands.
## See Meshtastic CLI docs (https://meshtastic.org/docs/software/python/cli/) for more information.
#meshtastic_cli="--set lora.modem_preset LONG_FAST"
#meshtastic_cli="--set device.role CLIENT"
## Radio module to use. Options are:
## `ebyte-e22-900m30s`
## `ebyte-e22-900m22s`
## `ebyte-e80-900m22s` (experimental)
## `heltec-ht-ra62`
## `seeed-wio-sx1262`
## `waveshare-sx126x-xxxm`
## `ai-thinker-ra-01sh`
## `sx1262_tcxo` (for Ebyte E22-900M30SM, Ebyte E22-900M22S, Heltec HT-RA62, Seeed Wio SX1262)
## `sx1262_xtal` (for AiThinker RA01SH, and Waveshare Pi hat)
## `lr1121_tcxo` (experimental, for Ebyte E80-900M2213S)
## `none` (for simulated radio)
## "ebyte-e22-900m30s"
## "ebyte-e22-900m22s"
## "ebyte-e80-900m22s" (experimental)
## "heltec-ht-ra62"
## "seeed-wio-sx1262"
## "waveshare-sx126x-xxxm"
## "ai-thinker-ra-01sh"
## "sx1262_tcxo" (for Ebyte E22-900M30SM, Ebyte E22-900M22S, Heltec HT-RA62, Seeed Wio SX1262)
## "sx1262_xtal" (for AiThinker RA01SH, and Waveshare Pi hat)
## "lr1121_tcxo" (experimental, for Ebyte E80-900M2213S)
## "none" (for simulated radio)
#meshtastic_lora_radio="radio_name"
## URL from Meshtastic QR code to configure channels
#meshtastic_url="https://meshtastic.org/e/..."
#meshtastic_url="https://meshtastic.org/e/XX..."
## Meshtastic security settings. CaSe SeNsItIvE
#meshtastic_public_key="XX="
#meshtastic_private_key="XX="
## The admin key list can contain up to three keys - if more are added they will be ignored.
## The USB configuration tool supports clearing the admin key list, after which you will need to re-add your admin key/s in a second operation.
## To clear the admin key list, enter `meshtastic_admin_key="clear"`
#meshtastic_admin_key="XX="
#meshtastic_legacy_admin="false"
## Meshtastic i2c state.
## Enabling i2c without devices connected will lead to slowdowns and error messages.
## Options are "enable" and "disable"
meshtastic_i2c="disable"
### If the following line is uncommented, USB config will be skipped if a log file is present on the USB drive, indicating the tool has already been run on this system
#dont_run_if_log_exists

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Before After
Before After

Binary file not shown.

View file

@ -9,51 +9,74 @@ echo "tmpfs /run tmpfs rw,nodev,nosuid,size=32M 0 0" | tee -a /etc/fstab
#echo "deb [arch=all signed-by=/etc/apt/keyrings/meshtastic-deb.asc] https://meshtastic.github.io/deb stable main" | tee /etc/apt/sources.list.d/meshtastic-deb.list >/dev/null
echo "Removing netdevice rules..."
ln -s /dev/null /etc/udev/rules.d/80-net-setup-link.rules
echo "Setting up kernel modules..."
touch /lib/modules/5.10.160/modules.order
touch /lib/modules/5.10.160/modules.builtin
depmod -a 5.10.160
if [[ $? -eq 2 ]]; then echo "Error, step failed..."; fi
echo "Setting localtime to UTC..."
rm /etc/localtime
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
echo "Installing packages..."
apt update
DEBIAN_FRONTEND=noninteractive apt install -y --option Dpkg::Options::="--force-confold" linux-firmware wireless-tools git python3.10-venv libgpiod-dev libyaml-cpp-dev libbluetooth-dev openssl libssl-dev libulfius-dev liborcania-dev evtest screen avahi-daemon protobuf-compiler telnet fonts-noto-color-emoji ninja-build chrony qrencode software-properties-common python-is-python3 python3.10-venv lsof spi-tools python3-luma.oled
DEBIAN_FRONTEND=noninteractive apt install -y --option Dpkg::Options::="--force-confold" linux-firmware wireless-tools git python3.10-venv libgpiod-dev libyaml-cpp-dev libbluetooth-dev openssl libssl-dev libulfius-dev liborcania-dev evtest screen avahi-daemon protobuf-compiler telnet fonts-noto-color-emoji ninja-build chrony qrencode software-properties-common python-is-python3 python3.10-venv lsof spi-tools python3-luma.oled samba vim mtd-utils jq rsync
if [[ $? -eq 2 ]]; then echo "Error, step failed..."; fi
DEBIAN_FRONTEND=noninteractive apt upgrade -y --option Dpkg::Options::="--force-confold"
# requires software-properties-common, so must be done in a separate command unless added manually
echo "Adding Meshtastic repository and installing meshtastic..."
add-apt-repository -y ppa:meshtastic/beta
DEBIAN_FRONTEND=noninteractive apt install -y --option Dpkg::Options::="--force-confold" meshtasticd
# Tempfix for SEGFAULT
wget https://github.com/meshtastic/firmware/releases/download/v2.5.11.8e2a3e5/meshtasticd_2.5.11.8e2a3e5_armhf.deb
DEBIAN_FRONTEND=noninteractive apt install -y --option Dpkg::Options::="--force-confold" ./meshtasticd_2.5.11.8e2a3e5_armhf.deb
rm ./meshtasticd_2.5.11.8e2a3e5_armhf.deb
#wget https://github.com/meshtastic/firmware/releases/download/v2.5.11.8e2a3e5/meshtasticd_2.5.11.8e2a3e5_armhf.deb
#DEBIAN_FRONTEND=noninteractive apt install -y --option Dpkg::Options::="--force-confold" ./meshtasticd_2.5.11.8e2a3e5_armhf.deb
#rm ./meshtasticd_2.5.11.8e2a3e5_armhf.deb
echo "Installing dependencies for meshing-around and meshtastic cli..."
#pip config set global.extra-index-url https://www.piwheels.org/simple
pip3 install requests pyephem pytap2 meshtastic pypubsub geopy maidenhead beautifulsoup4 dadjokes schedule wikipedia googlesearch-python
pip3 install requests pyephem pytap2 meshtastic pypubsub geopy maidenhead beautifulsoup4 dadjokes schedule wikipedia googlesearch-python pubsub datetime
if [[ $? -eq 2 ]]; then echo "Error, step failed..."; fi
echo "Setting MOTD..."
echo "Downloading ttyd and enabling service..."
wget -qO- https://api.github.com/repos/tsl0922/ttyd/releases/latest | grep "browser_download_url" | grep "armhf" | cut -d '"' -f 4 | xargs wget -O /opt/ttyd/ttyd
chmod +x /opt/ttyd/ttyd
systemctl enable ttyd
echo "Cloning Control for Meshtastic by pdxlocations"
git clone https://github.com/pdxlocations/control.git /opt/control
pip install -r /opt/control/requirements.txt
chown -R femto /opt/control
git config --global --add safe.directory /opt/control # prevents git error when updating
echo "Setting MOTD..."
mv /etc/update-motd.d/10-help-text /etc/update-motd.d/10-help-text.bak
mv /etc/update-motd.d/60-unminimize /etc/update-motd.d/60-unminimize.bak
echo "Setting hostname to femtofox..."
echo "femtofox" | tee /etc/hostname > /dev/null
echo "Configuring autostart of systemd services..."
systemctl enable button
systemctl enable wifi-mesh-control
systemctl enable femto-runonce.service
systemctl enable femto-usb-config-tool.service
systemctl enable femto-boot-complete.service
systemctl enable femto-wifi-mesh-control
systemctl enable femto-watchclock-dog
systemctl disable ttyd # enabled on first boot
systemctl disable meshtasticd # enabled on first boot
systemctl disable apt-daily.timer
systemctl disable apt-daily-upgrade.timer
systemctl mask apt-daily.service # try prevent daily updates
systemctl mask apt-daily-upgrade.service # try prevent daily updates
systemctl disable unattended-upgrades
systemctl disable smbd nmbd # samba services, can be enabled via menu
systemctl disable NetworkManager
systemctl disable NetworkManager-dispatcher
systemctl disable NetworkManager-wait-online
@ -72,7 +95,6 @@ systemctl disable veritysetup.target
systemctl disable systemd-pstore.service
echo "Adding femto and pico users/groups..."
groupmod -n femto pico
usermod -l femto pico
usermod -aG sudo,input femto
@ -80,7 +102,6 @@ echo "femto ALL=(ALL:ALL) ALL" | tee /etc/sudoers.d/femto > /dev/null
chmod 440 /etc/sudoers.d/femto
# this seems messy, user:group should be set cleanly and not corrected after? OSC: somethings were owned my pico from factory
find / -group pico -exec chgrp femto {} \; 2>/dev/null
find / -user pico -exec chown femto {} \; 2>/dev/null
usermod -d /home/femto -m femto
@ -90,7 +111,20 @@ sudo chage -d 0 femto
usermod -a -G tty femto
usermod -a -G dialout femto
echo "Cleaning up chroot..."
# Ensure libgcc_s.so and libc_nonshared.a exist
mkdir -p /usr/lib/gcc/arm-linux-gnueabihf/11/
ln -sf /usr/lib/arm-linux-gnueabihf/libgcc_s.so.1 /usr/lib/gcc/arm-linux-gnueabihf/11/libgcc_s.so
ln -sf /usr/lib/arm-linux-gnueabihf/libgcc_s.so.1 /lib/libgcc_s.so.1
ln -sf /usr/lib/gcc/arm-linux-gnueabihf/11/libgcc_s.so /usr/lib/libgcc.so
# Add library paths
echo "/usr/lib/gcc/arm-linux-gnueabihf/11" | tee -a /etc/ld.so.conf.d/gcc.conf
ldconfig
# Back up libc_nonshared.a because build.sh removes it
cp /usr/lib/arm-linux-gnueabihf/libc_nonshared.a /usr/lib/arm-linux-gnueabihf/libc_nonshared.a.keep
echo "Cleaning up chroot..."
rm -rf /tmp/* && rm -rf /var/tmp/* && find /var/log -type f -exec truncate -s 0 {} + && : > /root/.bash_history && history -c
apt clean && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/* && rm -rf /var/tmp/* && find /var/log -type f -exec truncate -s 0 {} + && : > /root/.bash_history && history -c
exit

View file

@ -12,15 +12,11 @@ if [[ $(id -u) != 0 ]]; then
exit 1
fi
if [ -f /etc/os-release ]; then
. /etc/os-release
if [ "$VERSION_ID" != "22.04" ] || [ "$NAME" != "Ubuntu" ]; then
echo "This script is intended for Ubuntu 22.04, exiting..."
exit 1
fi
else
echo "This script is intended for Ubuntu 22.04, exiting..."
exit 1
[ -f /etc/os-release ] && . /etc/os-release
if [ "$VERSION_ID" != "22.04" ] || [ "$NAME" != "Ubuntu" ]; then
echo -e "This script is intended for Ubuntu 22.04, your operating system is not supported (but may work).\nPress Ctrl+C to cancel, or Enter to continue."
read
fi
sudoer=$(echo $SUDO_USER)
@ -61,8 +57,9 @@ clone_repos() {
fi
}
clone_with_retries "https://github.com/LuckfoxTECH/luckfox-pico.git" || return 1
clone_with_retries "https://github.com/noon92/femtofox.git" || return 1
#clone_with_retries "https://github.com/LuckfoxTECH/luckfox-pico.git" || return 1
clone_with_retries "https://github.com/Ruledo/luckfox-pico.git" || return 1
clone_with_retries "https://github.com/femtofox/femtofox.git" || return 1
return 0
}

View file

@ -4,11 +4,11 @@
#/etc/init.d/S50usbdevice start
#run only on first boot
if [ -e "/etc/.firstboot" ]; then
/usr/local/bin/femto-runonce.sh
fi
#if [ -e "/etc/.firstboot" ]; then
# /usr/local/bin/femto-runonce.sh
#fi
luckfox-config load
#luckfox-config load
# try enable RTC
echo 'ds1307 0x68' | sudo tee /sys/class/i2c-adapter/i2c-3/new_device > /dev/null 2>&1
@ -23,21 +23,21 @@ echo 34 > /sys/class/gpio/export && echo out > /sys/class/gpio/gpio34/direction
#(sleep 5 && cpufreq-set -u 408000 && echo "Boot complete, setting CPU frequency to 408mhz.") &
# run USB automount and config tool
/usr/local/bin/femto-usb-config-tool.sh
#/usr/local/bin/femto-usb-config-tool.sh
# boot complete
(
echo "Disabling ACT LED..."
echo "none" > /sys/class/leds/work/trigger &
sleep 1
# blink successful boot code
for i in $(seq 1 5); do
echo 1 > /sys/class/gpio/gpio34/value;
sleep 0.5;
echo 0 > /sys/class/gpio/gpio34/value;
sleep 0.5;
done
) &
#(
# echo "Disabling ACT LED..."
# echo "none" > /sys/class/leds/work/trigger &
# sleep 1
#
# # blink successful boot code
# for i in $(seq 1 5); do
# echo 1 > /sys/class/gpio/gpio34/value;
# sleep 0.5;
# echo 0 > /sys/class/gpio/gpio34/value;
# sleep 0.5;
# done
#) &
exit 0

View file

@ -1 +0,0 @@
# File to tell rc.local that this is the first boot. Will be deleted automatically.

View file

@ -0,0 +1,2 @@
APT::Periodic::Update-Package-Lists "0";
APT::Periodic::Unattended-Upgrade "0";

View file

@ -0,0 +1 @@
act_led=enable

View file

@ -1,5 +1,5 @@
major=0
minor=97
major=1
minor=0
patch=0
hotfix=

View file

@ -0,0 +1,11 @@
# this sets the mac address source to eth0, replacing the previous code that derived a seed from the CPU s/n.
# of course, eth0 also has its mac address derived from CPU s/n, but this way meshtastic uses the exact mac address, instead of a bastardized version converted to a 9 digit int with `| bc | tail -c -9`.
General:
MACAddressSource: eth0
# this activates the webserver
Webserver:
Port: 443 # Port for Webserver & Webservices
RootPath: /usr/share/meshtasticd/web # Root Dir of WebServer
SSLKey: /etc/meshtasticd/ssl/private_key.pem # Path to SSL Key, generated if>
SSLCert: /etc/meshtasticd/ssl/certificate.pem # Pa

View file

@ -8,4 +8,13 @@ iface lo inet loopback
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
metric 100
post-up sleep 5 && dhclient wlan0
pre-down ip route del default via $(ip route | awk '/default/ {print $3}') dev wlan0 metric 100
allow-hotplug eth0
iface eth0 inet dhcp
metric 10
post-up ip route replace default via $(ip route | awk '/default/ {print $3}') dev eth0 metric 10
pre-down ip route del default via $(ip route | awk '/default/ {print $3}') dev eth0 metric 10

View file

@ -0,0 +1,253 @@
#
# Sample configuration file for the Samba suite for Debian GNU/Linux.
#
#
# This is the main Samba configuration file. You should read the
# smb.conf(5) manual page in order to understand the options listed
# here. Samba has a huge number of configurable options most of which
# are not shown in this example
#
# Some options that are often worth tuning have been included as
# commented-out examples in this file.
# - When such options are commented with ";", the proposed setting
# differs from the default Samba behaviour
# - When commented with "#", the proposed setting is the default
# behaviour of Samba but the option is considered important
# enough to be mentioned here
#
# NOTE: Whenever you modify this file you should run the command
# "testparm" to check that you have not made any basic syntactic
# errors.
#======================= Global Settings =======================
[global]
## Browsing/Identification ###
# Change this to the workgroup/NT-domain name your Samba server will part of
workgroup = WORKGROUP
# server string is the equivalent of the NT Description field
server string = %h server (Samba, Ubuntu)
#### Networking ####
# The specific set of interfaces / networks to bind to
# This can be either the interface name or an IP address/netmask;
# interface names are normally preferred
; interfaces = 127.0.0.0/8 eth0
# Only bind to the named interfaces and/or networks; you must use the
# 'interfaces' option above to use this.
# It is recommended that you enable this feature if your Samba machine is
# not protected by a firewall or is a firewall itself. However, this
# option cannot handle dynamic or non-broadcast interfaces correctly.
; bind interfaces only = yes
#### Debugging/Accounting ####
# This tells Samba to use a separate log file for each machine
# that connects
log file = /var/log/samba/log.%m
# Cap the size of the individual log files (in KiB).
max log size = 1000
# We want Samba to only log to /var/log/samba/log.{smbd,nmbd}.
# Append syslog@1 if you want important messages to be sent to syslog too.
logging = file
# For more verbose logging:
; log level = 3
# Do something sensible when Samba crashes: mail the admin a backtrace
panic action = /usr/share/samba/panic-action %d
####### Authentication #######
# Server role. Defines in which mode Samba will operate. Possible
# values are "standalone server", "member server", "classic primary
# domain controller", "classic backup domain controller", "active
# directory domain controller".
#
# Most people will want "standalone server" or "member server".
# Running as "active directory domain controller" will require first
# running "samba-tool domain provision" to wipe databases and create a
# new domain.
server role = standalone server
obey pam restrictions = yes
# This boolean parameter controls whether Samba attempts to sync the Unix
# password with the SMB password when the encrypted SMB password in the
# passdb is changed.
unix password sync = yes
# For Unix password sync to work on a Debian GNU/Linux system, the following
# parameters must be set (thanks to Ian Kahan <<kahan@informatik.tu-muenchen.de> for
# sending the correct chat script for the passwd program in Debian Sarge).
passwd program = /usr/bin/passwd %u
passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
# This boolean controls whether PAM will be used for password changes
# when requested by an SMB client instead of the program listed in
# 'passwd program'. The default is 'no'.
pam password change = yes
# This option controls how unsuccessful authentication attempts are mapped
# to anonymous connections
map to guest = bad user
########## Domains ###########
#
# The following settings only takes effect if 'server role = classic
# primary domain controller', 'server role = classic backup domain controller'
# or 'domain logons' is set
#
# It specifies the location of the user's
# profile directory from the client point of view) The following
# required a [profiles] share to be setup on the samba server (see
# below)
; logon path = \\%N\profiles\%U
# Another common choice is storing the profile in the user's home directory
# (this is Samba's default)
# logon path = \\%N\%U\profile
# The following setting only takes effect if 'domain logons' is set
# It specifies the location of a user's home directory (from the client
# point of view)
; logon drive = H:
# logon home = \\%N\%U
# The following setting only takes effect if 'domain logons' is set
# It specifies the script to run during logon. The script must be stored
# in the [netlogon] share
# NOTE: Must be store in 'DOS' file format convention
; logon script = logon.cmd
# This allows Unix users to be created on the domain controller via the SAMR
# RPC pipe. The example command creates a user account with a disabled Unix
# password; please adapt to your needs
; add user script = /usr/sbin/adduser --quiet --disabled-password --gecos "" %u
# This allows machine accounts to be created on the domain controller via the
# SAMR RPC pipe.
# The following assumes a "machines" group exists on the system
; add machine script = /usr/sbin/useradd -g machines -c "%u machine account" -d /var/lib/samba -s /bin/false %u
# This allows Unix groups to be created on the domain controller via the SAMR
# RPC pipe.
; add group script = /usr/sbin/addgroup --force-badname %g
############ Misc ############
# Using the following line enables you to customise your configuration
# on a per machine basis. The %m gets replaced with the netbios name
# of the machine that is connecting
; include = /home/samba/etc/smb.conf.%m
# Some defaults for winbind (make sure you're not using the ranges
# for something else.)
; idmap config * : backend = tdb
; idmap config * : range = 3000-7999
; idmap config YOURDOMAINHERE : backend = tdb
; idmap config YOURDOMAINHERE : range = 100000-999999
; template shell = /bin/bash
# Setup usershare options to enable non-root users to share folders
# with the net usershare command.
# Maximum number of usershare. 0 means that usershare is disabled.
# usershare max shares = 100
# Allow users who've been granted usershare privileges to create
# public shares, not just authenticated ones
usershare allow guests = yes
#======================= Share Definitions =======================
# Un-comment the following (and tweak the other settings below to suit)
# to enable the default home directory shares. This will share each
# user's home directory as \\server\username
;[homes]
; comment = Home Directories
; browseable = no
# By default, the home directories are exported read-only. Change the
# next parameter to 'no' if you want to be able to write to them.
; read only = yes
# File creation mask is set to 0700 for security reasons. If you want to
# create files with group=rw permissions, set next parameter to 0775.
; create mask = 0700
# Directory creation mask is set to 0700 for security reasons. If you want to
# create dirs. with group=rw permissions, set next parameter to 0775.
; directory mask = 0700
# By default, \\server\username shares can be connected to by anyone
# with access to the samba server.
# Un-comment the following parameter to make sure that only "username"
# can connect to \\server\username
# This might need tweaking when using external authentication schemes
; valid users = %S
# Un-comment the following and create the netlogon directory for Domain Logons
# (you need to configure Samba to act as a domain controller too.)
;[netlogon]
; comment = Network Logon Service
; path = /home/samba/netlogon
; guest ok = yes
; read only = yes
# Un-comment the following and create the profiles directory to store
# users profiles (see the "logon path" option above)
# (you need to configure Samba to act as a domain controller too.)
# The path below should be writable by all users so that their
# profile directory may be created the first time they log on
;[profiles]
; comment = Users profiles
; path = /home/samba/profiles
; guest ok = no
; browseable = no
; create mask = 0600
; directory mask = 0700
[printers]
comment = All Printers
browseable = no
path = /var/spool/samba
printable = yes
guest ok = no
read only = yes
create mask = 0700
# Windows clients look for this share name as a source of downloadable
# printer drivers
[print$]
comment = Printer Drivers
path = /var/lib/samba/printers
browseable = yes
read only = yes
guest ok = no
# Uncomment to allow remote administration of Windows print drivers.
# You may need to replace 'lpadmin' with the name of the group your
# admin users are members of.
# Please note that you also need to set appropriate Unix permissions
# to the drivers directory for these users to have write rights in it
; write list = root, @lpadmin
[home]
path = /home/femto
browseable = yes
writable = yes
read only = no
create mask = 0775
directory mask = 0775
valid users = femto

View file

@ -0,0 +1,14 @@
[Unit]
Description=Boot Complete
DefaultDependencies=no
After=multi-user.target femto-usb-config-tool.service
[Service]
ExecStart=/usr/local/bin/femto-boot-complete.sh
Type=oneshot
Restart=no
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=default.target

View file

@ -0,0 +1,16 @@
[Unit]
Description=Foxbuntu First Boot
After=rc-local.service
Before=serial-getty@ttyFIQ0.service
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/femto-runonce.sh
Type=oneshot
Restart=no
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=default.target

View file

@ -0,0 +1,16 @@
[Unit]
Description=Foxbuntu USB Configuration Tool
After=rc-local.service
Before=serial-getty@ttyFIQ0.service
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/femto-usb-config-tool.sh
Type=oneshot
Restart=no
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=default.target

View file

@ -1,11 +1,12 @@
[Unit]
Description=Meshtastic control of wifi
Description=Watchclock-dog
After=network.target
[Service]
ExecStart=/usr/local/bin/wifi-mesh-control.sh
ExecStart=/usr/local/bin/femto-watchclock-dog.sh
Restart=always
User=root
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,12 @@
[Unit]
Description=Sync wifi updown with Meshtastic
After=meshtasticd.service
[Service]
ExecStart=/usr/local/bin/femto-wifi-mesh-control.sh
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target

View file

@ -1,3 +1,7 @@
[Service]
ExecStartPost=/bin/sh -c 'renice -n -20 -p $(pgrep meshtasticd)'
Nice=-20
[Unit]
After=rc-local.service
Wants=rc-local.service
After=network-online.target

View file

@ -0,0 +1,7 @@
[Unit]
After=femto-boot-complete.service multi-user.target
Conflicts=getty.target
Before=getty.target
[Service]
ExecStartPre=/bin/sleep 0.5

View file

@ -0,0 +1,14 @@
[Unit]
Description=ttyd Web Terminal
After=syslog.target
After=network.target
[Service]
ExecStart=/opt/ttyd/ttyd -W -6 --ssl --ssl-key /etc/ssl/private/ttyd.key --ssl-cert /etc/ssl/certs/ttyd.crt -i 0.0.0.0 login
Type=simple
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target

View file

@ -12,11 +12,11 @@ if [ -z "$DISTRIB_DESCRIPTION" ] && [ -x /usr/bin/lsb_release ]; then
fi
[ -r /etc/lsb-release ] && . /etc/lsb-release
foxbuntu_version=$(grep -oP 'major=\K[0-9]+' /etc/foxbuntu-release).$(grep -oP 'minor=\K[0-9]+' /etc/foxbuntu-release)$(output=$(grep -o 'patch=[1-9][0-9]*' /etc/foxbuntu-release | cut -d= -f2) && [ -n "$output" ] && echo ".$output")$(grep -oP 'hotfix=\K[a-z]+' /etc/foxbuntu-release)
spaces=$((11 - ${#foxbuntu_version}))
foxbuntu_version=$(femto-utils.sh -v)
spaces=$((21 - ${#foxbuntu_version}))
printf " For settings, run \`\033[0;31msudo femto-config\033[0m\`\n"
printf " Made for Femtofox https://www.femtofox.com\n"
printf " Foxbuntu v$foxbuntu_version%*s%s(%s)\n\n" $spaces "" "$DISTRIB_DESCRIPTION" "$(uname -r)"
printf " $foxbuntu_version%*s%s(%s)\n\n" $spaces "" "$DISTRIB_DESCRIPTION" "$(uname -r)"
printf "IP address: $(hostname -I | sed 's/ / /g') Uptime:$(uptime -p | awk '{$1=""; print $0}' | sed -e 's/ day\b/d/g' -e 's/ hour\b/h/g' -e 's/ hours\b/h/g' -e 's/ minute\b/m/g' -e 's/ minutes\b/m/g' | sed 's/,//g')\n"

View file

@ -1,11 +0,0 @@
[Unit]
Description=Run settime script at startup
Before=meshtasticd.service
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/settime.sh
[Install]
WantedBy=default.target

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2025 Shuanglei Tao <tsl0922@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,36 @@
#
# Run-time configuration file for dialog
#
# Automatically generated by "dialog --create-rc <file>"
#
#
# Types of values:
#
# Number - <number>
# String - "string"
# Boolean - <ON|OFF>
# Attribute - (foreground,background,highlight?,underline?,reverse?)
# Up arrow color
uarrow_color = (GREEN,WHITE,ON)
# Down arrow color
darrow_color = uarrow_color
# Active form text color
form_active_text_color = button_active_color
# Form text color
form_text_color = (WHITE,CYAN,ON)
# Readonly form item color
form_item_readonly_color = (BLUE,WHITE,ON)
# Item help-text color
itemhelp_color = (WHITE,BLUE,OFF)
# Selected tag color (menu items)
tag_selected_color = (WHITE,BLUE,ON)
# Tag color (menu items)
tag_color = (BLACK,WHITE,OFF)

View file

@ -0,0 +1,19 @@
#!/bin/bash
if grep -qE '^first_boot=true' /etc/femto.conf; then
echo "First boot, skipping \`boot complete\` tasks."
exit 0
fi
echo "Boot complete"
femto-utils.sh -a &
sleep 1
# blink successful boot code
for i in $(seq 1 5); do
echo 1 > /sys/class/gpio/gpio34/value;
sleep 0.5;
echo 0 > /sys/class/gpio/gpio34/value;
sleep 0.5;
done
exit 0

View file

@ -9,10 +9,8 @@ if [[ $EUID -ne 0 ]]; then
exit 1
fi
# pause
pause() {
echo "Press any key to continue..."
read -n 1 -s -r
loading() {
dialog --no-collapse --infobox "$1" 5 45
}
title="Install Wizard"
@ -21,63 +19,82 @@ wizard() {
femto-set-time.sh
new_hostname=$(dialog --title "$title" --cancel-label "Skip" --inputbox "Enter hostname:" 8 40 $(hostname) 3>&1 1>&2 2>&3)
new_hostname=$(dialog --title "Hostname" --cancel-label "Skip" --inputbox "Enter hostname:" 8 40 $(hostname) 3>&1 1>&2 2>&3)
if [ $? -eq 0 ]; then #unless cancel/no
femto-network-config.sh -n "$new_hostname"
dialog --title "$title" --msgbox "\nFemtofox is now reachable at\n$new_hostname.local" 8 40
dialog --title "Hostname" --msgbox "\nFemtofox is now reachable at\n$new_hostname.local" 8 40
fi
dialog --title "$title" --cancel-label "Skip" --yesno "\nConfigure Wi-Fi settings?" 8 40
dialog --title "$title" --yesno "Configure Wi-Fi settings?" 6 40
if [ $? -eq 0 ]; then #unless cancel/no
femto-config -w
fi
dialog --title "$title" --cancel-label "Skip" --yesno "\nConfigure Meshtastic?" 8 40
dialog --title "$title" --yesno "Configure Meshtastic?" 6 40
if [ $? -eq 0 ]; then #unless cancel/no
newurl=$(dialog --title "Meshtastic URL" --cancel-label "Skip" --inputbox "New Meshtasticd URL (SHIFT+INS to paste):" 8 50 3>&1 1>&2 2>&3)
if [ -n "$newurl" ]; then #if a URL was entered
femto-meshtasticd-config.sh -q "$newurl"
pause
if femto-config -c; then
while true; do
meshtastic_menu_choice=$(dialog --no-collapse --colors --cancel-label "Continue" --default-item "$meshtastic_menu_choice" --title "Meshtastic Configuration" --item-help --menu "Currently configured LoRa radio:\n$(femto-utils.sh -R "$(femto-meshtasticd-config.sh -k)")" 16 40 5 \
1 "Set LoRa radio model" "" \
2 "Set configuration URL" "" \
3 "Set private key" "" \
4 "Set public key" "" \
" " "" "" \
5 "Full Meshtastic settings menu" "" \
" " "" "" \
6 "Continue" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
case $meshtastic_menu_choice in
1) # Set LoRa radio model)
femto-config -l
;;
2) # Configure automatically with URL)
femto-config -c && (
femto-config -u
)
;;
3) # view/change private key)
femto-config -c && (
key=$(dialog --no-collapse --colors --title "Meshtastic Private Key" --cancel-label "Cancel" --inputbox "The private key of the device, used to create a shared key with a remote device for secure communication.\n\n\Z1This key should be kept confidential.\nSetting an invalid key will lead to unexpected behaviors.\Zn\n\nPrivate key (default: random)" 15 60 3>&1 1>&2 2>&3)
if [ $? -eq 0 ] && [[ -n "$key" ]]; then #unless cancel/no
loading "Sending command..."
dialog --no-collapse --colors --title "Meshtastic Private Key" --msgbox "$(femto-meshtasticd-config.sh -R "$key" && echo -e "\n\Z4Command successful!\Zn\n" || echo -e "\n\Z1Command failed.\Zn\n")" 0 0
fi
)
;;
4) # view/change public key)
femto-config -c && (
key=$(dialog --no-collapse --colors --title "Meshtastic Public Key" --cancel-label "Cancel" --inputbox "The public key of the device, shared with other nodes on the mesh to allow them to compute a shared secret key for secure communication.\n\n\ZuGenerated automatically\Zn to match private key.\n\n\Z1Don't change this if you don't know what you're doing.\Zn\n\nPublic key (default: generated from private key)" 16 60 3>&1 1>&2 2>&3)
if [ $? -eq 0 ] && [[ -n "$key" ]]; then #unless cancel/no
loading "Sending command..."
dialog --no-collapse --colors --title "Meshtastic Public Key" --msgbox "$(femto-meshtasticd-config.sh -U "$key" && echo -e "\n\Z4Command successful!\Zn\n" || echo -e "\n\Z1Command failed.\Zn\n")" 0 0
fi
)
;;
5) # Full Meshtastic settings menu)
femto-config -c && (
dialog --no-collapse --infobox "Loading Meshtastic settings menu...\n\nStopping conflicting services, will restart after exit...\n\nThis can take up to a minute." 9 50
femto-utils.sh -A stop
python /opt/control/main.py --host
femto-utils.sh -A start
)
;;
6) # return to previous menu)
break
;;
esac
done
fi
femto-config -l
key=$(dialog --title "$title" --cancel-label "Skip" --inputbox "Enter Meshtastic admin key (optional). If 3 admin keys are already in Meshtastic, more will be ignored.\n(SHIFT+INS to paste):" 11 50 3>&1 1>&2 2>&3)
if [ -n "$key" ]; then #if a URL was entered
femto-meshtasticd-config.sh -a "$key"
pause
fi
while true; do
choice=$(dialog --title "$title" --cancel-label "Skip" --menu "Enable/disable Meshtastic Legacy admin channel?" 12 40 5 \
1 "Enable" \
2 "Disable (default)" \
"" "" \
3 "Skip" 3>&1 1>&2 2>&3)
exit_status=$? # This line checks the exit status of the dialog command
if [ $exit_status -ne 0 ]; then # Exit the loop if the user selects "Cancel" or closes the dialog
break
fi
case $choice in
1) femto-meshtasticd-config.sh -o "true" && break ;;
2) femto-meshtasticd-config.sh -o "false" && break ;;
3) break ;;
*) dialog --msgbox "Invalid choice, please try again." 8 40 ;;
esac
done
fi
dialog --title "$title" --msgbox "\nSetup wizard complete!" 8 40
dialog --title "$title" --msgbox "Setup wizard complete!" 6 40
}
dialog --title "$title" --yesno "\
The install wizard will allow you to configure all the settings necessary to run your Femtofox.\n\
\n\
Running this wizard will overwrite some current settings.\n\
Proceed?" 0 0
The wizard takes several minutes to complete and will overwrite some current settings.\n\n\
Proceed?" 12 60
if [ $? -eq 0 ]; then #unless cancel/no
wizard
fi

View file

@ -1,13 +1,26 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root."
echo "Try \`sudo femto-config\`."
exit 1
fi
help=$(cat <<EOF
If script is run without arguments, a dialog menu UI will load.
Options are:
-h This message
-b List kernel modules set to load at boot
-a List active kernel modules
-x "kernelmodule" "enable" Set kernel module status (enable/disable)
-z "kernelmodule" "blacklist" Set kernel module blacklist status (blacklist/un-blacklist)
-y Get list of blacklisted kernel modules
EOF
)
module_dir="/lib/modules/5.10.160"
title="Kernel Module Manager"
module_switch() {
if [ $2 = "enable" ]; then
modprobe $1 # Load the selected module
@ -15,77 +28,144 @@ module_switch() {
if ! grep -Fxq "$1" /etc/modules; then # Add the module to /etc/modules if not already present
echo "$1" >> /etc/modules
fi
echo "$1 has been enabled and will be started at boot."
echo -e "\033[4m$1\033[0m has been enabled and will be started at boot.\n\nSome modules are unloaded automatically when not in use."
else
echo -e "Failed to enable \033[4m$1\033[0m."
exit 1
fi
elif [ $2 = "disable" ]; then
rmmod $1 # Disable the module
if [ $? -eq 0 ]; then
sed -i "/^$1$/d" /etc/modules
echo "$1 has been disabled and removed from boot."
else
exit 1
fi
rmmod $1 > /dev/null 2>&1 # Unload the module
sed -i "/^$1$/d" /etc/modules
echo -e "\033[4m$1\033[0m has been disabled and removed from boot.\n\nIt may be automatically loaded if compatible hardware is detected."
else
echo "Invalid argument \"$2\".\n$help"
fi
}
module_blacklist() {
if [ $1 = "list" ]; then
echo -e "$(ls "$module_dir"/*.blacklisted 2>/dev/null | sed -E 's|.*/([^.]*)\..*|\1|' | awk '{for(i=1;i<=NF;i++) {printf "\033[4m%s\033[0m", $i; if(i<NF) printf " ";} printf " ";} END {if (NR == 0) print "\033[4mnone\033[0m"}')"
elif [ $2 = "blacklist" ]; then
mv "$module_dir/$1.ko" "$module_dir/$1.ko.blacklisted" > /dev/null 2>&1
module_switch $1 disable > /dev/null 2>&1 # unload and disable the module
echo -e "$1 is blacklisted. A reboot is sometimes required for blacklisting to fully take effect."
elif [ $2 = "un-blacklist" ]; then
mv "$module_dir/$1.ko.blacklisted" "$module_dir/$1.ko" > /dev/null 2>&1
echo -e "$1 is un-blacklisted. A reboot is sometimes required for un-blacklisting to fully take effect."
else
echo "Invalid argument \"$1 $2\".\n$help"
fi
}
# Parse options
while getopts ":hx" opt; do
while getopts ":hbax:z:y" opt; do
case ${opt} in
h) # Option -l (set lora radio)
echo "$help"
exit 0
;;
b) # kernel modules set to start at boot)
echo -e "$(modules=$(sed -n '6,$p' /etc/modules | awk '{printf "\033[4m%s\033[0m ", $0}'); [ -z "$modules" ] && echo "\033[4mnone\033[0m" || echo "$modules")"
;;
a) # kernel modules currently active)
echo -e "$(modules=$(lsmod | awk 'NR>1 {printf "\033[4m%s\033[0m ", $1}'); [ -z "$modules" ] && echo "none" || echo "$modules")"
;;
x) # Option -x (Set kernel module status (enable/disable))
echo "$(module_switch $2 $3)"
;;
z) # Option -z (Set kernel module blacklist status (blacklist/un-blacklist))
echo "$(module_blacklist $2 $3)"
;;
y) # Option -y (Get list of blacklisted kernel modules)
echo "$(module_blacklist "list")"
;;
esac
done
if [ -n "$1" ]; then # if there are arguments, don't proceed to menu
exit
fi
dialog --infobox "Loading kernel module menu..." 5 45
dialog --no-collapse --colors --title "$title" --yesno "\
Kernel modules are loadable pieces of code that extend a Linux kernel's functionality without requiring a reboot. Common examples include device drivers, file systems, or system calls.\n\
\n\
This tool will allow you to manage kernel modules and add pre-compiled modules to Foxbuntu.\n\
\n\
Boot modules: $(femto-utils.sh -R "$(femto-kernel-modules.sh -b)")\n\
Blacklisted modules: $(femto-utils.sh -R "$(femto-kernel-modules.sh -y)")\n\
Active modules: $(femto-utils.sh -R "$(femto-kernel-modules.sh -a)")\n\
\n\
Continue?
" 0 0
[ ! $? -eq 0 ] && exit 1
modules=()
load_modules() {
dialog --infobox "Loading kernel module menu...\n\nExpected load time: 35 seconds." 6 45
modules=("Module name" "L/D Description" "" "")
# Create a list of modules (filename minus the .ko)
for module in $(ls "/lib/modules/5.10.160"/*.ko); do
module_name=$(basename "$module" .ko)
modules+=("$module_name" "$(modinfo $module_name | grep -i 'description' | cut -d: -f2 | sed 's/^[ \t]*//')")
done
# Create a list of modules (filename minus the .ko)
for module in $(ls $module_dir/*.ko*); do
module_name=$(basename "$module" | sed 's/\([^.]*\).*/\1/')
modules+=("$module_name" "$(lsmod | grep -q "^$module_name " && echo ✅ || echo ❌)$(femto-kernel-modules.sh -b | sed 's/\x1b\[[0-9;]*m//g' | grep -qw "$module_name" && echo ✅ || echo ❌) $(basename "$module" | grep -q "blacklisted" && echo "BLACKLISTED" || modinfo "$module_name" | grep -i 'description' | cut -d: -f2 | sed 's/^[ \t]*//' )")
done
modules_changed="false"
}
load_modules
modules_changed="false"
while true; do
[ $modules_changed = "true" ] && load_modules
# Create the menu options
option=$(dialog --cancel-label "Back" --title "Kernel Modules" --menu "" 42 103 8 "${modules[@]}" 3>&1 1>&2 2>&3)
exit_status=$? # Check the exit status of the dialog command
if [ $exit_status -ne 0 ]; then # Exit the loop if the user selects "Cancel" or closes the dialog
selected_module=$(dialog --no-collapse --cancel-label "Return" --ok-label "Open" --title "$title" --no-shadow --default-item "$selected_module" --help-button --menu "" 42 103 8 "${modules[@]}" 3>&1 1>&2 2>&3)
exit_status=$?
if [ $exit_status -eq 1 ]; then # "Return" button
break
fi
# Get the module name from the selection
selected_module=$option
# Get the full modinfo for the module and process it for dialog
modinfo_output=$(modinfo $selected_module | sed ':a;N;$!ba;s/\n/\\n/g') # add \n to module info
# Check if the module is currently enabled
if lsmod | grep -q "^$selected_module "; then
dialog --colors --title "Disable Module" --yesno "The module '$selected_module' is currently \Z2\Zuenabled\Zn.\n\nDo you want to disable it?\n\nFull module info:\n$modinfo_output\n\nNote: Unused dependencies will be removed automatically." 25 0
if [ $? -eq 0 ]; then
dialog --msgbox "$(module_switch $selected_module disable)" 7 60
fi
elif [ $exit_status -eq 2 ]; then # "Help" button
dialog --no-collapse --colors --title "Kernel Module Manager Help" --msgbox "In the kernel module manager menu,\nL=Module is loaded\nB=Module is set to start at boot.\n\nIf module is blacklisted, \`BLACKLISTED\` will show in the description." 0 0
else
dialog --colors --title "Enable Module" --yesno "The module '$selected_module' is currently \Z1disabled\Zn.\n\nDo you want to enable it?\n\nFull module info:\n$modinfo_output\n\nNote: Dependencies will be loaded automatically." 25 0
if [ $? -eq 0 ]; then
dialog --msgbox "$(module_switch $selected_module enable)" 7 60
fi
[ "$selected_module" = "" ] || [ "$selected_module" = "Module name" ] && continue # do nothing if no valid module name is selected
modules_changed="false"
# Get the full modinfo for the module and process it for dialog
while true; do
modinfo_output=$(modinfo $selected_module 2>/dev/null | sed ':a;N;$!ba;s/\n/\\n/g') # add \n to module info
if [ ! -e "$module_dir/$selected_module.ko" ]; then
module_info="\Z1\ZuMODULE BLACKLISTED!\Zn\n\n$selected_module has been blacklisted and will not load on boot.\
$(lsmod | grep -q "^$selected_module " && echo "\n\n$selected_module is currently \Z4\Zuloaded\Zn!\n\
Some modules require reboot for blacklist to take effect if they're in use when blacklisted.")"
else
module_info="Module is currently $(lsmod | grep -q "^$selected_module " && echo "\Z4loaded\Zn" || echo "\Z1unloaded\Zn") and is set $(femto-utils.sh -R "$(femto-kernel-modules.sh -b | sed 's/\x1b\[[0-9;]*m//g' | grep -qw "$selected_module" && echo "\Z4to load at boot\Zn" || echo "\Z1not to load at boot\Zn. It may load automatically if needed")").\n\
\n\
Full module info:\n$modinfo_output\n\nNote: Dependencies are loaded/unloaded automatically."
fi
dialog --colors --yes-label "Return" --no-label "Disable" --extra-button --extra-label "Enable" --help-button --help-label "Blacklist" --title "$selected_module" --yesno "$module_info" 0 0
exit_status=$? # This line checks the exit status of the dialog command
if [ $exit_status -eq 0 ]; then # "Back" button
break
elif [ $exit_status -eq 3 ]; then # "Enable" button
dialog --colors --title "$selected_module" --msgbox "$(femto-utils.sh -R "$(module_switch $selected_module enable)")" 0 0
modules_changed="true"
elif [ $exit_status -eq 1 ]; then # "Disable" button
dialog --colors --title "$selected_module" --msgbox "$(femto-utils.sh -R "$(module_switch $selected_module disable)")" 0 0
modules_changed="true"
elif [ $exit_status -eq 2 ]; then # "Blacklist" button
dialog --no-collapse --colors --title "$selected_module" --yes-label "Return" --no-label "Un-blacklist" --extra-button --extra-label "Blacklist" --yesno "$selected_module is currently $([ -e "$module_dir/$selected_module.ko" ] && echo "\Z4\Zunot blacklisted\Zn" || echo "\Z1\Zublacklisted\Zn").\n\nBlacklisting prevents a kernel module from loading.\n\nWould you like to blacklist $selected_module?" 0 0
exit_status=$?
if [ $exit_status -eq 0 ]; then
continue
elif [ $exit_status -eq 3 ]; then # blacklist
dialog --colors --title "$selected_module" --msgbox "$(femto-utils.sh -R "$(module_blacklist $selected_module blacklist)")" 8 50
modules_changed="true"
else # blacklist
dialog --colors --title "$selected_module" --msgbox "$(femto-utils.sh -R "$(module_blacklist $selected_module un-blacklist)")" 8 50
modules_changed="true"
fi
fi
done
fi
done
exit 0
exit 0

View file

@ -11,26 +11,30 @@ Options are:
EOF
)
anykey="echo -e \"\nPress any key to continue...\n\" && read -n 1 -s -r"
pause() {
echo -e "\nPress any key to continue..."
read -n 1 -s -r
}
femtofox_short_license="\
Femtofox and Foxbuntu are published under CC BY-NC-ND - noncommercial.\n\
Femtofox is comprised of two projects, with two different licenses:\n\
1. Femtofox - the hardware, which is licensed \"CC BY-NC-ND - noncommercial\". Summary: you may copy and share and modify the hardware files, but cannot sell them without license from Femtofox, and must give attribution to Femtofox.\n\
2. Foxbuntu - refers to the modifications to Ubuntu made as part of the Femtofox project, which is licensed GNU GPLv3. Summary: you may use, modify and distribute (including for commercial purposes) Foxbuntu, but must give attribution to Femtofox and distribute this license with your project. Any modified version must remain open source.\n\
\n\
For more information, visit us at www.femtofox.com.\n\
\n\
Summary:\n\
You can share Femtofox and Foxbuntu or make modifications, but can't sell it except by arrangement (license) with us.\n\
In this context, Foxbuntu refers to the modifications to Ubuntu made as part of the Femtofox project.\n\
\n\
Boilerplate:\n\
Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.\n\
You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.\n\
NonCommercial — You may not use the material for commercial purposes.\n\
NoDerivatives — If you remix, transform, or build upon the material, you may not distribute the modified material (for commercial purposes).\n\
\n\
View the long licenses for more information.\n\
Contact us to license Femtofox."
meshtastic_license="\
Meshtastic is a registered trademark of Meshtastic LLC. Meshtastic software components are released under various licenses, see GitHub for details. No warranty is provided - use at your own risk."
The Meshtastic firmware is licensed GPL3.\n\
\n\
Meshtastic is a registered trademark of Meshtastic LLC. Meshtastic software components are released under various licenses, see GitHub for details. No warranty is provided - use at your own risk.\n\
\n\
Some of the verbiage in the help-texts in the menus is sourced from the Meshtastic website, also licensed GPL3.\n\
\n\
For more information about Meshtastic, visit https://www.meshtastic.org\
"
luckfox_license="Luckfox and Luckfox Pico Mini are property of Luckfox Technology. Femtofox does not represent Luckfox Technology in any way, shape or form. Visit their website at https://www.luckfox.com/."
@ -91,7 +95,7 @@ https://www.femtofox.com\n\
u) # Option -u (Ubuntu licenses)
echo "$ubuntu_license"
;;
\?) # Invalid option
\?) # Invalid option)
echo "Invalid option: -$OPTARG"
echo -e "$help"
exit 1
@ -102,13 +106,13 @@ done
# if no arguments, show all licenses
if [ $# -eq 0 ]; then
echo "$femtofox_short_license"
eval $anykey
pause
echo "$(cat /usr/share/doc/femtofox/long_license)"
eval $anykey
pause
echo "$meshtastic_license"
eval $anykey
pause
echo "$luckfox_license"
eval $anykey
pause
eval "$ubuntu_license"
eval $anykey
pause
fi

View file

@ -8,20 +8,27 @@ help=$(cat <<EOF
Options are:
-h This message
-i Get important node info
-C "all" Get node configuration, by category. Multiple categories can be selected by comma delineation. \`quiet\`: do not echo to console. Options are \`quiet\`, \`all\`, \`nodeinfo\`, \`settings\`, \`channels\`
-g Gets the current configuration URL and QR code
-k Get current LoRa radio selection
-l "RADIO" Choose LoRa radio model. Options are \`lr1121_tcxo\`, \`sx1262_tcxo\`, \`sx1262_xtal\`, \`none\` (simradio)
-q "URL" Set configuration URL
-v View current admin keys
-a "KEY" Set admin key
-u Get current public key
-U "KEY" Set public key
-r Get current private key
-R "KEY" Set private key
-a View current admin keys
-A "KEY" Set admin key
-c Clear admin keys
-p Get legacy admin channel state
-o "true" Set legacy admin channel state (true/false = enabled/disabled), case sensitive
-r Test mesh connectivity by sending "test" to channel 0 and waiting for. Will attempt 3 times
-s Start/restart Meshtasticd Service
-t Stop Meshtasticd Service
-S Get Meshtasticd Service state
-u Upgrade Meshtasticd
-w Test mesh connectivity by sending "test" to channel 0 and waiting for. Will attempt 3 times
-s Start/restart Meshtasticd service
-t Stop Meshtasticd service
-M "enable" Enable/disable Meshtasticd service. Options: "enable" "disable"
-S Get Meshtasticd service state
-I "enable" Manage i2c state. Options: "enable" "disable" "check"
-z Upgrade Meshtasticd
-x Uninstall Meshtasticd
-m Meshtastic update tool. Syntax: \`femto-meshtasticd-config.sh -m \"--set security.admin_channel_enabled false\" 10 \"Disable legacy admin\"\`
Will retry the \`--set security.admin_channel_enabled false\` command until successful or up to 10 times, and tag status reports with \`Disable legacy admin\` via echo and to system log.
@ -38,16 +45,17 @@ meshtastic_update() {
local command="$1"
local attempts=$2
local ref="$3: "
echo "${ref:+$ref}meshtastic --host $command"
echo "Submitting to Meshtastic..."
for retries in $(seq 1 $attempts); do
local output=$(meshtastic --host $command) #>&2 lets meshtastic's output display on screen
echo $output
logger $output
if echo "$output" | grep -qiE "Abort|invalid|Error|refused|Errno"; then
output=$(eval meshtastic --host $command 2>&1 | tee /dev/fd/2) # display the output on screen live. Use eval so quotes will be handled correctly in $command
logger "$output"
if echo "$output" | grep -qiE "Abort|invalid|Error|error|unrecognized|refused|Errno|failed|Failed"; then
if [ "$retries" -lt $attempts ]; then
local msg="${ref:+$ref}Meshtastic command failed, retrying ($(($retries + 1))/$attempts)..."
echo "$msg"
logger "$msg"
femto-meshtasticd-config.sh -s
sleep 2 # Add a small delay before retrying
fi
else
@ -62,6 +70,7 @@ meshtastic_update() {
fi
done
if [ -z "$success" ]; then
echo -e "$output"
msg="${ref:+$ref}Meshtastic command FAILED."
echo "$msg"
logger "$msg"
@ -69,38 +78,146 @@ meshtastic_update() {
fi
}
get_meshtastic_settings() {
for retries in $(seq 1 3); do
if meshtastic_info=$(meshtastic --host --info); then # if successful
success="true"
break
else # if failed
if [ "$retries" -lt 3 ]; then # if under 3 retries
echo "Meshtastic command failed, retrying ($(($retries + 1))/3)..."
femto-meshtasticd-config.sh -s
sleep 2 # Add a small delay before retrying
fi
fi
done
if [ -z "$success" ]; then # if failed all retries
echo "Meshtastic command FAILED."
exit 1 # always exit script if failed
fi
if [[ "$1" == *"all"* ]] || [[ "$1" == *"nodeinfo"* ]]; then
# myInfo
eval "myInfo_owner='$(echo "$meshtastic_info" | grep "^Owner: " | sed 's/^Owner: //')'"
[[ "$1" != *"quiet"* ]] && echo "myInfo_owner:$myInfo_owner"
while IFS="=" read -r varname value; do
eval "myInfo_$varname='$value'" # Create a variable with the formatted name
[[ "$1" != *"quiet"* ]] && echo "myInfo_$varname:$value"
done < <(
echo "$(echo "$meshtastic_info" | grep '^My info: ' | sed 's/^My info: //')" |
jq -r 'to_entries[] | "\(.key)=\(.value)"'
)
# metadata
while IFS="=" read -r varname value; do
eval "metadata_$varname='$value'" # Create a variable with the formatted name
[[ "$1" != *"quiet"* ]] && echo "metadata_$varname:$value"
done < <(
echo "$(echo "$meshtastic_info" | grep '^Metadata: ' | sed 's/^Metadata: //')" |
jq -r 'to_entries[] | "\(.key)=\(.value)"'
)
metadata_nodedbCount=$(echo "$meshtastic_info" | grep -oP '"![a-zA-Z0-9]+":\s*\{' | wc -l)
[[ "$1" != *"quiet"* ]] && echo "metadata_nodedbCount:$metadata_nodedbCount"
# nodeinfo
while IFS='=' read -r var value; do
eval "nodeinfo_$var=\"$value\""
[[ "$1" != *"quiet"* ]] && echo "nodeinfo_$var:$value"
done < <(echo "$(echo "$meshtastic_info" | sed -n '/Nodes in mesh:/,$p' | sed '1s/^Nodes in mesh: *//' | sed '/^[[:space:]]*$/q' | jq -r 'to_entries | .[0] | "\(.key)=\(.value)"' | sed 's/^[^=]*=//;s/^[ \t]*}//')" | jq -r '
def recurse:
if type == "object" then
to_entries | .[] | "\(.key)=\(.value | recurse)"
elif type == "array" then
. | tostring
else
.
end;
recurse' | sed '/=/ {s/\(.*\)=\(.*\)=/\1_\2=/; }'
)
fi
if [[ "$1" == *"all"* ]] || [[ "$1" == *"settings"* ]]; then
# settings
while IFS="=" read -r varname value; do
eval "$varname='$value'"
[[ "$1" != *"quiet"* ]] && echo "$varname:$value"
done < <(
echo "$(echo "$meshtastic_info" | sed -n '/Preferences: {/,$p' | sed '1s/.*/{/; /^[[:space:]]*$/q')" |
jq -r 'to_entries[] | select(.value | type == "object") | .key as $block | .value | to_entries[] | "\($block)_\(.key)=\(.value)"'
)
# module settings
while IFS="=" read -r varname value; do
eval "$varname='$value'"
[[ "$1" != *"quiet"* ]] && echo "$varname:$value"
done < <(
echo "$(echo "$meshtastic_info" | sed -n '/Module preferences: {/,$p' | sed '1s/.*/{/; /^[[:space:]]*$/q')" |
jq -r 'to_entries[] | select(.value | type == "object") | .key as $block | .value | to_entries[] | "\($block)_\(.key)=\(.value)"'
)
fi
if [[ "$1" == *"all"* ]] || [[ "$1" == *"channels"* ]]; then
# channels
while read index line; do
channel_type=$(echo "$line" | awk '{print $3}')
psk_type=$(echo "$line" | grep -o 'psk=[^ ]*' | cut -d= -f2)
eval "channel${index}_type='$channel_type'"
[[ "$1" != *"quiet"* ]] && echo "channel${index}_type:$channel_type"
eval "channel${index}_psk_type='$psk_type'"
[[ "$1" != *"quiet"* ]] && echo "channel${index}_psk_type:$psk_type"
# get the json portion of the channel listing
while IFS=":" read -r key value; do
eval "$key='$value'"
[[ "$1" != *"quiet"* ]] && echo "$key:$value"
done < <(
echo "$(echo "$line" | sed 's/.*\({.*\)/\1/')" | jq -r 'to_entries | .[] | "channel'${index}'_\(.key):\(.value)"'
)
done < <(
echo "$meshtastic_info" | awk '/Channels:/ {f=1; next} f && NF {print} f && !NF {exit}' | nl -v 0
)
eval "url_primary_channel='$(echo "$meshtastic_info" | sed -n 's/^Primary channel URL: //p')'"
[[ "$1" != *"quiet"* ]] && echo "url_primary_channel:$url_primary_channel"
if echo "$meshtastic_info" | grep -q "^Complete URL (includes all channels): "; then
url_all_channels=$(echo "$meshtastic_info" | sed -n 's/^Complete URL (includes all channels): //p')
[[ "$1" != *"quiet"* ]] && echo "url_all_channels:$url_all_channels"
fi
fi
}
# Parse options
while getopts ":higkl:q:va:cpo:sStruxm" opt; do
while getopts ":hiC:gkl:q:uU:rR:aA:cpo:sM:StI:wuzxm" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
i) # Option -i (Get important node info)
output=$(meshtastic --host --info)
preset_or_settings="Use preset? $(echo "$output" | grep -oP '"usePreset":\s*\K\w+')\n"
if echo "$output" | grep -qP '"usePreset":\s*true'; then
preset_or_settings+="Preset: $(echo "$output" | grep -oP '"modemPreset":\s*"\K[^"]+')"
else
preset_or_settings+="\
Bandwidth: $(echo "$output" | grep -oP '"bandwidth":\s*\K\w+')\n\
Spread factor: $(echo "$output" | grep -oP '"spreadFactor":\s*\K\w+')\n\
Coding rate: $(echo "$output" | grep -oP '"codingRate":\s*\K\w+')"
fi
get_meshtastic_settings quiet,nodeinfo,settings
echo -e "\
Version: $(echo "$output" | grep -oP '"firmwareVersion":\s*"\K[^"]+' | head -n 1)\n\
Node name: $(echo "$output" | grep -oP 'Owner:\s*\K.*' | head -n 1)\n\
NodeID: !$(printf "%08x\n" $(echo "$output" | grep -oP '"myNodeNum":\s*\K\d+' | head -n 1)) (nodenum: $(echo "$output" | grep -oP '"myNodeNum":\s*\K\d+' | head -n 1))\n\
TX enabled? $(txEnabled=$(echo "$output" | grep -oP '"txEnabled":\s*\K\w+'); [[ "$txEnabled" == "true" ]] && echo "\033[0;34menabled\033[0m" || echo "\033[0;31mdisabled\033[0m")\n\
Role: $(echo "$output" | grep -oP '"role":\s*"\K[^"]+' | head -n 1)\n\
$preset_or_settings\n\
Frequency offset: $(echo "$output" | grep -oP '"bandwidth":\s*\K\w+')
Region: $(echo "$output" | grep -oP '"region":\s*"\K[^"]+')\n\
Hop limit: $(echo "$output" | grep -oP '"hopLimit":\s*\K\w+')\n\
$(channelNum=$(echo "$output" | grep -oP '"channelNum":\s*\K\d+' | head -n 1); [[ -n "$channelNum" && "$channelNum" -gt 0 ]] && echo -e "Frequency slot: $channelNum\n")\
$(overrideFrequency=$(echo "$output" | grep -oP '"overrideFrequency":\s*\K[0-9.]+'); [[ -n "$overrideFrequency" && $(echo "$overrideFrequency > 0" | bc) -eq 1 ]] && echo "Override freq: $overrideFrequency\n")\
Public key: $(echo "$output" | grep -oP '"publicKey":\s*"\K[^"]+' | head -n 1)\n\
Nodes in nodedb: $(echo "$output" | grep -oP '"![a-zA-Z0-9]+":\s*\{' | wc -l)\
"
Service:$(femto-meshtasticd-config.sh -S)
Version:$metadata_firmwareVersion
Node name:$myInfo_owner
NodeID:$nodeinfo_user_id
Nodenum:$myInfo_myNodeNum
TX enabled:$lora_txEnabled
Use preset:$lora_usePreset
Preset:$lora_modemPreset
Bandwidth:$lora_bandwidth
Spread factor:$lora_spreadFactor
Coding rate:$lora_codingRate
Role:$device_role
Freq offset:$lora_frequencyOffset
Region:$lora_region
Hop limit:$lora_hopLimit
Freq slot:$lora_channelNum
Override freq:$lora_overrideFrequency
Public key:$security_publicKey
Nodes in db:$metadata_nodedbCount"
;;
C) # Option -C (Complete node config)
get_meshtastic_settings $OPTARG
;;
g) # Option -g (get config URL)
url=$(meshtastic --host --qr-all | grep -oP '(?<=Complete URL \(includes all channels\): )https://[^ ]+') #add look for errors
@ -110,7 +227,7 @@ Nodes in nodedb: $(echo "$output" | grep -oP '"![a-zA-Z0-9]+":\s*\{' | wc -l)\
echo $url
;;
k) # Option -k (get current lora radio model)
ls /etc/meshtasticd/config.d 2>/dev/null | xargs -r -n 1 basename | sed 's/^femtofox_//;s/\.yaml$//' | grep . || echo -e "\033[0;31mnone (simulated radio)\033[0m"
ls /etc/meshtasticd/config.d 2>/dev/null | grep '^femtofox_' | xargs -r -n 1 basename | sed 's/^femtofox_//;s/\.yaml$//' | grep . || echo -e "\033[0;31mnone (simulated radio)\033[0m"
;;
l) # Option -l (choose lora radio model)
prepare="rm -f /etc/meshtasticd/config.d/femtofox* && echo \"Radio type $OPTARG selected.\""
@ -126,34 +243,57 @@ Nodes in nodedb: $(echo "$output" | grep -oP '"![a-zA-Z0-9]+":\s*\{' | wc -l)\
eval $prepare
cp /etc/meshtasticd/available.d/femtofox/femtofox_SX1262_XTAL.yaml /etc/meshtasticd/config.d
systemctl restart meshtasticd
elif [ "$OPTARG" = "lora-meshstick-1262" ]; then
eval $prepare
cp /etc/meshtasticd/available.d/lora-meshstick-1262.yaml /etc/meshtasticd/config.d/femtofox_lora-meshstick-1262.yaml # ugly code for the special case of the meshstick, which is not femto. Allows it to be detected by femto scripts and removed if radio changes
systemctl restart meshtasticd
elif [ "$OPTARG" = "none" ]; then
eval $prepare
systemctl restart meshtasticd
else
echo "$OPTARG is not a valid option. Options are \`lr1121_tcxo\`, \`sx1262_tcxo\`, \`sx1262_xtal\`, \`none\` (simradio)"
echo "$OPTARG is not a valid option. Options are \`lr1121_tcxo\`, \`sx1262_tcxo\`, \`sx1262_xtal\`, \`lora-meshstick-1262\`, \`none\` (simradio)"
fi
;;
q) # Option -q (set config URL)
meshtastic_update "--seturl $OPTARG" 10 "Set URL"
meshtastic_update "--seturl $OPTARG" 3 "Set URL"
;;
v) # Option -v (view admin keys)
u) # Option -u (get public key)
meshtastic_update " --get security.public_key" 3 "Get public key" | sed -n 's/.*base64:\([A-Za-z0-9+/=]*\).*/\1/p'
;;
U) # Option -U (set public key)
meshtastic_update " --set security.public_key base64:$OPTARG" 3 "Set public key"
;;
r) # Option -r (get private key)
meshtastic_update " --get security.private_key" 3 "Get private key" | sed -n 's/.*base64:\([A-Za-z0-9+/=]*\).*/\1/p'
;;
R) # Option -R (set private key)
meshtastic_update " --set security.private_key base64:$OPTARG" 3 "Set private key"
;;
a) # Option -a (view admin keys)
echo "Getting admin keys..."
keys=$(meshtastic --host --get security.admin_key | grep -oP '(?<=base64:)[^,"]+' | sed "s/'//g" | sed "s/]//g" | nl -w1 -s'. ' | sed 's/^/|n/' | tr '\n' ' ') #add look for errors
echo "${keys:-none}"
echo "${keys:- none}"
;;
a) # Option -a (add admin key)
meshtastic_update "--set security.admin_key base64:$OPTARG" 10 "Set admin key"
A) # Option -A (add admin key)
meshtastic_update "--set security.admin_key base64:$OPTARG" 3 "Set admin key"
;;
c) # Option -c (clear admin key list)
meshtastic_update "--set security.admin_key 0" 10 "Set admin key"
meshtastic_update "--set security.admin_key 0" 3 "Clear admin keys"
;;
p) # Option -p (view current legacy admin state)
meshtastic_update "--get security.admin_channel_enabled" 3 "Get legacy admin state"
state=$(meshtastic_update "--get security.admin_channel_enabled" 3 "Get legacy admin state" 2>/dev/null)
if echo "$state" | grep -q "True"; then
echo -e "\033[0;34menabled\033[0m"
elif echo "$state" | grep -q "False"; then
echo -e "\033[0;31mdisabled\033[0m"
elif echo "$state" | grep -q "Error"; then
echo -e "\033[0;31merror\033[0m"
fi
;;
o) # Option -o (set legacy admin true/false)
meshtastic_update "--set security.admin_channel_enabled $OPTARG" 10 "Set legacy admin state"
meshtastic_update "--set security.admin_channel_enabled $OPTARG" 3 "Set legacy admin state"
;;
r) # Option -r (mesh connectivity test)
w) # Option -w (mesh connectivity test)
for ((i=0; i<=2; i++)); do
if meshtastic --host --ch-index 0 --sendtext "test" --ack 2>/dev/null | grep -q "ACK"; then
echo -e "Received acknowledgement...\n\n\033[0;34mMesh connectivity confirmed!\033[0m"
@ -168,20 +308,46 @@ Nodes in nodedb: $(echo "$output" | grep -oP '"![a-zA-Z0-9]+":\s*\{' | wc -l)\
systemctl restart meshtasticd
echo "Meshtasticd service started/restarted."
;;
S) # Option -S (Get Meshtasticd Service state)
if echo "$(systemctl status meshtasticd)" | grep -q "active (running)"; then
echo -e "\033[4m\033[0;34mrunning\033[0m"
elif echo "$(systemctl status meshtasticd)" | grep -q "inactive (dead)"; then
echo -e "\033[4m\033[0;31mnot running\033[0m"
M) # Option -M (Meshtasticd Service disable/enable)
if [ "$OPTARG" = "enable" ]; then
systemctl enable meshtasticd
systemctl restart meshtasticd
elif [ "$OPTARG" = "disable" ]; then
systemctl disable meshtasticd
systemctl stop meshtasticd
else
echo "unknown"
echo "-M argument requires either \"enable\" or \"disable\""
echo -e "$help"
fi
;;
S) # Option -S (Get Meshtasticd Service state)
femto-utils.sh -C "meshtasticd" # this functionality has been moved
;;
t) # Option -t (stop Meshtasticd service)
systemctl stop meshtasticd
echo "Meshtasticd service stopped."
;;
u) # Option -u (upgrade meshtasticd)
I) # Option -I (Manage i2c state. Options: "enable" "disable" "check")
yaml_file="/etc/meshtasticd/config.d/femto_config.yaml"
if [ "$OPTARG" = "enable" ]; then
echo -e "\nI2C:\n I2CDevice: /dev/i2c-3" >> $yaml_file
femto-meshtasticd-config.sh -s
elif [ "$OPTARG" = "disable" ]; then
sed -i '/I2C:/,/I2CDevice: \/dev\/i2c-3/d' $yaml_file
femto-meshtasticd-config.sh -s
elif [ "$OPTARG" = "check" ]; then
if grep -q "I2C:" $yaml_file && grep -q "I2CDevice: /dev/i2c-3" $yaml_file; then
echo -e "\033[0;34menabled\033[0m"
else
echo -e "\033[0;31mdisabled\033[0m"
fi
else
echo "Invalid argument \`-I $OPTARG\`. Options are \`enable\` \`disable\` \`check\`."
echo -e "$help"
exit 1
fi
;;
z) # Option -z (upgrade meshtasticd)
apt update
apt install --only-upgrade meshtasticd
;;

View file

@ -0,0 +1,501 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo femto-meshtasticd-config\`."
exit 1
fi
export NCURSES_NO_UTF8_ACS=1
export TERM=xterm-256color
export LANG=C.UTF-8
title="Meshtastic LoRa Settings"
args=$@
send_settings() {
if [ -n "$command" ]; then
set -o pipefail
echo "meshtastic --host $command"
output=$(eval "femto-meshtasticd-config.sh -m '$command' 5 'Save Meshtastic settings'" | tee /dev/tty)
exit_status=$?
set +o pipefail
if [ $exit_status -eq 1 ]; then
dialog --no-collapse --colors --title "$title" --msgbox "$(echo -e "\Z1Command FAILED!\Zn\n\nLog:\n$output")" 0 0
elif [ $exit_status -eq 0 ]; then
dialog --no-collapse --colors --title "$title" --msgbox "$(echo -e "\Z4Command Successful!\Zn\n\nLog:\n$output")" 0 0
fi
fi
[ "$1" = "wizard" ] && [ -z "$args" ] && dialog --no-collapse --title "$title" --colors --msgbox "Meshtastic LoRa Settings Wizard complete!" 6 50 # if in wizard mode AND there are no script arguments, display the message
}
config_url() {
femto-config -c && (
newurl=$(dialog --no-collapse --colors --title "Meshtastic URL" --inputbox "The Meshtastic configuration URL allows for automatic configuration of all Meshtastic LoRa settings and channels.\nEntering a URL may \Z1\ZuOVERWRITE\Zn your LoRa settings and channels!\n\nNew Meshtastic LoRa configuration URL (SHIFT+INS to paste):" 13 63 3>&1 1>&2 2>&3)
if [ -n "$newurl" ]; then #if a URL was entered
command+="--seturl $newurl "
fi
# if we're in wizard mode AND there are no script arguments, then display a message
send_settings $1
)
}
lora_settings_actions() {
if [ "$1" = "set_lora_radio_model" ] || [ "$1" = "wizard" ]; then
choice="" # zero the choice before loading the submenu
while true; do
echo "Checking LoRa radio..."
#Display filename, if exists: $(files=$(ls /etc/meshtasticd/config.d/* 2>/dev/null) && [ -n "$files" ] && echo "\n\nConfiguration files in use:\n$files" | paste -sd, -))
choice=$(dialog --no-collapse --colors --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "$choice" --title "Meshtastic LoRa radio" --item-help --menu "Currently configured LoRa radio:\n$(femto-utils.sh -R "$(femto-meshtasticd-config.sh -k)")$(ls -1 /etc/meshtasticd/config.d 2>/dev/null | grep -v '^femto_' | paste -sd ', ' - | sed 's/^/ (/; s/$/)/; s/,/, /g' | grep -v '^ ()$')" 22 50 10 \
"Radio name:" "Configuration:" "" \
"" "" "" \
"Ebyte e22-900m30s" "(SX1262_TCXO)" "Included in Femtofox Pro" \
"Ebyte e22-900m22s" "(SX1262_TCXO)" "" \
"Ebyte e80-900m22s" "(SX1262_XTAL)" "" \
"Heltec ht-ra62" "(SX1262_TCXO)" "" \
"Seeed wio-sx1262" "(SX1262_TCXO)" "" \
"Waveshare sx126x-xxxm" "(SX1262_XTAL)" "Not recommended due issues with sending longer messages" \
"AI Thinker ra-01sh" "(SX1262_XTAL)" "" \
"LoRa Meshstick 1262" "(meshstick-1262)" "USB based LoRa radio from Mark Birss. https://github.com/markbirss/MESHSTICK" \
"Simulated radio" "(none)" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
local radio=""
case $choice in
"Ebyte e22-900m30s")
radio="sx1262_tcxo"
;;
"Ebyte e22-900m22s")
radio="sx1262_tcxo"
;;
"Ebyte e80-900m22s")
radio="sx1262_xtal"
;;
"Heltec ht-ra62")
radio="sx1262_tcxo"
;;
"Seeed wio-sx1262")
radio="sx1262_tcxo"
;;
"Waveshare sx126x-xxxm")
radio="sx1262_xtal"
;;
"AI Thinker ra-01sh")
radio="femto_sx1262_xtal"
;;
"LoRa Meshstick 1262")
radio="lora-meshstick-1262"
;;
"Simulated radio")
radio="none"
;;
"Skip")
return
;;
esac
if [ -n "$radio" ]; then #if a radio was selected
femto-meshtasticd-config.sh -l "$radio" -s # set the radio, then restart meshtasticd
dialog --no-collapse --colors --title "$title" --msgbox "$(echo -e "Radio \Zu$choice\Zn selected.\nMeshtasticd service restarted.\Zn")" 7 45
break
fi
done
[ "$1" = "set_lora_radio_model" ] && return
fi
if femto-config -c; then
if [ "$1" = "wizard" ]; then
choice="" # zero the choice before loading the submenu
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "Cancel" --default-item "True" --item-help --menu "Meshtastic configuration method" 8 50 0 \
"Automatic configuration with URL" "" "" \
"Manual configuration" "" "" \
" " "" "" \
"Cancel" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] && return # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
[ "$choice" == "Manual configuration" ] && break
[ "$choice" == "Automatic configuration with URL" ] && config_url "$1"
return
done
fi
dialog --no-collapse --infobox "Getting current settings from Meshtasticd.\n\nThis can take a minute..." 6 50
while IFS=':' read -r key value; do
eval "${key}=\"${value}\"" # Create a variable with the key name and assign it the value
done < <(sudo femto-meshtasticd-config.sh -C settings)
if [ "$1" = "region" ] || [ "$1" = "wizard" ]; then
options=("UNSET" "US" "EU_433" "EU_868" "CN" "JP" "ANZ" "KR" "TW" "RU" "IN" "NZ_865" "TH" "LORA_24" "UA_433" "UA_868" "MY_433" "MY_919" "SG_923")
menu_items=()
# Create menu options from the array
for i in "${!options[@]}"; do
if [ $i -eq 0 ]; then
menu_items+=("${options[$i]}" "(default)" "") # First item with "(default)"
else
menu_items+=("${options[$i]}" "" "") # Other items without "(default)"
fi
done
menu_items+=("" "" "" "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "")
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "$lora_region" --item-help --menu "Sets the region for your node. As long as this is not set, the node will display a message and not transmit any packets.\n\nRegion? (current: ${lora_region})" 0 0 0 \
"${menu_items[@]}" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue # Restart loop if no choice made
command+="--set lora.region $choice "
break
done
fi
if [ "$1" = "use_modem_preset" ] || [ "$1" = "wizard" ]; then
choice="" # zero the choice before loading the submenu
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "${lora_usePreset^}" --item-help --menu "Presets are pre-defined modem settings (Bandwidth, Spread Factor, and Coding Rate) which influence both message speed and range. The vast majority of users use a preset.\n\nUse modem preset? (current: ${lora_usePreset:-unknown})" 0 0 0 \
"True" "(default)" "" \
"False" "" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
using_preset=$choice
command+="--set lora.use_preset $(echo "$choice" | tr '[:upper:]' '[:lower:]') "
break
done
fi
if [ "$1" = "wizard" ] && [ "$using_preset" = "False" ]; then
dialog --no-collapse --title "$title" --colors --msgbox "Not using preset, so skipping Preset setting." 6 50
else
if [ "$1" = "preset" ] || [ "$1" = "wizard" ]; then
options=("LONG_FAST" "LONG_SLOW" "VERY_LONG_SLOW" "MEDIUM_SLOW" "MEDIUM_FAST" "SHORT_SLOW" "SHORT_FAST" "SHORT_TURBO")
menu_items=()
# Create menu options from the array
for i in "${!options[@]}"; do
if [ $i -eq 0 ]; then
menu_items+=("${options[$i]}" "(default)" "") # First item with "(default)"
else
menu_items+=("${options[$i]}" "" "") # Other items without "(default)"
fi
done
menu_items+=("" "" "" "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "")
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "${lora_modemPreset^}" --item-help --menu "The default preset will provide a strong mixture of speed and range, for most users.\n\nPreset? (current: ${lora_modemPreset:-unknown})" 0 0 0 \
"${menu_items[@]}" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue # Restart loop if no choice made
command+="--set lora.modem_preset $choice "
break
done
fi
fi
if [ "$1" = "wizard" ] && [ "$using_preset" = "True" ]; then
dialog --no-collapse --title "$title" --colors --msgbox "Using preset, so skipping Bandwidth, Spread Factor and Coding Rate settings." 7 50
else
if [ "$1" = "bandwidth" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --item-help --default-item $lora_bandwidth --menu "Width of the frequency \"band\" used around the calculated center frequency. Only used if modem preset is disabled.\n\nBandwidth? (current: ${lora_bandwidth:-unknown})" 0 0 0 \
0 "(default, automatic)" "" \
31 "" "" \
62 "" "" \
125 "" "" \
250 "" "" \
500 "" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue # Restart loop if no choice made
command+="--set lora.bandwidth $choice "
break
done
fi
if [ "$1" = "spread_factor" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --item-help --default-item $lora_spreadFactor --menu "Indicates the number of chirps per symbol. Only used if modem preset is disabled.\n\nSpread factor? (current: ${lora_spreadFactor:-unknown})" 0 0 0 \
0 "(default, automatic)" "" \
7 "" "" \
8 "" "" \
9 "" "" \
10 "" "" \
11 "" "" \
12 "" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue # Restart loop if no choice made
command+="--set lora.spread_factor $choice "
break
done
fi
if [ "$1" = "coding_rate" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --item-help --default-item $lora_codingRate --menu "The proportion of each LoRa transmission that contains actual data - the rest is used for error correction.\n\nCoding rate (only used if modem preset is disabled)? (current: ${lora_codingRate:-unknown})" 0 0 0 \
0 "(default, automatic)" "" \
5 "" "" \
6 "" "" \
7 "" "" \
8 "" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue # Restart loop if no choice made
command+="--set lora.coding_rate $choice "
break
done
fi
fi
if [ "$1" = "frequency_offset" ] || [ "$1" = "wizard" ]; then
while true; do
input=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --inputbox "This parameter is for advanced users with advanced test equipment.\n\nFrequency offset (default: 0)" 0 0 ${lora_frequencyOffset:-unknown} 3>&1 1>&2 2>&3)
[[ -z $input || ($input =~ ^([0-9]{1,6})(\.[0-9]+)?$ && $(echo "$input <= 1000000" | bc -l) -eq 1) ]] && break # exit loop if user input a number between 0 and 1000000. Decimals allowed
dialog --no-collapse --title "$title" --msgbox "Must be between 0-1000000. Decimals allowed." 6 50
done
if [ $? -ne 1 ] && [ -n "$input" ]; then
command+="--set lora.frequency_offset $input "
fi
fi
if [ "$1" = "hop_limit" ] || [ "$1" = "wizard" ]; then
while true; do
input=$(dialog --no-collapse --colors --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --inputbox "The maximum number of intermediate nodes between Femtofox and a node it is sending to. Does not impact received messages.\n\n\Z1WARNING:\Zn Excessive hop limit increases congestion!\n\nHop limit. Must be 0-7 (default: 3)" 0 0 ${lora_hopLimit:-unknown} 3>&1 1>&2 2>&3)
[[ -z $input || ($input =~ ^[0-7]$) ]] && break # exit loop if user input an integer between 0 and 7
dialog --no-collapse --title "$title" --msgbox "Must be an integer between 0 and 7." 6 50
done
if [ $? -ne 1 ] && [ -n "$input" ]; then
command+="--set lora.hop_limit $input "
fi
fi
if [ "$1" = "tx_enabled" ] || [ "$1" = "wizard" ]; then
choice="" # zero the choice before loading the submenu
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "${lora_txEnabled^}" --item-help --menu "Enables/disables the radio chip. Useful for hot-swapping antennas.\n\nEnable TX? (current: ${lora_txEnabled:-unknown})" 0 0 0 \
"True" "(default)" "" \
"False" "" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
command+="--set lora.tx_enabled $(echo "$choice" | tr '[:upper:]' '[:lower:]') "
break
done
fi
if [ "$1" = "tx_power" ] || [ "$1" = "wizard" ]; then
while true; do
input=$(dialog --no-collapse --colors --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --inputbox "\
\Z1\ZuWARNING!\Zn\n\
Setting a 33db radio above 8db will \Zupermanently\Zn damage it.\n\
ERP above 27db violates EU law.\n\
ERP above 36db violates US (unlicensed) law.\n\
\n\
If 0, will use the maximum continuous power legal in your region.
\n\
\n\
TX power in dBm. Must be 0-30 (0 for automatic)" 0 0 ${lora_txPower:-unknown} 3>&1 1>&2 2>&3)
[[ -z $input || $input =~ ^([12]?[0-9]|30)$ ]] && break # exit loop if user input an integer between 0 and 30
dialog --no-collapse --title "$title" --msgbox "Must be an integer between 0 and 30." 6 50
done
if [ $? -ne 1 ] && [ -n "$input" ]; then
command+="--set lora.tx_power $input "
fi
fi
if [ "$1" = "frequency_slot" ] || [ "$1" = "wizard" ]; then
while true; do
input=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --inputbox "Determines the exact frequency the radio transmits and receives. If unset or set to 0, determined automatically by the primary channel name.\n\nFrequency slot (0 for automatic)" 0 0 ${lora_channelNum:-unknown} 3>&1 1>&2 2>&3)
[[ -z $input || ($input =~ ^[0-9]+$) ]] && break # exit loop if user input an integer 0 or higher
dialog --no-collapse --title "$title" --msgbox "Must be an integer 0 or higher." 6 50
done
if [ $? -ne 1 ] && [ -n "$input" ]; then
command+="--set lora.channel_num $input "
fi
fi
if [ "$1" = "override_duty_cycle" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "$(echo "${lora_overrideDutyCycle:-False}" | sed 's/^./\U&/')" --item-help --menu "May have legal ramifications.\n\nOverride duty cycle? (current: ${lora_overrideDutyCycle:-unknown})" 0 0 0 \
"True" "" "" \
"False" "(default)" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
command+="--set lora.override_duty_cycle $(echo "$choice" | tr '[:upper:]' '[:lower:]') "
break
done
fi
if [ "$1" = "sx126x_rx_boosted_gain" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "$(echo "${lora_sx126xRxBoostedGain:-True}" | sed 's/^./\U&/')" --item-help --menu "This is an option specific to the SX126x chip series which allows the chip to consume a small amount of additional power to increase RX (receive) sensitivity.\n\nEnable SX126X RX boosted gain? (current: ${lora_sx126xRxBoostedGain:-unknown})" 0 0 0 \
"True" "(default)" "" \
"False" "" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
command+="--set lora.sx126x_rx_boosted_gain $(echo "$choice" | tr '[:upper:]' '[:lower:]') "
break
done
fi
if [ "$1" = "override_frequency" ] || [ "$1" = "wizard" ]; then
while true; do
input=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --inputbox "Overrides frequency slot. May have legal ramifications.\n\nOverride frequency in MHz (0 for none)." 0 0 ${lora_overrideFrequency:-unknown} 3>&1 1>&2 2>&3)
[[ -z $input || ($input =~ ^[0-9]+(\.[0-9]+)?$) ]] && break # exit loop if user input a number 0 or higher (decimals allowed)
dialog --no-collapse --title "$title" --msgbox "Must be a number 0 or higher. Decimals allowed." 6 53
done
if [ $? -ne 1 ] && [ -n "$input" ]; then
command+="--set lora.override_frequency $input "
fi
fi
if [ "$1" = "ignore_mqtt" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "$(echo "${lora_ignoreMqtt:-unknown}" | sed 's/^./\U&/')" --item-help --menu "Ignores any messages it receives via LoRa that came via MQTT somewhere along the path towards the device.\n\nIgnore MQTT? (current: ${lora_ignoreMqtt:-unknown})" 0 0 0 \
"True" "" "" \
"False" "(default)" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
command+="--set lora.ignore_mqtt $(echo "$choice" | tr '[:upper:]' '[:lower:]') "
break
done
fi
if [ "$1" = "ok_to_mqtt" ] || [ "$1" = "wizard" ]; then
while true; do
choice=$(dialog --no-collapse --title "$title" --cancel-label "$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" --default-item "$(echo "${lora_configOkToMqtt:-unknown}" | sed 's/^./\U&/')" --item-help --menu "Indicates that the user approves their packets to be uplinked to MQTT brokers.\n\nOK to MQTT? (current: ${lora_configOkToMqtt:-unknown})" 0 0 0 \
"True" "" "" \
"False" "(default)" "" \
" " "" "" \
"$([[ "$1" == "wizard" ]] && echo "Skip" || echo "Cancel")" "" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] || [ "$choice" == "Cancel" ] || [ "$choice" == "Skip" ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
[ "$choice" == "" ] && continue #restart loop if no choice made
command+="--set lora.config_ok_to_mqtt $(echo "$choice" | tr '[:upper:]' '[:lower:]') "
break
done
fi
send_settings $1
fi
}
# Parse options
help="If script is run without arguments, menu will load.\n\
Options are:\n\
-h This message\n\
-w Wizard mode (skips main menu)\
"
while getopts ":hw" opt; do
case ${opt} in
h) # Option -h (help)
echo -e $help
;;
w) # Option -w (Wizard mode)
lora_settings_actions "wizard"
;;
\?) # Unknown option)
echo -e "Unknown argument $1.\n$help"
;;
esac
done
[ -n "$1" ] && exit # if there were arguments, exit before loading the menu
command="" # initialize command
LoRa_menu_choice="" # zero the choice before loading the submenu
while true; do
command="" # initialize command
LoRa_menu_choice=$(dialog --no-collapse --title "Meshtastic LoRa Settings" --default-item "$LoRa_menu_choice" --cancel-label "Back" --item-help --menu "Select a LoRa setting or run the wizard" 30 50 20 \
1 "Wizard (set all)" "" \
2 "Set LoRa radio model" "" \
3 "Configure automatically with URL" "" \
4 "Region" "" \
5 "Use modem preset" "" \
6 "Preset" "" \
7 "Bandwidth" "" \
8 "Spread factor" "" \
9 "Coding rate" "" \
10 "Frequency offset" "" \
11 "Hop limit" "" \
12 "Enable/disable TX" "" \
13 "TX power" "" \
14 "Frequency slot" "" \
15 "Override duty cycle" "" \
16 "SX126X RX boosted gain " "" \
17 "Override frequency" "" \
18 "Ignore MQTT" "" \
19 "OK to MQTT" "" \
" " "" "" \
20 "Back to Meshtastic Menu" "" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
case $LoRa_menu_choice in
1) # Wizard (set all)
lora_settings_actions "wizard"
;;
2) # Set LoRa radio model)
lora_settings_actions "set_lora_radio_model"
;;
3) # Configure automatically with URL)
config_url
;;
4) # Region)
lora_settings_actions "region"
;;
5) # Use modem preset)
lora_settings_actions "use_modem_preset"
;;
6) # Preset)
lora_settings_actions "preset"
;;
7) # Bandwidth)
lora_settings_actions "bandwidth"
;;
8) # Spread factor)
lora_settings_actions "spread_factor"
;;
9) # Coding rate)
lora_settings_actions "coding_rate"
;;
10) # Frequency offset)
lora_settings_actions "frequency_offset"
;;
11) # Hop limit)
lora_settings_actions "hop_limit"
;;
12) # Enable/disable TX)
lora_settings_actions "tx_enabled"
;;
13) # TX power)
lora_settings_actions "tx_power"
;;
14) # Frequency slot)
lora_settings_actions "frequency_slot"
;;
15) # Override duty cycle)
lora_settings_actions "override_duty_cycle"
;;
16) # SX126X RX boosted gain)
lora_settings_actions "sx126x_rx_boosted_gain"
;;
17) # Override frequency)
lora_settings_actions "override_frequency"
;;
18) # Ignore MQTT)
lora_settings_actions "ignore_mqtt"
;;
19) # OK to MQTT)
lora_settings_actions "ok_to_mqtt"
;;
20) break ;;
esac
done

View file

@ -15,6 +15,7 @@ Options are:
-c "COUNTRY" Set Wi-Fi 2-letter country code (such as US, DE)
-r Restart Wi-Fi
-e Get ethernet settings
-i Get IPv4 addresses
-w Get Wi-Fi settings
-n "HOSTNAME" Change hostname
-t Test internet connection
@ -37,7 +38,7 @@ if [ $# -eq 0 ]; then
fi
# Parse options
while getopts ":hx:Ts:p:c:ewn:tr" opt; do
while getopts ":hx:Ts:p:c:eiwn:tr" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
@ -54,10 +55,10 @@ while getopts ":hx:Ts:p:c:ewn:tr" opt; do
T) # Option -T (toggle wifi state)
if [ "$(cat /etc/wifi_state.txt)" == "up" ]; then
logger "Toggling wifi off"
femto-network-config.sh -x "up"
femto-network-config.sh -x "down"
else
logger "Toggling wifi on"
femto-network-config.sh -x "down"
femto-network-config.sh -x "up"
fi
;;
s) # Option -s (ssid)
@ -77,42 +78,52 @@ while getopts ":hx:Ts:p:c:ewn:tr" opt; do
;;
e) # Option -e (ethernet settings)
status=$(ip link show eth0 | grep -o 'state [A-Za-z]*' | awk '{print $2}')
echo -e "Ethernet status: $([ "$status" == "UP" ] && echo -e "\033[4m\033[0;34mconnected\033[0m" || echo -e "\033[0;31mdisconnected\033[0m")"
echo -e "\
Eth status:$([ "$status" == "UP" ] && echo -e "\033[4m\033[0;34mconnected\033[0m" || echo -e "\033[0;31mdisconnected\033[0m")"
if [ "$status" == "UP" ]; then
echo "IPv4 Address: $(ifconfig eth0 | grep 'inet ' | awk '{print $2}')\n\
IPv6 Address: $(ifconfig eth0 | grep 'inet6 ' | awk '{print $2}')"
echo -e "\
IPv4 Address:$(ifconfig eth0 | grep 'inet ' | awk '{print $2}')
IPv6 Address:$(ifconfig eth0 | grep 'inet6 ' | awk '{print $2}')"
fi
echo -e "MAC Address: $(ifconfig eth0 | grep 'ether ' | awk '{print $2}')\n\
Hostname: $(hostname).local"
echo -e "\
MAC Address:$(ifconfig eth0 | grep 'ether ' | awk '{print $2}')\n\
Hostname:$(hostname).local"
;;
w) # Option -w (wifi settings)
wifi_settings="SSID: $(grep -m 1 '^\s*ssid=' "$wpa_supplicant_conf" | cut -d '"' -f 2)\n\
Password: (hidden)\n\
Country: $(grep -m 1 "^country=" "$wpa_supplicant_conf" | cut -d '=' -f 2)"
wifi_settings="\
SSID:$(grep -m 1 '^\s*ssid=' "$wpa_supplicant_conf" | cut -d '"' -f 2)\n\
Password:(hidden)\n\
Country:$(grep -m 1 "^country=" "$wpa_supplicant_conf" | cut -d '=' -f 2)"
if ip link show wlan0 2>/dev/null | grep -q "wlan0"; then
mac_address_line="MAC address: $(ifconfig wlan0 | grep ether | awk '{print $2}')\n"
mac_address_line="\
MAC address:$(ifconfig wlan0 | grep ether | awk '{print $2}')"
if [ "$(cat /etc/wifi_state.txt)" = "up" ]; then
echo -e "Wi-Fi status: \033[4m\033[0;34menabled\033[0m\n\
Connected to: $(iwconfig 2>/dev/null | grep -i 'ESSID' | awk -F 'ESSID:"' '{print $2}' | awk -F '"' '{print $1}' | sed 's/^$/none/')\n\
Signal Strength: $(iwconfig 2>/dev/null | grep -i 'Signal level' | awk -F 'Signal level=' '{print $2}' | awk '{print $1}')\n\
Current IP: $(hostname -I | awk '{print $1}')\n
Hostname: $(hostname).local\n\
echo -e "\
Wi-Fi status:\033[4m\033[0;34menabled\033[0m\n\
Connected to:$(iwconfig 2>/dev/null | grep -i 'ESSID' | awk -F 'ESSID:"' '{print $2}' | awk -F '"' '{print $1}' | sed 's/^$/none/')\n\
Sig. strength:$(iwconfig 2>/dev/null | grep -i 'Signal level' | awk -F 'Signal level=' '{print $2}' | awk '{print $1}')\n\
Current IP:$(ip addr show wlan0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)\n
Hostname:$(hostname).local\n\
$mac_address_line"
else
if ip link show wlan0 &>/dev/null; then # if wlan0 exists
echo -e "Wi-Fi status: \033[0;31mdisabled\033[0m\n\
echo -e "\
Wi-Fi status:\033[0;31mdisabled\033[0m\n\
\n\
$wifi_settings"
fi
fi
else
echo -e "Wi-Fi status: \033[0;31mwlan0 not detected\033[0m\n\
echo -e "\
Wi-Fi status:\033[0;31mwlan0 not detected\033[0m\n\
\n\
Wi-Fi settings:\n\
$wifi_settings"
fi
;;
i) # Option -i (Get all IPv4 addresses)
hostname -I | awk '{for(i=1; i<=NF; i++) {if(i>1) printf ", "; printf $i} print ""}'
;;
t) # Option -t (test internet connection)
# Define ping targets and initialize counter
targets=("1.1.1.1" "8.8.8.8")
@ -129,23 +140,26 @@ $wifi_settings"
if [ "$successful" -eq 0 ]; then
echo -e "\033[0;31mNo internet connection detected.\033[0m"
else
echo -e "Internet connection is \033[4m\033[0;32mup\033[0m.\n\nPinged $(echo "${targets[*]}" | sed 's/ /, /g').\nReceived $successful/$total responses."
echo -e "Internet connection is \033[4m\033[0;34mup\033[0m.\n\nPinged $(echo "${targets[*]}" | sed 's/ /, /g').\nReceived $successful/$total responses."
fi
;;
r) # Option -r (restart Wi-Fi)
updated_wifi="true"
;;
n) # Option -n (set hostname)
old_hostname=$(hostname)
sed -i "s/$(hostname)/$OPTARG/g" /etc/hosts
hostnamectl set-hostname "$OPTARG"
systemctl restart avahi-daemon
echo "Regenerating web terminal ssl keys..."
[ "$OPTARG" != "$old_hostname" ] && /usr/local/bin/packages/ttyd.sh -k
;;
\?) # Invalid option
\?) # Invalid option)
echo "Invalid option: -$OPTARG"
echo -e "$help"
exit 1
;;
:) # Missing argument for option
:) # Missing argument for option)
echo "Option -$OPTARG requires a setting."
echo -e "$help"
exit 1
@ -155,7 +169,7 @@ done
if [ "$updated_wifi" = true ]; then
ip link set wlan0 up
systemctl restart wpa_supplicant
#systemctl restart wpa_supplicant
wpa_cli -i wlan0 reconfigure # <-------- add watch for FAIL response, error out
timeout 30s dhclient -v
#timeout 30s dhclient -v
fi

View file

@ -19,10 +19,10 @@ fi
femtofox="\
┌──────────┬────┬─────┬────┬───────────────┬───┬───────────────┐\n\
│⚪:⛊KILL ●│● │USB-C│ ●│● PWR-IN │✚ ▬│ 3.3-5V ⚪│\n\
│⚪:♥KILL ●│● │USB-C│ ●│● PWR-IN │✚ ▬│ 3.3-5V ⚪│\n\
├───────┐ ●│● └─────┘ ●│● └───┘ │\n\
│ USB-C │ ●│● ●│● ┌─────────────────────────────┐ │\n\
│ PWR ⛊ │ ●│● LUCKFOX ●│● │ ┌─────────────┐ │ │\n\
│ PWR ♥ │ ●│● LUCKFOX ●│● │ ┌─────────────┐ │ │\n\
│ DEBUG │ ●│● PICO MINI ●│● │ │ │ │ │\n\
├───────┘ ●│● ●│● │ │ │ │ │\n\
├───┐ ●│● FOXHOLE ●│● │ E │ │ │ │\n\
@ -36,31 +36,32 @@ femtofox="\
│ ● RX- │ I2C GROVE │ 3 │ SEEED │ │ │\n\
│ ● RX+ │ ┌───────┐ │ 0 │WIO SX1262│ │ │\n\
│ ● GND ETHERNET │ │● ● ● ●│ │ S │ │ │ │\n\
│ ● TX- │ ├───────┤ │ └───────────┘ │ │\n\
│ ● TX- │ ╞═══════╡ │ └───────────┘ │ │\n\
│ ● TX+ │ │● ● ● ●│ │ │ │\n\
├──────────────────┘ └───────┘ └─────────────────────────────┘ │\n\
│ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ■ │\n\
│⚪● ● ● ● ● ● ⛊ ⛊ ⛊ ● ⛊ ⛊ ● ● ● ● ● ● ● ●⚪│\n\
│⚪● ● ● ● ● ● ♥ ♥ ♥ ● ● ♥ ♥ ● ● ● ● ● ● ●⚪│\n\
└──────────────────────────────────────────────────────────────┘\n\
\n\
R M M \n\
G X G C I O 3 G S S 3 \n\
N E N L S S V N C D V \n\
D N D K O I 3 D L A 3 \n\
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ■ \n\
● ● ● ● ● ● ⛊ ⛊ ⛊ ● ● ⛊ ⛊ ● ● ● ● ● ● ● \n\
● ● ● ● ● ● ♥ ♥ ♥ ● ● ♥ ♥ ● ● ● ● ● ● ● \n\
C B I G G G G S S G R T G R R T G 5 5 \n\
S U R N P N P R R N X X N S X X N V V \n\
0 S Q D I D I A A D 2 2 D T 4 4 D \n\
Y O O 1 0 \n\
⛊ Denotes Pro features: \n\
♥ Denotes Pro features: \n\
On Community Edition, PWR/DEBUG USB-C replaced by 4pin UART2. \n\
PWR/DEBUG USB-C also carries serial with no added adapter. \n\
KILL: add PWR switch or thermal cutoff/fuse & remove resistor. "
KILL: add PWR switch or thermal cutoff/fuse & remove resistor."
femtofox_zero="\
┌────┐ ┌────┐ \n\
│⚪ \ / ⚪│ \n\
│⚪ \ / ⚪│ \n\
│ \ / │ \n\
│ └─────────┘ │ \n\
│ ┌─────────────────┐ │ \n\
@ -84,11 +85,11 @@ UART4-TX │ ● │ │ │ WIO │ │ │ ● │ I2C SCL \n\
├───┘ │ │SX 1262│ │ └───┤ \n\
│ │ └───────┘ │ ● │ UNUSED \n\
│ └─────────────┘ ● │ GND \n\
│⚪ ETH ⚪│ \n\
│⚪ ETH ⚪│ \n\
└────────●─●─●─●─●────────┘ \n\
R R G T T \n\
X X N X X \n\
- + D - + \n"
- + D - + "
femtofox_tiny="coming soon"
@ -137,4 +138,5 @@ while getopts "hlfzt" opt; do
exit 1
;;
esac
done
done
exit

View file

@ -1,86 +1,125 @@
#!/bin/bash
log_message() {
echo "First boot: $1" # Echo to the screen
echo -e "\e[32mFirst boot\e[0m: $1" # Echo to the screen
logger "First boot: $1" # Log to the system log
}
if [ ! -e "/etc/.firstboot" ]; then
if ! systemctl is-enabled femto-runonce &>/dev/null; then # if not the first boot
who | grep -q . || exit 0 # if not logged in, exit script. May not deal well with future web UI
# prevents weirdness over tty
export NCURSES_NO_UTF8_ACS=1
export TERM=xterm-256color
export LANG=C.UTF-8
dialog --title "Femtofox run once utility" --yesno "\
This does not appear to be this system's first boot.\n\
Re-running this script will restore RTC support, set the Meshtastic nodeid and eth0 MAC address to be derivative of the CPU serial number, set the Meshtastic wifi status to \`enabled\` and then reboot.\n\
\n\
Re-running this script will:\n\
* Resize filesystem to fit the SD card\n\
* Allocate the swap file\n\
* Replace the SSH encryption keys\n\
* Replace the Web Terminal SSL encryption keys\n\
* Set the eth0 MAC to be derivative of CPU serial number\n\
* Add terminal type to user femto's .bashrc\n\
* Add a shortcut \`sfc\` to user femto's .bashrc\n\
* Enable the meshtasticd service\n\
* Add compiler support\n\
\n\
Finally, the Femtofox will reboot.\n\
\n\
Re-running this script after first boot should not cause any harm, but may not work as expected.\n\
\n\
Proceed?" 14 60
Proceed?" 24 60
if [ $? -eq 1 ]; then #if cancel/no
exit 1
exit 0
fi
fi
echo -e "\e[32m******* First boot *******\e[0m"
# pulse LED during firstboot
(
while true; do
echo 1 > /sys/class/gpio/gpio34/value;
sleep 0.5;
echo 0 > /sys/class/gpio/gpio34/value;
sleep 0.5;
done
) &
# Perform filesystem resize
log_message "Resizing filesystem. This can take up to 10 minutes, depending on microSD card size and speed"
sudo resize2fs /dev/mmcblk1p5
sudo resize2fs /dev/mmcblk1p6
sudo resize2fs /dev/mmcblk1p7
log_message "Resizing filesystem..."
resize2fs /dev/mmcblk1p5
resize2fs /dev/mmcblk1p6
resize2fs /dev/mmcblk1p7
log_message "Resizing filesystem complete."
# allocate swap file
if [ ! -f /etc/.filesystem_swap ]; then # check if swap file already exists
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile > /dev/null
sudo swapon /swapfile > /dev/null
if [ ! -f /swapfile ]; then # check if swap file already exists
log_message "Allocating swap file..."
fallocate -l 1G /swapfile
chmod 600 /swapfile
mkswap /swapfile > /dev/null
swapon /swapfile > /dev/null
echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab > /dev/null
touch /etc/.filesystem_swap
log_message "Swap file allocated."
else
log_message "Swap file already allocated, skipping."
log_message "Swap file already allocated, skipping..."
fi
# add RTC support
bash -c 'echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-3/new_device'
log_message "Added ds1307/ds3231 RTC support."
# prevent randomized mac address for eth0. If `eth0`` is already present in /etc/network/interfaces, skip
if ! grep -q "eth0" /etc/network/interfaces; then
log_message "Setting eth0 MAC address to derivative of CPU s/n."
cat <<EOF >> /etc/network/interfaces
# static mac address for onboard ethernet (castellated pins)
allow-hotplug eth0
iface eth0 inet dhcp
hwaddress ether $(awk '/Serial/ {print $3}' /proc/cpuinfo | tail -c 11 | sed 's/^\(.*\)/a2\1/' | sed 's/\(..\)/\1:/g;s/:$//')
EOF
mac="$(awk '/Serial/ {print $3}' /proc/cpuinfo | tail -c 11 | sed 's/^\(.*\)/a2\1/' | sed 's/\(..\)/\1:/g;s/:$//')"
file="/etc/network/interfaces"
if ! grep -q " hwaddress ether $mac" "$file"; then
log_message "Setting eth0 MAC address to $mac (derivative of CPU s/n)..."
awk -v mac="$mac" '
{ print }
/allow-hotplug eth0/ { count=5 }
count && --count == 0 { print " hwaddress ether " mac }
' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
else
log_message "eth0 already exists in /etc/network/interfaces, skipping."
log_message "eth0 mac address already set in /etc/network/interfaces, skipping..."
fi
# Add term stuff to .bashrc
lines="export NCURSES_NO_UTF8_ACS=1
export TERM=xterm-256color
export LANG=C.UTF-8"
# Check if the lines are already in .bashrc
if ! grep -Fxq "$lines" /home/femto/.bashrc; then
echo "$lines" >> /home/femto/.bashrc
echo "Added TERM, LANG and NCURSES_NO_UTF8_ACS to .bashrc"
if ! grep -Fxq "$lines" /home/femto/.bashrc; then # Check if the lines are already in .bashrc
log_message "Adding TERM, LANG and NCURSES_NO_UTF8_ACS to .bashrc..."
echo "$lines" >> /home/femto/.bashrc
else
echo "TERM, LANG and NCURSES_NO_UTF8_ACS already present in .bashrc, skipping"
log_message "TERM, LANG and NCURSES_NO_UTF8_ACS already present in .bashrc, skipping..."
fi
# set meshtastic nodeid to derivative of CPU serial number (unique to this board)
seed=$(sed -n '/Serial/ s/^.*: \(.*\)$/\U\1/p' /proc/cpuinfo | bc | tail -c 9)
#seed=$((0x$(awk '/Serial/ {print $3}' /proc/cpuinfo) & 0x3B9AC9FF)) #alternate method for generating seed - not in use
sed -i "s|^ExecStart=/usr/sbin/meshtasticd.*|ExecStart=/usr/sbin/meshtasticd -h $seed|" /usr/lib/systemd/system/meshtasticd.service
log_message "Using Luckfox CPU S/N to generate nodeid for Meshtastic."
systemctl daemon-reload
# Fix Compiler
log_message "Adding compiler support..."
cp /usr/lib/arm-linux-gnueabihf/libc_nonshared.a.keep /usr/lib/arm-linux-gnueabihf/libc_nonshared.a
# Add a cheeky alias to .bash_aliases
if ! grep -Fxq "alias sfc='sudo femto-config'" /home/femto/.bashrc; then # Check if the lines are already in .bash_aliases
echo "alias sfc='sudo femto-config'" >> /home/femto/.bashrc
log_message "Added \`alias sfc='sudo femto-config'\` to .bashrc"
else
log_message "\`alias sfc='sudo femto-config'\` already present in .bashrc, skipping..."
fi
log_message "Enabling meshtasticd service..."
systemctl enable meshtasticd
systemctl restart meshtasticd
#generate SSH keys
log_message "Generating new SSH encryption keys. This can take a few minutes..."
femto-utils.sh -E
#generate ttyd SSL keys
log_message "Generating new Web Terminal (ttyd) SSL encryption keys. This can take a few minutes..."
/usr/local/bin/packages/ttyd.sh -k
log_message "Enabling Web Terminal (ttyd) service..."
systemctl enable ttyd
# remove first boot flag
rm /etc/.firstboot
log_message "Removing first boot flag and rebooting in 5 seconds..."
systemctl disable femto-runonce
log_message "Disabled first boot service and rebooting in 5 seconds..."
sleep 5
reboot
reboot

View file

@ -1,8 +1,11 @@
#!/bin/bash
export NCURSES_NO_UTF8_ACS=1 # prevents weirdness over tty
# prevents weirdness over tty
export NCURSES_NO_UTF8_ACS=1
export TERM=xterm-256color
export LANG=C.UTF-8
if [[ $EUID -ne 0 ]]; then
echo -e "This script must be run as root. Try \`sudo femto-set-timezone\`."
echo -e "This script must be run as root. Try \`sudo femto-set-time.sh\`."
exit 1
fi
@ -11,32 +14,56 @@ arg_count=$#
help=$(cat <<EOF
If no argument is specified, a menu system will be used. Options are:
-h This message
-t "TIMEZONE" Set timezone
-t "TIMEZONE" Set time zone
-T "TIMESTAMP" Set timestamp (unix timestamp)
EOF
)
log_message() {
logger $1
if [ $arg_count -eq 0 ]; then
dialog --msgbox "$1" 12 50
else
echo $1
fi
}
set_timezone() {
if timedatectl set-timezone "$1"; then
log_message "\nTime zone set to $1 (UTC$(date +%z)) successfully."
echo "Setting time zone..."
ln -f -s /usr/share/zoneinfo/$1 /etc/localtime >/dev/null 2>&1
dpkg-reconfigure --frontend noninteractive tzdata >/dev/null 2>&1
if [ ! -f /usr/share/zoneinfo/$1 >/dev/null 2>&1 ]; then
echo -e "Invalid timezone: $1"
return 1
fi
desired_offset=$(TZ=$1 date +"%:z")
current_offset=$(date +"%:z")
if [ "$desired_offset" != "$current_offset" ]; then
echo -e "FAILED to set timezone to $1. Expected GMT offset: $desired_offset, but got: $current_offset"
return 1
else
log_message "\nFailed to set the time zone to $1."
exit 1
echo "Set timezone to $current_offset"
return 0
fi
}
while getopts ":t:h" opt; do
set_timestamp() {
for i in {1..5}; do
if date -s "@$1" >/dev/null 2>&1; then
if hwclock --systohc >/dev/null 2>&1; then
echo "Time Zone updated to:\n$(timedatectl show --property=Timezone --value) $(date +%Z) (UTC$(date +%:z))\nSystem time updated to:\n$(date)\n\nNew time successfully saved to RTC.\nTime & date are also set automatically from internet, if connected."
return 0
else
echo "System time updated to:\n$(date +"%B %d, %Y %H:%M:%S") $(timedatectl show --property=Timezone --value) ($(date +"UTC%z" | sed -E 's/GMT([+-])0?([0-9]{1,2})00/GMT\1\2/'))\n\nUnable to communicate with RTC module. An RTC module can remember system time between reboots/power outages.\nTime & date are also set automatically from internet, if connected."
return 0
fi
fi
done
echo "Failed to set system time to $(date -d @$1) after 5 attempts."
return 1
}
while getopts ":t:T:h" opt; do
case ${opt} in
t) # Option -t (timezone)
set_timezone "$OPTARG"
[ $? -eq 1 ] && exit 1
;;
T) # Option -t (timestamp)
set_timestamp "$OPTARG"
[ $? -eq 1 ] && exit 1 || exit 0
;;
h) # Option -h (help)
echo -e "$help"
@ -44,47 +71,62 @@ while getopts ":t:h" opt; do
esac
done
# Fetch available time zones
echo "Loading timezones..."
timezones=$(timedatectl list-timezones)
# Build the options array
options=()
while IFS= read -r timezone; do
options+=("$timezone" "x")
done <<< "$timezones"
# Convert options array to string
options_str=$(printf '%s\n' "${options[@]}")
# Show timezone selection menu with preselection of current timezone
selected_timezone=$(dialog --title "Select Timezone" \
--default-item "$(cat /etc/timezone)" \
--menu "Current timezone: $(cat /etc/timezone) (UTC$(date +%z))" 20 60 10 \
$(printf "%s " "${options[@]}") 3>&1 1>&2 2>&3)
exit_status=$?
if [[ $exit_status -eq 0 && -n "$selected_timezone" ]]; then
# Set the selected time zone
set_timezone $selected_timezone
else
exit 1
fi
DATE=$(echo "$(dialog --title "Select Date" --calendar "Choose a date:\nCurrent date: $(date "+%B %d, %Y")\nPress [TAB] to select." 0 0 $(date +%d) $(date +%m) $(date +%Y) 3>&1 1>&2 2>&3)" | awk -F/ '{printf "%04d-%02d-%02d", $3, $2, $1}')
if [ $? -eq 1 ]; then #if cancel/no
exit 1
fi
TIME=$(dialog --title "Set Time" --timebox "Select time:\nCurrent time: $(date +%H:%M:%S)\nPress [TAB] to select." 0 0 3>&1 1>&2 2>&3) # Dialog timebox for time
if [ $? -eq 1 ]; then #if cancel/no
exit 1
fi
if date -s "$DATE $TIME"; then # set time
if hwclock --systohc; then
rtc="New time successfully saved to RTC."
else
rtc="Unable to communicate with RTC module. An RTC module can save system time between reboots/power outages."
if [ $arg_count -eq 0 ]; then # if the script was launched with no arguments, then load the UI.
echo "Loading current time settings..."
current_timezone=$(timedatectl show --property=Timezone --value)
dialog --no-collapse --title "System time" --yesno "\
Current system time:\n\
$(date +"%B %d, %Y %H:%M:%S") $(timedatectl show --property=Timezone --value) ($(date +"UTC%z" | sed -E 's/GMT([+-])0?([0-9]{1,2})00/GMT\1\2/'))\n\
$(hwclock >/dev/null 2>&1 && echo "RTC module found!" || echo "RTC module not found.")\n\
\n\
Set new time and timezone?" 10 50
if [ $? -eq 1 ]; then #unless cancel/no
exit 0
fi
log_message "System time updated to:\n$(date)\n\n$rtc\nTime & date are also set automatically from internet."
else
log_message "Failed to set system time."
exit 1
# Fetch available time zones
echo "Loading time zones..."
timezones=$(timedatectl list-timezones)
# Build the options array
options=()
while IFS= read -r timezone; do
options+=("$timezone" "x")
done <<< "$timezones"
# Convert options array to string
options_str=$(printf '%s\n' "${options[@]}")
# Show timezone selection menu with preselection of current timezone
selected_timezone=$(dialog --title "Set Time Zone" \
--default-item "$current_timezone" \
--menu "Current time zone: $current_timezone (UTC$(date +%z))" 20 50 10 \
$(printf "%s " "${options[@]}") 3>&1 1>&2 2>&3)
exit_status=$?
if [[ $exit_status -eq 0 && -n "$selected_timezone" ]]; then
# Set the selected time zone
set_timezone $selected_timezone
else
exit 1
fi
DATE=$(dialog --title "Set Date" --calendar "Current date: $(date "+%B %d, %Y") \nPress [TAB] to select." 0 0 $(date +%d) $(date +%m) $(date +%Y) 3>&1 1>&2 2>&3)
if [ $? -ne 0 ]; then
exit 1
fi
DATE=$(echo "$DATE" | awk -F'/' '{print $3"-"$2"-"$1}') #reformat to YYYY-MM-DD
TIME=$(dialog --title "Set Time" --timebox "Current time: $(date +%H:%M:%S)\nPress [TAB] to select." 0 0 3>&1 1>&2 2>&3) # Dialog timebox for time
if [ $? -eq 1 ]; then #if cancel/no
exit 1
fi
msg="$(set_timestamp $(date -d "$DATE $TIME" +%s))"
exit_status=$?
logger $msg
if [ $arg_count -eq 0 ]; then
dialog --msgbox "$msg" 13 50
else
echo -e $msg
fi
exit $exit_status #exit status matches set_timestamp exit status
fi

View file

@ -4,50 +4,67 @@ title="Software Manager"
package_dir="/usr/local/bin/packages"
install() {
dialog --no-collapse --title "$title" --yesno "\nInstall $($package_dir/$1.sh -N)\n\nProceed?" 10 40
if [ $? -eq 1 ]; then #if cancel/no
return 1
fi
dialog --no-collapse --title "Install $($package_dir/$1.sh -N)" --yesno "\nInstallation requires internet connectivity.\n\nInstall $($package_dir/$1.sh -N)?" 10 40
[ $? -eq 1 ] && return 1 #if cancel/no
echo "Installing $($package_dir/$1.sh -N)..."
# Run the installation script, capturing the output and displaying it in real time
output=$($package_dir/$1.sh -i)
echo $output
install_status=$? # Capture the exit status of the eval command
output="$($package_dir/$1.sh -i 2>&1 | tee /dev/tty)"
install_status=$([[ "$output" == *"failed"* ]] && echo 1 || echo 0)
# Capture the exit status of the eval command
if [ ${#output} -gt 2048 ]; then # Truncate to 2048 characters and append ellipsis and note if necessary
truncated_output="${output:0:2000}...\nLOG TRUNCATED"
if [[ "$output" =~ user_message: ]]; then # preserve user_message by adding to end of string
truncated_output="$truncated_output\n$(echo "$output" | sed -n 's/.*\(user_message:.*\)/\1/p')"
fi
output="$truncated_output"
fi
user_message=$(echo "$output" | awk '/user_message: / {found=1; split($0, arr, "user_message: "); print arr[2]; next} found {print}' | sed '/^$/q') # grab the user_message, if present
#output=$(echo -e "$output" | sed '/user_message: /,$d') # remove the user message from the detailed output
output=$(echo -e "$output" | sed '/user_message: /,$d') # remove the user message from the detailed output
echo $install_status
if [ $install_status -eq 0 ]; then # if the installation was successful
dialog --no-collapse --colors --title "$title" --beep --msgbox "\n\ZuInstallation of $($package_dir/$1.sh -N) successful!\Zn$([ -n "$user_message" ] && echo "\n\n$user_message")\n\nLog:\n$(echo $output)" 0 0 # if there's a user_message, display it with two preceeding line breaks
dialog --no-collapse --colors --title "$title" --beep --msgbox "\ZuInstallation of $($package_dir/$1.sh -N) successful!\Zn$([ -n "$user_message" ] && echo "\n\n$user_message")\n\nLog:\n$(echo $output)" 0 0 # if there's a user_message, display it with two preceeding line breaks
else
dialog --no-collapse --colors --title "$title" --beep --msgbox "\n\ZuInstallation of $($package_dir/$1.sh -N) FAILED!\Zn\n\n$user_message\n\nLog:\n$(echo -e $output)" 0 0 # if there's a user_message, display it with two preceeding line breaks
dialog --no-collapse --colors --title "$title" --beep --msgbox "\ZuInstallation of $($package_dir/$1.sh -N) FAILED!\Zn\n\n$user_message\n\nLog:\n$(echo -e $output)" 0 0 # if there's a user_message, display it with two preceeding line breaks
fi
}
uninstall() {
dialog --no-collapse --title "$title" --yesno "\nUninstall $1\n\nProceed?" 10 40
if [ $? -eq 1 ]; then #if cancel/no
return 1
fi
dialog --no-collapse --title "Uninstall $($package_dir/$1.sh -N)" --yesno "\nNote: reinstallation will require internet connectivity.\n\nUninstall $($package_dir/$1.sh -N)?" 10 40
[ $? -eq 1 ] && return 1 #if cancel/no
echo "Uninstalling $($package_dir/$1.sh -N)..."
output=$(eval "$package_dir/$1.sh -u 2>&1 | tee /dev/tty")
install_status=$? # Capture the exit status of the eval command
user_message=$(echo "$output" | awk '/user_message: / {found=1; split($0, arr, "user_message: "); print arr[2]; next} found {print}' | sed '/^$/q') # grab the user_message, if present
#output=$(echo "$output" | sed '/user_message: /,$d') # remove the user message from the detailed output
output=$(echo "$output" | sed '/user_message: /,$d') # remove the user message from the detailed output
if [ $install_status -eq 0 ]; then # if the installation was successful
dialog --no-collapse --colors --title "$title" --beep --msgbox "\n\ZuUninstallation of $($package_dir/$1.sh -N) successful!\Zn$([ -n "$user_message" ] && echo "\n\n$user_message")\n\nLog:\n$(echo -e "$output")" 0 0 # if there's a user_message, display it with two preceeding line breaks
else
dialog --no-collapse --colors --title "$title" --beep --msgbox "\n\ZuUninstallation of $($package_dir/$1.sh -N) FAILED!\Zn\n\n$user_message\n\nLog:\n$(echo "$output")" 0 0 # if there's a user_message, display it with two preceeding line breaks
fi
fi
}
initialize() {
dialog --no-collapse --title "$title" --yesno "\nIntialize $($package_dir/$1.sh -N)\n\nInitialization runs commands that require user interaction and so can only be run from terminal.\n\nInitialize $($package_dir/$1.sh -N)?" 13 50
[ $? -eq 1 ] && return 1 #if cancel/no
clear
echo "Initializing $($package_dir/$1.sh -N)..."
eval "$package_dir/$1.sh -a"
if [ $? -eq 0 ]; then # if the installation was successful
dialog --no-collapse --colors --title "$title" --beep --msgbox "\nInitialization of $($package_dir/$1.sh -N) successful!" 8 50 # if there's a user_message, display it with two preceeding line breaks
else
dialog --no-collapse --colors --title "$title" --beep --msgbox "\nInitialization of $($package_dir/$1.sh -N) FAILED!" 8 50 # if there's a user_message, display it with two preceeding line breaks
fi
}
upgrade() {
dialog --no-collapse --title "$title" --yesno "\nUpgrade $1\n\nProceed?" 10 40
if [ $? -eq 1 ]; then #if cancel/no
return 1
fi
dialog --no-collapse --title "Upgrade $($package_dir/$1.sh -N)" --yesno "\nUpgrade requires internet connectivity.\n\nUpgrade $($package_dir/$1.sh -N)?" 10 40
[ $? -eq 1 ] && return 1 #if cancel/no
echo "Upgrading $($package_dir/$1.sh -N)..."
output=$(eval "$package_dir/$1.sh -g 2>&1 | tee /dev/tty")
install_status=$? # Capture the exit status of the eval command
output="$($package_dir/$1.sh -g 2>&1 | tee /dev/tty)"
install_status=$([[ "$output" == *"failed"* ]] && echo 1 || echo 0)
user_message=$(echo "$output" | awk '/user_message: / {found=1; split($0, arr, "user_message: "); print arr[2]; next} found {print}' | sed '/^$/q') # grab the user_message, if present
output=$(echo "$output" | sed '/user_message: /,$d') # remove the user message from the detailed output
if [ $install_status -eq 0 ]; then # if the installation was successful
@ -55,7 +72,6 @@ upgrade() {
else
dialog --no-collapse --colors --title "$title" --beep --msgbox "\n\ZuUpgrade of $($package_dir/$1.sh -N) FAILED!\Zn\n\n$user_message\n\nLog:\n$output" 0 0 # if there's a user_message, display it with two preceeding line breaks
fi
}
@ -63,91 +79,106 @@ upgrade() {
package_intro() {
echo "Loading package info..."
# check if each field in the package info is supported by the package, and if so get it and insert it into the package info dialog
dialog --no-collapse --colors --title "$title" --msgbox "\
$($package_dir/$1.sh -N)\n\
$(if $package_dir/$1.sh -O | grep -q 'A'; then echo -e "by $($package_dir/$1.sh -A)"; fi)\n\
dialog --no-collapse --colors --title "$title" --yes-label "Continue" --no-label "Back" --yesno "\
$($package_dir/$1.sh -N)\n\
$(if $package_dir/$1.sh -O | grep -q 'A'; then echo -e "by $($package_dir/$1.sh -A)"; fi)\n\
$(if $package_dir/$1.sh -O | grep -q 'D'; then echo "\n$($package_dir/$1.sh -D)"; fi)\n\
\n\
$(echo "Currently: " && $package_dir/$1.sh -I && echo "\Zuinstalled\Zn" || echo " \Zunot installed\Zn")\n\
$(echo "Currently: " && $package_dir/$1.sh -I && echo "\Zuinstalled\Zn" || echo "\Zunot installed\Zn")\n\
$([ -n "$($package_dir/$1.sh -E)" ] && $package_dir/$1.sh -I && echo "Service status: \Zu$(femto-utils.sh -C "$($package_dir/$1.sh -E)" | sed 's/\x1b\[[0-9;]*m//g')\Zn\n")\
$(if output=$($package_dir/$1.sh -L); [ -n "$output" ]; then echo "Installs to: \Zu$output\Zn\n"; fi)\
$(if output=$($package_dir/$1.sh -C); [ -n "$output" ]; then echo "Conflicts with: \Zu$output\Zn\n"; fi)\
An internet connection is required for installation.\n\
$(if $package_dir/$1.sh -O | grep -q 'U'; then echo "\nFor more information, visit $($package_dir/$1.sh -U)"; fi)" 0 0
$(if output=$($package_dir/$1.sh -T); [ -n "$output" ]; then echo "License: \Zu$output\Zn\n"; fi)\
$(if $package_dir/$1.sh -O | grep -q 'U'; then echo "Website: \Zu$($package_dir/$1.sh -U)\Zn"; fi)" 0 0
[ $? -eq 1 ] && return 1 # Exit the loop if the user selects "Cancel" or closes the dialog
package_menu $1 # after user hits "OK", move on to package menu
}
package_menu() {
choice=""
while true; do
echo "Loading package menu..."
license_button=""
if $package_dir/$1.sh -O | grep -q 'G' && $package_dir/$1.sh -I; then license_button="--help-button --help-label License"; fi
# for each line, check if it's supported by the package, display it if the current install state of the package is appropriate (example: don't display "install" if the package is already installed, don't display "stop service" for a package with no services)
choice=$(dialog --no-collapse --title "$title" --cancel-label "Back" --menu "$($package_dir/$1.sh -N)" 17 45 5 \
if $package_dir/$1.sh -I; then service_state=$(femto-utils.sh -C "$($package_dir/$1.sh -E)"); fi
# Removed from menu list until can be fixed - contact does not launch. When returned to list, should be first entry
menu_list="\
$(if $package_dir/$1.sh -O | grep -q 'l' && $package_dir/$1.sh -I; then echo "Run software x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'i' && ! $package_dir/$1.sh -I; then echo "Install x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'u' && $package_dir/$1.sh -I; then echo "Uninstall x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'a' && $package_dir/$1.sh -I; then echo "Initialize x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'g' && $package_dir/$1.sh -I; then echo "Upgrade x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'e' && $package_dir/$1.sh -I; then echo "Enable service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'd' && $package_dir/$1.sh -I; then echo "Disable service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 's' && $package_dir/$1.sh -I; then echo "Stop service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'r' && $package_dir/$1.sh -I; then echo "Start/restart service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'S' && $package_dir/$1.sh -I; then echo "Get service status x"; fi) \
"" "" \
$(if $package_dir/$1.sh -O | grep -q 'e' && $package_dir/$1.sh -I && [[ ! $service_state =~ "enabled" ]]; then echo "Enable service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'e' && $package_dir/$1.sh -I && [[ ! $service_state =~ "disabled" ]]; then echo "Disable service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'e' && $package_dir/$1.sh -I && [[ ! $service_state =~ "not running" ]]; then echo "Stop service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'e' && $package_dir/$1.sh -I; then echo "Start/restart service x"; fi) \
$(if $package_dir/$1.sh -O | grep -q 'S' && $package_dir/$1.sh -I; then echo "Detailed service status x"; fi)"
menu_count=$(( $(echo "$menu_list" | grep -o " x" | wc -l) $(if $package_dir/$1.sh -O | grep -q 'e' && $package_dir/$1.sh -I; then echo "+1"; fi) )) # count the number of menu items by counting how many times " x" shows up, +1 if there's a service. This is a stupid way to do this, but because each menu item only contains one space (the rest being space-sized invisible chars) it works. It's late at night, OKAY?!
if $package_dir/$1.sh -O | grep -q 'e' && [ "$($package_dir/$1.sh -E | wc -w)" -gt 1 ]; then
multiple_services_note="\nService will appear as \"running\" if any of the services are active."
menu_count=$((menu_count + 2))
fi
choice=$(dialog --no-collapse --colors --title "$($package_dir/$1.sh -N)" $license_button --cancel-label "Back" --default-item "$choice" --menu "$(if $package_dir/$1.sh -O | grep -q 'S' && $package_dir/$1.sh -I; then echo "Service status: $(femto-utils.sh -R "$service_state")"; fi)$multiple_services_note" $(( menu_count + 9 )) 45 $(( menu_count + 3 )) \
$menu_list \
" " "" \
"Back to software manager" "" 3>&1 1>&2 2>&3)
exit_status=$? # This line checks the exit status of the dialog command
if [ $exit_status -ne 0 ]; then # Exit the loop if the user selects "Cancel" or closes the dialog
break
fi
# execute the actual commands
case $choice in
"Run software") eval "$package_dir/$1.sh -l" ;;
"Install") install $1 ;;
"Uninstall") uninstall $1 ;;
"Upgrade") upgrade $1 ;;
"Enable service") eval "$package_dir/$1.sh -e" ;;
"Disable service") eval "$package_dir/$1.sh -d" ;;
"Stop service") eval "$package_dir/$1.sh -s" ;;
"Start/restart service") eval "$package_dir/$1.sh -r" ;;
"Get service status") dialog --no-collapse --title "$title" --msgbox "$(eval "$package_dir/$1.sh -S")" 0 0 ;;
"Back to software manager") break ;;
esac
exit_status=$? # This line checks the exit status of the dialog command
if [ $exit_status -eq 1 ]; then # Exit the loop if the user selects "Cancel" or closes the dialog
return
elif [ $exit_status -eq 2 ]; then # Help ("extra") button
dialog --no-collapse --colors --title "$($package_dir/$1.sh -N) License" --msgbox " \Zu$($package_dir/$1.sh -N)\Zn\n$(if output=$($package_dir/$1.sh -T); [ -n "$output" ]; then echo "License: $output"; fi)\n\n$($package_dir/$1.sh -G)" 0 0
else
# execute the actual commands
case $choice in
"Run software") eval "$package_dir/$1.sh -l" ;;
"Install") install $1 ;;
"Uninstall") uninstall $1 ;;
"Initialize") initialize $1 ;;
"Upgrade") upgrade $1 ;;
"Enable service") echo "Enabling and starting service..." && eval "$package_dir/$1.sh -e" && eval "$package_dir/$1.sh -r" ;;
"Disable service") echo "Disabling and stopping service..." && eval "$package_dir/$1.sh -d" && eval "$package_dir/$1.sh -s" ;;
"Stop service") echo "Stopping service..." && eval "$package_dir/$1.sh -s" ;;
"Start/restart service") echo "Starting/restarting service..." && eval "$package_dir/$1.sh -r" ;;
"Detailed service status") echo "Getting service status..." && dialog --no-collapse --title "$title" --msgbox "$(eval "$package_dir/$1.sh -S")" 0 0 ;;
"Back to software manager") break ;;
esac
fi
done
}
# generate menu from filenames in /usr/local/bin/packages
while true; do
title="$title"
option=""
option=$(dialog --no-collapse --cancel-label "Back" --menu "$title" 0 0 6 \
1 "The Comms Channel BBS, TC²BBS" \
2 "Contact (Meshtastic client)" \
3 "Meshing Around by Spud" \
4 "Mosquitto MQTT Broker" \
5 "Mosquitto MQTT Client" \
"" ""\
6 "Back to Main Menu" 3>&1 1>&2 2>&3)
exit_status=$? # This line checks the exit status of the dialog command
if [ $exit_status -ne 0 ]; then # Exit the loop if the user selects "Cancel" or closes the dialog
break
fi
case $option in
1) package_intro "tc2_bbs" ;;
2) package_intro "contact_client" ;;
3) package_intro "meshing_around" ;;
4) package_intro "mosquitto_mqtt_broker" ;;
5) package_intro "mosquitto_mqtt_client" ;;
6) break ;;
esac
echo "Loading packages..."
menu_entries=("Package name" "Installed?" "" "")
index=1
for file in /usr/local/bin/packages/*.sh; do
filename=$(basename "$file" .sh)
[[ "$filename" == femto_* ]] && continue # skip filenames starting with femto_
menu_entries+=("$(/usr/local/bin/packages/"$filename".sh -N)" "$($package_dir/$filename.sh -I && echo "✅ " || echo "❌ ")")
((index++)) # keeping an index to determine menu window height
done
menu_entries+=(" " "") # add blank line and "Back to Main Menu" entry
menu_entries+=("Back to main menu" "")
software_option=$(dialog --no-collapse --cancel-label "Back" --default-item "$software_option" --menu "$title" $((11 + index)) 50 $((index + 3)) "${menu_entries[@]}" 3>&1 1>&2 2>&3)
[ $? -eq 1 ] && break # Exit the loop if the user selects "Cancel" or closes the dialog
case_block=" case \$software_option in"
index=1
for file in /usr/local/bin/packages/*.sh; do
filename=$(basename "$file" .sh)
[[ "$filename" == femto_* ]] && continue # skip filenames starting with femto_
case_block+="
\"$(/usr/local/bin/packages/"$filename".sh -N)\") package_intro \"$filename\" ;;"
((index++))
done
case_block+="
\"Back to main menu\") break ;;
esac" #add return to main menu option
eval "$case_block" # Execute the generated case statement
done
exit 0
# 4 "Mosquitto MQTT broker" \
# 5 "GPS and Telemetry" \
# 4) mosquitto ;;
# 5) gpsd ;;
exit 0

View file

@ -1,14 +1,34 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo femto-meshtasticd-config\`."
exit 1
fi
mount_point="/mnt/usb" # Set the mount point
# Function to log to screen, syslog and logfile to be saved to usb drive
log_message() {
echo "USB config: $1"
echo -e "\e[32mUSB config\e[0m: $1"
logger "USB config: $1"
echo "$(date +"%Y-%m-%d %H:%M:%S") $1" >> /tmp/femtofox-config.log
}
if systemctl is-enabled femto-runonce &>/dev/null; then
log_message "First boot, skipping USB Configuration Tool."
exit 0
fi
exit_script() {
if [[ -n "$partial_failure" ]]; then
log_message "\033[0;31mPartial failure in usb-config-tool...\033[0m"
for _ in {1..2}; do #boot code
blink "1" && sleep 0.5
done
for _ in {1..2}; do #boot code
blink "0.25" && sleep 0.5
done
fi
if [ ! -z "$usb_path" ]; then #if usb path is populated
if ! df -T /mnt/usb 2>/dev/null | grep -qw 'ntfs'; then
log_message "USB configuration script complete. Copying femtofox-config.log to USB drive."
@ -50,6 +70,8 @@ if [ ! -d "$mount_point" ]; then
mkdir -p "$mount_point"
fi
echo -e "\e[32m******* USB configuration tool *******\e[0m"
# Debugging: Log and echo the extracted device name
log_message "USB device found: $full_device_path"
@ -62,7 +84,7 @@ else
if [ $? -eq 0 ]; then
log_message "USB drive mounted successfully at $mount_point."
else
log_message "Failed to mount USB drive."
log_message "\e[31mFailed to mount USB drive.\e[0m"
blink "5" && sleep "0.5" #boot code
exit_script 1
fi
@ -96,6 +118,8 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
wifi_command="femto-network-config.sh"
meshtastic_security_command="femto-meshtasticd-config.sh"
dont_run_if_log_exists=""
software_install=""
meshtastic_i2c=""
# Escape and read the fields from the USB config file if they exist
while IFS='=' read -r key value; do
@ -105,6 +129,7 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
fi
value=$(echo "$value" | tr -d '"')
case "$key" in
act_led) act_led=$(escape_sed "$value") ;;
wifi_ssid) wifi_ssid=$(escape_sed "$value") ;;
wifi_psk) wifi_psk=$(escape_sed "$value") ;;
wifi_country) wifi_country=$(escape_sed "$value") ;;
@ -112,27 +137,28 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
timezone) timezone=$(escape_sed "$value") ;;
meshtastic_url) meshtastic_url=$(escape_sed "$value") ;;
meshtastic_legacy_admin) meshtastic_legacy_admin=$(escape_sed "$value") ;;
meshtastic_public_key) meshtastic_public_key=$(escape_sed "$value") ;;
meshtastic_private_key) meshtastic_private_key=$(escape_sed "$value") ;;
meshtastic_admin_key) meshtastic_admin_key=$(escape_sed "$value") ;;
dont_run_if_log_exists) dont_run_if_log_exists=$(escape_sed "$value") ;;
software_install) software_install=$(escape_sed "$value") ;;
meshtastic_i2c) meshtastic_i2c=$(escape_sed "$value") ;;
esac
done < <(grep -E '^(wifi_ssid|wifi_psk|wifi_country|meshtastic_lora_radio|timezone|meshtastic_url|meshtastic_legacy_admin|meshtastic_admin_key|dont_run_if_log_exists)=' "$usb_config")
done < <(grep -E '^(act_led|wifi_ssid|wifi_psk|wifi_country|meshtastic_lora_radio|timezone|meshtastic_url|meshtastic_legacy_admin|meshtastic_public_key|meshtastic_private_key|meshtastic_admin_key|dont_run_if_log_exists|software_install|meshtastic_i2c)=' "$usb_config")
# Check if the log exits and if the dont_run_if_log_exists line is set in the script
if $log_exists && [[ $dont_run_if_log_exists = "true" ]]; then
log_message "\`dont_run_if_log_exists\` is set to \"true\" and log exists, ignoring."
log_message "\e[31m\`dont_run_if_log_exists\` is set to \"true\" and log exists, ignoring.\e[0m"
for _ in {1..2}; do #boot code
blink "1.5" && sleep 0.5
done
exit_script 1
fi
# Update wpa_supplicant.conf with the new values, if specified
if [[ -n "$wifi_country" ]]; then
# Update country field
wifi_command="$wifi_command -c \"$wifi_country\""
log_message "Updating Wi-Fi country in wpa_supplicant.conf to $wifi_country."
found_config="true"
update_wifi="true"
if [[ -n "$act_led" ]]; then
# Update the ssid in the network block
log_message "Updating Activity LED status to \`$act_led\`."
femto-utils.sh -a "$act_led"
fi
if [[ -n "$wifi_ssid" ]]; then
@ -146,11 +172,27 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
if [[ -n "$wifi_psk" ]]; then
# Update the psk in the network block
wifi_command="$wifi_command -p \"$wifi_psk\""
log_message "Updating Wi-Fi PSK in wpa_supplicant.conf to \`$wifi_psk\`."
#log_message "Updating Wi-Fi PSK in wpa_supplicant.conf to \`$wifi_psk\`."
log_message "Updating Wi-Fi PSK in wpa_supplicant.conf to *HIDDEN*."
found_config="true"
update_wifi="true"
fi
# Update wpa_supplicant.conf with the new values, if specified
if [[ -n "$wifi_country" ]]; then
# Update country field
wifi_command="$wifi_command -c \"$wifi_country\""
log_message "Updating Wi-Fi country in wpa_supplicant.conf to $wifi_country."
found_config="true"
update_wifi="true"
fi
if [ "$update_wifi" = true ]; then #if wifi config found, restart wifi
log_message "Making changes to wifi settings and restarting wifi."
wifi_command="$wifi_command -r"
eval $wifi_command 2>&1 | tee -a /tmp/femtofox-config.log
log_message "wpa_supplicant.conf updated and wifi restarted. Enabling Meshtastic wifi setting."
fi
#get meshtastic_lora_radio model, if specified, and copy appropriate yaml to /etc/meshtasticd/config.d/
if [[ -n "$meshtastic_lora_radio" ]]; then
@ -192,12 +234,18 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
radio="none"
;;
*)
log_message "Invalid LoRa radio name: $meshtastic_lora_radio, ignoring."
log_message "\033[0;31mInvalid LoRa radio name: $meshtastic_lora_radio, ignoring.\033[0m"
partial_failure=true
;;
esac
if [[ -n "$radio" ]]; then # if a radio was found
femto-meshtasticd-config.sh -l "$radio" -s 2>&1 | tee -a /tmp/femtofox-config.log # set the radio and restart the service
log_message "Set LoRa radio to $meshtastic_lora_radio, restarting Meshtasticd."
if [ $? -eq 0 ]; then
log_message "Set LoRa radio to $meshtastic_lora_radio, restarting Meshtasticd."
else
log_message "\033[0;31mSeting LoRa radio to $meshtastic_lora_radio FAILED, restarting Meshtasticd.\033[0m" | tee -a /tmp/femtofox-config.log
partial_failure=true
fi
fi
fi
@ -205,6 +253,10 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
timezone=$(echo "$timezone" | sed 's/\\//g')
log_message "Updating system timezone to $timezone."
femto-set-time.sh -t "$timezone"
if [ $? -eq 1 ]; then
partial_failure=true
log_message "\033[0;31mSeting timezone to $timezone FAILED.\033[0m" | tee -a /tmp/femtofox-config.log
fi
found_config="true"
fi
@ -213,8 +265,22 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
log_message "Updating Meshtastic URL."
found_config="true"
fi
if [[ -n "$meshtastic_admin_key" ]]; then
if [[ -n "$meshtastic_public_key" ]]; then # public key
meshtastic_public_key="$(echo "$meshtastic_public_key" | sed 's/\\//g')" # remove weirdo windows characters
log_message "Updating Meshtastic public key."
found_config="true"
meshtastic_security_command+=" -U \"$meshtastic_public_key\"" # add to the command list
fi
if [[ -n "$meshtastic_private_key" ]]; then # private key
meshtastic_private_key="$(echo "$meshtastic_private_key" | sed 's/\\//g')" # remove weirdo windows characters
log_message "Updating Meshtastic private key."
found_config="true"
meshtastic_security_command+=" -R \"$meshtastic_private_key\"" # add to the command list
fi
if [[ -n "$meshtastic_admin_key" ]]; then # admin key
meshtastic_admin_key=$(echo "$meshtastic_admin_key" | sed 's/\\//g') # remove weirdo windows characters
if [ "$meshtastic_admin_key" = "clear" ]; then
log_message "Clearing Meshtastic admin key list."
@ -224,48 +290,97 @@ if [ -f "$mount_point/femtofox-config.txt" ]; then
log_message "Updating Meshtastic admin key."
fi
found_config="true"
meshtastic_security_command+=" -a \"$meshtastic_admin_key\"" # add to the command list
meshtastic_security_command+=" -A \"$meshtastic_admin_key\"" # add to the command list
fi
if [[ -n "$meshtastic_legacy_admin" ]]; then
if [[ -n "$meshtastic_legacy_admin" ]]; then # legacy admin
meshtastic_legacy_admin=$(echo "$meshtastic_legacy_admin" | sed 's/\\//g') # remove weirdo windows characters
log_message "Updating Meshtastic legacy admin."
found_config="true"
meshtastic_security_command+=" -o \"$meshtastic_legacy_admin\"" # add to the command list
fi
if [ "$found_config" = true ]; then #if we found a config file containing valid data
if [ "$update_wifi" = true ]; then #if wifi config found, restart wifi
log_message "Making changes to wifi settings and restarting wifi."
wifi_command="$wifi_command -r"
eval $wifi_command 2>&1 | tee -a /tmp/femtofox-config.log
log_message "wpa_supplicant.conf updated and wifi restarted. Enabling Meshtastic wifi setting."
# get meshtastic_cli= lines and run them
while IFS='=' read -r key value; do
log_message "Meshtastic CLI command found."
femto-meshtasticd-config.sh -m "$value" 3 "Meshtastic CLI command" 2>&1 | tee -a /tmp/femtofox-config.log
if [ $? -eq 1 ]; then
partial_failure=true
log_message "\033[0;31mMeshtastic CLI command \`meshtastic --host $value\` FAILED.\033[0m" | tee -a /tmp/femtofox-config.log
fi
found_config=true
done < <(grep '^meshtastic_cli=' "$usb_config" | sed -E 's/^meshtastic_cli=["]?(.*[^"])["]?$/meshtastic_cli=\1/')
# install software packages from software_install=
package_dir="/usr/local/bin/packages"
export HOME=/root
IFS=',' read -ra packages <<< "$software_install"
for package in "${packages[@]}"; do
if [[ -f "/usr/local/bin/packages/${package}.sh" ]]; then
found_config=true
log_message "Installing $($package_dir/${package}.sh -N) in non-interactive mode..." | tee -a /tmp/femtofox-config.log
for i in {1..5}; do
set -o pipefail
$package_dir/${package}.sh -xi | tee -a /tmp/femtofox-config.log
last_install_attempt_state=${PIPESTATUS[0]}
set +o pipefail
if [ $last_install_attempt_state -eq 0 ]; then
log_message "\033[0;32mInstallation of $($package_dir/${package}.sh -N) successful!\033[0m"
break
fi
[ $i = 5 ] && log_message "Installation failed... Is internet connected?" && break
log_message "Installation failed ($((i+1))/5). Retrying..."
sleep 4
done
if [ $last_install_attempt_state -ne 0 ]; then
log_message "\033[0;31mInstallation of $($package_dir/${package}.sh -N) unsuccessful!\033[0m"
partial_failure=true
fi
else
log_message "\033[0;31mSoftware package $package_dir/${package}.sh does not exist, ignoring...\033[0m"
partial_failure=true
fi
done
if [[ -n "$meshtastic_i2c" ]]; then # set meshtastic i2c state
femto-meshtasticd-config.sh -I $meshtastic_i2c 2>&1 | tee -a /tmp/femtofox-config.log
log_message "Set Meshtastic i2c state to \`$meshtastic_i2c\`."
found_config="true"
fi
if [ "$found_config" = true ]; then #if we found a config file containing valid data
if [ "$meshtastic_url" != "" ]; then
log_message "Connecting to Meshtastic radio and submitting $meshtastic_url"
femto-meshtasticd-config.sh -q "$meshtastic_url" 2>&1 | tee -a /tmp/femtofox-config.log
if [ $? -eq 1 ]; then
partial_failure=true
log_message "\033[0;31mSetting Meshtastic URL to $meshtastic_url FAILED.\033[0m" | tee -a /tmp/femtofox-config.log
fi
fi
if [ "$meshtastic_security_command" != "femto-meshtasticd-config.sh" ]; then
log_message "Connecting to Meshtastic radio and submitting $meshtastic_security_command"
eval "$meshtastic_security_command" 2>&1 | tee -a /tmp/femtofox-config.log
if [ $? -eq 1 ]; then
partial_failure=true
log_message "\033[0;31mSetting Meshtastic security settings FAILED.\033[0m" | tee -a /tmp/femtofox-config.log
fi
fi
for _ in {1..10}; do #do our successful config boot code
blink "0.125" && sleep 0.125
done
else #if no valid data in config file
log_message "femtofox-config.txt does not contain valid configuration info, ignoring."
log_message "\e[31mfemtofox-config.txt does not contain valid configuration info, ignoring.\e[0m"
for _ in {1..5}; do #boot code
blink "1.5" && sleep 0.5
done
exit_script 1
fi
else
log_message "USB drive mounted but femtofox-config.txt not found, ignoring."
log_message "\e[31mUSB drive mounted but femtofox-config.txt not found, ignoring.\e[0m"
for _ in {1..3}; do #boot code
blink "1.5" && sleep 0.5
done

View file

@ -0,0 +1,326 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo femto-meshtasticd-config\`."
exit 1
fi
help=$(cat <<EOF
Options are:
-h This message
-a "enable" Enable/disable ACT LED. Options: "enable" "disable" "check". If no argument is specified, setting in /etc/femto.conf will be used
-r Reboot
-s Shutdown
-l "enable" Enable/disable logging. Options: "enable" "disable" "check"
-i System info (all)
-p Peripherals info
-c CPU info
-n Networking info
-o OS info
-S Storage & RAM info
-t "enable" Enable/disable/start/stop/check ttyd (web terminal). Options: "enable" "disable" "start" "stop" "check"
-E Generate/overwrite SSH encryption keys
-C "service" Check if service is enabled, disabled, running
-R "command" Replace colors for dialog menus
-A "stop" Stop/start services that are using the meshtastic API so the Control for Meshtastic settings UI can run without interference. Options: "stop" "start"
-v Get Foxbuntu version
EOF
)
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
act_led() {
if [ "$1" = "disable" ]; then
echo "none" > /sys/class/leds/work/trigger
grep -qE '^act_led=' /etc/femto.conf && sed -i -E 's/^act_led=.*/act_led=disable/' /etc/femto.conf || echo 'act_led=disable' | tee -a /etc/femto.conf > /dev/null
echo "Disabled activity LED."
exit 0
elif [ "$1" = "enable" ]; then
echo "activity" > /sys/class/leds/work/trigger
grep -qE '^act_led=' /etc/femto.conf && sed -i -E 's/^act_led=.*/act_led=enable/' /etc/femto.conf || echo 'act_led=enable' | tee -a /etc/femto.conf > /dev/null
echo "Enabled activity LED."
exit 0
elif [ "$1" = "check" ]; then
if grep -qE '^act_led=enable' /etc/femto.conf; then
echo -e "\033[0;34menabled\033[0m"
elif grep -qE '^act_led=disable' /etc/femto.conf; then
echo -e "\033[0;31mdisabled\033[0m"
else
echo "unknown"
fi
elif [ -z $1 ]; then
local state=$(act_led "check" 2>/dev/null)
if [[ "$state" =~ "enabled" ]]; then
act_led "enable"
elif [[ "$state" =~ "disabled" ]]; then
act_led "disable"
fi
fi
}
cpu_info() {
local core="Luckfox Pico"
local cpu_model="$(tr -d '\0' </proc/device-tree/compatible | awk -F, '{print $1, $NF}')"
local cpu_architecture="$(uname -m) ($(dpkg --print-architecture) $(python3 -c "import platform; print(platform.architecture()[0])"))"
local cpu_temp="$(echo "scale=1; $(cat /sys/class/thermal/thermal_zone0/temp) / 1000" | bc)°C"
local cpu_speed="$(lscpu | grep "CPU min MHz" | awk '{print int($4)}')-$(lscpu | grep "CPU max MHz" | awk '{print int($4)}')mhz"
local cpu_serial="$(awk '/Serial/ {print $3}' /proc/cpuinfo)"
echo -e "\
Core:$core\n\
Model:$cpu_model\n\
Architecture:$cpu_architecture\n\
Speed:$cpu_speed x $(nproc) cores\n\
Temperature:$cpu_temp\n\
Serial #:$cpu_serial"
}
storage_info() {
local microsd_size="$(df --block-size=1 / | awk 'NR==2 {total=$2; avail=$4; total_human=sprintf("%.2f", total/1024/1024/1024); avail_human=sprintf("%.2f", avail/1024/1024/1024); printf "%.2f GB (%.2f%% free)", total_human, (avail/total)*100}')"
local memory="$(free -m | awk 'NR==2{printf "%d MB (%.2f%% free)\n", $2, 100 - (($3/$2)*100)}')"
local swap="$(free -m | awk 'NR==3 {if ($2 > 1000) {printf "%.2f GB (%.2f%% free)", $2/1024, ($4/$2)*100} else {printf "%d MB (%.2f%% free)", $2, ($4/$2)*100}}')"
local mounted_drives="$( [ "$(for dir in /mnt/*/; do [ -d "$dir" ] && echo -n "/mnt${dir#"/mnt"} "; done)" ] && echo "$(for dir in /mnt/*/; do [ -d "$dir" ] && echo -n "/mnt${dir#"/mnt"} "; done | sed 's/\/$//')" || echo "none" )"
echo -e "\
microSD size:$microsd_size\n\
Memory:$memory\n\
Swap:$swap\n\
Mnted drives:$mounted_drives"
}
os_info() {
local os_version="$(femto-utils.sh -v) ($(lsb_release -d | awk -F'\t' '{print $2}') $(lsb_release -c | awk -F'\t' '{print $2}'))"
local system_uptime="$(uptime -p | awk '{$1=""; print $0}' | sed -e 's/ day\b/d/g' -e 's/ hour\b/h/g' -e 's/ hours\b/h/g' -e 's/ minute\b/m/g' -e 's/ minutes\b/m/g' | sed 's/,//g')"
local kernel_active_modules="$(lsmod | awk 'NR>1 {print $1}' | tr '\n' ' ' && echo)"
local kernel_boot_modules="$(modules=$(sed -n '6,$p' /etc/modules | sed ':a;N;$!ba;s/\n/, /g;s/, $//'); [ -z "$modules" ] && echo "none" || echo "$modules")"
local kernel_modules_blacklist="$(femto-kernel-modules.sh -y | sed 's/\x1B\[[0-9;]*m//g')" #remove underline
local ttyd_enabled="$(femto-utils.sh -C "ttyd")"
local logging_enabled="$(logging "check" | sed 's/\x1b\[[0-9;]*m//g')"
local act_led="$(femto-utils.sh -a "check" | sed -r 's/\x1B\[[0-9;]*[mK]//g')" #remove color from output
echo -e "\
OS:$os_version\n\
Kernel ver:$(uname -r)\n\
Uptime:$system_uptime\n\
System time:$(date)\n\
K mods active:$kernel_active_modules\n\
K boot mods:$kernel_boot_modules\n\
K mod blcklst: $kernel_modules_blacklist
Web terminal:$ttyd_enabled\n\
Logging:$logging_enabled\n\
Activity LED:$act_led"
}
networking_info() {
local wifi_status="$(femto-network-config.sh -w | grep -v '^$' | grep -v '^Hostname')" #remove hostname line, as it's identical to the one in ethernet settings
local eth_status="$(femto-network-config.sh -e)"
echo -e "$wifi_status\n\
$eth_status"
}
peripherals_info() {
local usb_mode="$(cat /sys/devices/platform/ff3e0000.usb2-phy/otg_mode)"
local spi0_state="$([ "$(awk -F= '/^SPI0_M0_STATUS/ {print $2}' /etc/luckfox.cfg)" -eq 1 ] && echo "enabled" || echo "disabled")"
local spi0_speed="$((0x$(xxd -p /sys/firmware/devicetree/base/spi@ff500000/spidev@0/spi-max-frequency | tr -d '\n')))"
local i2c3_state="$([ "$(awk -F= '/^I2C3_M1_STATUS/ {print $2}' /etc/luckfox.cfg)" -eq 1 ] && echo "enabled" || echo "disabled")"
local i2c3_speed="$(awk -F= '/^I2C3_M1_SPEED/ {print $2}' /etc/luckfox.cfg)"
local uart3_state="$([ "$(awk -F= '/^UART3_M1_STATUS/ {print $2}' /etc/luckfox.cfg)" -eq 1 ] && echo "enabled" || echo "disabled")"
local uart4_state="$([ "$(awk -F= '/^UART4_M1_STATUS/ {print $2}' /etc/luckfox.cfg)" -eq 1 ] && echo "enabled" || echo "disabled")"
local lora_radio="$(femto-meshtasticd-config.sh -k)"
local usb_devices="$(lsusb | grep -v 'root hub' | awk 'NR>0{printf "USB:"; for(i=7;i<=NF;i++) printf "%s ", $i; print ""} END {if (NR == 0) printf "USB:none detected"}')"
# gather i2c addresses
i2c_addresses="" # initialize empty string to collect populated addresses
while IFS= read -r line; do # iterate over each row of output (captured at end of while loop)
if [[ "$line" =~ ^[0-9a-f]+: ]]; then # check if the row contains addresses (skip header row)
columns=($line) # split the line into columns based on spaces
row="${columns[0]:0:1}" # use the first numeral of the row number
for col_idx in "${!columns[@]}"; do # iterate columns
if [[ $col_idx -gt 0 && "${columns[$col_idx]}" != "--" ]]; then # skip first column (row numbers)
[[ "$row" == "0" ]] && col_idx=$((col_idx + 8)) # if first row, we start at #7, so add 8 to the column number reported
i2c_addresses+="0x$(printf "%x" "$((16#$row))")$(printf "%x" $((col_idx - 1))) " # calculate hexadecimal with '0x'
fi
done
fi
done <<< "$(echo "$(timeout 3 i2cdetect -y 3)")" # when no i2c devices are connected, i2cdetect tries to connect for a solid 25 seconds. The timeout prevents this
[[ -z "$i2c_addresses" ]] && i2c_addresses="none detected" # if no addresses found, "none detected"
echo -e "LoRa radio:$lora_radio\n\
$usb_devices\n\
i2c devices:$i2c_addresses\n\
USB mode:$usb_mode\n\
SPI-0 state:$spi0_state\n\
SPI-0 speed:$spi0_speed\n\
i2c-3 state:$i2c3_state\n\
i2c-3 speed:$i2c3_speed\n\
UART-3 state:$uart3_state\n\
UART-4 state:$uart4_state"
}
all_system_info() {
echo -e "\
Femtofox\n\
CPU:\n\
$(cpu_info)\n\
\n\
Operating System:\n\
$(os_info)\n\
\n\
Storage:\n\
$(storage_info)\n\)
\n\
Networking (wlan0 & eth0):\n\
$(networking_info)\n\
\n\
Peripherals:\n\
$(peripherals_info)\n\
\n\
Meshtasticd:\n\
$(femto-meshtasticd-config.sh -i)"
}
# enable/disable/check system logging
logging() {
if [ "$1" = "disable" ]; then
msg="Disabling system logging by making /var/log immutable."
logger $msg
echo $msg
chattr +i /var/log
return 0
elif [ "$1" = "enable" ]; then
chattr -i /var/log
msg="Enabling system logging by making /var/log writable."
logger $msg
echo $msg
return 0
elif [ "$1" = "check" ]; then
lsattr -d /var/log | grep -q 'i' && echo -e "\033[0;31mdisabled\033[0m" || echo -e "\033[0;34menabled\033[0m"
else
echo "\`$1\` is not a valid argument for -L. Options are \"enable\" and \"disable\"."
echo -e "$help"
fi
}
# Dialog uses a different method to display colors, and is limited to only these 8.
replace_colors() {
input="$1"
input="${input//$(echo -e '\033[0;30m')/\\Z0}" # black
input="${input//$(echo -e '\033[0;31m')/\\Z1}" # red
input="${input//$(echo -e '\033[0;32m')/\\Z2}" # green
input="${input//$(echo -e '\033[0;33m')/\\Z3}" # yellow
input="${input//$(echo -e '\033[0;34m')/\\Z4}" # blue
input="${input//$(echo -e '\033[0;35m')/\\Z5}" # magenta
input="${input//$(echo -e '\033[0;36m')/\\Z6}" # cyan
input="${input//$(echo -e '\033[0;37m')/\\Z7}" # white
input="${input//$(echo -e '\033[7m')/\\Zr}" # invert
input="${input//$(echo -e '\033[4m')/\\Zu}" # underline
input="${input//$(echo -e '\e[39m')/\\Z0}" # reset colors not underline
input="${input//$(echo -e '\033[0m')/\\Zn}" # reset all
echo "$input"
}
while getopts ":harsl:ipcnoSEC:R:A:v" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
a) # Option -a (ACT LED enable/disable/check)
act_led $2
exit 0 # exit immediately for boot speed
;;
r) # Option -r (reboot)
echo -e "Rebooting..."
reboot
;;
s) # Option -s (shutdown)
echo -e "Shutting down...\n\nPower consumption will not stop."
logger "User requested system halt"
halt
;;
l) logging $OPTARG ;; # Option -l (Logging enable/disable/check)
i) all_system_info ;; # Option -i (sysinfo)
p) peripherals_info ;; # Option -p (Peripherals info)
c) cpu_info ;; # Option -c (CPU info)
n) networking_info ;; # Option -n (Networing info)
o) os_info ;; # Option -o (OS info)
S) storage_info ;; # Option -S (Storage & RAM info)
E) # Option -E (new SSH encryption keys)
rm /etc/ssh/ssh_host_*
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
chmod 600 /etc/ssh/ssh_host_*_key
chmod 644 /etc/ssh/ssh_host_*_key.pub
chown root:root /etc/ssh/ssh_host_*
systemctl restart ssh
;;
C) # Option -C (Check service status)
if systemctl is-enabled $OPTARG &>/dev/null; then
state_message="\033[0;34m\033[4menabled\033[0m, "
else
state_message="\033[0;31m\033[4mdisabled\033[0m, "
fi
full_status=$(systemctl status $OPTARG)
if echo $full_status | grep -q "active (running)"; then
state_message+="\033[4m\033[0;34mrunning\033[0m"
exit_state=0
elif echo $full_status | grep -q "inactive (dead)"; then
state_message+="\033[4m\033[0;31mnot running\033[0m"
exit_state=1
elif echo $full_status | grep -q "failed"; then
state_message+="\033[4m\033[0;31mfailed\033[0m"
exit_state=1
elif echo $full_status | grep -q "activating"; then
state_message+="\033[4mactivating\033[0m"
exit_state=2
else
state_message+="\033[4munknown\033[0m"
exit_state=2
fi
echo -e "$state_message"
exit $exit_state
;;
R) # replace colors)
replace_colors "$OPTARG"
;;
A) # Stop/start services that are using the meshtastic API)
# this code cycles through all the software packages and looks for ones that are installed, conflict with Control and have a service that is enabled. If it finds such a software package, it either stops or starts it, according to $OPTARG
if [[ $OPTARG == "stop" ]]; then
action_text="Stopping"
action="s"
elif [[ $OPTARG == "start" ]]; then
action_text="Starting"
action="r"
else
echo "\`$OPTARG\` is not a valid argument for -A. Options are \"stop\" and \"start\"."
echo -e "$help"
exit 1
fi
for file in /usr/local/bin/packages/*.sh; do
filename=$(basename "$file")
[[ "$filename" == femto_* ]] && continue # Skip files starting with "femto_"
if sudo "$file" -I; then
if echo "$(sudo "$file" -C)" | grep -q "\"full control\" Meshtastic software"; then
service_state=$(sudo femto-utils.sh -C "$(sudo $file -E)")
if [[ $service_state =~ "enabled" ]] ; then
echo "$action_text $(sudo $file -N) service..."
eval "sudo $file -$action"
fi
fi
fi
done
;;
v) # get foxbuntu version)
echo "Foxbuntu v$(grep -oP 'major=\K[0-9]+' /etc/foxbuntu-release).$(grep -oP 'minor=\K[0-9]+' /etc/foxbuntu-release).$(grep -oP 'patch=\K[0-9]+' /etc/foxbuntu-release)$(grep -oP 'hotfix=\K\S+' /etc/foxbuntu-release)"
;;
\?) # Unknown argument)
echo -e "Unknown argument $1.\n$help"
;;
esac
done

View file

@ -0,0 +1,58 @@
#!/usr/bin/env bash
THRESHOLD=$((7 * 24 * 60 * 60)) # 1 week in seconds
LOGFILE="/var/log/time_change.log"
LAST_TIME_FILE="/tmp/last_time"
# Ensure the log file exists and is writable
if [ ! -f "$LOGFILE" ]; then
touch "$LOGFILE" || { echo "ERROR: Cannot create log file $LOGFILE"; exit 1; }
fi
if [ ! -w "$LOGFILE" ]; then
echo "ERROR: Log file $LOGFILE is not writable"
exit 1
fi
# Ensure the last time file exists and is writable
if [ ! -f "$LAST_TIME_FILE" ]; then
date +%s > "$LAST_TIME_FILE" || { echo "ERROR: Cannot create last time file $LAST_TIME_FILE"; exit 1; }
fi
if [ ! -w "$LAST_TIME_FILE" ]; then
echo "ERROR: Last time file $LAST_TIME_FILE is not writable"
exit 1
fi
while true; do
# Check if meshtasticd service is running
if ! systemctl is-active --quiet meshtasticd; then
#echo "meshtasticd service is not running. Skipping..." | tee -a "$LOGFILE"
sleep 30
continue
fi
NEW_TIME=$(date +%s)
# Ensure last_time file is readable before using it
if [ ! -r "$LAST_TIME_FILE" ]; then
echo "ERROR: Last time file $LAST_TIME_FILE is not readable" | tee -a "$LOGFILE"
exit 1
fi
OLD_TIME=$(cat "$LAST_TIME_FILE")
TIME_DIFF=$((NEW_TIME - OLD_TIME))
if [ "${TIME_DIFF#-}" -ge "$THRESHOLD" ]; then
echo "$(date) - Large time change detected ($TIME_DIFF seconds), restarting meshtasticd" | tee -a "$LOGFILE"
systemctl restart meshtasticd
fi
# Ensure last_time file is writable before updating it
if [ -w "$LAST_TIME_FILE" ]; then
echo "$NEW_TIME" > "$LAST_TIME_FILE"
else
echo "ERROR: Failed to write to $LAST_TIME_FILE" | tee -a "$LOGFILE"
exit 1
fi
sleep 30
done

View file

@ -17,11 +17,13 @@ get_mobile_wifi_state() {
set_mobile_wifi_state() {
local state="$1"
local meshtastic_output
if [[ "$state" == "up" ]]; then
meshtastic_output=$(meshtastic --host 127.0.0.1 --set network.wifi_enabled true 2>&1)
meshtastic_output=$(meshtastic --host 127.0.0.1 --set network.wifi_enabled true 2>&1 || true)
else
meshtastic_output=$(meshtastic --host 127.0.0.1 --set network.wifi_enabled false 2>&1)
meshtastic_output=$(meshtastic --host 127.0.0.1 --set network.wifi_enabled false 2>&1 || true)
fi
log "Set Meshtastic Wi-Fi state to $state. Output: $meshtastic_output"
}
@ -67,8 +69,8 @@ monitor_changes() {
while true; do
PID=$(ps -C meshtasticd -o pid= | tr -d ' ')
#if [[ -n "$PID" ]] && sudo lsof /dev/spidev0.0 | grep -q "$PID"; then
if [[ -n "$PID" ]] && sudo lsof /dev/spidev0.0 | grep -q "$PID" && [[ -d /sys/class/net/wlan0 ]]; then
#if [[ -n "$PID" ]] && sudo lsof /dev/spidev0.0 | grep -q "$PID" && [[ -d /sys/class/net/wlan0 ]]; then
if [[ -n "$PID" ]] && sudo lsof /dev/spidev0.0 | grep -q "$PID" && [[ -d /sys/class/net/wlan0 ]] && systemctl is-active --quiet meshtasticd; then
local current_mobile_state current_wlan_state
current_mobile_state=$(get_mobile_wifi_state)
current_wlan_state=$(cat /sys/class/net/wlan0/operstate)

View file

@ -1,58 +1,25 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo femto-meshtasticd-config\`."
exit 1
fi
args="$@" # arguments to this script
interactive="true"
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interactive unavailable)
Actions:
-i Install
-u Uninstall
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-L Get Install location
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't really possible
# Arguments to the script are stored in $args
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interactive="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
name="Contact" # software name
author="pdxlocations" # software author - OPTIONAL
description="A Text-Based Console UI for Meshtastic Nodes.\nAfter install, run \`contact\` to launch." # software description - OPTIONAL (but strongly recommended!)
description="A Text-Based Console UI for Meshtastic Nodes. Formerly called Curses Client.\nAfter install, run \`contact\` to launch." # software description - OPTIONAL (but strongly recommended!)
URL="https://github.com/pdxlocations/contact/" # software URL. Can contain multiple URLs - OPTIONAL
options="xiuglNADUOLIto" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="python /opt/contact/main.py --host" # command to launch software, if applicable
options="xiuglNADUOLGTCI" # script options in use by software package. For example, for a package with no service, exclude `edsrS`
launch="echo \"Stopping conflicting services (if any), will restart after exit...\" && sudo femto-utils.sh -A stop && sudo -u ${SUDO_USER:-$(whoami)} env LANG=$LANG TERM=$TERM NCURSES_NO_UTF8_ACS=$NCURSES_NO_UTF8_ACS python /opt/contact/main.py --host && echo \"Restarting conflicting services (if any)...\" && sudo femto-utils.sh -A start" # command to launch software, if applicable
service_name="" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
location="/opt/contact" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
conflicts="" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
license="$location/LICENSE" # file to cat to display license
license_name="GPL3" # license name, such as MIT, GPL3, custom, whatever. short text string.
conflicts="\"Full control\" Meshtastic software, such as TC²-BBS and Meshing Around - but only while running." # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
if [ $# -eq 0 ]; then
@ -68,6 +35,7 @@ install() {
echo "user_message: Git clone failed. Is internet connected?"
exit 1
fi
pip install -r $location/requirements.txt
chown -R femto $location #give ownership of installation directory to $user
git config --global --add safe.directory $location # prevents git error when updating
echo "Creating \`contact\` shortcut."
@ -85,7 +53,9 @@ $launch" | sudo tee /usr/local/bin/contact > /dev/null
# uninstall script
uninstall() {
rm -rf $location
echo "Removed \`$location\`."
rm /usr/local/bin/contact
echo "Removed \`contact\` shortcut."
echo "user_message: All files removed."
exit 0 # should be `exit 1` if the installation failed
}
@ -113,53 +83,12 @@ check() {
fi
}
while getopts ":h$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
interactive="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
sudo -u ${SUDO_USER:-$(whoami)} $launch
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
L) echo -e $location ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
esac
done
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -0,0 +1,74 @@
#!/bin/bash
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
name="Control for Meshtastic" # software name
author="pdxlocations" # software author - OPTIONAL
description="Control for Meshtastic is a fully-featured Meshtastic configuration tool made for running in console, utilizing Curses.\n\nControl is installed by default on Femtofox and is used for Meshtastic configuration in femto-config. Uninstallation is not recommended." # software description - OPTIONAL (but strongly recommended!)
URL="https://github.com/pdxlocations/control" # software URL. Can contain multiple URLs - OPTIONAL
options="hxiuglNADUOLGTIC" # script options in use by software package. For example, for a package with no service, exclude `edsrS`
launch="echo \"Stopping conflicting services (if any), will restart after exit...\" && sudo femto-utils.sh -A stop && sudo -u ${SUDO_USER:-$(whoami)} env LANG=$LANG TERM=$TERM NCURSES_NO_UTF8_ACS=$NCURSES_NO_UTF8_ACS python /opt/control/main.py --host && echo \"Restarting conflicting services (if any)...\" && sudo femto-utils.sh -A start" # command to launch software, if applicable
license="/opt/control/LICENSE" # file to cat to display license
location="/opt/control" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
license="$location/LICENSE" # file to cat to display license
license_name="GPL3" # license name, such as MIT, GPL3, custom, whatever. short text string
conflicts="\"Full control\" Meshtastic software, such as TC²-BBS and Meshing Around - but only while running." # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
if ! git clone https://github.com/pdxlocations/control.git /opt/control; then
echo "user_message: Git clone failed. Is internet connected?"
exit 1
fi
pip install -r $location/requirements.txt
chown -R femto $location #give ownership of installation directory to $user
git config --global --add safe.directory $location # prevents git error when updating
echo "user_message: To launch, go to Meshtastic settings. Launching manually may conflict with \`full control\` Meshtastic software such as BBS."
exit 0 # should be `exit 1` if operation failed
}
# uninstall script
uninstall() {
rm -rf $location
echo "Removed \`$location\`."
echo "user_message: All files removed."
exit 0 # should be `exit 1` if operation failed
}
#upgrade script
upgrade() {
cd $location
if ! git pull; then
echo "user_message: Git pull failed. Is internet connected?"
exit 1
fi
exit 0
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
#the following works for cloned repos, but not for apt installs
if [ -d "$location" ]; then
#echo "Already installed"
exit 0
else
#echo "Not installed"
exit 1
fi
}
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -0,0 +1,106 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo\`."
exit 1
fi
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
interactive="true" # by default, we're in interactive mode
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interaction unavailable)
Actions:
-i Install
-u Uninstall
-a Interactive initialization script: code that must be run to initialize the installation prior to use, but can only be run from terminal
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-E Get service name
-L Get install location
-G Get license
-T Get license name
-P Get package name
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
while getopts ":$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
interactive="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
a) # Option -a (interactive initialization)
interactive_init
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
eval "$launch"
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
E) # Option -E (Get service name)
echo $service_name
;;
L) echo -e $location ;;
G) # Option -G (Get license)
license
;;
T) # Option -T (Get license name)
echo $license_name
;;
P) echo -e $package_name ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
\?) exit 1 ;; # Unknown option)
esac
done

View file

@ -0,0 +1,87 @@
#!/bin/bash
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
name="name" # software name
author="author" # software author - OPTIONAL
description="description" # software description - OPTIONAL (but strongly recommended!)
URL="URL" # software URL. Can contain multiple URLs - OPTIONAL
options="hxiuagedsrlNADUOSELGTPCI" # script options in use by software package. For example, for a package with no service, exclude `edsrS`
launch="/opt/package/run.sh" # command to launch software, if applicable
license="/opt/package/license" # file to cat to display license
service_name="service_name" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
package_name="apt_package" # apt package name, if applicable. Can be multiple packages separated by spaces, but if at least one is installed the package will show as "installed" even if the others aren't
location="/opt/location" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
license="$location/LICENSE" # file to cat to display license
license_name="GPL3" # license name, such as MIT, GPL3, custom, whatever. short text string
conflicts="package1, package2" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
# for apt packages, this method allows onscreen output during install:
# DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty || { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
# DEBIAN_FRONTEND=noninteractive apt-get install $package_name -y 2>&1 | tee /dev/tty || { echo "user_message: apt install failed. Is internet connected?"; exit 1; }
echo "user_message: Exit message to user, displayed prominently in post-install"
exit 0 # should be `exit 1` if operation failed
}
# uninstall script
uninstall() {
echo "user_message: Exit message to user, displayed prominently in post-install"
exit 0 # should be `exit 1` if operation failed
}
# code that must be run to initialize the installation prior to use, but can only be run from terminal
interactive_init() {
exit 0 # should be `exit 1` if operation failed
}
# upgrade script
upgrade() {
echo "user_message: Exit message to user, displayed prominently in post-install"
exit 0 # should be `exit 1` if operation failed
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
## the following works for cloned repos, but not for apt installs
# if [ -d "$location" ]; then
# exit 0
# else
# exit 1
# fi
## this works for apt packages
# if dpkg-query -W -f='${Status}' $package_name 2>/dev/null | grep -q "install ok installed"; then
# exit 0
# else
# exit 1
# fi
}
# display license - limit to 2000 chars
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
## custom getopts example for this package
# if [[ "$1" == "-k" ]]; then
# generate_keys
# fi
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
# extra help example for this package
# if [[ "$1" == "-h" ]]; then
# echo -e "Additional argument for this package:\n\
# -k Generate SSL keys. Must be first argument."
# fi
exit 0

View file

@ -1,48 +1,9 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo\`."
exit 1
fi
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
args="$@" # arguments to this script
interactive="true"
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interactive unavailable)
Actions:
-i Install
-u Uninstall
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-L Get Install location
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't really possible
# Arguments to the script are stored in $args
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interactive="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
@ -52,11 +13,13 @@ name="Meshing Around" # software name
author="Spud" # software author - OPTIONAL
description="Meshing Around is a feature-rich bot designed to enhance your Meshtastic network experience with a variety of powerful tools and fun features. Connectivity and utility through text-based message delivery. Whether you're looking to perform network tests, send messages, or even play games, mesh_bot.py has you covered." # software description - OPTIONAL (but strongly recommended!)
URL="https://github.com/SpudGunMan/meshing-around" # software URL. Can contain multiple URLs - OPTIONAL
options="xiugedsrNADUOSLCIto" # script options in use by software package. For example, for a package with no service, exclude `edsr`
options="xiugedsrNADUOSELGTCI" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="" # command to launch software, if applicable
service_name="mesh_bot pong_bot mesh_bot_reporting" # the name of the service, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
service_name="mesh_bot" # the name of the service, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
location="/opt/meshing-around" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
conflicts="TC²-BBS, any other \"full control\" style bots" # comma delineated plain-text list of packages with which this package conflicts. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
license="$location/LICENSE" # file to cat to display license
license_name="GPL3" # license name, such as MIT, GPL3, custom, whatever. short text string
conflicts="TC²-BBS, other \"full control\" Meshtastic software, Control (only when running)." # comma delineated plain-text list of packages with which this package conflicts. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
@ -64,6 +27,7 @@ install() {
echo "user_message: Git clone failed. Is internet connected?"
exit 1
fi
pip install -r $location/requirements.txt
if [ "$interactive" = "true" ]; then #interactive install
"$location/install.sh" | tee /dev/tty
echo "user_message: To change settings, run \`sudo nano $location/config.ini\`"
@ -74,7 +38,6 @@ install() {
fi
}
# uninstall script
uninstall() {
# stop, disable and remove the service, reload systemctl daemon, remove the installation directory and quit
@ -96,6 +59,10 @@ uninstall() {
exit 0
}
# code that must be run to initialize the installation prior to use, but can only be run from terminal
interactive_init() {
exit 0
}
#upgrade script
upgrade() {
@ -117,54 +84,12 @@ check() {
fi
}
while getopts ":h$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
echo "Running in non-interactive mode"
interactive="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
sudo -u ${SUDO_USER:-$(whoami)} $launch
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
L) echo -e $location ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
esac
done
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -1,48 +1,9 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo\`."
exit 1
fi
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
args="$@" # arguments to this script
interaction="true"
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interaction unavailable)
Actions:
-i Install
-u Uninstall
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-L Get Install location
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't really possible
# Arguments to the script are stored in $args
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
@ -53,17 +14,20 @@ name="Mosquitto MQTT Broker" # software name
author="Eclipse Foundation" # software author - OPTIONAL
description="Eclipse Mosquitto is an open source (EPL/EDL licensed) message broker that implements the MQTT protocol versions 5.0, 3.1.1 and 3.1. Mosquitto is lightweight and is suitable for use on all devices from low power single board computers to full servers.\n\nThe MQTT protocol provides a lightweight method of carrying out messaging using a publish/subscribe model. This makes it suitable for Internet of Things messaging such as with low power sensors or mobile devices such as phones, embedded computers or microcontrollers.\n\nThe Mosquitto project also provides a C library for implementing MQTT clients, and the very popular mosquitto_pub and mosquitto_sub command line MQTT clients.\n\nMosquitto is part of the Eclipse Foundation, and is an iot.eclipse.org project. The development is driven by Cedalo." # software description - OPTIONAL (but strongly recommended!)
URL="https://mosquitto.org/" # software URL. Can contain multiple URLs - OPTIONAL
options="xiugedslNADUOSLCIto" # script options in use by software package. For example, for a package with no service, exclude `edsr`
options="xiugedsrNADUOSEGTPCI" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="" # command to launch software, if applicable
service_name="mosquitto" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
package_name="mosquitto" # apt package name, if applicable
location="" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
license="usr/share/doc/mosquitto/copyright" # file to cat to display license
license_name="EPL/EDL" # license name, such as MIT, GPL3, custom, whatever. short text string
conflicts="" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
echo "apt update can take a long while..."
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
DEBIAN_FRONTEND=noninteractive apt-get install mosquitto -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
DEBIAN_FRONTEND=noninteractive apt-get install $package_name -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt install failed. Is internet connected?"; exit 1; }
echo "user_message: Installation requires more setup. For a guide, see https://docs.vultr.com/how-to-install-mosquitto-mqtt-broker-on-ubuntu-24-04"
exit 0 # should be `exit 1` if operation failed
}
@ -71,7 +35,7 @@ install() {
# uninstall script
uninstall() {
DEBIAN_FRONTEND=noninteractive apt remove -y mosquitto 2>&1 | tee /dev/tty
DEBIAN_FRONTEND=noninteractive apt remove -y $package_name 2>&1 | tee /dev/tty
/usr/local/bin/mosquitto_mqtt_broker.sh -s # stop service
/usr/local/bin/mosquitto_mqtt_broker.sh -d # disable service
echo "user_message: Some files may remain on system. To remove, run \`sudo apt remove --purge mosquitto -y\` and \`sudo apt autoremove -y\`."
@ -82,67 +46,26 @@ uninstall() {
#upgrade script
upgrade() {
echo "apt update can take a long while..."
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
DEBIAN_FRONTEND=noninteractive apt upgrade -y mosquitto 2>&1 | tee /dev/tty
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
DEBIAN_FRONTEND=noninteractive apt upgrade -y $package_name 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt upgrade failed. Is internet connected?"; exit 1; }
exit 0 # should be `exit 1` if operation failed
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
if dpkg -l | grep -q mosquitto; then
if dpkg-query -W -f='${Status}' $package_name 2>/dev/null | grep -q "install ok installed"; then
exit 0
else
exit 1
fi
}
while getopts ":h$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
interaction="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
sudo -u ${SUDO_USER:-$(whoami)} $launch
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
L) echo -e $location ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
esac
done
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -1,48 +1,9 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo\`."
exit 1
fi
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
args="$@" # arguments to this script
interaction="true"
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interaction unavailable)
Actions:
-i Install
-u Uninstall
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-L Get Install location
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't really possible
# Arguments to the script are stored in $args
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
@ -53,17 +14,20 @@ name="Mosquitto MQTT Client" # software name
author="Eclipse Foundation" # software author - OPTIONAL
description="Eclipse Mosquitto is an open source (EPL/EDL licensed) message broker that implements the MQTT protocol versions 5.0, 3.1.1 and 3.1. Mosquitto is lightweight and is suitable for use on all devices from low power single board computers to full servers.\n\nThe MQTT protocol provides a lightweight method of carrying out messaging using a publish/subscribe model. This makes it suitable for Internet of Things messaging such as with low power sensors or mobile devices such as phones, embedded computers or microcontrollers.\n\nThe Mosquitto project also provides a C library for implementing MQTT clients, and the very popular mosquitto_pub and mosquitto_sub command line MQTT clients.\n\nMosquitto is part of the Eclipse Foundation, and is an iot.eclipse.org project. The development is driven by Cedalo." # software description - OPTIONAL (but strongly recommended!)
URL="https://mosquitto.org/" # software URL. Can contain multiple URLs - OPTIONAL
options="xiugedslNADUOSLCIto" # script options in use by software package. For example, for a package with no service, exclude `edsr`
options="xiugedsrNADUOSEGTPCI" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="" # command to launch software, if applicable
service_name="" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
location="" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
license="usr/share/doc/mosquitto-clients/copyright" # file to cat to display license
license_name="EPL/EDL" # license name, such as MIT, GPL3, custom, whatever. short text string
package_name="mosquitto-clients" # apt package name, if applicable
conflicts="" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
echo "apt update can take a long while..."
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
DEBIAN_FRONTEND=noninteractive apt-get install mosquitto-clients -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
DEBIAN_FRONTEND=noninteractive apt-get install $package_name -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt install failed. Is internet connected?"; exit 1; }
echo "user_message: Installation requires more setup. For a guide, see https://docs.vultr.com/how-to-install-mosquitto-mqtt-broker-on-ubuntu-24-04"
exit 0 # should be `exit 1` if operation failed
}
@ -80,67 +44,26 @@ uninstall() {
#upgrade script
upgrade() {
echo "apt update can take a long while..."
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
DEBIAN_FRONTEND=noninteractive apt upgrade -y mosquitto-clients 2>&1 | tee /dev/tty
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
DEBIAN_FRONTEND=noninteractive apt upgrade -y $package_name 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt upgrade failed. Is internet connected?"; exit 1; }
exit 0 # should be `exit 1` if operation failed
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
if dpkg -l | grep -q mosquitto-clients; then
if dpkg-query -W -f='${Status}' $package_name 2>/dev/null | grep -q "install ok installed"; then
exit 0
else
exit 1
fi
}
while getopts ":h$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
interaction="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
sudo -u ${SUDO_USER:-$(whoami)} $launch
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
L) echo -e $location ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
esac
done
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -1,150 +0,0 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo\`."
exit 1
fi
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
args="$@" # arguments to this script
interaction="true"
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interaction unavailable)
Actions:
-i Install
-u Uninstall
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-L Get Install location
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't really possible
# Arguments to the script are stored in $args
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
name="name" # software name
author="author" # software author - OPTIONAL
description="description" # software description - OPTIONAL (but strongly recommended!)
URL="URL" # software URL. Can contain multiple URLs - OPTIONAL
options="xiugedsrlNADUOSLCIto" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="" # command to launch software, if applicable
service_name="service_name" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
location="/opt/location" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
conflicts="package name, other package name" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
# for apt packages, this method allows onscreen output during install:
# DEBIAN_FRONTEND=noninteractive sudo apt-get install mosquitto -y 2>&1 | tee /dev/tty # allows output to be shown onscreen
echo "user_message: Exit message to user, displayed prominently in post-install"
exit 0 # should be `exit 1` if operation failed
}
# uninstall script
uninstall() {
echo "user_message: Exit message to user, displayed prominently in post-install"
exit 0 # should be `exit 1` if operation failed
}
# upgrade script
upgrade() {
echo "user_message: Exit message to user, displayed prominently in post-install"
exit 0 # should be `exit 1` if operation failed
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
# the following works for cloned repos, but not for apt installs
if [ -d "$location" ]; then
exit 0
else
exit 1
fi
# this works for apt packages
if [ dpkg -l | grep -q package-name ] ; then
exit 0
else
exit 1
fi
}
while getopts ":h$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
interaction="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
sudo -u ${SUDO_USER:-$(whoami)} $launch
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
L) echo -e $location ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
esac
done
exit 0

View file

@ -0,0 +1,83 @@
#!/bin/bash
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
user_message="To connect to network share, enter \`\\\\femtofox\\home\` in Windows, \`smb://$(hostname)/home\` in MacOS or \`smbclient //$(hostname)/femto -U femto\` in Linux. Default configuration shares /home/femto. Edit \`/etc/samba/smb.conf\` to add other shares.\n\nTroubleshooting: if Windows refuses to connect after succeeding previously, hit [win]+R and enter \`net use * /delete\`."
init_instructions="To enable file sharing, run \`Initialize\` in the femto-config Samba menu to set a Samba password."
name="Samba File Sharing" # software name
author="Software Freedom Conservancy" # software author - OPTIONAL
description="Femtofox comes with Samba preinstalled but disabled. $init_instructions\n\n$user_message" # software description - OPTIONAL (but strongly recommended!)
URL="https://www.samba.org/" # software URL. Can contain multiple URLs - OPTIONAL
options="xiuagedsrNADUOSEGTPCI" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="" # command to launch software, if applicable
service_name="smbd nmbd" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
location="" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
license="/usr/share/doc/samba/copyright" # file to cat to display license
license_name="GPL3" # license name, such as MIT, GPL3, custom, whatever. short text string
package_name="samba" # apt package name, if applicable
conflicts="" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
echo "apt update can take a long while..."
# DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
# DEBIAN_FRONTEND=noninteractive apt-get install $package_name -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt install failed. Is internet connected?"; exit 1; }
if [ "$interactive" = "true" ]; then # interactive install
interactive_init
else # noninteractive installation (such as web-UI)
echo -e "user_message: IMPORTANT: $init_instructions\n\n$user_message"
exit 0 # should be `exit 1` if operation failed
fi
}
# uninstall script
uninstall() {
DEBIAN_FRONTEND=noninteractive apt remove -y $package_name 2>&1 | tee /dev/tty
echo "user_message: Some files may remain on system. To remove, run \`sudo apt remove --purge $package_name -y\` and \`sudo apt autoremove -y\`."
exit 0 # should be `exit 1` if operation failed
}
# code that must be run to initialize the installation prior to use, but can only be run from terminal
interactive_init() {
echo -e "\nSet user \`Femto\` login password:"
smbpasswd -a femto
/usr/local/bin/packages/samba.sh -e
/usr/local/bin/packages/samba.sh -r
echo -e "user_message: Samba initialized, and service enabled and started. $user_message"
exit 0
}
# upgrade script
upgrade() {
echo "apt update can take a long while..."
DEBIAN_FRONTEND=noninteractive apt-get update -y 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt update failed. Is internet connected?"; exit 1; }
DEBIAN_FRONTEND=noninteractive apt upgrade -y $package_name 2>&1 | tee /dev/tty | grep -q "Err" && { echo "user_message: apt upgrade failed. Is internet connected?"; exit 1; }
exit 0 # should be `exit 1` if operation failed
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
if dpkg-query -W -f='${Status}' $package_name 2>/dev/null | grep -q "install ok installed"; then
exit 0
else
exit 1
fi
}
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -1,63 +1,26 @@
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Try \`sudo\`."
exit 1
fi
if [ $# -eq 0 ]; then
echo "No arguments provided."
echo -e "$help"
exit 1
fi
args="$@" # arguments to this script
interactive="true"
help=$(cat <<EOF
Arguments:
-h This message
Environment - must be first argument:
-x User UI is not terminal (script interactive unavailable)
Actions:
-i Install
-u Uninstall
-g Upgrade
-e Enable service, if applicable
-d Disable service, if applicable
-s Stop service
-r Start/Restart
-l Command to run software
Information:
-N Get name
-A Get author
-D Get description
-U Get URL
-O Get options supported by this script
-S Get service status
-L Get Install location
-C Get Conflicts
-I Check if installed. Returns an error if not installed
EOF
)
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't really possible
# Arguments to the script are stored in $args
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interactive="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
name="TC2-BBS" # software name
name="TC²-BBS" # software name
author="The Comms Channel" # software author - OPTIONAL
description="The TC²-BBS system integrates with Meshtastic devices. The system allows for message handling, bulletin boards, mail systems, and a channel directory." # software description - OPTIONAL (but strongly recommended!)
URL="https://github.com/TheCommsChannel/TC2-BBS-mesh" # software URL. Can contain multiple URLs - OPTIONAL
options="xiugedsrlNADUOSLCIto" # script options in use by software package. For example, for a package with no service, exclude `edsr`
options="xiugedsrNADUOSELGTCI" # script options in use by software package. For example, for a package with no service, exclude `edsr`
launch="python /opt/TC2-BBS-mesh/server.py" # command to launch software, if applicable
service_name="mesh-bbs" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
location="/opt/TC2-BBS-mesh" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
conflicts="Meshing Around, other \"full control\" packages" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
license="$location/LICENSE" # file to cat to display license
license_name="GPL3" # license name, such as MIT, GPL3, custom, whatever. short text string
conflicts="Meshing Around, other \"full control\" Meshtastic software, Control (only when running)." # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
@ -65,6 +28,7 @@ install() {
echo "user_message: Git clone failed. Is internet connected?"
exit 1
fi
pip install -r $location/requirements.txt
chown -R femto $location #give ownership of installation directory to $user
git config --global --add safe.directory $location # prevents git error when updating
@ -93,7 +57,9 @@ uninstall() {
systemctl stop $service_name
rm /etc/systemd/system/$service_name.service
systemctl daemon-reload
echo "Disabled and removed \`$service_name\` service."
rm -rf $location
echo "Removed \`$location\`."
echo "user_message: Service removed, all files deleted."
exit 0
}
@ -119,53 +85,12 @@ check() {
fi
}
while getopts ":h$options" opt; do
case ${opt} in
h) # Option -h (help)
echo -e "$help"
;;
x) # Option -x (no user interaction available)
interactive="false"
;;
i) # Option -i (install)
install
;;
u) # Option -u (uninstall)
uninstall
;;
g) # Option -g (upgrade)
upgrade
;;
e) # Option -e (Enable service, if applicable)
systemctl enable $service_name
;;
d) # Option -d (Disable service, if applicable)
systemctl disable $service_name
;;
s) # Option -s (Stop service)
systemctl stop $service_name
;;
r) # Option -r (Start/Restart)
systemctl restart $service_name
;;
l) # Option -l (Run software)
echo "Launching $name..."
sudo -u ${SUDO_USER:-$(whoami)} $launch
;;
N) echo -e $name ;;
A) echo -e $author ;;
D) echo $description ;;
U) echo -e $URL ;;
O) echo -e $options ;;
S) # Option -S (Get service status)
systemctl status $service_name
;;
L) echo -e $location ;;
C) echo -e $conflicts ;;
I) # Option -I (Check if already installed)
check
;;
esac
done
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
exit 0

View file

@ -0,0 +1,110 @@
#!/bin/bash
### For package maintainer:
# Fill the following fields and choose the options that are in use by this package
# Populate the install, uninstall and upgrade functions
# Remember that this script may be launched in terminal, via web UI or another method, so inputs aren't always possible
# This system supports both interactive and non-interactive installs. For non-interactive installs, $interaction="false". In this cause special instructions to the user should be given as user_message, such as `After installation, edit /opt/software/config.ini`
# Successful operations should `exit 0`, fails should `exit 1`
# Messages to the user (such as configuration instructions, explanatory error messages, etc) should be given as: `echo "user_message: text"`
# Everything following `user_message: ` will be displayed prominently to the user, so it must the last thing echoed
name="ttyd Web Terminal" # software name
author="Shuanglei Tao" # software author - OPTIONAL
description="ttyd is a simple command-line tool for sharing terminal over the web.\n\nWhen running, ttyd is available at https://$(hostname).local:7681\nttyd is installed and enabled by default on Foxbuntu.\n\nSSL encryption is provided by keys generated during first-boot or during installation. Your browser may give a warning (net::ERR_CERT_AUTHORITY_INVALID) about the self-signed encryption certificate. This is normal. In Chromium (Chrome, Edge) click \"Advanced\" and \"Continue to femtofox.local (unsafe)\"" # software description - OPTIONAL (but strongly recommended!)
URL="https://github.com/tsl0922/ttyd" # software URL. Can contain multiple URLs - OPTIONAL
options="hxiugedsrNADUOSELGTCIk" # script options in use by software package. For example, for a package with no service, exclude `edsrS`
launch="" # command to launch software, if applicable
service_name="ttyd" # the name of the service/s, such as `chrony`. REQUIRED if service options are in use. If multiple services, separate by spaces "service1 service2"
package_name="" # apt package name, if applicable. Can be multiple packages separated by spaces, but if at least one is installed the package will show as "installed" even if the others aren't
location="/opt/ttyd" # install location REQUIRED if not apt installed. Generally, we use `/opt/software-name`
license="$location/LICENSE" # file to cat to display license
license_name="MIT" # license name, such as MIT, GPL3, custom, whatever. short text string
conflicts="" # comma delineated plain-text list of packages with which this package conflicts. Blank if none. Use the name as it appears in the $name field of the other package. Extra plaintext is allowed, such as "packageA, packageB, any other software that uses the Meshtastic CLI"
# install script
install() {
mkdir $location
if ! wget -P "$location/" https://raw.githubusercontent.com/tsl0922/ttyd/refs/heads/main/LICENSE; then # we are required by ttyd to download and store the license
echo "user_message: Download failed. Is internet connected?"
exit 1
fi
if ! wget -qO- https://api.github.com/repos/tsl0922/ttyd/releases/latest | grep "browser_download_url" | grep "armhf" | cut -d '"' -f 4 | xargs wget -O $location/ttyd; then
echo "user_message: Download failed. Is internet connected?"
exit 1
fi
chmod +x /opt/ttyd/ttyd
echo "Generating SSL keys..."
generate_keys
systemctl enable ttyd
systemctl start ttyd
echo "user_message: ttyd service started and should be available at https://$(hostname).local:7681"
exit 0 # should be `exit 1` if operation failed
}
# uninstall script
uninstall() {
systemctl disable ttyd
systemctl stop ttyd
rm -rf $location
echo "user_message: Binary removed. Service has been disabled but service file retained. SSL encryption keys have been retained."
exit 0 # should be `exit 1` if operation failed
}
# code that must be run to initialize the installation prior to use, but can only be run from terminal
interactive_init() {
exit 0 # should be `exit 1` if operation failed
}
# upgrade script
upgrade() {
systemctl stop ttyd
if ! wget -qO- https://api.github.com/repos/tsl0922/ttyd/releases/latest | grep "browser_download_url" | grep "armhf" | cut -d '"' -f 4 | xargs wget -O $location/ttyd; then
echo "user_message: Download failed. Is internet connected?"
exit 1
fi
systemctl start ttyd
echo "user_message: New binary downloaded and service restarted."
exit 0 # should be `exit 1` if operation failed
}
# Check if already installed. `exit 0` if yes, `exit 1` if no
check() {
# the following works for cloned repos, but not for apt installs
if [ -d "$location" ]; then
exit 0
else
exit 1
fi
}
# display license
license() {
echo -e "Contents of $license:\n\n $([[ -f "$license" ]] && awk -v max=2000 -v file="$license" '{ len += length($0) + 1; if (len <= max) print; else if (!cut) { cut=1; printf "%s...\n\nFile truncated, see %s for complete license.", substr($0, 1, max - len + length($0)), file; exit } }' "$license")"
}
# custom for this package
generate_keys() {
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -keyout /etc/ssl/private/ttyd.key -out /etc/ssl/certs/ttyd.crt -subj "/CN=$(hostname)" -addext "subjectAltName=DNS:$(hostname)"
chmod 600 /etc/ssl/private/ttyd.key
chmod 644 /etc/ssl/certs/ttyd.crt
if systemctl is-enabled ttyd &>/dev/null; then # if service is enabled
systemctl restart ttyd
fi
}
# custom getopts for ttyd: generate key
if [[ "$1" == "-k" ]]; then
generate_keys
fi
# parse arguments
source /usr/local/bin/packages/femto_argument_parse.sh "$@"
# extra help for this package
if [[ "$1" == "-h" ]]; then
echo -e "Additional argument for this package:\n\
-k Generate SSL keys. Must be first argument."
fi
exit 0

View file

@ -1,3 +1,17 @@
Femtofox is comprised of two projects, with two different licenses:
1. Femtofox - the hardware, which is licensed "CC BY-NC-ND - noncommercial". Summary: you may copy and share and modify the hardware files, but cannot sell them without license from Femtofox, and must give attribution to Femtofox.
2. Foxbuntu - refers to the modifications to Ubuntu made as part of the Femtofox project, which is licensed GNU GPLv3. Summary: you may use, modify and distribute (including for commercial purposes) Foxbuntu, but must give attribution to Femtofox and distribute this license with your project. Any modified version must remain open source.
See below for the full license texts.
Hardware (Femtofox) license:
Summary:
Attribution — You must give appropriate credit , provide a link to the license, and indicate if changes were made . You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
NonCommercial — You may not use the material for commercial purposes .
NoDerivatives — If you remix, transform, or build upon the material, you may not distribute the modified material.
Contact us to license Femtofox.
The license:
Attribution-NonCommercial-NoDerivatives 4.0 International
@ -400,4 +414,682 @@ understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
Creative Commons may be contacted at creativecommons.org.
Software (Foxbuntu) license:
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 100 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
<g transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)">
<path d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z"/>
</g>
<g transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)">
<path d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 100 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
<g transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)">
<path d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z" style="fill:white;"/>
</g>
<g transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)">
<path d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z" style="fill:white;"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="512" height="512" viewBox="0 0 512 512" xml:space="preserve">
<desc>Created with Fabric.js 4.6.0</desc>
<defs>
</defs>
<g transform="matrix(1 0 0 1 256 256)" id="xYQ9Gk9Jwpgj_HMOXB3F_" >
<path style="stroke: rgb(213,130,139); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(103,234,148); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-256, -256)" d="M 0 0 L 512 0 L 512 512 L 0 512 z" stroke-linecap="round" />
</g>
<g transform="matrix(1.79 0 0 1.79 313.74 258.36)" id="1xBsk2n9FZp60Rz1O-ceJ" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: round; stroke-miterlimit: 2; fill: rgb(44,45,60); fill-rule: evenodd; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-250.97, -362.41)" d="M 250.908 330.267 L 193.126 415.005 L 180.938 406.694 L 244.802 313.037 C 246.174 311.024 248.453 309.819 250.889 309.816 C 253.326 309.814 255.606 311.015 256.982 313.026 L 320.994 406.536 L 308.821 414.869 L 250.908 330.267 Z" stroke-linecap="round" />
</g>
<g transform="matrix(1.81 0 0 1.81 145 256.15)" id="KxN7E9YpbyPgz0S4z4Cl6" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: round; stroke-miterlimit: 2; fill: rgb(44,45,60); fill-rule: evenodd; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-115.14, -528.06)" d="M 87.642 581.398 L 154.757 482.977 L 142.638 474.713 L 75.523 573.134 L 87.642 581.398 Z" stroke-linecap="round" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

View file

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
<link rel="manifest" href="site.webmanifest" />
<link rel="mask-icon" href="Logo_Black.svg" color="#67ea94" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@xz/fonts@1/serve/cascadia-code.min.css"
/>
<meta name="theme-color" content="#67ea94" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"
/>
<meta name="description" content="Meshtastic Web App" />
<title>Meshtastic Web</title>
<script type="module" crossorigin src="/index-b9vwykds.js"></script>
<link rel="stylesheet" crossorigin href="/index-wV0rbIjU.css">
</head>
<body>
<div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -1,16 +0,0 @@
{
"name": "Meshtastic",
"short_name": "Meshtastic",
"start_url": ".",
"description": "Meshtastic web app",
"icons": [
{
"src": "/icon.svg",
"sizes": "any",
"type": "image/svg+xml"
}
],
"theme_color": "#67ea94",
"background_color": "#67ea94",
"display": "standalone"
}

View file

@ -0,0 +1,538 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
#include "rv1106-evb.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/display/media-bus-format.h>
/ {
chosen {
bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyFIQ0 root=/dev/mmcblk0p7 rootwait snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0";
};
backlight: backlight {
status = "okay";
compatible = "pwm-backlight";
pwms = <&pwm1 0 100000 50000>;
brightness-levels = <
0 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63
64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87
88 89 90 91 92 93 94 95
96 97 98 99 100 101 102 103
104 105 106 107 108 109 110 111
112 113 114 115 116 117 118 119
120 121 122 123 124 125 126 127
128 129 130 131 132 133 134 135
136 137 138 139 140 141 142 143
144 145 146 147 148 149 150 151
152 153 154 155 156 157 158 159
160 161 162 163 164 165 166 167
168 169 170 171 172 173 174 175
176 177 178 179 180 181 182 183
184 185 186 187 188 189 190 191
192 193 194 195 196 197 198 199
200 201 202 203 204 205 206 207
208 209 210 211 212 213 214 215
216 217 218 219 220 221 222 223
224 225 226 227 228 229 230 231
232 233 234 235 236 237 238 239
240 241 242 243 244 245 246 247
248 249 250 251 252 253 254 255>;
default-brightness-level = <255>;
};
panel: panel {
compatible = "simple-panel";
backlight = <&backlight>;
reset-gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>;
reset-delay-ms = <200>;
status = "okay";
bus-format = <MEDIA_BUS_FMT_RGB666_1X18>;
width-mm = <85>;
height-mm = <85>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <30000000>;
hactive = <720>;
vactive = <720>;
hback-porch = <44>;
hfront-porch = <46>;
vback-porch = <18>;
vfront-porch = <16>;
hsync-len = <2>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
};
};
};
reserved_memory: reserved-memory {
status = "okay";
#address-cells = <1>;
#size-cells = <1>;
ranges;
drm_logo: drm-logo@00000000 {
compatible = "rockchip,drm-logo";
reg = <0x0 0x0>;
};
linux,cma {
status = "okay";
compatible = "shared-dma-pool";
inactive;
reusable;
size = <0xA00000>; //10M
linux,cma-default;
};
mmc_ecsd: mmc@3f000 {
reg = <0x3f000 0x00001000>;
};
};
acodec_sound: acodec-sound {
compatible = "simple-audio-card";
simple-audio-card,name = "rv1106-acodec";
simple-audio-card,format = "i2s";
simple-audio-card,mclk-fs = <256>;
simple-audio-card,cpu {
sound-dai = <&i2s0_8ch>;
};
simple-audio-card,codec {
sound-dai = <&acodec>;
};
};
dsm_sound: dsm-sound {
status = "disabled";
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,mclk-fs = <256>;
simple-audio-card,name = "rockchip,dsm-sound";
simple-audio-card,bitclock-master = <&sndcodec>;
simple-audio-card,frame-master = <&sndcodec>;
sndcpu: simple-audio-card,cpu {
sound-dai = <&i2s0_8ch>;
};
sndcodec: simple-audio-card,codec {
sound-dai = <&dsm>;
};
};
vcc_1v8: vcc-1v8 {
compatible = "regulator-fixed";
regulator-name = "vcc_1v8";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vcc_3v3: vcc-3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc_3v3";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
vdd_arm: vdd-arm {
compatible = "regulator-fixed";
regulator-name = "vdd_arm";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <1000000>;
regulator-init-microvolt = <900000>;
regulator-always-on;
regulator-boot-on;
};
leds: leds {
compatible = "gpio-leds";
work_led: work{
gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "activity";
default-state = "on";
};
};
};
/***************************** audio ********************************/
&i2s0_8ch {
#sound-dai-cells = <0>;
status = "okay";
};
&acodec {
#sound-dai-cells = <0>;
pa-ctl-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_HIGH>;
status = "okay";
};
/************************* FIQ_DUBUGGER ****************************/
&fiq_debugger {
rockchip,irq-mode-enable = <1>;
status = "okay";
};
/***************************** USB *********************************/
&u2phy {
status = "okay";
};
&u2phy_otg {
status = "okay";
};
&usbdrd {
status = "okay";
};
&usbdrd_dwc3 {
extcon = <&u2phy>;
status = "okay";
};
/***************************** DSM *********************************/
&dsm {
status = "disabled";
};
&cpu0 {
cpu-supply = <&vdd_arm>;
};
/*************************** CSI *********************************/
&csi2_dphy_hw {
status = "okay";
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
csi_dphy_input0: endpoint@0 {
reg = <0>;
remote-endpoint = <&sc3336_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csi_dphy_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi_csi2_input>;
};
};
};
};
&i2c4 {
status = "okay";
clock-frequency = <400000>;
pinctrl-names = "default";
// pinctrl-0 = <&i2c4m2_xfer>;
sc3336: sc3336@30 {
compatible = "smartsens,sc3336";
status = "okay";
reg = <0x30>;
clocks = <&cru MCLK_REF_MIPI0>;
clock-names = "xvclk";
reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&mipi_refclk_out0>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "CMK-OT2119-PC1";
rockchip,camera-module-lens-name = "30IRC-F16";
port {
sc3336_out: endpoint {
remote-endpoint = <&csi_dphy_input0>;
data-lanes = <1 2>;
};
};
};
};
&mipi0_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csi_dphy_output>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_in>;
};
};
};
};
&rkcif {
status = "okay";
};
&rkcif_mipi_lvds {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mipi_pins>;
port {
/* MIPI CSI-2 endpoint */
cif_mipi_in: endpoint {
remote-endpoint = <&mipi_csi2_output>;
};
};
};
&rkcif_mipi_lvds_sditf {
status = "okay";
port {
/* MIPI CSI-2 endpoint */
mipi_lvds_sditf: endpoint {
remote-endpoint = <&isp_in>;
};
};
};
&rkisp {
status = "okay";
};
&rkisp_vir0 {
status = "okay";
port@0 {
isp_in: endpoint {
remote-endpoint = <&mipi_lvds_sditf>;
};
};
};
/***************************** ADC ********************************/
&saradc {
status = "okay";
vref-supply = <&vcc_1v8>;
};
&tsadc {
status = "okay";
};
/**************************** LCD/TP ******************************/
&pwm1 {
status = "okay";
pinctrl-names = "active";
pinctrl-0 = <&pwm1m2_pins>;
};
&display_subsystem {
status = "okay";
logo-memory-region = <&drm_logo>;
};
&rgb {
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&lcd_pins>;
ports {
rgb_out: port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
rgb_out_panel: endpoint@0 {
reg = <0>;
remote-endpoint = <&panel_in_rgb>;
};
};
};
};
&rgb_in_vop {
status = "okay";
};
&route_rgb {
status = "disabled";
};
&vop {
status = "okay";
};
&i2c3 {
clock-frequency = <100000>;
GT911:touchscreen {
compatible = "goodix,gt911";
reg = <0x14>;
interrupt-parent = <&gpio0>;
interrupts = <RK_PA3 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
};
};
/**************************** PINCTRL ******************************/
// SPI
&spi0 {
pinctrl-0 = <&spi0m0_clk &spi0m0_miso &spi0m0_mosi &spi0m0_cs0>;
#address-cells = <1>;
#size-cells = <0>;
spidev@0 {
compatible = "rockchip,spidev";
spi-max-frequency = <50000000>;
reg = <0>;
};
};
// I2C
&i2c1 {
pinctrl-0 = <&i2c1m1_xfer>;
};
&i2c2 {
pinctrl-0 = <&i2c2m0_xfer>;
};
&i2c3 {
pinctrl-0 = <&i2c3m0_xfer &i2c3m1_xfer &i2c3m2_xfer &tp_rst &tp_irq>;
};
&i2c4 {
pinctrl-0 = <&i2c4m0_xfer &i2c4m1_xfer &i2c4m2_xfer>;
};
// UART
&uart0 {
pinctrl-0 = <&uart0m0_xfer &uart0m1_xfer>;
};
&uart1 {
pinctrl-0 = <&uart1m1_xfer>;
};
&uart3 {
pinctrl-0 = <&uart3m0_xfer &uart3m1_xfer>;
};
&uart4 {
pinctrl-0 = <&uart4m0_xfer>;
};
&uart5 {
pinctrl-0 = <&uart5m1_xfer>;
};
// PWM
&pwm0 {
pinctrl-0 = <&pwm0m1_pins>;
};
&pwm2 {
pinctrl-0 = <&pwm2m1_pins &pwm2m2_pins>;
};
&pwm3 {
pinctrl-0 = <&pwm3m2_pins>;
};
&pwm4 {
pinctrl-0 = <&pwm4m0_pins &pwm4m1_pins &pwm4m2_pins>;
};
&pwm5 {
pinctrl-0 = <&pwm5m1_pins &pwm5m2_pins>;
};
&pwm6 {
pinctrl-0 = <&pwm6m1_pins &pwm6m2_pins>;
};
&pwm7 {
pinctrl-0 = <&pwm7m0_pins &pwm7m1_pins>;
};
&pwm8 {
pinctrl-0 = <&pwm8m1_pins>;
};
&pwm9 {
pinctrl-0 = <&pwm9m1_pins>;
};
&pwm10 {
pinctrl-0 = <&pwm10m1_pins &pwm10m2_pins>;
};
&pwm11 {
pinctrl-0 = <&pwm11m1_pins &pwm11m2_pins>;
};
&pinctrl {
spi0 {
spi0m0_clk: spi0m0-clk {
rockchip,pins = <1 RK_PC1 4 &pcfg_pull_none>;
};
spi0m0_mosi: spi0m0-mosi {
rockchip,pins = <1 RK_PC2 6 &pcfg_pull_none>;
};
spi0m0_miso: spi0m0-miso {
rockchip,pins = <1 RK_PC3 6 &pcfg_pull_none>;
};
spi0m0_cs0: spi0m0-cs0 {
rockchip,pins = <1 RK_PC0 4 &pcfg_pull_none>;
};
};
touchscreen {
tp_rst:tp-rst {
rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
};
tp_irq:tp-irq {
rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};

View file

@ -0,0 +1,147 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106.dtsi"
#include "rv1106-luckfox-pico-ultra-ipc.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/display/media-bus-format.h>
/ {
model = "Luckfox Pico Ultra W";
compatible = "rockchip,rv1103g-38x38-ipc-v10", "rockchip,rv1106g3";
restart-poweroff {
compatible = "restart-poweroff";
};
sdio_pwrseq: sdio-pwrseq {
compatible = "mmc-pwrseq-simple";
pinctrl-names = "default";
reset-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>;
};
wireless_bluetooth: wireless-bluetooth {
compatible = "bluetooth-platdata";
uart_rts_gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
pinctrl-names = "default", "rts_gpio";
pinctrl-0 = <&uart1m0_rtsn>;
pinctrl-1 = <&uart1_gpios>;
BT,wake_gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>;
BT,wake_host_irq = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
/**********CRU**********/
//&cru {
// assigned-clocks =
// <&cru PLL_GPLL>, <&cru PLL_CPLL>,
// <&cru ARMCLK>,
// <&cru ACLK_PERI_ROOT>, <&cru HCLK_PERI_ROOT>,
// <&cru PCLK_PERI_ROOT>, <&cru ACLK_BUS_ROOT>,
// <&cru PCLK_TOP_ROOT>, <&cru PCLK_PMU_ROOT>,
// <&cru HCLK_PMU_ROOT>, <&cru CLK_500M_SRC>;
// assigned-clock-rates =
// <1188000000>, <700000000>,
// <1104000000>,
// <400000000>, <200000000>,
// <100000000>, <300000000>,
// <100000000>, <100000000>,
// <200000000>, <700000000>;
//};
/**********NPU**********/
//&npu {
// assigned-clock-rates = <700000000>;
//};
/**********EMMC**********/
&emmc {
bus-width = <8>;
cap-mmc-highspeed;
non-removable;
// mmc-hs200-1_8v;
rockchip,default-sample-phase = <90>;
no-sdio;
no-sd;
memory-region-ecsd = <&mmc_ecsd>;
post-power-on-delay-ms = <0>;
status = "okay";
};
&fiq_debugger {
rockchip,irq-mode-enable = <1>;
status = "okay";
};
/**********SDIO-WIFI**********/
&sdmmc {
max-frequency = <50000000>;
bus-width = <4>;
cap-sd-highspeed;
cap-sdio-irq;
keep-power-in-suspend;
non-removable;
rockchip,default-sample-phase = <90>;
// no-sd;
// no-mmc;
supports-sdio;
mmc-pwrseq = <&sdio_pwrseq>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_bus4 &sdmmc0_det>;
status = "okay";
};
&pinctrl{
sdmmc0{
sdmmc0_det: sdmmc0-det {
rockchip,pins =
/* sdmmc0_det */
<3 RK_PA1 1 &pcfg_pull_down>;
};
};
};
/**********ETH**********/
&gmac {
status = "okay";
};
/**********USB**********/
&usbdrd_dwc3 {
status = "okay";
dr_mode = "host";
#dr_mode = "host";
};
/**********RTC**********/
&rtc {
status = "okay";
};
/**********BT**********/
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn>;
};
&pinctrl {
wireless-bluetooth {
uart1_gpios: uart1-gpios {
rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
/**********SPI**********/
&spi0 {
status = "okay";
spidev@0 {
spi-max-frequency = <50000000>;
};
};

View file

@ -0,0 +1,81 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106.dtsi"
#include "rv1106-luckfox-pico-ultra-ipc.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/display/media-bus-format.h>
/ {
model = "Luckfox Pico Ultra";
compatible = "rockchip,rv1103g-38x38-ipc-v10", "rockchip,rv1106g3";
};
/**********CRU**********/
//&cru {
// assigned-clocks =
// <&cru PLL_GPLL>, <&cru PLL_CPLL>,
// <&cru ARMCLK>,
// <&cru ACLK_PERI_ROOT>, <&cru HCLK_PERI_ROOT>,
// <&cru PCLK_PERI_ROOT>, <&cru ACLK_BUS_ROOT>,
// <&cru PCLK_TOP_ROOT>, <&cru PCLK_PMU_ROOT>,
// <&cru HCLK_PMU_ROOT>, <&cru CLK_500M_SRC>;
// assigned-clock-rates =
// <1188000000>, <700000000>,
// <1104000000>,
// <400000000>, <200000000>,
// <100000000>, <300000000>,
// <100000000>, <100000000>,
// <200000000>, <700000000>;
//};
/**********NPU**********/
//&npu {
// assigned-clock-rates = <700000000>;
//};
/**********EMMC**********/
&emmc {
bus-width = <8>;
cap-mmc-highspeed;
non-removable;
// mmc-hs200-1_8v;
rockchip,default-sample-phase = <90>;
no-sdio;
no-sd;
memory-region-ecsd = <&mmc_ecsd>;
post-power-on-delay-ms = <0>;
status = "okay";
};
&fiq_debugger {
rockchip,irq-mode-enable = <1>;
status = "okay";
};
/**********ETH**********/
&gmac {
status = "okay";
};
/**********USB**********/
&usbdrd_dwc3 {
status = "okay";
dr_mode = "host";
};
/**********RTC**********/
&rtc {
status = "okay";
};
/**********SPI**********/
&spi0 {
status = "okay";
spidev@0 {
spi-max-frequency = <50000000>;
};
};

View file

@ -1368,7 +1368,25 @@ CONFIG_SCSI_UFSHCD=y
CONFIG_NETDEVICES=y
CONFIG_MII=y
# CONFIG_NET_CORE is not set
CONFIG_NET_CORE=y
# CONFIG_BONDING is not set
# CONFIG_DUMMY is not set
# CONFIG_WIREGUARD is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_FC is not set
# CONFIG_NET_TEAM is not set
# CONFIG_MACVLAN is not set
# CONFIG_IPVLAN is not set
# CONFIG_VXLAN is not set
# CONFIG_GENEVE is not set
# CONFIG_BAREUDP is not set
# CONFIG_GTP is not set
# CONFIG_MACSEC is not set
# CONFIG_NETCONSOLE is not set
CONFIG_TUN=m
# CONFIG_TUN_VNET_CROSS_LE is not set
# CONFIG_VETH is not set
# CONFIG_NLMON is not set
# CONFIG_ARCNET is not set
#
@ -2986,6 +3004,7 @@ CONFIG_VIDEO_RK_IRCUT=y
# CONFIG_VIDEO_VS6624 is not set
# CONFIG_VIDEO_MIS2031 is not set
# CONFIG_VIDEO_MIS4001 is not set
# CONFIG_VIDEO_MIS5001 is not set
# CONFIG_VIDEO_MT9M001 is not set
# CONFIG_VIDEO_MT9M032 is not set
# CONFIG_VIDEO_MT9M111 is not set

View file

@ -1,28 +0,0 @@
## Foxbuntu Installation Guide
### Requirements for installing Foxbuntu
To install Foxbuntu, you'll need the following:
1. microSD card. You can select one from [supported hardware](supported_hardware.md), but any card over 8gb and supporting UHS-I *should* work.
2. microSD card reader for your PC.
3. USB OTG adapter (USB-C to USB-A).
4. USB flash drive.
5. A Femtofox.
### Installation instructions
1. Download the latest stable [Foxbuntu release](https://github.com/noon92/femtofox/releases). At the bottom of the release, click the <u>.7z</u> file to download.
2. Flash the image your MicroSD card using [Balena Etcher](https://etcher.balena.io/) or your favorite flashing program. You will likely get a warning that the image appears to be invalid or has no partition table. This is normal.
3. Insert the microSD card into the Luckfox Pico Mini. The microSD slot is on the back of the board.
4. Following the instructions on the [USB Configuration Tool](usb_config.md) page, prepare your USB flash drive with your desired settings.
5. Using a USB OTG adapter, plug the USB flash drive into the *data* USB port.
> [!TIP]
> Optional: attach a USB to serial adapter to the Femtofox via the TX2 and RX2 pins for debug console. Remember to bridge the grounds!
> Optional: plug an RJ45 cable in to the ethernet port, if you have one installed.
7. Connect the Femtofox to power, either via the *power* USB-C port (on the same side as the ethernet port) or via the 3.3v or the 5v JST power plugs.
8. The Femtofox will perform its first boot. This can take up to 5 minutes (subsequent boots ~40 seconds). When boot is complete, the USR LED will blink 5 times, 1/2 a second each. At this point, Meshtastic should be running and if you plug in a wifi adapter it should work.
9. To connect to your Femtofox via SSH, open [PuTTY](https://www.putty.org/) or your favorite SSH client and connect to your Femtofox via `femtofox.local` or its IP (check your router).
* Username: `femto`
* Password: `femto`
You will be prompted to change this on first login.
<!--stackedit_data:
eyJoaXN0b3J5IjpbMTM3NzgzMjcyNF19
-->

View file

@ -1,108 +0,0 @@
## Supported Hardware
| Hardware | Confirmed working | Expected to work | Notes |
|-|-|-|--|
|LoRa radios (working with Meshtasticd)|<li>[Waveshare RPi LoRa hat without GNSS](https://www.waveshare.com/sx1262-lorawan-hat.htm?sku=22002)*<li>[Seeed Wio SX1262](https://www.seeedstudio.com/Wio-SX1262-Wireless-Module-p-5981.html)<li>[Ebyte E220900M30S](https://aliexpress.com/item/4000543921245.html)<li>AI Thinker RA-01SH<li>[Heltec HT-RA62](https://www.aliexpress.com/item/1005005445349105.html)|<li>Ebyte E22-900mm22s<li>[Ebyte E22-900m22s](https://www.aliexpress.com/item/1005001808069127.html)<li>Any SPI LoRa radio that's Meshtastic compatible|*Waveshare RPi hat is not recommended as it has issues with sending longer messages.|
|MicroSD cards|<li>[Kingston Endurance 32gb](https://www.kingston.com/en/memory-cards/high-endurance-microsd-card)<li>[Sandisk Ultra UHS-I 32gb](https://shop.sandisk.com/products/memory-cards/microsd-cards/sandisk-ultra-uhs-i-microsd?sku=SDSQUA4-032G-GN6MA)|Any reasonably fast (UHS-I or better) card with 8gb or more|Stick with reputable manufacturers (Kingston, PNY Samsung, Sandisk, Transcend...)<br>The faster the better! Consider sticking with "endurance" cards, especially for remotely deployed nodes.|
|RTC (real time clock)|<li>[DS3231M](https://vi.aliexpress.com/item/1005007143842437.html)<li>[DS1307](https://vi.aliexpress.com/item/1005007143542894.html)|DS1337, DS1338, DS1340, other DS3231 variants |Some DS3231 modules are listed as having a supercapacitor - these are usually actually lithium coin cells.|
|Meshtastic nodes|USB+UART: [RAK4631 with RAK19007 or RAK19003 base board](https://store.rakwireless.com/products/wisblock-meshtastic-starter-kit)| |RAK4630 and 4631 are the same.|
|USB wifi adapter chipsets|||See below| |
|Misc. hardware|<li>USB hubs (powered or not)<li>Thumb drives<li>SD card readers||If power draw exceeds supply, the device will reboot, bootloop or hard crash. Unpowered USB hubs seem to be notorious for causing reboots.<br>Some users have reported that USB-C flash drives do not work. This requires more study.|
### Wifi chipsets
The following wifi chipsets/devices have their drivers included in the OS images. Most of these have not been tested. Note that power consumption metrics are for a specific version of a chipset and may not apply to all implementations.
|Chipset: |Tested?|Recommended?|Power usage |Notes|
|-----------------------|-------|------------|------------|-----|
|**<u>Realtek:** | | | | |
|rtl8187 | | | | |
|rtl8187b | | | | |
|rtl8188[cr]u | | | | |
|rtl8188cu | | | | |
|rtl8188ee | | | | |
|rtl8188eu<br>rtl8188eus<br>rtl8188cus|✔️|✔️|Idle: 0.25w<br>TXing: 0.4w<br>Off: 0.026w|Model tested:<br>[TP-LINK TL-WN725N **V2**](https://techinfodepot.shoutwiki.com/wiki/TP-LINK_TL-WN725N_v2): working<br>[TP-Link TL-WR722N **V4**](https://techinfodepot.shoutwiki.com/wiki/TP-LINK_TL-WN722N_v1.x): working (v2, v3 *should* be identical)|
|rtl8188ru | | | | |
|rtl819[12]cu | | | | |
|rtl8191cu | | | | |
|rtl8192ce | | | | |
|rtl8192cu |✔️ |❔ | |Tested:<br>[Edimax EW-7811Un](https://techinfodepot.shoutwiki.com/wiki/Edimax_EW-7811Un): working|
|rtl8192de | | | | |
|rtl8192e | | | | |
|rtl8192ee | | | | |
|rtl8192eu |✔️ |❌ | |Buggy|
|rtl8192se | | | | |
|rtl8273,8188,8191,8192 | | | | |
|rtl8712u | | | | |
|rtl8723ae | | | | |
|rtl8723au | | | | |
|rtl8723be | | | | |
|rtl8812bu |✔️ |❌ | |Tested:<br>[TP-LINK Archer T3U](https://techinfodepot.shoutwiki.com/wiki/TP-LINK_Archer_T3U): **NOT** working|
|rtl8821ae | | | | |
|rtl8821au |✔️ |❌ | |Tested:<br>[TP-Link Archer T2U Plus](https://www.tp-link.com/us/home-networking/usb-adapter/archer-t2u-plus/): **NOT** working|
|rtl8xxx other | | | | |
| | | | | |
|**<u>Mediatek:** | | | | |
|mt7601u |✔️ |✔️ |Idle: 0.739w|Tested:<br>[Genbasic RF 2A4M1](https://www.amazon.com/dp/B0BNFKJPXS): working|
|mt76x0u | | | | |
|mt76x2u | | | | |
|mt7663s | | | | |
|mt7663u | | | | |
| | | | | |
|**<u>Atheros:** | | | | |
|ar5008 | | | | |
|ar5523 | | | | |
|ar6003 | | | | |
|ar6004 | | | | |
|ar9001 | | | | |
|ar9002 | | | | |
|ar9170 | | | | |
|ar9271 |✔️ |❔ | |Tested:<br>[TP-Link TL-WR722N **V1**](https://techinfodepot.shoutwiki.com/wiki/TP-LINK_TL-WN722N_v1.x): working<br>[Penguin Wireless TPE-N150USB](https://www.thinkpenguin.com/gnu-linux/penguin-wireless-n-usb-adapter-gnu-linux-tpe-n150usb): buggy<br>[Generic AR9271 w/SMA antenna](https://www.aliexpress.com/item/1005007556237899.html): buggy<br>Work in progress|
|ar9k | | | | |
|ath11k | | | | |
|ar10k | | | | |
|wcn3660 | | | | |
|wcn3680 | | | | |
| | | | | |
|**<u>Ralink:** | | | | |
|rt2501/rt73 | | | | |
|rt2571 | | | | |
|rt2571w | | | | |
|rt2572 | | | | |
|rt2573 | | | | |
|rt25xx | | | | |
|rt2671 | | | | |
|rt27xx | | | | |
|rt28xx | | | | |
|rt28xx unknown | | | | |
|rt30xx | | | | |
|rt3070 |✔️ |❔ | |Tested:<br>[Alfa AWUS036NEH](https://techinfodepot.shoutwiki.com/wiki/ALFA_Network_AWUS036NEH): buggy|
|rt33xx | | | | |
|rt3573 | | | | |
|rt35xx | | | | |
|rt53xx | | | | |
|rt55xx | | | | |
| | | | | |
|**<u>Atmel:** | | | | |
|at76c503 | | | | |
|at76c505 | | | | |
|at76c505a | | | | |
| | | | | |
|**<u>Microchip Atmel:**| | | | |
|wilc1000 | | | | |
| | | | | |
|**<u>Zydas:** | | | | |
|zd1201 | | | | |
|zd1211 | | | | |
|zd1211b | | | | |
| | | | | |
|**<u>RNDIS USB:** | | | | |
|Asus WL169gE | | | | |
|Belkin F5D7051 | | | | |
|BT Voyager 1055 | | | | |
|Buffalo WLI-U2-KG125S | | | | |
|BUFFALO WLI-USB-G54 | | | | |
|Eminent EM4045 | | | | |
|Linksys WUSB54GSC | | | | |
|Linksys WUSB54GSv1 | | | | |
|Linksys WUSB54GSv2 | | | | |
|U.S. Robotics USR5420 | | | | |
|U.S. Robotics USR5421 | | | | |

View file

@ -1,79 +0,0 @@
## USB Configuration Tool
To configure some Femtofox settings such as wifi, you can insert a USB flash drive containing a configuration file. On boot, the system will automatically recognize, mount and implement the settings you specify. The tool can also be run from the `femto-config` tool, in the `Utilities` menu.
Configurable settings are:
- Wifi SSID
- Wifi PSK (password)
- Wifi country
- Timezone
- Meshtastic:
- LoRa radio model
- [URL](https://meshtastic.org/docs/software/python/cli/#--seturl-seturl) (used to configure LoRa settings and channels)
- Security: Add Admin Key
- Security: Clear Admin Key List
- Security: [Legacy Admin Channel](https://meshtastic.org/docs/configuration/radio/security/#admin-channel-enabled) enable/disable
### Instructions
The USB drive must be formatted with a single FAT32, exFAT, NTFS (read only - log will not be saved to drive) or ext4 partition. Add a file named `femtofox-config.txt` and whichever settings you would like to change (CaSe sEnSiTiVe).
&emsp;&emsp;&emsp;&emsp; **<a href download="assets/femtofox-config.txt">[Get an example USB configuration file here</a>](assets/femtofox-config.txt)**
```
wifi_ssid="Your SSID name"
wifi_psk="wifipassword"
wifi_country="US"
timezone="America/New_York"
meshtastic_lora_radio="ebyte-e22-900m30s"
meshtastic_url="https://meshtastic.org/e/#CgMSAQESCAgBOAFAA0gB"
meshtastic_admin_key="T/b8EGvi/Nqi6GyGefJt/jOQr+5uWHHZuBavkNcUwWQ="
meshtastic_legacy_admin="true"
dont_run_if_log_exists="true"
```
> [!NOTE]
> Enter as many or as few settings as you like.
>
> For `wifi_country`, insert your country's [ISO/IEC alpha2 two letter country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements) (such as US, GB, DE, IN, etc.) in capital letters.
>
> Use a timezone as it appears in [the tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
>
> &emsp;&emsp;**Meshtastic**
> For `meshtastic_lora_radio`, choose your radio from the supported hardware list.
> Options are:
> * `ebyte-e22-900m30s`
> * `ebyte-e22-900m22s`
> * `ebyte-e80-900m22s` *(experimental)*
> * `heltec-ht-ra62`
> * `seeed-wio-sx1262`
> * `waveshare-sx126x-xxxm`
> * `ai-thinker-ra-01sh`
> * `sx1262_tcxo` *(for Ebyte E22-900M30SM, Ebyte E22-900M22S, Heltec HT-RA62, Seeed Wio SX1262)*
> * `sx1262_xtal` *(for AiThinker RA01SH, and Waveshare Pi hat)*
> * `lr1121_tcxo` *(experimental, for Ebyte E80-900M2213S)*
> * `none` *(for simulated radio)*
>
> Clearing the `meshtastic_admin_key` list: The admin key list can contain up to three keys - *if more are added they will be ignored*. The USB configuration tool supports clearing the admin key list, after which you will need to re-add your admin key/s in a second operation. To clear the admin key list, enter `meshtastic_admin_key="clear"`.
> [!NOTE]
> `dont_run_if_log_exists="true"` will prevent the USB configuration tool from working if there's a log present on the USB drive, indicating it has already been run. There is also an LED boot code for this, described below.
**To apply your configuration, reboot the Femtofox with the USB drive plugged in. No other USB drives can be plugged in at the same time.**
A log (`femtofox-config.log`) is saved to `/home/femto` and the USB drive (except on NTFS, which is read only).
<br>
### Boot codes
When the Femtofox is finished booting, it will blink its User LED (see below) in a pattern which can be used to gather info on its status or help diagnose issues.
![LEDs](assets/images/leds.png)
| LED blink pattern | Meaning | Possible causes | Solutions |
|--|--|--|--|
|<center>⚠️<br>________________<br>1 very long blink, lasting 5 seconds| Failed to mount USB drive. Ignoring.| <li>Invalid filesystem<li>Corrupted partition table<li>Defective USB drive<li>Defective USB OTG adapter | <li>Use a supported partition (FAT32, exFAT, NTFS, ext4)<li>Repair partition table<li>Try another USB drive<li>Try another USB OTG adapter |
|<center>⚠️<br>\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_<br>2 long blinks, each lasting 1.5 seconds | femtofox-config.txt is configured to skip if log exists. | USB drive mounted successfully but femtofox-config.txt contains `dont_run_if_log_exists="true"` and a log is present on the USB drive. Ignoring. | Remove log from USB drive or remove `dont_run_if_log_exists` line from femtofox-config.txt |
|<center>⚠️<br>\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_<br>3 long blinks, each lasting 1.5 seconds | USB drive mounted successfully but femtofox-config.txt was not found. Ignoring.| Config file missing. | Create configuration file as described above. |
|<center>⚠️<br>\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_&nbsp;&nbsp;\_\_\_\_\_<br>5 long blinks, each lasting 1.5 seconds | USB drive mounted successfully and femtofox-config.txt was found but did not contain readable configuration data. Ignoring.| Configuration file improperly formatted or contains no data. | Check configuration file contents as described above. |
|<center>⚠️<br>\_\_\_&nbsp;&nbsp;\_\_\_&nbsp;&nbsp;\_&nbsp;&nbsp;\_&nbsp;&nbsp;\_\_\_&nbsp;&nbsp;\_\_\_&nbsp;&nbsp;\_&nbsp;&nbsp;\_<br>2 long blinks, each lasting 1 second, then 2 short blinks, each lasting 1/4 of a second. Repeats twice | Error while trying to implement a Meshtastic setting after 3 attempts. Some settings may have been implemented successfully.| <li>The error may be transient.<li>Configuration file may contain improper data. | <li>Try again.<li>Check configuration file contents as described above.<li>Check the log.<br><br>This pattern may flash before other patterns. The pattern will repeat once for each failed setting.|
|<center>✅<br>. . . . . . . . . .<br>10 very fast blinks, each lasting 1/8th of a second | USB drive mounted successfully, and femtofox-config.txt was found and contained configuration data which was sent for deployment. Any affected services will now restart. You can disconnect the USB drive. | This does not mean that the information in the config file is correct - only that it was readable.<br>Note that the "success" boot code will flash if at least one setting is successfully read - even if the setting was not implemented successfully.|
|<center>✅<br>\_\_&nbsp;&nbsp;\_\_&nbsp;&nbsp;\_\_&nbsp;&nbsp;\_\_&nbsp;&nbsp;\_\_<br>5 medium blinks, each lasting 0.5 seconds | Boot complete. Appears on every successful boot and always appears last.| | |
> [!NOTE]
> Boot codes can appear in sequence - for example: one long (4 second) blink, followed by 5 medium (half second) blinks means the USB drive failed to mount, and that the boot sequence is complete.
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTE3MzAwMTU5Nl19
-->