matebook-applet
matebook-applet copied to clipboard
Support MacOS
People are running MacOS on Matebooks, and it looks like matebook-applet
would be welcome there.
It should be relatively easy to add MacOS-specific endpoints and have them probed when running the applet on MacOS. All our dependencies support MacOS, so there shouldn't be a problem.
Two things prevent me from implementing this straight away:
- Their current way of doing things doesn't allow to set arbitrary thresholds. Setting arbitrary thresholds is more versatile and is our preferred way of interacting with endpoints. It can be worked around, but I'd prefer not to if there's a way.
- It's unclear how to get the currently set values on MacOS.
Here I am. As I said, I am very happy to collaborate with you. Thank you very much for your willingness!
Their current way of doing things doesn't allow to set arbitrary thresholds. Setting arbitrary thresholds is more versatile and is our preferred way of interacting with endpoints. It can be worked around, but I'd prefer not to if there's a way.
I have to do some tests on the script created by @ldan93 but, in my opinion, it should be possible to set arbitrary thresholds.
It's unclear how to get the currently set values on MacOS.
@ldan93 uses the following steps:
- loading (i.e. injecting during boot phase) a sort of library/driver (created mainly for debugging purpouses) called kext on macOS i.e.
ACPI_Debug.kext
- loading a
SSDT-RMDT.aml
file during boot phase which is a file with user-defined methods in ACPI language for interacting withACPI_Debug.kext
- using
ioio
utility for calling those user-defined methods declared inSSDT-RMDT.aml
file
I think it should be possible pass some arbitrary values to ioio
utility -> user-defined methods in SSDT-RMDT.aml
file
in my opinion, it should be possible to set arbitrary thresholds.
From what I have understood, there's no straightforward way (using that script) to set, for example, 35-75 or 56-71 (i.e. totally arbitrary values for both high and low as long as low<high). Having such a possibility would be ideal, and make the applet adaptation much less of a hassle.
it should be possible pass some arbitrary values to
ioio
utility -> user-defined methods inSSDT-RMDT.aml
file
I need to read into all of this more, I'm totally unfamiliar with the whole ioio
deal, or even with how MacOS talks to ACPI in the first place.
Basically, here's what I have in mind as an algorithm:
- The applet issues a command that returns the current battery limit values. This can be basically a command you'd put into a terminal to read the results from the same terminal. It can be complicated, if needed, involve more than one step and such. This command is the first thing that needs to be figured out.
- The applet parses what it got from that command, and either figures out the current settings (and can display it for the user) or decides that what it received doesn't make sense and maybe the user didn't install all the necessary utilities or hasn't loaded the necessary modules at boot-time. In the latter case the applet can throw a error message and advise the user to go read some manuals and install the required things.
- At the user's command, the applet sets the required limits, and goes back to 1. to check that the limits have been set as asked.
Actually, this is how it currently works on Linux. Figuring out the command (set of commands) for 1. is the first step (and half the job, really).
Hello @nekr0z and @profzei Porting matebook-applet to MacOs would be very very nice, thank you for your implication ! The current implementation is very hacky but I'm sure there are some workarounds. Here are some thoughts :
- About setting arbitrary thresholds : there is a way. We can write an ACPI method that takes the thresholds as an argument and then sets them. The only limitation is that you can only pass one argument to an ACPI method with ioio. The most convenient way would be to directly send the whole argument used by the \SBTT method (ie. XXYY0000 where XX is the max value and YY the min value coded in hexadecimal)
- About getting the current values : it's quite tricky. Currently, what my basic script does is : request the values through an ACPI call, and then the values are written in the system logs of MacOS. Theoretically, we might be able to extract the values from the terminal by parsing the system log file, but this is not ideal. I'm sure there is a more conventional way of getting EC/ACPI values in MacOS, but I don't know how... We might ask for help in the ACPI-Debug's thread on Tonymacx86...
send the whole argument used by the \SBTT method (ie. XXYY0000 where XX is the max value and YY the min value coded in hexadecimal)
Perfect, we'll do that.
we might be able to extract the values from the terminal by parsing the system log file, but this is not ideal.
Yep, I've already toyed with this idea. Doable, but too many moving parts, I'd prefer some other alternative.
So, I've written a basic ACPI Method (DGB5) in SSDT-RMDT.aml
It takes the XXYY0000 argument as an input.
In terminal, you must type in :
./ioio -s org_rehabman_ACPIDebug dbg5 ARG
Where ARG is XXYY0000 converted to a decimal number (because ioio expects a decimal number)
Ex : if you want to set the thresholds to 60-80 (so 3C-50 in hex) --> the SBTT method needs to receive "0x503C0000" --> this is 1346109440 in decimal :
./ioio -s org_rehabman_ACPIDebug dbg5 1346109440
./ioio -s org_rehabman_ACPIDebug dbg5 ARG
Is there a reasonable expectation of where ioio
is on the system? ./
requires cd
to that directory, which is not straightforward to do for a GUI app ;-)
Well, currently I put ioio
in /Applications/Utilities
. But I'm thinking it might be better to put it in the /usr/local/bin
folder. So, this way the ioio command could be invoked system-wide no matter the current active directory. What do you think ?
I think if we can't really rely on ioio
being accessible from some standard place (or PATH
, or whatever), I'd better figure out how to talk to kext
directly. ;-)
Well, ioio
is basically a binary that must be downloaded and manually copied somewhere by the user. It's not installed through a standardised package like in a Linux environment. But that's not really a problem, since we can tell users where to put the binary in @profzei documentation. Or maybe you could package ioio with matebook applet ?
About avoiding using ioio
: well, after some research, I truly think this utility is the most convenient way of calling ACPI method from user-space, and more generally it is precisely designed to interact with kernel extensions. But if you find a better option, that's perfect !
About getting the current thresholds, I've investigated the process of parsing system logs. Even if it's not the best path, this is achievable with this script I wrote :
#!/bin/sh
# threshold.sh
log stream --predicate 'senderImagePath contains "ACPIDebug"' | sed -n 's/.*XXYYZZ", \(.*\), "ZZYYXX.*/\1/p' &
sleep 0.2
ioio -s org_rehabman_ACPIDebug dbg4 0
sleep 0.2
killall log
- We can monitor the log specifically related to the ACPIDebug kext with the
log stream ...
command - I've modified the ACPI method reading the thresholds (dbg4), so that its output is printed in log between a "XXYYZZ" and "ZZYYXX" string
- The sed command then finds the XXYYZZ MIN MAX ZZYYXX pattern, cleans the log, and outputs the thresholds to shell when the log process is killed :
(In my example, the thresholds are 40-50%, so 28-32 in hexadecimal)
OK, I'm getting close to hacking up a crude prototype, but my lack of MacOS knowledge starts showing. Please enlighten me, because I'm kinda lost here.
- They do have
PATH
in OS X, don't they? And I can reasonably expectioio
to be inPATH
, right? - OS X is basically BSD and is supposed to have
ioreg
that knows everything about the current state of hardware-related variables. Could we get thresholds fromioreg
?
They do have PATH in OS X, don't they? And I can reasonably expect ioio to be in PATH, right?
Positive answer! (we can put ioio
into PATH
)
Could we get thresholds from ioreg?
I tried to look at into my ioreg but I didn't find any useful info about battery thresholds maybe because I didn't look for the "right entry"
Positive answer! (we can put
ioio
intoPATH
)
That's good. Makes it actually feasible to use ioio
, at least for a start. I've found a library that supposedly allows talking to KEXT directly, but since I know very little about KEXT and can't really debug things without running OS X on my Matebook (which I'm not planning to do), the debugging would be extremely hard.
I tried to look at into my ioreg but I didn't find any useful info about battery thresholds
Would you mind patching your ioreg
output to a text file (i.e. ioreg > ioreg.txt
) and letting me have a look? It will only give one of the planes by default, but the ACPI devices are likely to be shown...
In other news: I've been able to compile matebook-applet
on OS X and make it run. Cross-compiling graphical applications turns out to be unfeasible, so I requisitioned my wife's old MacBook Air. Unfortunately, it runs very ancient OS X (10.8 or something), which is probably why I'm getting compilation errors and applet mode crashes. The good thing is, windowed mode does run, so I can do some debugging (as much as possible without the actual hardware, that is).
If someone has Go installed, I'd appreciate if you tried to clone this repository, check out the darwin
branch, go run build.go
, and try to run ./matebook-applet -vv
to confirm it indeed does run and puts the icon in the tray (it doesn't do much more on OS X yet) instead of crashing like on the machine I have. :) If, however, you don't have Go installed, don't bother: we'll have a working prototype soon, we'll test it in the windowed mode, and then merge it to master branch and have Travis build it on a decent enough OS X version…
On my computer, with macOS 10.15, it builds but it doesn't run/put the icon in the tray... I have attached the build logs and the output of ./matebook-applet -vv
: logs.txt.zip
On my computer, with macOS 10.15, it builds but it doesn't run/put the icon in the tray... I have attached the build logs and the output of
./matebook-applet -vv
: logs.txt.zip
Thank you so very much! It's awesome that you have Go set up, your help in debugging is priceless.
Looks like we're hitting a known issue with the systray library. It only manifests on OS X. Since your behaviour is the same as mine, I can further debug this one by myself.
But first let's get at least something working. I've pushed some new code to the darwin
branch. It would be awesome if you could build it (the build log will spit some warnings, don't mind), run ./matebook-applet -vv -w
, and show me the output. It would be absolutely great if you used the SSDT-RMDT that you posted before and not the one you've customized for the script: it's the exact output that I'm interested in.
What's supposed to happen is for the applet to do all the steps from threshold.sh
up to the point of getting the relevant log line, then clean up by killing the log
process. The actual parsing is not yet coded, so the applet will assume battery protection is off and draw the window accordingly.
You're welcome !
So I've built the new code and run it with my previous custom SSDT-RMDT (the one without the XXYYZZ stuff).
Here's the output : logs2.txt.zip
The window is drawn :
I've been thinking about something else : I used your applet in Linux before switching to MacOs. I've just remembered that there was an option to tweak Fn-Lock. I definitely think I could quite easily add relevant ACPI methods in the SSDT-RMDT to get and set Fn-Lock state, so we could also implement this later on.
@ldan93 thanks again! We're closing in.
I've been trying to nail that systray issue, but with no luck yet. I still have a couple of ideas to try, so not all is lost (yet). For now I've simply disabled the applet mode for OS X (i.e. it's always -w
, even it you don't specify it).
I've pushed more code, and would appreciate a final test. If I got it right, it should parse the thresholds, paint a window and even allow setting the thresholds. If I made a mistake somewhere (which is totally possible and actually likely) and something doesn't work, I'd appreciate the -vv
output. ;)
I definitely think I could quite easily add relevant ACPI methods in the SSDT-RMDT to get and set Fn-Lock state, so we could also implement this later on.
Totally. If battery thresholds work, implementing FnLock control will be a piece of cake. All I need is:
- the hook to read state (i.e.
ioio -s org_rehabman_ACPIDebug WHATEVER
), - a sample of a log line I'm looking for (like
kernel: (ACPIDebug) ACPIDebug: { "Reading (hexadecimal values):", 0x28, 0x3c, }
you gave me for thresholds, and - the hook to set state.
Ok, I was finally able to make the applet mode work. Unfortunately, with these libraries on OS X there seems to be no way to have a window drawn and the systray at the same time, so no custom threshold settings for the applet mode, sorry. Should work in the windowed mode, though.
Thank you so much !! Seeing this project materialising at such a great pace is so cool !
So, the applet mode is drawn as expected and the applet is able to set the thresholds. Here are some observations :
-
At the moment, matebook-applet is still reporting that Battery protection is OFF even though it's not the case
-
From what I understand from reading the verbose mode : after clicking on a battery protection mode, matebook-applet sets the thresholds, and immediately reads the new thresholds by checking the logs. I think this check is done a bit too early : everytime a threshold is set, the log displayed in verbose is still reporting the previous state, even though the new threshold seems to be actually set. I don't know if I'm making myself clear, but you will see in my logs that every time I click on a mode, battery threshold reading seems to always be "one step behind". Is this the expected behaviour ?
* still reporting that Battery protection is OFF even though it's not the case
Oops, missed that one. Should be working with the latest code.
* Is this the expected behaviour ?
Not really. :) I've put a 500 ms delay in the latest commit, hope it does the trick. We can always increase it if that's not enough.
Try again?
-
The applet is no longer reporting Protection OFF 👍
-
I think the 500ms delay is slightly not enough : the logs are now accurate... 2/3 of the time. Maybe we can try 1 sec ?
-
Is there a way of running the applet without having a Terminal window opened ? (Launching the binary from the file explorer or putting it in the startup programs always open a Terminal in the background)
- delay is slightly not enough : the logs are now accurate... 2/3 of the time.
Actually, there used to be the same issue with the linux driver, and we even have code to mitigate it. That has long been obsolete, as the linux driver was fixed by Ayman, but the code is still there. I activated it for OS X, should to the trick.
- Is there a way of running the applet without having a Terminal window opened ? (Launching the binary from the file explorer or putting it in the startup programs always open a Terminal in the background)
I wouldn't really know, MacOS is not really my realm. ;) From what I gathered so far, I need to make something called an App Bundle, which should be relatively straightforward to do. I was planning on figuring this out as soon as we have the applet really working, so it looks like that's what I'll be doing next.
The plan is to have a build script option to generate that App Bundle thing when building for MacOS.
There is a small issue that I forgot to report :
- Setting battery protection OFF works : the battery charges again
- BUT it is not reported by the applet : it displays "HOME", whatever what the previous mode was, and in the logs it seems the thresholds are read as x28/x46 logs4.txt.zip
When I wrote my first hacky script, I actually noticed the same strange behaviour : setting thresholds to 0-100 and then reading them would report an unreliable output...
Apart from that, everything is working really nice, thanks again for your wonderful work 👍
@ldan93 The applet uses the log trick to report thresholds (as you might have already guessed). Since the log doesn't show the protection is off, the applet can't guess it.
On Linux the driver always reports the thresholds as 0-100 or 0-0 when battery protection is off, and that's how the applet figures it out. We either need to set the thresholds to those values as part of switching the protection off, or else we need some command or a log trick for the applet to probe whether the protection is off.
Currently for setting the thresholds the applet uses your DBG5 method, except for actually for switching it off, which is done by calling your DBG0 method. Looks like the DBG0 method, while turning the protection off, fails to change the thresholds that later get reported in the log. I noticed that it has \SBTT (0x64000000)
inside, so it does try to set 0-100
. I wonder if trying to set 0-0
instead would do the trick…
Setting 0-0 doesn't do the trick...
About the DBG0 method : actually, we should not use this one, this was a very bad implementation I wrote... Because of the "Sleep" function in the ACPI code, it makes the Matebook freeze for one second. Just using the DBG5 method with 0 - 100 values (so the argument would be 1677721600
) disables battery protection in a more acceptable way. Would you mind using this way ?
Then, I've done some reverse engineering on the EC registry. I think we've got a way of knowing whether battery protection is OFF or ON :
- We must read the
0x0343
field of the EC registry with the\_SB.PCI0.LPCB.EC0.RRAM
method (the same way we read the thresholds in DBG4) - From my understanding :
0x80
means battery protection if OFF, and0xc0
means it's ON (I'm not 100% sure, but this has been consistent across many tries) - ATM moment I've modified the DBG4 method so it sends on more line to log with battery protection state (after the line with the thresholds). Here's how it looks in the logs. But if you want me to implement Battery protection state reading in a dedicated method (DBGsomething), I can also do this.
* From my understanding : `0x80` means battery protection if OFF, and `0xc0` means it's ON (I'm not 100% sure, but this has been consistent across many tries)
Nope. Well, maybe your model is an exemption, but on all MateBooks I've seen, including mine, that one is for "charging allowed/disallowed". If your protection is on, it will be 0xc0
when the required level is reached (so that the laptop doesn't charge the battery anymore), and turn into 0x80
as soon as the battery charge drops below the desired level.
OK then, this was a bad guess, never mind...
Setting 0-0 doesn't do the trick...
You did it manually via DBG5, right? Not via the applet? Because the applet wouldn't really do that for now.
we should not use this one
OK, will change.
You did it manually via DBG5, right? Not via the applet? Because the applet wouldn't really do that for now.
Yep ! Setting it to 0 strangely resets the thresholds to 40-70...