├── .gitignore
├── README.md
├── configs
├── .fbtermrc
├── .zshrc
└── ido.zsh-theme
├── images
├── bg
│ ├── bg1.jpg
│ └── bg2.jpg
├── bgc-image.jpg
├── devterm.jpg
├── en2ja.jpg
└── fcitx-moz.jpg
└── scripts
├── battery
├── brightness
├── en2ja
├── fbstart
├── gearbox
└── ja2en
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DevTerm hobby project
2 |
3 | I bought this amazing device: [DevTerm A-0604](https://www.clockworkpi.com/devterm). It has a beefy ARM processor, runs a custom version of [Armbian](https://www.armbian.com/), embraces Open Source / Open Hardware philosophy and looks dope!
4 |
5 | It also has LightDM + xfce as a GUI but it's kinda boring to use this awesome retro-looking device with any kind of a graphical interface. **Let's try to set it up for a serious business and a maximum entertainment without any GUI** - just how it was in the good old days.
6 |
7 | Last Linux distro I've touched (not counting servers) was Red Hat Linux 9 (not RHEL!). I know nothing about modern linuxes + I always forget all the voodoo you have to do to make them work. So here I'll be storing my notes and useful scripts as I go with this hobby project
8 |
9 |
10 |
11 | ## Roadmap
12 | - [x] disable GUI
13 | - [x] enable ssh connection
14 | - [x] connect to home wifi
15 | - [x] basic scripts (battery charge and brightness control)
16 | - [x] render UTF, Cyrillic, Japanese in TTY
17 | - [x] battery indicator in zsh prompt
18 | - [ ] nice setup for tmux (themes, plugins)
19 | - [ ] email client (gmail, protonmail)
20 | - [x] games: nethack
21 | - [ ] games: dcss
22 | - [x] ~~twitter~~ mastodon client
23 | - [x] hckrnews client
24 | - [x] stonks tracker
25 | - [ ] IDE / code editor
26 | - [ ] text editor
27 | - [ ] rust
28 | - [ ] can I see pictures in the TTY?
29 | - [ ] what about video?
30 | - [x] music / spotify player
31 | - [ ] gamepad to scroll text in terminal
32 | - [ ] soluiton for browser
33 | - [ ] start fdterm+fcitx on load
34 | - [x] bg image in fbterm
35 | - [x] japanese input in tty
36 | - [x] google translate in terminal
37 | - [x] auth by usb stick
38 | - [ ] plug a mini cassette recorder, do some magic to let me store data using cute tiny mini audio-cassettes.. yum!
39 | - [x] some cool p2p stuff
40 |
41 | ## Notes
42 |
43 | 1) Terminal. Standard TTY has a very limited capabilities to render fonts. Had troubles to render Japanese characters (kanji, hirogana and katakana). Got success with using `fdterm` with [Iosevka Term](https://typeof.net/Iosevka/) and [Noto Sans JP](https://fonts.google.com/noto/specimen/Noto+Sans+JP?subset=japanese) fonts. Downloaded them and copied into `/usr/share/fonts/(truetype|opentype)` and update `~/.fbtermrc`. If the first font doesn't contain the glyph for the rendering character, it will try second font and etc (1). (Still need to try to figure out how to autostart `fdterm`)
44 |
45 | 2) To connect to WiFi I've tried `wpa_cli` but you need to be really smart to use it. Not my case. Fallbacked to use `nmcli` and it works like a charm `nmcli device wifi connect password
46 |
47 | 3) Browser. Had some hopes for [Browsh](https://www.brow.sh/) but it's super slow (uses headless Firefox behind the scenes) and rendering getting borked in `fdterm`. Have to use `lynx` for now, and my Macbook
48 |
49 | 4) Translations. After quick search was able to find `libtranslate-bin` but there were no builds for ARM64 and I was about to start building it from sources. However, looked for alternatives in the apt repo and found [translate-shell](https://github.com/soimort/translate-shell). Works amazingly well for my needs
50 |
51 | 5) There is a cool zsh plugin as part of `oh-my-zsh` called [battery](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/battery). To make it work you need to install `acpi` and update your prompt. Works flawlessly but I want to use battery indicator in `tmux`
52 |
53 | 6) Games. [DCSS](https://crawl.develz.org/) is a cool roguelike crawler. Doesn't have ARM64 binary, got the [source](https://github.com/crawl/crawl), followed the [instructions](https://github.com/crawl/crawl/blob/master/crawl-ref/INSTALL.md) and built it without any problems. However attempting to start it throws an error `Terminal too small` because it needs min height of 24 lines (DevTerm is only 19). Tried to change [this](https://github.com/crawl/crawl/blob/01218726429e4ea9e687ec3926d8e238243f126e/crawl-ref/source/defines.h#L24) and disable checks for the resolution. Now it crashes.
54 |
55 | 7) Used [this guide](https://forum.clockworkpi.com/t/using-gamepad-arrows-and-buttons-in-command-line-apps/7059/2?u=godzil) to change the way gamepad on DevTerm keyboard works
56 |
57 | 8) Installed `gpm` (using [this](https://www.geeksforgeeks.org/gpm-command-in-linux-with-examples/)) to enable mouse in tty. Didn't need to setup anything. It just works
58 |
59 | 9) Hackernews. Use [hn-text](https://github.com/piqoni/hn-text), install via `go install github.com/piqoni/hn-text@latest`
60 |
61 | 10) Games. [Nethack](https://packages.debian.org/sid/games/nethack-console) just works!
62 |
63 | 11) CPU scaling. Clockworkpi made a [script](https://forum.clockworkpi.com/t/devterm-a-06-core-cpu-frequency-scaling/7135) to adjust CPU/GPU cores dynamically
64 |
65 | 12) Spotify. You can get [spotifyd](https://github.com/Spotifyd/spotifyd) complied from sources without a problem, just follow the official [docs](https://spotifyd.github.io/spotifyd/installation/Ubuntu.html) - that allows to play spotify on a devterm. Now, there is [spotify-tui](https://github.com/Rigellute/spotify-tui) to control it via the terminal (to register correctly I [had to tunnel the dev server](https://github.com/Rigellute/spotify-tui/issues/732) as lynx wasn't able to render the spotify auth page. App itself works but still missing a lot of features.
66 |
67 | 13) Mastodon client. [toot](https://github.com/ihabunek/toot) is a terminal based client written in Python. Install it by running `pip install --user toot`. Doesn't support 2-factor auth but otherwise, works like charm
68 |
69 | 15) To track our stocks portfolio, we will be using [mop](https://github.com/mop-tracker/mop). It's a Go program that we will have to build ourselves. We need Go amd64 binaries ([provided officially](https://golang.google.cn/dl/)) then just follow the [manual](https://go.dev/doc/install) to move them into the right folder, then build `mop` according to official documentation
70 |
71 | ## Japanese input method in terminal
72 |
73 | I stumbled upon [this good video](https://www.youtube.com/watch?v=lJoXhS4EUJs) where Brodie Robertson talks about input method frameworks, input method engines and shows how to setup `fcitx` with `fcitx-moz` to enable Japanese input method for Arch linux.
74 |
75 | However we need to make all of it working in our terminal. Luckily for us there is `fbterm` support and as a double win - we have all needed packages in Armbian repo. So I've installed `sudo apt install fcitx fcitx-mozc fcitx-frontend-fbterm fcitx-ui-classic`.
76 |
77 | Configuration in `~/.config/fcitx/config` seems pretty odd. I wasn't able to make it work with any other trigger key except for the default one (Ctrl+Space). However I changed `SwitchKey` to be `L_ALT` (instead of defaule L_SHIFT) and it made my life better.
78 |
79 | To be able to use Ctlr+Space combination I had to update permissions for `fbterm` by executing `setcap 'cap_sys_tty_config+ep' /usr/bin/fbterm `
80 |
81 | Then to start `fbterm` with `fcitx` you simply run `fcitx-fbterm-helper -l`. Press Ctrl+Space to enable it and then Alt to switch between US and JA input methods.
82 |
83 |
84 |
85 | ## Set background image in terminal
86 |
87 | We have [this good guide](https://askubuntu.com/questions/278863/how-do-i-set-up-a-background-image-for-console) that I followed to make the magic happen. We need to build `fbv` from sources and for that we need to:
88 |
89 | - get stock libjpeg dev by using `sudo apt-get install libjpeg-dev`
90 | - build libungif from sources:
91 | ```
92 | git clone https://github.com/Distrotech/libungif.git
93 | autoreconf -f -i
94 | ./configure
95 | make
96 | sudo make install
97 | ```
98 | - build old libpng (1.2) because `fbv` doesn't like the latest one Armbian repo has
99 |
100 | ```
101 | # get .tar.gz from https://sourceforge.net/projects/libpng/
102 | tar xfv
103 | ./configure
104 | make
105 | sudo make install
106 | sudo ldconfig
107 | ```
108 |
109 | Now it's time to get and build `fbv`:
110 |
111 | ```
112 | wget http://s-tech.elsat.net.pl/fbv/fbv-1.0b.tar.gz
113 | tar xfv fbv-1.0b.tar.gz
114 | ./configure
115 | sudo checkinstall
116 | ```
117 |
118 | Now according to the `fbterm` [manual](https://linux.die.net/man/1/fbterm), this is the script we can create to run fbterm with the background image:
119 |
120 | ```
121 | #!/bin/bash
122 |
123 | # fbterm-bi: a wrapper script to enable background image with fbterm
124 | # usage: fbterm-bi /path/to/image fbterm-options
125 |
126 | echo -ne "\e[?25l" # hide cursor
127 |
128 | fbv -ciuker "$1" << EOF
129 | q
130 | EOF
131 |
132 | shift
133 | export FBTERM_BACKGROUND_IMAGE=1
134 | exec fbterm "$@"
135 | ```
136 |
137 | I've slightly modified it and put in this repo as `./scripts/fbstart`. Remember, we actually don't start `fbterm` directly but run it via `fcitx-fbterm-helper` instead. If you are doing the same thing, you would also would like to edit `/usr/bin/fcitx-fbterm-helper` to comment all `echo` lines there. Otherwise those messages will become the part of your background.
138 |
139 | One more thing: for some reason my `fbterm` requires a counter clockwise rotation to render itself correctly, so I had to rotate the image as well.
140 |
141 | At the end it looks like this:
142 |
143 |
144 |
145 | ## Login & sudo via Yubikey (USB Security Key)
146 |
147 | I have [Yubikey 5 NFC](https://www.yubico.com/products/yubikey-5-overview/) so it was logical to set it up with DevTerm.
148 |
149 | First you need to generate One Time Password (OTP) and upload it to [Yubikey Cloud](https://upload.yubico.com/), then you have to generate [API keys](https://upgrade.yubico.com/getapikey/) - store it somewhere secure.
150 |
151 | For the same step you can download and use Yubikey Manager app on your other machine. I used it to setup long button press on a key to return the OTP
152 |
153 | Then you will have to get [yubico-pam](https://github.com/Yubico/yubico-pam). I've built it myself following the instruction in the README. But to do that you will have to build a fee other dependencies first. Namely
154 | [yubico-c](https://developers.yubico.com/yubico-c/) and [yubico-c-client](https://developers.yubico.com/yubico-c-client/)
155 |
156 | And to build them I had to install quite a few libraries (maybe even missing something):
157 |
158 | ```
159 | sudo apt-get install libcurl4-openssl-dev libpam-dev help2man libxslt1-dev docbook-xsl xsltproc libxml2-utils asciidoc
160 | ```
161 |
162 | After that follow the configuration instructions for [yubico-pam](https://github.com/Yubico/yubico-pam#configuration), add to `/etc/pam.d/sudo` and `/etc/pam.d/login` this (you can remove `debug` later after you verify that it works:
163 |
164 | ```
165 | auth sufficient pam_yubico.so id=[Your API ID] debug
166 | ```
167 |
168 | then create `~/.yubico/authorized_yubikeys` with your username and Yubikey ID (that's the info from "Public identity" field when you generate your OTP password)
169 |
170 | ```
171 | username:
172 | ```
173 |
174 | then move `pam_yubico.so` to `/lib/security/`
175 |
176 | ```
177 | mv /usr/local/lib/security/pam_yubico.so /lib/security/
178 | ```
179 |
180 | and that's it! Next time you login/sudo you will prompted by `YubiKey for 'USERNAME':` and you just need to simply touch your key. You should see something like this:
181 |
182 | ```
183 | debug: pam_yubico.c:943 (parse_cfg): called.
184 | debug: pam_yubico.c:944 (parse_cfg): flags 32768 argc 2
185 | debug: pam_yubico.c:946 (parse_cfg): argv[0]=id=00000
186 | debug: pam_yubico.c:946 (parse_cfg): argv[1]=debug
187 | debug: pam_yubico.c:947 (parse_cfg): id=00000
188 | debug: pam_yubico.c:948 (parse_cfg): key=(null)
189 | debug: pam_yubico.c:949 (parse_cfg): debug=1
190 | debug: pam_yubico.c:950 (parse_cfg): debug_file=1
191 | debug: pam_yubico.c:951 (parse_cfg): alwaysok=0
192 | debug: pam_yubico.c:952 (parse_cfg): verbose_otp=0
193 | debug: pam_yubico.c:953 (parse_cfg): try_first_pass=0
194 | debug: pam_yubico.c:954 (parse_cfg): use_first_pass=0
195 | debug: pam_yubico.c:955 (parse_cfg): always_prompt=0
196 | debug: pam_yubico.c:956 (parse_cfg): nullok=0
197 | debug: pam_yubico.c:957 (parse_cfg): ldap_starttls=0
198 | debug: pam_yubico.c:958 (parse_cfg): ldap_bind_as_user=0
199 | debug: pam_yubico.c:959 (parse_cfg): authfile=(null)
200 | debug: pam_yubico.c:960 (parse_cfg): ldapserver=(null)
201 | debug: pam_yubico.c:961 (parse_cfg): ldap_uri=(null)
202 | debug: pam_yubico.c:962 (parse_cfg): ldap_connection_timeout=0
203 | debug: pam_yubico.c:963 (parse_cfg): ldap_bind_user=(null)
204 | debug: pam_yubico.c:964 (parse_cfg): ldap_bind_password=(null)
205 | debug: pam_yubico.c:965 (parse_cfg): ldap_filter=(null)
206 | debug: pam_yubico.c:966 (parse_cfg): ldap_cacertfile=(null)
207 | debug: pam_yubico.c:967 (parse_cfg): ldapdn=(null)
208 | debug: pam_yubico.c:968 (parse_cfg): ldap_clientcertfile=(null)
209 | debug: pam_yubico.c:969 (parse_cfg): ldap_clientkeyfile=(null)
210 | debug: pam_yubico.c:970 (parse_cfg): user_attr=(null)
211 | debug: pam_yubico.c:971 (parse_cfg): yubi_attr=(null)
212 | debug: pam_yubico.c:972 (parse_cfg): yubi_attr_prefix=(null)
213 | debug: pam_yubico.c:973 (parse_cfg): url=(null)
214 | debug: pam_yubico.c:974 (parse_cfg): urllist=(null)
215 | debug: pam_yubico.c:975 (parse_cfg): capath=(null)
216 | debug: pam_yubico.c:976 (parse_cfg): cainfo=(null)
217 | debug: pam_yubico.c:977 (parse_cfg): proxy=(null)
218 | debug: pam_yubico.c:978 (parse_cfg): token_id_length=12
219 | debug: pam_yubico.c:979 (parse_cfg): mode=client
220 | debug: pam_yubico.c:980 (parse_cfg): chalresp_path=(null)
221 | debug: pam_yubico.c:981 (parse_cfg): mysql_server=(null)
222 | debug: pam_yubico.c:982 (parse_cfg): mysql_port=0
223 | debug: pam_yubico.c:983 (parse_cfg): mysql_user=(null)
224 | debug: pam_yubico.c:984 (parse_cfg): mysql_database=(null)
225 | debug: pam_yubico.c:1020 (pam_sm_authenticate): pam_yubico version: 2.28
226 | debug: pam_yubico.c:1035 (pam_sm_authenticate): get user returned: ido
227 | debug: pam_yubico.c:222 (authorize_user_token): Dropping privileges
228 | debug: util.c:351 (check_user_token): Authorization line: ido:***********
229 | debug: util.c:356 (check_user_token): Matched user: ido
230 | debug: util.c:362 (check_user_token): Authorization token: :***********
231 | debug: util.c:362 (check_user_token): Authorization token: (null)
232 | debug: pam_yubico.c:1157 (pam_sm_authenticate): Tokens found for user
233 | YubiKey for `ido':
234 | debug: pam_yubico.c:1220 (pam_sm_authenticate): conv returned 44 bytes
235 | debug: pam_yubico.c:1234 (pam_sm_authenticate): Skipping first 0 bytes. Length is 44, token_id set to 12 and token OTP always 32.
236 | debug: pam_yubico.c:222 (authorize_user_token): Dropping privileges
237 | debug: util.c:351 (check_user_token): Authorization line: ido::***********
238 | debug: util.c:356 (check_user_token): Matched user: ido
239 | debug: util.c:362 (check_user_token): Authorization token: :***********
240 | debug: util.c:366 (check_user_token): Match user/token as ido/:***********
241 | debug: pam_yubico.c:1276 (pam_sm_authenticate): OTP: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ID: :***********
242 | debug: pam_yubico.c:1277 (pam_sm_authenticate): Token is associated to the user. Validating the OTP...
243 | debug: pam_yubico.c:1279 (pam_sm_authenticate): ykclient return value (0): Success
244 | debug: pam_yubico.c:1280 (pam_sm_authenticate): ykclient URL used: https://api.yubico.com/wsapi/2.0/verify?id=00000&nonce=aaaaaaaayxnvkpqixgkufyhbxnyxztvg&otp=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa×tamp=1
245 | debug: pam_yubico.c:1348 (pam_sm_authenticate): done. [Success]
246 | ````
247 |
248 | Done!
249 |
250 | ## Screenshots
251 |
252 | (1) Translations + JA glyph rendering in fbterm
253 |
254 |
255 |
256 | ## License
257 |
258 | MIT unless specified otherwise
259 |
--------------------------------------------------------------------------------
/configs/.fbtermrc:
--------------------------------------------------------------------------------
1 | # Configuration for FbTerm
2 |
3 | # Lines starting with '#' are ignored.
4 | # Note that end-of-line comments are NOT supported, comments must be on a line of their own.
5 |
6 |
7 | # font family names/pixelsize used by fbterm, multiple font family names must be seperated by ','
8 | # and using a fixed width font as the first is strongly recommended
9 | font-names=Iosevka Term,Noto Sans JP
10 | font-size=20
11 |
12 | # force font width (and/or height), usually for non-fixed width fonts
13 | # legal value format: n (fw_new = n), +n (fw_new = fw_old + n), -n (fw_new = fw_old - n)
14 | #
15 | font-width=9
16 | #font-height=
17 |
18 | # default color of foreground/background text
19 | # available colors: 0 = black, 1 = red, 2 = green, 3 = brown, 4 = blue, 5 = magenta, 6 = cyan, 7 = white
20 | color-foreground=7
21 | color-background=0
22 |
23 | # max scroll-back history lines of every window, value must be [0 - 65535], 0 means disable it
24 | history-lines=1000
25 |
26 | # up to 5 additional text encodings, multiple encodings must be seperated by ','
27 | # run 'iconv --list' to get available encodings.
28 | text-encodings=
29 |
30 | # cursor shape: 0 = underline, 1 = block
31 | # cursor flash interval in milliseconds, 0 means disable flashing
32 | cursor-shape=0
33 | cursor-interval=500
34 |
35 | # additional ascii chars considered as part of a word while auto-selecting text, except ' ', 0-9, a-z, A-Z
36 | word-chars=._-
37 |
38 | # change the clockwise orientation angle of screen display
39 | # available values: 0 = 0 degree, 1 = 90 degrees, 2 = 180 degrees, 3 = 270 degrees
40 | screen-rotate=1
41 |
42 | # specify the favorite input method program to run
43 | input-method=
44 |
45 | # treat ambiguous width characters as wide
46 | #ambiguous-wide=yes
47 |
--------------------------------------------------------------------------------
/configs/.zshrc:
--------------------------------------------------------------------------------
1 | # If you come from bash you might have to change your $PATH.
2 | export PATH=$HOME/bin:/usr/local/bin:$HOME/devterm-items/scripts:$PATH
3 |
4 | # Path to your oh-my-zsh installation.
5 | export ZSH=/etc/oh-my-zsh
6 | export ZSH_CACHE_DIR=~/.oh-my-zsh/cache
7 |
8 | # Set name of the theme to load --- if set to "random", it will
9 | # load a random theme each time oh-my-zsh is loaded, in which case,
10 | # to know which specific one was loaded, run: echo $RANDOM_THEME
11 | # See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
12 | ZSH_THEME="ido"
13 |
14 | # Set list of themes to pick from when loading at random
15 | # Setting this variable when ZSH_THEME=random will cause zsh to load
16 | # a theme from this variable instead of looking in $ZSH/themes/
17 | # If set to an empty array, this variable will have no effect.
18 | # ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
19 |
20 | # Uncomment the following line to use case-sensitive completion.
21 | # CASE_SENSITIVE="true"
22 |
23 | # Uncomment the following line to use hyphen-insensitive completion.
24 | # Case-sensitive completion must be off. _ and - will be interchangeable.
25 | # HYPHEN_INSENSITIVE="true"
26 |
27 | # Uncomment the following line to disable bi-weekly auto-update checks.
28 | DISABLE_AUTO_UPDATE="true"
29 |
30 | # Uncomment the following line to automatically update without prompting.
31 | DISABLE_UPDATE_PROMPT="true"
32 |
33 | # Uncomment the following line to change how often to auto-update (in days).
34 | # export UPDATE_ZSH_DAYS=13
35 |
36 | # Uncomment the following line if pasting URLs and other text is messed up.
37 | # DISABLE_MAGIC_FUNCTIONS="true"
38 |
39 | # Uncomment the following line to disable colors in ls.
40 | # DISABLE_LS_COLORS="true"
41 |
42 | # Uncomment the following line to disable auto-setting terminal title.
43 | # DISABLE_AUTO_TITLE="true"
44 |
45 | # Uncomment the following line to enable command auto-correction.
46 | # ENABLE_CORRECTION="true"
47 |
48 | # Uncomment the following line to display red dots whilst waiting for completion.
49 | # Caution: this setting can cause issues with multiline prompts (zsh 5.7.1 and newer seem to work)
50 | # See https://github.com/ohmyzsh/ohmyzsh/issues/5765
51 | # COMPLETION_WAITING_DOTS="true"
52 |
53 | # Uncomment the following line if you want to disable marking untracked files
54 | # under VCS as dirty. This makes repository status check for large repositories
55 | # much, much faster.
56 | # DISABLE_UNTRACKED_FILES_DIRTY="true"
57 |
58 | # Uncomment the following line if you want to change the command execution time
59 | # stamp shown in the history command output.
60 | # You can set one of the optional three formats:
61 | # "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
62 | # or set a custom format using the strftime function format specifications,
63 | # see 'man strftime' for details.
64 | # HIST_STAMPS="mm/dd/yyyy"
65 |
66 | # Would you like to use another custom folder than $ZSH/custom?
67 | # ZSH_CUSTOM=/path/to/new-custom-folder
68 |
69 | # Which plugins would you like to load?
70 | # Standard plugins can be found in $ZSH/plugins/
71 | # Custom plugins may be added to $ZSH_CUSTOM/plugins/
72 | # Example format: plugins=(rails git textmate ruby lighthouse)
73 | # Add wisely, as too many plugins slow down shell startup.
74 | plugins=(evalcache git git-extras debian tmux screen history extract colorize web-search zsh-autosuggestions battery)
75 |
76 | ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=4"
77 |
78 | source $ZSH/oh-my-zsh.sh
79 |
80 | # User configuration
81 |
82 | # export MANPATH="/usr/local/man:$MANPATH"
83 |
84 | # You may need to manually set your language environment
85 | # export LANG=en_US.UTF-8
86 |
87 | # Preferred editor for local and remote sessions
88 | # if [[ -n $SSH_CONNECTION ]]; then
89 | # export EDITOR='vim'
90 | # else
91 | # export EDITOR='mvim'
92 | # fi
93 |
94 | # Compilation flags
95 | # export ARCHFLAGS="-arch x86_64"
96 |
97 | # Set personal aliases, overriding those provided by oh-my-zsh libs,
98 | # plugins, and themes. Aliases can be placed here, though oh-my-zsh
99 | # users are encouraged to define aliases within the ZSH_CUSTOM folder.
100 | # For a full list of active aliases, run `alias`.
101 | #
102 | # Example aliases
103 | # alias zshconfig="mate ~/.zshrc"
104 | # alias ohmyzsh="mate ~/.oh-my-zsh"
105 |
--------------------------------------------------------------------------------
/configs/ido.zsh-theme:
--------------------------------------------------------------------------------
1 | if [ $UID -eq 0 ]; then CARETCOLOR="red"; else CARETCOLOR="blue"; fi
2 |
3 | local return_code="%(?..%{$fg[red]%}%? ↵%{$reset_color%})"
4 |
5 | PROMPT='%{$reset_color%}%{${fg[green]}%}%3~ $(git_prompt_info)%{${fg_bold[$CARETCOLOR]}%}$CARET_POINTER%{${reset_color}%} '
6 | RPROMPT='$(battery_pct_prompt) %F{yellow}%D{%L:%M} %D{%p}%f'
7 |
8 | CARET_POINTER="%{$fg[red]%}❯%{$reset_color%}%{$fg[yellow]%}❯%{$reset_color%}%{$fg[green]%}❯%{$reset_color%}"
9 |
10 | ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg[yellow]%}‹"
11 | ZSH_THEME_GIT_PROMPT_SUFFIX="› %{$reset_color%}"
12 |
--------------------------------------------------------------------------------
/images/bg/bg1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idooo/devterm-hobby-project/cfeebedc9cf9bda2bc1edc43ade1718424f7e86a/images/bg/bg1.jpg
--------------------------------------------------------------------------------
/images/bg/bg2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idooo/devterm-hobby-project/cfeebedc9cf9bda2bc1edc43ade1718424f7e86a/images/bg/bg2.jpg
--------------------------------------------------------------------------------
/images/bgc-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idooo/devterm-hobby-project/cfeebedc9cf9bda2bc1edc43ade1718424f7e86a/images/bgc-image.jpg
--------------------------------------------------------------------------------
/images/devterm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idooo/devterm-hobby-project/cfeebedc9cf9bda2bc1edc43ade1718424f7e86a/images/devterm.jpg
--------------------------------------------------------------------------------
/images/en2ja.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idooo/devterm-hobby-project/cfeebedc9cf9bda2bc1edc43ade1718424f7e86a/images/en2ja.jpg
--------------------------------------------------------------------------------
/images/fcitx-moz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idooo/devterm-hobby-project/cfeebedc9cf9bda2bc1edc43ade1718424f7e86a/images/fcitx-moz.jpg
--------------------------------------------------------------------------------
/scripts/battery:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 | upower -i /org/freedesktop/UPower/devices/battery_axp20x_battery
3 |
--------------------------------------------------------------------------------
/scripts/brightness:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | # From here
4 | # https://forum.clockworkpi.com/t/changing-brightness-terminal/7070
5 |
6 | sudo bash -c "echo $1 > /sys/class/backlight/backlight@0/brightness"
7 |
--------------------------------------------------------------------------------
/scripts/en2ja:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | # install https://github.com/soimort/translate-shell
4 | # sudo apt-get install translate-shell
5 |
6 | trans -t ja -f en "$1"
7 |
8 |
--------------------------------------------------------------------------------
/scripts/fbstart:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # starts fbterm with background image and fcitx
4 |
5 | clear
6 |
7 | DIR=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
8 | IMAGE=../images/bg/bg2.jpg
9 |
10 | echo $DIR
11 | echo -ne "\e[?25l" # hide cursor
12 |
13 | fbv -ciuker "$DIR/$IMAGE" << EOF
14 | q
15 | EOF
16 |
17 | shift
18 | export FBTERM_BACKGROUND_IMAGE=1
19 | exec fcitx-fbterm-helper -l
20 |
--------------------------------------------------------------------------------
/scripts/gearbox:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | # From official DevTerm repo
4 | # https://github.com/clockworkpi/DevTerm
5 | # https://forum.clockworkpi.com/t/devterm-a-06-core-cpu-frequency-scaling/7135
6 |
7 | import glob
8 | import os
9 | import sys,getopt
10 | import subprocess
11 | import time
12 |
13 | # The gearings below were picked based on various tests by the ClockworkPi devs.
14 | # The maximum-performance maximum-power gearing is present for completeness, but
15 | # shouldn't be needed for most uses.
16 | #
17 | # You can customise the gearings by editing the list below. The valid freqencies
18 | # for CPU can be looked up here (substituting for ):
19 | # /sys/devices/system/cpu/cpu/cpufreq/scaling_available_frequencies
20 | #
21 | # The valid GPU frequencies can be looked up here:
22 | # /sys/devices/platform/ff9a0000.gpu/devfreq/ff9a0000.gpu/available_frequencies
23 | #
24 | # Gears are numbered in-order, starting from 1.
25 | # It's up to you to ensure that they are sorted by performance :)
26 | def gears():
27 | return [
28 | gear(
29 | little=(600000,),
30 | use="simple writing tasks with long battery life"),
31 | gear(
32 | little=(800000,) * 2,
33 | use="browsing most websites with long battery life"),
34 | gear(
35 | little=(1008000,) * 4,
36 | gpu_freq=400000000,
37 | use="most 2D games and emulators"),
38 | gear(
39 | big=(1008000,) * 2,
40 | gpu_freq=400000000,
41 | use="playing videos and 3D games"),
42 | gear(
43 | big=(1200000,) * 2,
44 | gpu_freq=400000000,
45 | use="performance-first tasks"),
46 | gear(
47 | little=(1416000,) * 4,
48 | big=(1800000,) * 2,
49 | gpu_freq=800000000,
50 | use="max performance, max power (usage)"),
51 | ]
52 |
53 | GPU_GOV_SIMPLE = "simple_ondemand"
54 | GPU_GOV_PERF = "performance"
55 |
56 | # Helper to convert the concise gear format above into a full description.
57 | #
58 | # `little` and `big` define the number of A53 and A72 CPU cores to enable, and
59 | # their maximum frequencies (in kHZ). Cores that are omitted or set to zero are
60 | # disabled.
61 | def gear(
62 | little=(0, 0, 0, 0),
63 | big=(0, 0),
64 | gpu_freq=200000000,
65 | gpu_gov=GPU_GOV_SIMPLE,
66 | use="",
67 | ):
68 | # Extend to 4 little and 2 big cores (matching the A06).
69 | assert len(little) <= 4
70 | assert len(big) <= 2
71 | cpu = little + (0,) * (4 - len(little)) + big + (0,) * (2 - len(big))
72 |
73 | # At least one CPU must be enabled
74 | assert sum(cpu) > 0
75 | return {
76 | "cpu": cpu,
77 | "gpu_freq": gpu_freq,
78 | "gpu_gov": gpu_gov,
79 | "use": use,
80 | }
81 |
82 | # We placed gears() at the top of the file to make it easier to find and edit.
83 | # Now that we've defined the helpers it needs, evaluate the gears.
84 | gears = gears()
85 |
86 | def load_gear(gear):
87 | return gears[gear - 1]
88 |
89 |
90 |
91 | cur_stat = []
92 | cur_stat.append("+-----------------------------------+-----------------+-----------+")
93 | cur_stat.append("| Cortex-A53 | Cortex-A72 | Mali-T860 |")
94 | cur_stat.append("+--------+--------+--------+--------+--------+--------+-----------+")
95 | cur_stat.append("| CPU 0 | CPU 1 | CPU 2 | CPU 3 | CPU 4 | CPU 5 | GPU |")
96 | cur_stat.append("+--------+--------+--------+--------+--------+--------+-----------+")
97 | cur_stat.append("| 600MHz | OFF | OFF | OFF | OFF | OFF | 400MHz |") #5
98 | cur_stat.append("+--------+--------+--------+--------+--------+--------+-----------+")
99 |
100 |
101 | def isDigit(x):
102 | try:
103 | float(x)
104 | return True
105 | except ValueError:
106 | return False
107 |
108 |
109 | class A06:
110 | cpus = []
111 | cpu_scaling_governor= "schedutil"
112 | gear = load_gear(1) # 1-5
113 | null_out = "2>/dev/null"
114 | def __init__(self):
115 | self.cpus = []
116 | self.init_cpu_infos()
117 | self.cpu_total_count = len(self.cpus)
118 |
119 | def init_cpu_infos(self):
120 | self.cpus = glob.glob('/sys/devices/system/cpu/cpu[0-9]')
121 | self.cpus.sort()
122 |
123 | def get_cpu_gov(self):
124 | if self.gear["cpu"][0] > 0:
125 | cpu_gov_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
126 | else:
127 | cpu_gov_path = "/sys/devices/system/cpu/cpufreq/policy4/scaling_governor"
128 | gov = ""
129 | with open(cpu_gov_path,"r") as f: gov = f.read().strip()
130 | return gov
131 |
132 | def set_cpu_gov0( self,gov):
133 | cpu_gov_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"
134 | try:
135 | subprocess.run( "echo %s | sudo tee %s " %(gov,cpu_gov_path),shell=True,stdout=subprocess.DEVNULL)
136 | except:
137 | print("set cpu governor failed")
138 |
139 | def set_cpu_gov4( self,gov):
140 | cpu_gov_path = "/sys/devices/system/cpu/cpufreq/policy4/scaling_governor"
141 | try:
142 | subprocess.run( "echo %s | sudo tee %s" %(gov,cpu_gov_path),shell=True,stdout=subprocess.DEVNULL)
143 | except:
144 | print("set cpu governor failed")
145 |
146 |
147 | def get_cpu_on_off(self,cpu_num):
148 | cpu_onoff_file = "/sys/devices/system/cpu/cpu%d/online" % cpu_num
149 | onoff = "0"
150 | max_freq = "0"
151 | with open(cpu_onoff_file,"r") as f: onoff = f.read().strip()
152 | if onoff == "1":
153 | cpu_max_freq_file = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq" % cpu_num
154 | with open(cpu_max_freq_file,"r") as f: max_freq = f.read().strip()
155 | mhz = int(max_freq)/1000
156 | return "%dMhz" % mhz
157 |
158 | return "OFF"
159 |
160 |
161 | def set_cpu_on_off(self,cpu_num,onoff):
162 | cpu_onoff_file = "/sys/devices/system/cpu/cpu%d/online" % cpu_num
163 | try:
164 | #print("echo %d | sudo tee %s" %(onoff,cpu_onoff_file) )
165 | subprocess.run( "echo %d | sudo tee %s" %(onoff,cpu_onoff_file),shell=True,stdout=subprocess.DEVNULL)
166 | except:
167 | print("set cpu %d on off failed" % cpu_num)
168 |
169 | def set_cpu_max_freq(self,cpu_num,max_freq):
170 | cpu_max_freq_file = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq" % cpu_num
171 | try:
172 | subprocess.run( "echo %d | sudo tee %s" %(max_freq,cpu_max_freq_file),shell=True,stdout=subprocess.DEVNULL)
173 | except:
174 | print("set cpu %d max freq failed" % cpu_num)
175 |
176 | def get_gpu_freq(self):
177 | gpu_sys_path = "/sys/devices/platform/ff9a0000.gpu/devfreq/ff9a0000.gpu"
178 | gpu_freq_path = os.path.join(gpu_sys_path,"max_freq")
179 | freq = ""
180 | with open(gpu_freq_path,"r") as f: freq = f.read().strip()
181 | mhz = int(freq)/1000000
182 | return "%dMHz" % mhz
183 |
184 | def set_gpu(self,gov,hz):
185 | gpu_sys_path = "/sys/devices/platform/ff9a0000.gpu/devfreq/ff9a0000.gpu"
186 | gpu_gov_path = os.path.join(gpu_sys_path,"governor")
187 | gpu_freq_path = os.path.join(gpu_sys_path,"max_freq")
188 | try:
189 | subprocess.run("echo %s | sudo tee %s" %(gov,gpu_gov_path),shell=True,stdout=subprocess.DEVNULL)
190 | subprocess.run("echo %d | sudo tee %s" %(hz, gpu_freq_path),shell=True,stdout=subprocess.DEVNULL)
191 | except:
192 | print("set gpu failed")
193 |
194 |
195 | def print_cpu_gpu_gov(self):
196 | print("CPU Governor: %s GPU Governor: %s" % (self.get_cpu_gov(), self.gear["gpu_gov"]))
197 |
198 | def print_cur_status(self):
199 | global cur_stat
200 |
201 | stat_str = "|%s|%s|%s|%s|%s|%s|%s|"
202 |
203 | cpu0 = self.get_cpu_on_off(0).center(8)[:8]
204 | cpu1 = self.get_cpu_on_off(1).center(8)[:8]
205 | cpu2 = self.get_cpu_on_off(2).center(8)[:8]
206 | cpu3 = self.get_cpu_on_off(3).center(8)[:8]
207 | cpu4 = self.get_cpu_on_off(4).center(8)[:8]
208 | cpu5 = self.get_cpu_on_off(5).center(8)[:8]
209 | gpu = self.get_gpu_freq().center(11)[:11]
210 |
211 | table_str = stat_str %(cpu0,cpu1,cpu2,cpu3,cpu4,cpu5,gpu)
212 | print("\nCurrent Status:")
213 | for idx,val in enumerate(cur_stat):
214 | if idx == 5:
215 | print(table_str)
216 | else:
217 | print(val)
218 |
219 | self.print_cpu_gpu_gov()
220 |
221 | def set_gear(self,g):
222 | self.gear = load_gear(g)
223 |
224 | if g > 3:
225 | for (cpu, freq) in reversed(list(enumerate(self.gear["cpu"]))):
226 | enabled = freq > 0
227 | self.set_cpu_on_off(cpu, int(enabled))
228 | if enabled:
229 | self.set_cpu_max_freq(cpu, freq)
230 | else:
231 | for (cpu, freq) in enumerate(self.gear["cpu"]):
232 | enabled = freq > 0
233 | self.set_cpu_on_off(cpu, int(enabled))
234 | if enabled:
235 | self.set_cpu_max_freq(cpu, freq)
236 |
237 | self.set_gpu(self.gear["gpu_gov"], self.gear["gpu_freq"])
238 |
239 | # TODO: Generalise this
240 | if self.gear["cpu"][0] > 0:
241 | self.set_cpu_gov0(self.cpu_scaling_governor)
242 | else:
243 | self.set_cpu_gov4(self.cpu_scaling_governor)
244 |
245 |
246 |
247 | def print_gear_map(gear):
248 | print(" +-----------------------------------+-----------------+-----------+")
249 | print(" | Cortex-A53 | Cortex-A72 | Mali-T860 |")
250 | print(" +--------+--------+--------+--------+--------+--------+-----------+")
251 | print(" | CPU 0 | CPU 1 | CPU 2 | CPU 3 | CPU 4 | CPU 5 | GPU |")
252 | div = "+---+--------+--------+--------+--------+--------+--------+-----------+"
253 | print(div)
254 |
255 | def freq(khz):
256 | mhz = khz/1000
257 | if mhz >= 1000:
258 | return "%d MHz" % mhz
259 | elif mhz > 0:
260 | return " %d MHz" % mhz
261 | else:
262 | return " OFF "
263 |
264 | for idx, val in enumerate(gears):
265 | g = idx + 1
266 | selected = g == gear
267 | print("|%s|%s| %s |%s" % (
268 | ("*%s*" if selected else " %s ") % g,
269 | "|".join([freq(cpu) for cpu in val["cpu"]]),
270 | freq(val["gpu_freq"]/1000),
271 | " <===" if selected else "",
272 | ))
273 | print(div)
274 |
275 | def print_help_msg():
276 | print("Usage: devterm-a06-gearbox [OPTION]...")
277 | print("Show or set the CPU operating frequency,online status and GPU operating frequency for DevTerm A06.")
278 | print()
279 | print(" -s, --set [n] set a speed mode between the number 1-%d:" % len(gears))
280 | for (i, _) in enumerate(gears):
281 | print(" %d for %s." % (i + 1, gears[i]["use"]))
282 | print()
283 | print("Examples:")
284 | # TODO: Generate this example
285 | print("Set to mode 1, single LITTLE core @600MHz(max), GPU@200MHz.")
286 | print(" $ devterm-a06-gearbox -s 1")
287 |
288 | def is_root():
289 | return os.geteuid() == 0
290 |
291 | def main(argv):
292 | gear = 1
293 | try:
294 | opts, args = getopt.getopt(argv,"hs:",["set="])
295 | except getopt.GetoptError:
296 | print_help_msg()
297 | sys.exit(2)
298 | for opt, arg in opts:
299 | if opt == '-h':
300 | print_help_msg()
301 | sys.exit()
302 | elif opt in ("-s","--set"):
303 | if(isDigit(arg)):
304 | gear = int(arg)
305 | if gear not in range(1, len(gears) + 1):
306 | print("illegal input: mode range 1-%d" % len(gears))
307 | sys.exit(-1)
308 |
309 |
310 | DT = A06()
311 |
312 | if len(argv) == 0:
313 | DT.print_cur_status()
314 | sys.exit(0)
315 |
316 | DT = A06()
317 | if is_root():
318 | DT.set_gear(gear)
319 | print_gear_map(gear)
320 | DT.print_cpu_gpu_gov()
321 | else:
322 | print("Require super user privilege to set mode,try run it with sudo")
323 | sys.exit(1)
324 |
325 | if __name__ == "__main__":
326 | main(sys.argv[1:])
327 |
--------------------------------------------------------------------------------
/scripts/ja2en:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | # install https://github.com/soimort/translate-shell
4 | # sudo apt-get install translate-shell
5 |
6 | trans -t en -f ja "$1"
7 |
8 |
--------------------------------------------------------------------------------