aboutsummaryrefslogblamecommitdiff
path: root/brightness_ctrl.cpp
blob: d83b4cfccd1c623e42c618efecb40c216f80f91f (plain) (tree)
1
2
3
4
5
6
7
8
9

                      






                                                
                                                         



                            
                                 
                                                             










                                                                                     



                                                                                         









                                                    

                                                                            

                                                       
                                                          







                                                   

















                                                   
                                                                  
                                                                       
                                                                                


                                                         
 





                                                                                       
























                                                                             
                                




                                                                                  
                                
























                                                                                            


                                             
//Chris Xiong 2018
//3-Clause BSD License
#include "brightness_ctrl.hpp"
#include "utils.hpp"
#include <cmath>
#include <algorithm>
#define log10_n(x) ((x)<1?0:log10(x))
void BrightnessControl::_brightness_slide(int p)
{
	std::lock_guard<std::mutex> adjust_lck(adjust_m);
	p+=offset;
	if(p>100)p=100;
	if(p<0)p=0;
	int pbr=maxbr*p/100;
	if(pbr<minabr)pbr=minabr;
	LOG('I',"brightness adjust: %d->%d/%d",br,pbr,maxbr);
	int d=1;if(pbr<br)d=-1;double dd=1;
	while(d>0&&br+round(d*dd)<=pbr||d<0&&br+round(d*dd)>=pbr)
	{
		br+=(int)round(d*dd);writeint(brpath.c_str(),br);
		dd=dd*1.2;std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
	br=pbr;writeint(brpath.c_str(),br);
}

void BrightnessControl::init(float initv,SensorALS *s)
{
	cur=std::upper_bound(thresh.begin(),thresh.end(),(int)roundf(initv))
		-thresh.begin();
	if(thresh.size()+1!=value.size())LOG('W',
		"Size of threshold array should be one more than size of value array",0);
	als=s;set_offset(0,0);
}
void BrightnessControl::set_path(filesystem::path p)
{
	cpath=p;
	brpath=cpath/"brightness";
	maxbrpath=cpath/"max_brightness";
	maxbr=readint(maxbrpath.c_str());
	br=readint(brpath.c_str());
}
void BrightnessControl::set_thresh(const std::vector<int> &_th){thresh=_th;}
void BrightnessControl::set_value(const std::vector<int> &_v){value=_v;}
void BrightnessControl::set_delay(int _d){delay=_d;}
void BrightnessControl::set_trigrange(int _tr){tr=_tr;}
void BrightnessControl::set_minabr(int _mbr){minabr=_mbr;}

void BrightnessControl::set_offset(int rel,int off)
{
	if(rel)offset+=rel*off;else offset=off;
	if(offset>100)offset=100;
	if(offset<-100)offset=-100;
	brightness_slide(value[cur]);
}
void BrightnessControl::set_frozen(bool frozen)
{
	if(frozen)
	{
		doffset=offset;
		offset=value[cur]+offset;
		if(offset>100)offset=100;
		if(offset<0)offset=0;
	}
	else
	{
		offset=doffset;
		force_adjust();
	}
}
int BrightnessControl::get_offset(){return offset;}
int BrightnessControl::get_brightness()
{
	//On some devices there are EC-controlled key combinations
	//that bypasses lightsd entirely (e.g. Fn+Space on ThinkPad for
	//keyboard backlight). So we have to turn to sysfs for the real value...
	if(brpath.empty())return 0;
	return round(readint(brpath.c_str())*100./maxbr);
}

void BrightnessControl::force_adjust()
{
	cur=std::upper_bound(thresh.begin(),thresh.end(),(int)roundf(als->get_value()))
		-thresh.begin();
	brightness_slide(value[cur]);
}
void BrightnessControl::on_sensor_report(float v)
{
	int lb=cur>0?thresh[cur-1]:0;
	int ub=cur<thresh.size()?thresh[cur]:~0U>>1;
	if(v<lb-log10_n(lb)*tr||v>ub+log10_n(ub)*tr)
	{
		if(direction!=(v>ub))
		{
			{
				std::lock_guard<std::mutex> lck(interrupt_m);
				direction=(v>ub);
			}
			interrupt.notify_one();
			std::this_thread::yield();
		}
		{
			std::lock_guard<std::mutex> lcd(threshnotify_m);
			//nothing to do within this lock
		}
		threshnotify.notify_one();
		std::this_thread::yield();
	}
}
void BrightnessControl::brightness_slide(int p)
{
	if(cpath.empty())return;
	std::thread brth(&BrightnessControl::_brightness_slide,std::ref(*this),p);
	brth.detach();
}
void BrightnessControl::worker()
{
	if(cpath.empty())return;
	while(1)
	{
		std::unique_lock<std::mutex>lock_thresh(threshnotify_m);
		threshnotify.wait(lock_thresh);
		lock_thresh.unlock();
		std::cv_status intr;
		do{
			std::unique_lock<std::mutex>lock_interrupt(interrupt_m);
			intr=interrupt.wait_for(lock_interrupt,std::chrono::seconds(delay));
			lock_interrupt.unlock();
		}while(intr==std::cv_status::no_timeout);
		//carry out brightness adjustment here
		float val=als->get_value();
		int lb=cur>0?thresh[cur-1]:0;
		int ub=cur<thresh.size()?thresh[cur]:~0U>>1;
		while(val>ub)
		{
			++cur;lb=thresh[cur-1];
			ub=cur<thresh.size()?thresh[cur]:~0U>>1;
		}
		while(val<lb)
		{
			--cur;lb=cur>0?thresh[cur-1]:0;
			ub=thresh[cur];
		}
		brightness_slide(value[cur]);
	}
}