diff --git a/doc/variables.xml b/doc/variables.xml
index a2b5d528..7a1f14e1 100644
--- a/doc/variables.xml
+++ b/doc/variables.xml
@@ -2777,49 +2777,251 @@
-
-
-
-
-
-
+
- Nvidia graficcard support for the XNVCtrl
- library. Each option can be shortened to the least
- significant part. Temperatures are printed as float, all
- other values as integer.
-
+ Nvidia graphics card information via the XNVCtrl
+ library.
+
+ Possible arguments: (Temperatures are
+ printed as float, all other values as integer. Bracketed
+ arguments are aliases)
+
+
- threshold
-
+ gputemp
+ (temp)
+
- temp
-
+ gputempthreshold
+ (threshold)
+
- ambient
-
+ ambienttemp
+ (ambient)
+
+
+
+
+
+ gpufreqcur
+ (gpufreq)
+
- gpufreq
-
+ gpufreqmin
+
- memfreq
-
+ gpufreqmax
+
+
+
+
+ memfreqcur
+ (memfreq)
+
+
+
+ memfreqmin
+
+
+
+ memfreqmax
+
+
+
+
+
+ mtrfreqcur
+ (mtrfreq)
+
+
+
+ mtrfreqmin
+
+
+
+ mtrfreqmax
+
+
+
+
+
+ perflevelcur
+ (perflevel)
+
+
+
+ perflevelmin
+
+
+
+ perflevelmax
+
+
+
+ perfmode
+
+
+
+
+
+ gpuutil
+
+
+
+ membwutil
+
+
+
+ videoutil
+
+
+
+ pcieutil
+
+
+
+
+
+ memused
+ (mem)
+
+
+
+ memfree
+ (memavail)
+
+
+
+ memmax
+ (memtotal)
+
+
+
+ memutil
+ (memperc)
+
+
+
+
+
+ fanspeed
+
+
+
+ fanlevel
+
+
+
+
imagequality
-
+
+
+
+
+
+
+
+
+
+ Same as nvidia, except it draws its output in a
+ horizontal bar. The height and width parameters are optional,
+ and default to the default_bar_height and default_bar_width
+ config settings, respectively.
+
+ Note the following arguments are incompatible:
+
+
+ gputempthreshold
+ (threshold)
+
+
+ gpufreqmin
+
+
+ gpufreqmax
+
+
+ memfreqmin
+
+
+ memfreqmax
+
+
+ mtrfreqmin
+
+
+ mtrfreqmax
+
+
+ perflevelmin
+
+
+ perflevelmax
+
+
+ perfmode
+
+
+ memtotal
+ (memmax)
+
+
+ fanspeed
+
+
+
+
+
+
+
+
+
+
+
+
+ Same as nvidiabar, except a round gauge
+ (much like a vehicle speedometer). The height
+ and width parameters are optional, and default to the
+ default_gauge_height and default_gauge_width config
+ settings, respectively.
+
+ For possible arguments see nvidia and nvidiabar.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Same as nvidiabar, except a horizontally
+ scrolling graph with values from 0-100 plotted on the
+ vertical axis. The height and width parameters are
+ optional, and default to the default_graph_height and
+ default_graph_width config settings, respectively.
+
+ For possible arguments see nvidia and nvidiabar. To learn more
+ about the -t -l and gradient color options,
+ see execgraph.
+
+
diff --git a/src/core.cc b/src/core.cc
index 4a312898..d4b35967 100644
--- a/src/core.cc
+++ b/src/core.cc
@@ -1802,30 +1802,30 @@ struct text_object *construct_text_object(char *s, const char *arg,
obj->callbacks.free = &free_combine;
#ifdef BUILD_NVIDIA
END OBJ_ARG(nvidia, 0, "nvidia needs an argument")
- if (set_nvidia_type(obj, arg)) {
+ if (set_nvidia_query(obj, arg, NONSPECIAL)) {
CRIT_ERR(obj, free_at_crash, "nvidia: invalid argument"
- " specified: '%s'\n", arg);
+ " specified: '%s'", arg);
}
obj->callbacks.print = &print_nvidia_value;
obj->callbacks.free = &free_nvidia;
END OBJ_ARG(nvidiabar, 0, "nvidiabar needs an argument")
- if (scan_nvidia_args(obj, arg, BAR)) {
+ if (set_nvidia_query(obj, arg, BAR)) {
CRIT_ERR(obj, free_at_crash, "nvidiabar: invalid argument"
- " specified: '%s'\n", arg);
+ " specified: '%s'", arg);
}
obj->callbacks.barval = &get_nvidia_barval;
obj->callbacks.free = &free_nvidia;
END OBJ_ARG(nvidiagraph, 0, "nvidiagraph needs an argument")
- if (scan_nvidia_args(obj, arg, GRAPH)) {
+ if (set_nvidia_query(obj, arg, GRAPH)) {
CRIT_ERR(obj, free_at_crash, "nvidiagraph: invalid argument"
- " specified: '%s'\n", arg);
+ " specified: '%s'", arg);
}
obj->callbacks.graphval = &get_nvidia_barval;
obj->callbacks.free = &free_nvidia;
END OBJ_ARG(nvidiagauge, 0, "nvidiagauge needs an argument")
- if (scan_nvidia_args(obj, arg, GAUGE)) {
+ if (set_nvidia_query(obj, arg, GAUGE)) {
CRIT_ERR(obj, free_at_crash, "nvidiagauge: invalid argument"
- " specified: '%s'\n", arg);
+ " specified: '%s'", arg);
}
obj->callbacks.gaugeval = &get_nvidia_barval;
obj->callbacks.free = &free_nvidia;
diff --git a/src/nvidia.cc b/src/nvidia.cc
index 74c8c1db..11fa7317 100644
--- a/src/nvidia.cc
+++ b/src/nvidia.cc
@@ -43,7 +43,6 @@
* so that all quirks are located there
* - Implement nvs->print_type to allow control over how the value is printed
* (int, float, temperature...)
- * - Rename set_nvidia_type() to set_nvidia_query (requires changes in core.cc)
*
* Showcase (conky.conf):
* --==| NVIDIA | ==--
@@ -282,9 +281,31 @@ typedef enum _SEARCH_ID {
SEARCH_MAX
} SEARCH_ID;
+// Translate special_type into command string
+const char* translate_nvidia_special_type[] = {
+ "nvidia", // NONSPECIAL
+ "", // HORIZONTAL_LINE
+ "", // STIPPLED_HR
+ "nvidiabar", // BAR
+ "", // FG
+ "", // BG
+ "", // OUTLINE
+ "", // ALIGNR
+ "", // ALIGNC
+ "nvidiagague", // GAUGE
+ "nvidiagraph", // GRAPH
+ "", // OFFSET
+ "", // VOFFSET
+ "", // FONT
+ "", // GOTO
+ "" // TAB
+};
+
// Global struct to keep track of queries
struct nvidia_s {
+ const char *command;
+ const char *arg;
QUERY_ID query;
TARGET_ID target;
ATTR_ID attribute;
@@ -340,11 +361,20 @@ namespace {
nvidia_display_setting nvidia_display;
}
-// Extract arguments for nvidiabar, etc, and run set_nvidia_type
-int scan_nvidia_args (struct text_object *obj, const char *args, unsigned int special_t) {
- const char *arg = args;
- switch (special_t) {
+// Evaluate module parameters and prepare query
+int set_nvidia_query(struct text_object *obj, const char *arg, unsigned int special_type)
+{
+ struct nvidia_s *nvs;
+ int aid;
+
+ // Initialize global struct
+ obj->data.opaque = malloc(sizeof(struct nvidia_s));
+ nvs = static_cast(obj->data.opaque);
+ memset(nvs, 0, sizeof(struct nvidia_s));
+
+ // Extract arguments for nvidiabar, etc, and run set_nvidia_query
+ switch (special_type) {
case BAR:
arg = scan_bar(obj, arg, 100);
break;
@@ -354,28 +384,11 @@ int scan_nvidia_args (struct text_object *obj, const char *args, unsigned int sp
case GAUGE:
arg = scan_gauge(obj, arg, 100);
break;
- default:
- return 1;
}
// Return error if no argument
// (sometimes scan_graph gets excited and eats the whole string!
if (!arg) return 1;
-
- return set_nvidia_type(obj, arg);
-}
-
-
-// Evaluate module parameters and prepare query
-int set_nvidia_type(struct text_object *obj, const char *arg)
-{
- struct nvidia_s *nvs;
- int aid;
-
- // Initialize global struct
- obj->data.opaque = malloc(sizeof(struct nvidia_s));
- nvs = static_cast(obj->data.opaque);
- memset(nvs, 0, sizeof(struct nvidia_s));
// Translate parameter to id
for (aid=0; aid < ARG_UNKNOWN; aid++) {
@@ -384,6 +397,10 @@ int set_nvidia_type(struct text_object *obj, const char *arg)
}
//fprintf(stderr, "parameter: %s -> aid: %d\n", arg, aid);
+ // Save pointers to the arg and command strings for dubugging and printing
+ nvs->arg = translate_module_argument[aid];
+ nvs->command = translate_nvidia_special_type[special_type];
+
// Evaluate parameter
switch(aid) {
@@ -569,11 +586,37 @@ int set_nvidia_type(struct text_object *obj, const char *arg)
break;
default: // Unknown/invalid argument
+ // Error printed by core.cc
return 1;
}
return 0;
}
+// Return the amount of targets present (or -1 on error)
+static inline int get_nvidia_target_count(Display *dpy, TARGET_ID tid)
+{
+ int num_tgts;
+ if (!XNVCTRLQueryTargetCount(dpy, translate_nvidia_target[tid], &num_tgts)) {
+ num_tgts = -1;
+ }
+
+ return num_tgts;
+}
+
+// Exit if we are unable to get targets of type tid on display dpy
+void check_nvidia_target_count(Display *dpy, TARGET_ID tid, ATTR_ID aid)
+{
+ int num_tgts = get_nvidia_target_count(dpy, tid);
+
+ if(num_tgts < 1) {
+ // Print error and exit if there's not enough targets to query
+ CRIT_ERR(NULL, NULL, "%s:"
+ "\n Trying to query Nvidia target failed (using the propietary drivers)."
+ "\n Are you sure they are installed correctly and a Nvidia GPU is in use?"
+ "\n (display: %d, target_id: %d, target_count: %d, attribute_id: %d)"
+ , __func__, dpy, tid, num_tgts, aid);
+ }
+}
// Retrieve attribute value via nvidia interface
static int get_nvidia_value(TARGET_ID tid, ATTR_ID aid)
@@ -581,8 +624,12 @@ static int get_nvidia_value(TARGET_ID tid, ATTR_ID aid)
Display *dpy = nvdisplay ? nvdisplay : display;
int value;
+ // Check for issues
+ check_nvidia_target_count(dpy, tid, aid);
+
// Query nvidia interface
if(!dpy || !XNVCTRLQueryTargetAttribute(dpy, translate_nvidia_target[tid], 0, 0, translate_nvidia_attribute[aid], &value)){
+ NORM_ERR("%s: Something went wrong running nvidia query (tid: %d, aid: %d)", __func__, tid, aid);
return -1;
}
@@ -602,9 +649,13 @@ static char* get_nvidia_string(TARGET_ID tid, ATTR_ID aid)
{
Display *dpy = nvdisplay ? nvdisplay : display;
char *str;
+
+ // Check for issues
+ check_nvidia_target_count(dpy, tid, aid);
// Query nvidia interface
if (!dpy || !XNVCTRLQueryTargetStringAttribute(dpy, translate_nvidia_target[tid], 0, 0, translate_nvidia_attribute[aid], &str)) {
+ NORM_ERR("%s: Something went wrong running nvidia string query (tid: %d, aid: %d)", __func__, tid, aid);
return NULL;
}
//fprintf(stderr, "%s", str);
@@ -746,19 +797,28 @@ double get_nvidia_barval(struct text_object *obj) {
// Assume failure
value = 0;
- // Convert query_result to a percentage
+ // Convert query_result to a percentage using ((val-min)÷(max-min)×100)+0.5 if needed.
if (nvs != NULL) {
switch (nvs->attribute) {
case ATTR_UTILS_STRING: // one of the percentage utils (gpuutil, membwutil, videoutil and pcieutil)
value = get_nvidia_string_value(nvs->target, ATTR_UTILS_STRING, nvs->token, nvs->search);
break;
case ATTR_MEM_UTIL: // memutil
+ case ATTR_MEM_USED:
temp1 = get_nvidia_value(nvs->target, ATTR_MEM_USED);
temp2 = get_nvidia_value(nvs->target, ATTR_MEM_TOTAL);
value = ((float)temp1 * 100 / (float)temp2) + 0.5;
break;
+ case ATTR_MEM_FREE: // memfree
+ temp1 = get_nvidia_value(nvs->target, ATTR_MEM_USED);
+ temp2 = get_nvidia_value(nvs->target, ATTR_MEM_TOTAL);
+ value = temp2 - temp1;
+ break;
+ case ATTR_FAN_SPEED: // fanspeed: Warn user we are using fanlevel
+ NORM_ERR("%s: invalid argument specified: '%s' (using 'fanlevel' instead).",
+ nvs->command, nvs->arg);
+ // No break, continue into fanlevel
case ATTR_FAN_LEVEL: // fanlevel
- case ATTR_FAN_SPEED: // TODO warn user to use fanlevel if they use fanspeed
value = get_nvidia_value(nvs->target, ATTR_FAN_LEVEL);
break;
case ATTR_GPU_TEMP: // gputemp (calculate out of gputempthreshold)
@@ -766,10 +826,40 @@ double get_nvidia_barval(struct text_object *obj) {
temp2 = get_nvidia_value(nvs->target, ATTR_GPU_TEMP_THRESHOLD);
value = ((float)temp1 * 100 / (float)temp2) + 0.5;
break;
- // TODO: calculate gpufreq, memfreq, etc
- // can use (val-min)÷(max-min)×100. Perhaps a helper function or macro
-
- // TODO: throw errors if unsupported args are used
+ case ATTR_AMBIENT_TEMP: // ambienttemp (calculate out of gputempthreshold for consistency)
+ temp1 = get_nvidia_value(nvs->target, ATTR_AMBIENT_TEMP);
+ temp2 = get_nvidia_value(nvs->target, ATTR_GPU_TEMP_THRESHOLD);
+ value = ((float)temp1 * 100 / (float)temp2) + 0.5;
+ break;
+ case ATTR_GPU_FREQ: // gpufreq (calculate out of gpufreqmax)
+ temp1 = get_nvidia_value(nvs->target, ATTR_GPU_FREQ);
+ temp2 = get_nvidia_string_value(nvs->target, ATTR_PERFMODES_STRING, (char*) "nvclockmax", SEARCH_MAX);
+ value = ((float)temp1 * 100 / (float)temp2) + 0.5;
+ break;
+ case ATTR_MEM_FREQ: // memfreq (calculate out of memfreqmax)
+ temp1 = get_nvidia_value(nvs->target, ATTR_MEM_FREQ);
+ temp2 = get_nvidia_string_value(nvs->target, ATTR_PERFMODES_STRING, (char*) "memclockmax", SEARCH_MAX);
+ value = ((float)temp1 * 100 / (float)temp2) + 0.5;
+ break;
+ case ATTR_FREQS_STRING: // mtrfreq (calculate out of memfreqmax)
+ if (nvs->token == "memTransferRate") {
+ // Just in case error for silly devs
+ CRIT_ERR(NULL, NULL, "%s: attribute is 'ATTR_FREQS_STRING' but token is not \"memTransferRate\" (arg: '%s')",
+ nvs->command, nvs->arg);
+ return 0;
+ }
+ temp1 = get_nvidia_string_value(nvs->target, ATTR_FREQS_STRING, nvs->token, SEARCH_MAX);
+ temp2 = get_nvidia_string_value(nvs->target, ATTR_PERFMODES_STRING, (char*) "memTransferRatemax", SEARCH_MAX);
+ if (temp2 > temp1) temp1 = temp2; // extra safe here
+ value = ((float)temp1 * 100 / (float)temp2) + 0.5;
+ break;
+ case ATTR_IMAGE_QUALITY: // imagequality
+ value = get_nvidia_value(nvs->target, ATTR_IMAGE_QUALITY);
+ break;
+
+ default: // Throw error if unsupported args are used
+ CRIT_ERR(NULL, NULL, "%s: invalid argument specified: '%s'",
+ nvs->command, nvs->arg);
}
}
diff --git a/src/nvidia.h b/src/nvidia.h
index 74bd43b9..7c805bd9 100644
--- a/src/nvidia.h
+++ b/src/nvidia.h
@@ -32,10 +32,9 @@
#ifndef NVIDIA_CONKY_H
#define NVIDIA_CONKY_H
-int scan_nvidia_args (struct text_object *obj, const char *args, unsigned int special_t);
-int set_nvidia_type(struct text_object *, const char *);
+int set_nvidia_query(struct text_object *, const char *, unsigned int);
void print_nvidia_value(struct text_object *, char *, int);
-double get_nvidia_barval(struct text_object *obj);
+double get_nvidia_barval(struct text_object *);
void free_nvidia(struct text_object *);
#endif