Open nekr0z opened 3 years ago
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:
ACPI_Debug.kext
SSDT-RMDT.aml
file during boot phase which is a file with user-defined methods in ACPI language for interacting with ACPI_Debug.kext
ioio
utility for calling those user-defined methods declared in SSDT-RMDT.aml
fileI 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:
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 :
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
log stream ...
command(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.
PATH
in OS X, don't they? And I can reasonably expect ioio
to be in PATH
, right?ioreg
that knows everything about the current state of hardware-related variables. Could we get thresholds from ioreg
?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:
ioio -s org_rehabman_ACPIDebug WHATEVER
),kernel: (ACPIDebug) ACPIDebug: { "Reading (hexadecimal values):", 0x28, 0x3c, }
you gave me for thresholds, andOk, 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 :
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 :
0x0343
field of the EC registry with the \_SB.PCI0.LPCB.EC0.RRAM
method (the same way we read the thresholds in DBG4)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)* 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...
Yep ! Setting it to 0 strangely resets the thresholds to 40-70...
That's not really strange (for pre-2020 MateBooks), it was a long shot anyway.
I've pushed new code. It doesn't do DBG0 anymore. Please test and confirm it works and turns the protection off still.
Also, the new code allows you to go run build.go -m
, which should give you a neat matebook-applet.app
bundle. If you open the directory in your Finder, it shows it without the .app
extension, but you can tell it from the binary by the icon, hopefully. This bundle can be run without terminal by simply double-clicking, and I suppose you could make it autostart, too (I don't know how it's done in MacOS, though).
The new code does turn off the protection as expected.
About the matebook-applet.app
: it launches, but the options are missing
I've tried to launch the matebook-applet
binary bundled inside the .app : it works as expected.
The new code does turn off the protection as expected.
But still the applet doesn't know it's turned off, right?
it launches, but the options are missing
Oops, I did not expect this. It looks like the app being launched from within the bundle can't access the log
executable. Some quick googling told me that this is indeed expected, a bundled app isn't allowed to execute commands outside of its bundle. This essentially means that unless we find a way to talk to the kext
directly, without log
and ioio
, the bundle will be useless. Which is a shame, because I spent quite some time figuring it all out. Well, there's no such thing as useless knowledge, is there? ;)
For now, you MacOS crowd will need to figure out the way to run the applet without the terminal for yourselves. Googling brings up AppleScript as a possible solution, I don't know how feasible that is.
There's actually a dirty hack I came across while googling this matter last night, but it's quite old and I don't know if it can trick the modern system. The idea is to make a symlink to the required application inside the bundle (presumably, it should go in the Content/Resources
subdir, but I'm not sure). The applet needs ioio
and log
, so these are the binaries that need to be symlinked.
I've tried the symlink trick inside Content/Ressources and also tried to copy paste the full binaries in this folder : still not working... I don't have a clue about what we could do about this. I will try to investigate...
But still the applet doesn't know it's turned off, right?
I've just checked : it displays an error in the applet (but the battery protection is effectively turned off) :
It's possible to set a threshold again despite this error. But, if matebook-applet is switched off without setting a new battery protection mode, at the next launch of the applet it's not possible to use it anymore :
I have toyed with the idea of talking directly to kext via the library I've mentioned. I think I could (given enough time and your debugging effort) rewrite ioio
in Go to include as part of the applet's driver, but that doesn't solve the log
problem.
at the next launch of the applet it's not possible to use it anymore
There are two issues here. First is a bug: the applet wouldn't read a singe-digit 0x6
from the log (you can see in the trace that the value got ignored. That one I've fixed, new code is pushed. The second issue is the fact that your system reports insane values (i.e. max threshold is lower that min). I think the applet (now that I fixed the bug) will still complain, but should work. Give it a try.
I will try to investigate...
I can't debug this, unfortunately, but you can try (with symlinks, copying binaries shouldn't work) giving explicit paths to binaries. I'm not really sure how they should be called from within a bundle. I coded simply "ioio"
and "log"
(so they get executed if they are in PATH), but it could be that from the bundle it should be "Resources/ioio"
or "../Resources/ioio"
, or some such.
The actual calls are in driver-darwin.go
file, lines 80 and 83; you may try changing these and rebuilding the bundle. You need to get both commands right for it to matter. Obviously, this would break the standalone executable, but we can statr working around that if you find a working setup.
There are two issues here. First is a bug: the applet wouldn't read a singe-digit
0x6
from the log (you can see in the trace that the value got ignored. That one I've fixed, new code is pushed.
It is fixed with the new code 👍
The second issue is the fact that your system reports insane values (i.e. max threshold is lower than min).
I think there is a bug in the implementation of setting a very low threshold : if I try to set a custom threshold in windowed mode, it doesn't work with threshold<16% (same insane values in logs) This would explain the 0-100 problem (which would only be a specific case of this broader bug)
When I manually set the value with DBG5 (ex : 0-100% = 0x64000000 = ioio -s org_rehabman_ACPIDebug dbg5 1677721600
, or 10-15% = 0x0F0A0000 =ioio -s org_rehabman_ACPIDebug dbg5 252313600
) and then launch the applet, it doesn't report anything weird...
Maybe another problem with single digit hex numbers ?
Maybe another problem with single digit hex numbers ?
Great catch! Indeed it was. Fixed, pushed, please test ;)
Great catch! Indeed it was. Fixed, pushed, please test ;)
Fixed !
I think I finally found a way of having battery protection OFF reported as 0-100, as in Linux :
ioio -s org_rehabman_ACPIDebug dbg6 0
. It bypasses SBTT and manually sets the thresholds to 0-100.From my tests, after using this command, matebook-applet is already able to tell that BP is OFF.
Could you please implement this command ?
And well, after that, apart from the bundled app thing, I guess we've got a 100% working app !! 😃
It bypasses SBTT and manually sets the thresholds to 0-100
Hmm... Did you consider rewriting DBG5 so that it bypasses SBTT and sets arbitrary thresholds? ;-) I mean, implementing DBG6 is easy, but I like the code without the corner cases much better.
after that, apart from the bundled app thing, I guess we've got a 100% working app !!
FnLock?
Hmm... Did you consider rewriting DBG5 so that it bypasses SBTT and sets arbitrary thresholds? ;-) I mean, implementing DBG6 is easy, but I like the code without the corner cases much better.
You're right, it makes much more sens. I've updated the DBG5 method : switching BP OFF is now functional.
FnLock?
About this : would you like Fn-Lock reading to be done in DBG5 or in a dedicated method ?
would you like Fn-Lock reading to be done in DBG5 or in a dedicated method ?
I hope you meant DBG4 ;-)
I can live with either option, but since FnLock is a totally separate thing, it would be more logical to have totally separate methods for it. IMHO.
OK, so I've implemented a DBG6 method to get the Fn-Lock state : it returns 0 (default behaviour = priority to brightness/sound/... keys) or 1 (priority to F1-F12 keys) :
Method (DBG6, 1, Serialized)
{
Local0 = \_SB.PCI0.LPCB.EC0.RRAM (0x03E6)
\RMDT.P2 ("Reading Fn-Lock state :", Local0)
}
The DBG7 method implements setting Fn-Lock state quite like DBG5 : the argument expected by the \SFRS method inside is a hex in a 0xY0000 format, where : Y = 2 enables Fn-Lock state (priority to brightness/sound/...) and Y = 1 switches it off, back to default behaviour. So that's 0x20000 and 0x10000, so 131072 and 65536 in the ioio command.
Method (DBG7, 1, Serialized)
{
Local0 = Arg0
\RMDT.P2 ("Value : ", Local0)
\SFRS (Local0)
\RMDT.P1 ("Fn-Lock state set")
}
Please find the relevant logs from log stream
.
Implemented and pushed. Please test, and please also test that I didn't break the battery functionality while refactoring for this implementation ;-)
Everything seems to be perfectly working ! This is so cool :) I will keep testing the applet during the coming days, to see if there are some edge-cases/issues that I didn't spot. In the meantime, I'm still investigating the app bundle stuff, but since I have absolutely zero knowledge about this, don't expect solutions very soon.
(What I'm going to say might be total nonsense since I don't really know what I'm talking about :) )
From what I understand, accessing external binaries from a .app ressource should work. It's only in the specific case of a sandboxed app (ex: apps submitted to the AppStore) that external binaries are supposed to be unreachable.
I've done some tests with Automator : If I package matebook-applet binary in an app bundle with Automator, it doesn't work (it launches but can't call external commands). But if I first declare the path variable in Automator's script , then the resulting .app works as expected. Here's my very simple Automator code :
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
'/Users/ldan93/matebook-applet/matebook-applet'
Do you have the option to explicitly declare the path folder the way I did ?
I can also report that launching the .app from Terminal with an explicit var_path option also works :
ENV_PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin open -a matebook-applet.app
Do you have the option to explicitly declare the path folder the way I did ?
Interesting! I need to dig deeper into this. Not really something that is sensible to do from within the app, but I feel there must be an option in Info.plist
for that...
I actually tried to set a custom PATH in the .plist, with LSEnvironment ( cf. https://apple.stackexchange.com/a/79845 ) but I had no luck... Maybe there's a parameter to set at compilation time ?
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: