double GetRaspberryPiTemperature(){ String result = LoadFile("/sys/devices/virtual/thermal/thermal_zone0/temp"); if(!result.IsEmpty()) return 0.001*ScanDouble(~result); return -55.0; }
double GetRaspberryPiTemperature(){ FILE *in=fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","rb"); char s[8]; if(fgets(s,8,in)) return 0.001*ScanDouble(s); return -55.0; }
Hi,
I attempted to read Raspberry Pi 4 SoC temperature with the below code. For some reason using LoadFile does not work:
double GetRaspberryPiTemperature(){ String result = LoadFile("/sys/devices/virtual/thermal/thermal_zone0/temp"); if(!result.IsEmpty()) return 0.001*ScanDouble(~result); return -55.0; }
So I had to revert using FILE and fgets instead:
double GetRaspberryPiTemperature(){ FILE *in=fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","rb"); char s[8]; if(fgets(s,8,in)) return 0.001*ScanDouble(s); return -55.0; }
Is this expected or is this a bug?
Best regards,
Tom
FileIn in; in.Open("/sys/devices/virtual/thermal/thermal_zone0/temp"); if(in.IsError()) return -100; // String result = in.GetLine(); // String result = in.Get(5); String result = in.GetAll(8); if(!result.IsEmpty()) return 0.001*ScanInt(~result); return -55.0;
#include <Core/Core.h> using namespace Upp; CONSOLE_APP_MAIN { String meminfo = LoadFile("/proc/meminfo"); Cout() << meminfo << "\n"; }
#include <Core/Core.h> using namespace Upp; String LoadFileRaw(const char *filename){ int fd = open(filename,O_RDONLY); if(fd!=-1){ char buf[4096]; StringBuffer s; int len; while((len=read(fd,buf,4096))==4096) s.Cat(buf,len); if(len>0) s.Cat(buf,len); close(fd); if(s.GetCount()>0) return s; } return String::GetVoid(); } CONSOLE_APP_MAIN { String meminfo = LoadFileRaw("/proc/meminfo"); Cout() << meminfo << "\n\n"; }
LoadFileRaw("/sys/devices/virtual/thermal/thermal_zone0/temp");
Hi,
This does work on both Raspberry Pi OS (on RPi4) and Linux Mint (on x86_64):
#include <Core/Core.h> using namespace Upp; String LoadFileRaw(const char *filename){ int fd = open(filename,O_RDONLY); if(fd!=-1){ char buf[4096]; StringBuffer s; int len; while((len=read(fd,buf,4096))==4096) s.Cat(buf,len); if(len>0) s.Cat(buf,len); close(fd); if(s.GetCount()>0) return s; } return String::GetVoid(); } CONSOLE_APP_MAIN { String meminfo = LoadFileRaw("/proc/meminfo"); Cout() << meminfo << "\n\n"; }
Also:
LoadFileRaw("/sys/devices/virtual/thermal/thermal_zone0/temp");
works fine on RPi4.
Best regards,
Tom
I suspect that the problem is somewhere here: Core/BlockStream.cpp:474
Probably that S_IFREG flag test. Maybe using S_IFBLK would fix it?
Mirek
bool FileStream::Open(const char *name, dword mode, mode_t tmode) { Close(); LLOG("Open " << name); int iomode = mode & ~SHAREMASK; handle = open(ToSystemCharset(name), iomode == READ ? O_RDONLY : iomode == CREATE ? O_CREAT|O_RDWR|O_TRUNC : O_RDWR|O_CREAT, tmode); if(handle >= 0) { struct stat st[1]; fstat(handle, st); if(!(st->st_mode & S_IFREG) || // not a regular file, e.g. folder - bad things would happen (mode & NOWRITESHARE) && flock(handle, LOCK_EX|LOCK_NB) < 0) { // lock if not sharing close(handle); handle = -1; return false; } int64 fsz = st->st_size;
More edit: It turns out that files in "/proc" or "/sys" are not really files. Not on disk, but not even in memory. Their contents is generated by the kernel on the fly. So, there is no way to tell their size and so fstat() returns zero. Only way to read them is to just read() them in until EOF.
Maybe they could be read up to the buffer (page) size and if the EOF is encountered, the filesize becomes determined...?
String LoadFile(const char *filename) { FindFile ff(filename); if(ff && ff.IsFile()) { #ifdef PLATFORM_POSIX if(ff.GetLength() == 0) { // handle special cases like /proc/... int fd = open(filename,O_RDONLY); if(fd >= 0) { const int CHUNK = 32768; StringBuffer s; for(;;) { int n = s.GetCount(); s.SetCount(n + CHUNK); int len = read(fd, ~s + n, CHUNK); if(len != CHUNK) { if(len > 0) s.SetCount(n + len); return s; } } } return String::GetVoid(); } #endif FileIn in(filename); return LoadStream(in); } return String::GetVoid(); }
Empty file issue fixed (with len >= 0).
Not sure what do you mean with IsVoid problem, piece of code maybe?
if(String::GetVoid().IsVoid()) Cout() << "String::GetVoid().IsVoid() works!\n"; else Cout() << "String::GetVoid().IsVoid() fails!\n"; if(IsVoid(String::GetVoid())) Cout() << "IsVoid(String::GetVoid()) works!\n"; else Cout() << "IsVoid(String::GetVoid()) fails!\n";
Hi Mirek,
You should close(fd) in the above code.
Best regards,
Victor
mirek wrote on Wed, 18 May 2022 11:29Empty file issue fixed (with len >= 0).
Not sure what do you mean with IsVoid problem, piece of code maybe?
OK, I found the reason causing part of my testing issues:
if(String::GetVoid().IsVoid()) Cout() << "String::GetVoid().IsVoid() works!\n"; else Cout() << "String::GetVoid().IsVoid() fails!\n"; if(IsVoid(String::GetVoid())) Cout() << "IsVoid(String::GetVoid()) works!\n"; else Cout() << "IsVoid(String::GetVoid()) fails!\n";
Best regards,
Tom
EDIT: Improved test code.
Tom1 wrote on Wed, 18 May 2022 10:47mirek wrote on Wed, 18 May 2022 11:29Empty file issue fixed (with len >= 0).
Not sure what do you mean with IsVoid problem, piece of code maybe?
OK, I found the reason causing part of my testing issues:
if(String::GetVoid().IsVoid()) Cout() << "String::GetVoid().IsVoid() works!\n"; else Cout() << "String::GetVoid().IsVoid() fails!\n"; if(IsVoid(String::GetVoid())) Cout() << "IsVoid(String::GetVoid()) works!\n"; else Cout() << "IsVoid(String::GetVoid()) fails!\n";
Best regards,
Tom
EDIT: Improved test code.
Uhm, that is actually API problem:
IsVoid(const Value&) function is about Value - it tells you that Value was not assigned anything. In above example you assign it a String, so it must return false.
I agree this is a bit confusing, but I am not sure there is a solution to that.
Mirek
bool IsVoid(const String &s){ return s.IsVoid(); }
How about introducing an additional IsVoid variant?:
bool IsVoid(const String &s){ return s.IsVoid(); }
Best regards,
Tom