code: plan9front

Download patch

ref: acfc389bb90944f3ac1200eec4a80b49adaf4e6a
parent: 25ad7eef2cbe2b3431111f241d85658f57034df6
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Sep 7 19:03:53 EDT 2022

reform/pm: calculate time to full (dis)charge; low→warn capacity; endless loop protection

--- a/sys/src/cmd/reform/pm.c
+++ b/sys/src/cmd/reform/pm.c
@@ -183,8 +183,13 @@
 lpccall(char cmd, u8int arg, void *ret)
 {
 	u32int con;
-	int i;
+	int i, try;
 
+	/* in case someone messed up and ran pm more than once */
+	try = 0;
+	while((rd(spi2, SPIx_CONREG) & CON_EN) != 0 && try++ < 50)
+		sleep(10);
+
 	con =
 		/* 8 bits burst */
 		CON_BURST_LENGTH*(8-1) |
@@ -231,9 +236,12 @@
 	wr(spi2, SPIx_CONREG, con | CON_XCH);
 
 	for(i = 0; i < 8; i++){
+		try = 0;
 		do{
 			sleep(10);
-		}while((rd(spi2, SPIx_STATREG) & STAT_RR) == 0);
+		}while((rd(spi2, SPIx_STATREG) & STAT_RR) == 0 && try++ < 50);
+		if(try >= 50) /* give up */
+			break;
 		((u8int*)ret)[i] = rd(spi2, SPIx_RXDATA);
 	}
 
@@ -255,6 +263,7 @@
 static char *
 readbattery(char *s, char *e)
 {
+	int hh, mm, ss, full, remain, warn, safe;
 	u8int st[8], ch[8];
 	s16int current;
 	char *state;
@@ -262,34 +271,43 @@
 	lpccall('c', 0, ch);
 	lpccall('q', 0, st);
 	current = (s16int)(st[2] | st[3]<<8);
+	remain = ch[0]|ch[1]<<8;
+	warn = ch[2]|ch[3]<<8;
+	full = ch[4]|ch[5]<<8;
+	safe = remain - warn;
 
+	hh = mm = ss = 0;
 	state = "unknown";
-	if(st[5] == Scharge){
+	switch(st[5]){
+	case Sfullycharged: state = "full"; break;
+	case Sovervolted: state = "balancing"; break;
+	case Scooldown: state = "cooldown"; break;
+	case Spowersave: state = "powersave"; break;
+	case Scharge:
 		if(current < 0)
 			state = "charging";
-		else if(current > 0)
+		if(current > 0)
 			state = "discharging";
-	}else{
-		switch(st[5]){
-		case Sfullycharged: state = "full"; break;
-		case Smissing: state = "missing"; break;
-		case Sovervolted: state = "balancing"; break;
-		case Scooldown: state = "cooldown"; break;
-		case Spowersave: state = "powersave"; break;
+		if(current != 0){
+			ss = (current < 0 ? full - safe : safe) * 3600 / abs(current);
+			hh = ss/3600;
+			ss -= 3600*(ss/3600);
+			mm = ss/60;
+			ss -= 60*(ss/60);
 		}
+		break;
+	case Smissing:
+		werrstr("battery is missing");
+		return nil;
 	}
 
-	if(st[5] != Smissing){
-		return seprint(s, e, "%d mA %d %d %d ? %d mV %d ? ??:??:?? %s\n",
-			st[4],
-			ch[0]|ch[1]<<8, ch[4]|ch[5]<<8, ch[4]|ch[5]<<8, ch[2]|ch[3]<<8,
-			st[0]|st[1]<<8,
-			state
-		);
-	}
-
-	werrstr("battery is missing");
-	return nil;
+	return seprint(s, e, "%d mA %d %d %d %d ? mV %d ? %02d:%02d:%02d %s\n",
+		st[4],
+		remain, full, full, warn,
+		st[0]|st[1]<<8,
+		hh, mm, ss,
+		state
+	);
 }
 
 static char *