aboutsummaryrefslogtreecommitdiff
path: root/brightness_ctrl.cpp
blob: d83b4cfccd1c623e42c618efecb40c216f80f91f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//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]);
	}
}