C++ FLTK displaying a sysctl value

I am trying to display a sysctl value in an FLTK Fl_Output box.
Code:
#include <stdlib.h>
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>

void box1cb(Fl_Widget *, void *) {
system("sysctl -n dev.cpu.0.temperature");
}

int main(int argc, char ** argv) {
  Fl_Window *window = new Fl_Window(400,200, "CPU Temperature");

  Fl_Output *box1 = new Fl_Output(180, 90, 70, 30, "CPU0");
  box1->callback(box1cb,0);
  box1->labelsize(20);

  window->end();
  window->show(argc,argv);
  return Fl::run();
}

What is the special sauce I need to display the sysctl value in the Fl_Output box? When I hit return in the box I get the value but returned in the calling command prompt not in GUI.
I tried 'fprint' statement in several spots and I can't figure this out.
Please help me.
I am not sure if I am missing something in the callback. With my previous usage the callback event was initiated by 'button pressing'.
On this learning adventure I just want to see the sysctl value on startup. No polling or redraw needed for now.
I have been through all the examples and I cannot figure it out.
 
I was thinking maybe my box is of wrong type. I saw Fl_Value_Output and wondered if I am using the correct output type.

So I changed type to Fl_Value_Output. It seems to behave differently but does not work. Not feedback in console at all.

For such a simple example I do not think I would even need a callback. Am I wrong?
 
No , you are not wrong but je need popen.


Code:
#include <stdlib.h>
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>
#include <string.h>
#define MAX_BUFFER_SIZE 100
#define COMMAND "sysctl -n dev.cpu.0.temperature"
int main(int argc, char ** argv)
{
Fl_Window *window = new Fl_Window(400,200, "CPU Temperature");
Fl_Output *box1 = new Fl_Output(180, 90, 70, 30, "");
FILE *fp;
char result_buffer[MAX_BUFFER_SIZE];
memset(result_buffer, 0, MAX_BUFFER_SIZE);
fp = popen(COMMAND, "r");
    if (fp == NULL) {
        printf("Failed to run command\n");
        exit(1);
    }
if (fgets(result_buffer, sizeof(result_buffer), fp) != NULL) {
        printf("System Command Output Stored in String: %s \n", result_buffer);
    } else {
        printf("No output was captured from the command.\n");
    }
 pclose(fp);
result_buffer[sizeof(result_buffer)-4]=0;
box1->value(result_buffer); // THE BOX HAS NOW AS TEXT THE RESULT OF THE SYSCTL COMMAND
box1->labelsize(20);
window->end();
window->show(argc,argv);
return Fl::run();
}

g++ test.cpp -lfltk ; ./a.out
 
What does FILE *fp do?

Compile troubles for me:
Code:
utput.cxx:29:1: error: use of undeclared identifier 'my_output_box'
   29 | my_output_box->value(resultbuffer) # THE BOX HAS NOW AS TEXT THE RESULT OF THE SYSCTL COMMAND
      | ^
output.cxx:29:22: error: use of undeclared identifier 'resultbuffer'; did you mean 'result_buffer'?
   29 | my_output_box->value(resultbuffer) # THE BOX HAS NOW AS TEXT THE RESULT OF THE SYSCTL COMMAND
      |                      ^~~~~~~~~~~~
      |                      result_buffer
output.cxx:15:6: note: 'result_buffer' declared here
   15 | char result_buffer[MAX_BUFFER_SIZE];
      |      ^
2 errors generated.
 
Working popen program ,without ugly control character

Code:
#include <stdlib.h>
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>
#include <string.h>
#include <algorithm>
#define MAX_BUFFER_SIZE 100
#define COMMAND "sysctl -n dev.cpu.0.temperature"
#include <stdio.h>
void print_hex(const char *s) {
    printf("[");
    // Loop through the string until the null terminator ('\\0') is reached
    while (*s) {
        // Cast the character to an unsigned int for safe promotion and use the %02x format specifier.
        // %02x prints the value as a two-digit hexadecimal number, using a leading zero for padding if necessary.
        printf("(%02x)", (unsigned int)(unsigned char)*s++);
    }
    printf("]");
    printf("\n"); // Print a newline at the end
}
void remove_char(char* str, char char_to_remove) {
    char *read_ptr = str; // Pointer to read from the original string
    char *write_ptr = str; // Pointer to write to the modified string
    while (*read_ptr) {
        // If the character at the read pointer is NOT the one to remove, 
        // copy it to the location of the write pointer and advance both pointers.
        if (*read_ptr != char_to_remove) {
            *write_ptr++ = *read_ptr++;
        } else {
            // If the character is the one to remove, only advance the read pointer, 
            // effectively skipping it. The write pointer stays in place until a 
            // valid character is found.
            read_ptr++;
        }
    }
    // Null-terminate the resulting string at the position of the write pointer
    *write_ptr = '\0';
}
int main(int argc, char ** argv) 
{
Fl_Window *window = new Fl_Window(400,200, "CPU Temperature");
Fl_Output *box1 = new Fl_Output(180, 90, 70, 30, "");
FILE *fp;
char result_buffer[MAX_BUFFER_SIZE];
memset(result_buffer, 0, MAX_BUFFER_SIZE);
fp = popen(COMMAND, "r");
    if (fp == NULL) {
        printf("Failed to run command\n");
        exit(1);
    }
if (fgets(result_buffer, sizeof(result_buffer), fp) != NULL) {
        printf("System Command Output Stored in String: %s \n", result_buffer);
    } else {
        printf("No output was captured from the command.\n");
    }
 pclose(fp);
result_buffer[sizeof(result_buffer)-1]='\0';
// To represent the actual control character in the code, use its ASCII value:
print_hex(result_buffer);

char char_to_remove = (char)0x0a;
printf("Original string: [%s] \n", result_buffer);
remove_char(result_buffer, char_to_remove);
printf("Filtered string: [%s] \n", result_buffer);
box1->value(result_buffer); // THE BOX HAS NOW AS TEXT THE RESULT OF THE SYSCTL COMMAND
box1->labelsize(20);
window->end();
window->show(argc,argv);
return Fl::run();
}
 
Last and final "popen" program,

Code:
#include <stdlib.h>
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>
#include <string.h>
#include <algorithm>
#define MAX_BUFFER_SIZE 100
#define COMMAND "sysctl -n dev.cpu.0.temperature"
#include <stdio.h>

size_t custom_strlen(const char* str, size_t max_len) {
    size_t length = 0;
    // Iterate through the array bounds
    while (length < max_len && str[length] != '\0') {
        length++;
    }
    return length;
}

int main(int argc, char ** argv) 
{
Fl_Window *window = new Fl_Window(400,200, "CPU Temperature");
Fl_Output *box1 = new Fl_Output(180, 90, 70, 30, "");
FILE *fp;
char result_buffer[MAX_BUFFER_SIZE];
memset(result_buffer, 0, MAX_BUFFER_SIZE);
fp = popen(COMMAND, "r");
    if (fp == NULL) {
        printf("Failed to run command\n");
        exit(1);
    }
if (fgets(result_buffer, sizeof(result_buffer), fp) != NULL) {
        printf("System Command Output Stored in String: %s \n", result_buffer);
    } else {
        printf("No output was captured from the command.\n");
    }
 pclose(fp);
printf("Original string: [%s] \n", result_buffer);
size_t len1 = custom_strlen(result_buffer, MAX_BUFFER_SIZE);
result_buffer[len1-1]=' '; // REMOVE UGLY CHARACTER
printf("Filtered string: [%s] \n", result_buffer);
box1->value(result_buffer); // THE BOX HAS NOW AS TEXT THE RESULT OF THE SYSCTL COMMAND
box1->labelsize(20);
window->end();
window->show(argc,argv);
return Fl::run();
}
 
Fyi, i use conky to show information about my system, but fltk was fun,
 
I prefer F# language when i can but currently learning C++.
Gone write for fun a C++ - Fltk system monitor program.
With a calender using , Fl_Multiline_Output.
When i finished watching the udemy course on Qt6 I'll migrate it to C++ - Qt6.
 
I built an example with Fl_Multiline_Output that really inspired me.
It was only PING in a window but I knew at that point what I wanted was feasible.

I look forward to learning gauges. FLTK's are limited but capable...

Could I build a R/C Vehicle/boat/robot onscreen display and control with FLTK/C++... That is something I am interested in.
There are some amazing drone computers these days like PixHawk ect. ect. and I have a soft spot for that type gear.

I really want to Thank Alain De Vos for the assistance. I am the person who need needs to study what was provided.
After tweaking the work for my taste I might dive into sysctlbyname.

I was thinking I will donate and EXTRA $100 to the foundation just for helping when I mail my check soon.

Maybe another EXTRA $200 to the foundation for helping me if I get libGPIO API working with FLTK.
 
The Amazon DeepRacer vehicle has an Intel E3930 CPU embedded. I like the whole concept here but "Amazon" and "Cloud" are not things I want for my learning project.

Make a FreeBSD FLTK ControlPanel for this guy? Point to point with collision avoidance.
 
OK Alain De Vos now the learning questions begin. I need to grasp this code not just cut and paste.

From a laymans reading I see you create a "results_buffer" to pass data to fltk box1.

What does the top section do? "Iterate through the array bounds" Is that array for the "results_buffer" ?

Back to this question:
What does FILE *fp do?
I see from here it is typedef

Why does it say "Denotes a C stream? Why does your C++ code need a C stream? Why did you chose fp as name? Is that shorthand for 'file pointer'?

Thanks for walking me thought this a little bit at a time.
 
Here's a version that uses sysctlbyname(3):
C++:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/errno.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>

void box1cb(void* output) {
  size_t size;
  int t_dK, t_C, t_F; //Default is deciKelvin see SYSCTL_ADD_PROC(9)
  char buf[128] = {""};
  size_t buflen = sizeof(buf);
  size = sizeof t_dK;

  if (0 == (sysctlbyname("dev.cpu.0.temperature", &t_dK, &size, NULL, 0))) {
    t_C = (t_dK - 2730) / 10;
    t_F = (t_dK * 1.8 / 10) - 459.67;
    printf("%d dK, %d C, %d F\n", t_dK, t_C, t_F);
    snprintf(buf, buflen, "%d F", t_F);
  } else {
    strerror_r(errno, buf, buflen); 
  }

  ((Fl_Output*)output)->value(buf);
  
  Fl::repeat_timeout(1.0, box1cb, output);
}

int main(int argc, char ** argv) {
  Fl_Window *window = new Fl_Window(400,200, "CPU Temperature");

  Fl_Output *box1 = new Fl_Output(180, 90, 70, 30, "CPU0");
  box1->labelsize(20);

  window->end();
  window->show(argc, argv);
  Fl::add_timeout(1.0, box1cb, box1);
  return Fl::run();
}

This thread was very helpful
😁
 
Fyi,

While the general public uses Fahrenheit, scientific research, industry, and the U.S. National Weather Service (behind the scenes) frequently use Celsius and Kelvin to coordinate with global partners and for scientific work where a shared standard is essential.

Common reasons people express dislike for the Fahrenheit system include:

  • Arbitrary Freezing/Boiling Points: Water freezes at 32°F and boils at 212°F, which seems illogical to many, especially when contrasted with Celsius, where these points are a simple 0°C and 100°C, respectively.
  • Lack of Intuition: For those who grew up with Celsius, a temperature like 20°C (nice) or 0°C (ice) is immediately intuitive, while the corresponding Fahrenheit temperatures (around 68°F and 32°F) lack that inherent sense.
  • Inconsistent Use: The United States is one of the last remaining countries to primarily use Fahrenheit, leading to confusion and the need for constant conversion when dealing with international contexts, science, or travel.
  • Cultural Inertia: The main reason the US continues to use Fahrenheit is often attributed to historical precedent and cultural inertia, rather than a practical advantage, despite its use of the metric system in scientific fields.
While some defend Fahrenheit by saying it offers a finer degree of precision for daily weather perception or an "intuitive" range of 0°F (very cold) to 100°F (very hot) for weather, most of the world and the scientific community use Celsius and Kelvin.
 
I found some ancient source for an Fl_Gauge widget. It still compiles and works with FLTK 1.3! Gotta love the FLTK guys. You'll need to drop the three files attached to this post in a directory somewhere. Compile them like this
Code:
c++ -o fltk_temp $(fltk-config --cxxflags) Fl_Gauge.cxx fltk_temp.cpp $(fltk-config --ldflags)

Run it like this
Code:
./fltk_temp

Should look something like this (don't have a screenshot utility installed at the moment.)
Fl_Gauge.jpg
 

Attachments

Back
Top