-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Frontlight action #3
Comments
There are two options for this action. Firstly, I could use I'll probably go with the first option, but I haven't decided if it should go into the Update: It seems I was slightly mistaken about the |
This is now becoming harder to implement than I originally thought due to the fact I'm now having to work around both C++ and Qt in addition to Nickel to try and initialize a FrontLight object. Update: Oh, and this just made it even more annoying (the FrontLight constructor connects a bunch of signals, and I just segfaulted): But, it may have actually made it slightly easier, as I might be able to (ab)use the main loop's object as a parent. |
Yeah, given the number of issues over the years with keeping frontlight status in sync across a bunch of stuff (all because the kernel did not expose a way to read the fl status until Mk.7, only set it), it doesn't surprise me all that much... Good luck ;). |
I've finally got some of the QObject trickery working: QObject *parent = new QObject(nullptr); // we can't just use another object directly, as FrontLight will replace the vtable
parent->moveToThread(QApplication::instance()->thread()); // the QObject doesn't have a thread to begin with
NM_ASSERT(parent->thread(), "our parent QObject doesn't have a thread for FrontLight to attach signals to");
FrontLight *fl = FrontLight_FrontLight(parent); // this will replace the vtable and attach some signals
NM_ASSERT(fl, "frontlight didn't return anything"); // it's more likely to just segfault in the constructor It doesn't segfault anymore, but I have to see if it can actually call stuff (although, the destructors working properly is a good sign)... |
Yeah. The only reason I'm still going through with this is because figuring this out will be useful for when I need to call other similar objects (and because it's fun). If it wasn't for that, I'd just defer this feature indefinitely until I have some other need for figuring this sort of thing out. |
OK, so it seems that does at least work for simple getters, which means I haven't messed up the memory layout: NM_RETURN_OK(nm_action_result_toast("test: %d", (reinterpret_cast<int(*)(FrontLight*)>(dlsym(RTLD_DEFAULT, "_ZNK10FrontLight11temperatureEv"))(fl)))); Now I just have to figure out which int param is which (and the temperature bool param) for Update: It seems to find the correct ChannelMixer in its own vtable, then forward the function call to it. One of the params (I'll have to do some math with the ChannelMixer assembly to figure it out) is for the animation. Update: I haven't tested it yet, but the second int parameter seems to be for the animation duration (or 0 for making it instant). |
Oh, and I don't remember if I've mentioned it before, but for if anyone wants to figure out the vtable addresses for themselves, you need to do the pointer math on the LDR instruction and the ones before it, then resolve that against the relocations and the dynstr table (you can use symdump from kobopatch for that, or you can use readelf). |
I've managed to get the frontlight changing working. Here's the relevant code (not including the FrontLight init from above): if (!strcmp(thingy, "level")) {
char *end;
long pct = strtol(value, &end, 10);
NM_ASSERT(*thingy && !*end && pct >= 0 && pct <= 100, "level (%%) invalid or out of range 0-100: '%s'", value);
bool (*Device__supportsLight)(Device*);
reinterpret_cast<void*&>(Device__supportsLight) = dlsym(RTLD_DEFAULT, "_ZNK6Device13supportsLightEv");
if (Device__supportsLight)
NM_ASSERT(Device__supportsLight(dev), "device does not have a light");
FrontLight_setBrightness(fl, (int)(pct), 0);
void (*PowerSettings__setFrontLightState)(Settings*, bool);
reinterpret_cast<void*&>(PowerSettings__setFrontLightState) = dlsym(RTLD_DEFAULT, "_ZN13PowerSettings18setFrontLightStateEb");
NM_ASSERT(PowerSettings__setFrontLightState, "could not dlsym PowerSettings::setFrontLightState");
void (*PowerSettings__setFrontLightLevel)(Settings*, int);
reinterpret_cast<void*&>(PowerSettings__setFrontLightLevel) = dlsym(RTLD_DEFAULT, "_ZN13PowerSettings18setFrontLightLevelEi");
NM_ASSERT(PowerSettings__setFrontLightLevel, "could not dlsym PowerSettings::setFrontLightLevel");
PowerSettings__setFrontLightState(settings, pct != 0);
vtable_ptr(settings) = vtable_target(PowerSettings_vtable);
if (pct) {
PowerSettings__setFrontLightLevel(settings, (int)(pct));
vtable_ptr(settings) = vtable_target(PowerSettings_vtable);
}
} Update: I have to fix the case when the level is 0, as it segfaults. Update: The segfault is caused by a race condition from me calling
|
Stupid workaround idea: spinning up a new detached thread and doing all of it in there, which would possibly allow you to wait as long as the needed animation timeout before calling the destructor? |
I just found an unusual issue with setTemperature. Because of something to do with how I'm calling it, it works, but seems to corrupt something and segfault after a short while (the stack trace is useless). Update: This log line appears right before it segfaults: Update: I've narrowed down the issue further, and it only seems to happen when something triggers the popup to receive the update, and only after a temperature change. I still don't know why it happens. It might be related to the fact that the slider only automatically updates when changing the brightness (it reads it every time the popup is opened), but not for the temperature (I'll have to see where it gets it from). Update: This snippet from the event may be relevant (note that
Update: the temperature is stored as a field in the class, rather than being read from the hardware.
That's a good idea! I think that might work. The only possible issue I see is that it makes it hard to do the user-visible errors, but I can probably work around that by passing it a struct of working function pointers. |
Update: this segfault actually happens for the brightness too ... I've decided not to implement this for now, and not for the next while (unless I suddenly realize why), as it's too intermittently buggy, it will be the most complex action, and I don't think it's worth the hassle. In addition, even if I did manage to get it working, I wouldn't be confident that it works completely, much less that it works on all firmware versions supported by NickelMenu. |
Even though it works (somewhat), it is too buggy with crashes to be usable.
I'm going to close this issue for now, as I don't see myself working on this in the foreseeable future. |
MR:post-3983396
The text was updated successfully, but these errors were encountered: