diff --git a/api.c b/api.c index c88c9155..7785ae8e 100644 --- a/api.c +++ b/api.c @@ -630,6 +630,195 @@ static char *escape_string(char *str, bool isjson) return buf; } +struct api_data *api_add_data_full(struct api_data *root, char *name, enum api_data_type type, void *data, bool copy_data) +{ + struct api_data *api_data; + + api_data = (struct api_data *)malloc(sizeof(struct api_data)); + + api_data->type = type; + api_data->name = name; + + if (root == NULL) { + root = api_data; + root->prev = root; + root->next = root; + } + else { + api_data->prev = root->prev; + root->prev = api_data; + api_data->next = root; + api_data->prev->next = api_data; + } + + api_data->data_was_malloc = copy_data; + + if (!copy_data) + api_data->data = data; + else + switch(type) { + case API_ESCAPE: + case API_STRING: + api_data->data = (void *)malloc(strlen((char *)data) + 1); + strcpy((char*)(api_data->data), (char *)data); + break; + case API_INT: + api_data->data = (void *)malloc(sizeof(int)); + *((int *)(api_data->data)) = *((int *)data); + break; + case API_UINT: + api_data->data = (void *)malloc(sizeof(unsigned int)); + *((unsigned int *)(api_data->data)) = *((unsigned int *)data); + break; + case API_UINT64: + api_data->data = (void *)malloc(sizeof(uint64_t)); + *((uint64_t *)(api_data->data)) = *((uint64_t *)data); + break; + case API_ULONG: + api_data->data = (void *)malloc(sizeof(unsigned long)); + *((unsigned long *)(api_data->data)) = *((unsigned long *)data); + break; + case API_DOUBLE: + case API_MHS: + case API_MHTOTAL: + case API_UTILITY: + case API_VOLTS: + case API_HS: + api_data->data = (void *)malloc(sizeof(double)); + *((double *)(api_data->data)) = *((double *)data); + break; + case API_BOOL: + api_data->data = (void *)malloc(sizeof(bool)); + *((bool *)(api_data->data)) = *((bool *)data); + break; + case API_TIMEVAL: + api_data->data = (void *)malloc(sizeof(struct timeval)); + memcpy(api_data->data, data, sizeof(struct timeval)); + break; + case API_TIME: + api_data->data = (void *)malloc(sizeof(time_t)); + *(time_t *)(api_data->data) = *((time_t *)data); + break; + case API_TEMP: + api_data->data = (void *)malloc(sizeof(float)); + *((float *)(api_data->data)) = *((float *)data); + break; + default: + applog(LOG_ERR, "API: unknown1 data type %d ignored", type); + api_data->type = API_STRING; + api_data->data_was_malloc = false; + api_data->data = (void *)UNKNOWN; + break; + } + + return root; +} + +static struct api_data *print_data(struct api_data *root, char *buf, bool isjson) +{ + struct api_data *tmp; + bool first = true; + char *quote; + + if (isjson) { + strcpy(buf, JSON0); + quote = JSON1; + } else { + strcpy(buf, COMMA); + quote = (char *)BLANK; + } + + buf = strchr(buf, '\0'); + + while (root) { + if (!first) + *(buf++) = *COMMA; + else + first = false; + + sprintf(buf, "%s%s%s%s", quote, root->name, quote, isjson ? ":" : "="); + + buf = strchr(buf, '\0'); + + switch(root->type) { + case API_STRING: + sprintf(buf, "%s%s%s", quote, (char *)(root->data), quote); + break; + case API_ESCAPE: + sprintf(buf, "%s%s%s", + quote, + escape_string((char *)(root->data), isjson), + quote); + break; + case API_INT: + sprintf(buf, "%d", *((int *)(root->data))); + break; + case API_UINT: + sprintf(buf, "%u", *((unsigned int *)(root->data))); + break; + case API_UINT64: + sprintf(buf, "%"PRIu64, *((uint64_t *)(root->data))); + break; + case API_ULONG: + case API_TIME: + sprintf(buf, "%lu", *((unsigned long *)(root->data))); + break; + case API_DOUBLE: + sprintf(buf, "%f", *((double *)(root->data))); + break; + case API_UTILITY: + case API_MHS: + sprintf(buf, "%.2f", *((double *)(root->data))); + break; + case API_VOLTS: + sprintf(buf, "%.3f", *((double *)(root->data))); + break; + case API_MHTOTAL: + sprintf(buf, "%.4f", *((double *)(root->data))); + break; + case API_HS: + sprintf(buf, "%.15f", *((double *)(root->data))); + break; + case API_BOOL: + sprintf(buf, "%s", *((bool *)(root->data)) ? "true" : "false"); + break; + case API_TIMEVAL: + sprintf(buf, "%ld.%06ld", + ((struct timeval *)(root->data))->tv_sec, + ((struct timeval *)(root->data))->tv_usec); + break; + case API_TEMP: + sprintf(buf, "%.2f", *((float *)(root->data))); + break; + default: + applog(LOG_ERR, "API: unknown2 data type %d ignored", root->type); + sprintf(buf, "%s%s%s", quote, UNKNOWN, quote); + break; + } + + buf = strchr(buf, '\0'); + + if (root->data_was_malloc) + free(root->data); + + if (root->next == root) { + free(root); + root = NULL; + } else { + tmp = root; + root = tmp->next; + root->prev = tmp->prev; + root->prev->next = root; + free(tmp); + } + } + + if (isjson) + strcat(buf, "}"); + + return root; +} + #ifdef HAVE_AN_FPGA static int numpgas() { @@ -819,15 +1008,33 @@ static char *message(int messageid, int paramid, char *param2, bool isjson) static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { + struct api_data *root = NULL; + char buf[TMPBUFSIZ]; + + sprintf(io_buffer, isjson + ? "%s," JSON_VERSION + : "%s" _VERSION, + message(MSG_VERSION, 0, NULL, isjson)); + + root = api_add_data(root, "CGMiner", API_STRING, VERSION); + root = api_add_data(root, "API", API_STRING, APIVERSION); + +/* sprintf(io_buffer, isjson ? "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE : "%s" _VERSION ",CGMiner=%s,API=%s" SEPSTR, message(MSG_VERSION, 0, NULL, isjson), VERSION, APIVERSION); +*/ + + root = print_data(root, buf, isjson); + strcat(io_buffer, buf); + strcat(io_buffer, isjson ? JSON_CLOSE : SEPSTR); } static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { + struct api_data *root = NULL; char buf[TMPBUFSIZ]; int gpucount = 0; int pgacount = 0; @@ -859,6 +1066,23 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, cpucount = opt_n_threads > 0 ? num_processors : 0; #endif + sprintf(io_buffer, isjson + ? "%s," JSON_MINECON + : "%s" _MINECON ",", + message(MSG_MINECON, 0, NULL, isjson)); + + root = api_add_data(root, "GPU Count", API_INT, &gpucount); + root = api_add_data(root, "PGA Count", API_INT, &pgacount); + root = api_add_data(root, "CPU Count", API_INT, &cpucount); + root = api_add_data(root, "Pool Count", API_INT, &total_pools); + root = api_add_data(root, "ADL", API_STRING, adl); + root = api_add_data(root, "ADL in use", API_STRING, adlinuse); + root = api_add_data(root, "Strategy", API_STRING, strategies[pool_strategy].s); + root = api_add_data(root, "Log Interval", API_INT, &opt_log_interval); + root = api_add_data(root, "Device Code", API_STRING, DEVICECODE); + root = api_add_data(root, "OS", API_STRING, OSINFO); + +/* strcpy(io_buffer, message(MSG_MINECON, 0, NULL, isjson)); sprintf(buf, isjson @@ -869,10 +1093,16 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, strategies[pool_strategy].s, opt_log_interval, DEVICECODE, OSINFO); strcat(io_buffer, buf); +*/ + + root = print_data(root, buf, isjson); + strcat(io_buffer, buf); + strcat(io_buffer, isjson ? JSON_CLOSE : SEPSTR); } #ifdef HAVE_OPENCL static void gpustatus(int gpu, bool isjson) { + struct api_data *root = NULL; char intensity[20]; char buf[TMPBUFSIZ]; char *enabled; @@ -909,6 +1139,38 @@ static void gpustatus(int gpu, bool isjson) else sprintf(intensity, "%d", cgpu->intensity); + root = api_add_data(root, "GPU", API_INT, &gpu); + root = api_add_data(root, "Enabled", API_STRING, &enabled); + root = api_add_data(root, "Status", API_STRING, &status); + root = api_add_data(root, "Temperature", API_TEMP, >); + root = api_add_data(root, "Fan Speed", API_INT, &gf); + root = api_add_data(root, "Fan Percent", API_INT, &gp); + root = api_add_data(root, "GPU Clock", API_INT, &gc); + root = api_add_data(root, "Memory Clock", API_INT, &gm); + root = api_add_data(root, "GPU Voltage", API_VOLTS, &gv); + root = api_add_data(root, "GPU Activity", API_INT, &ga); + root = api_add_data(root, "Powertune", API_INT, &pt); + + double mhs = cgpu->total_mhashes / total_secs; + root = api_add_data(root, "MHS av", API_MHS, &mhs); + + char mhsname[27]; + sprintf(mhsname, "MHS %ds", opt_log_interval); + root = api_add_data(root, mhsname, API_MHS, &(cgpu->rolling)); + + root = api_add_data(root, "Accepted", API_INT, &(cgpu->accepted)); + root = api_add_data(root, "Rejected", API_INT, &(cgpu->rejected)); + root = api_add_data(root, "Hardware Errors", API_INT, &(cgpu->hw_errors)); + root = api_add_data(root, "Utility", API_UTILITY, &(cgpu->utility)); + root = api_add_data(root, "Intensity", API_STRING, intensity); + + unsigned long last_share_pool = cgpu->last_share_pool_time > 0 ? cgpu->last_share_pool : -1; + root = api_add_data(root, "Last Share Pool", API_INT, &last_share_pool); + + root = api_add_data(root, "Last Share Time", API_ULONG, &(cgpu->last_share_pool_time)); + root = api_add_data(root, "Total MH", API_MHTOTAL, &(cgpu->total_mhashes)); + + /* sprintf(buf, isjson ? "{\"GPU\":%d,\"Enabled\":\"%s\",\"Status\":\"%s\",\"Temperature\":%.2f,\"Fan Speed\":%d,\"Fan Percent\":%d,\"GPU Clock\":%d,\"Memory Clock\":%d,\"GPU Voltage\":%.3f,\"GPU Activity\":%d,\"Powertune\":%d,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Intensity\":\"%s\",\"Last Share Pool\":%d,\"Last Share Time\":%lu,\"Total MH\":%.4f}" : "GPU=%d,Enabled=%s,Status=%s,Temperature=%.2f,Fan Speed=%d,Fan Percent=%d,GPU Clock=%d,Memory Clock=%d,GPU Voltage=%.3f,GPU Activity=%d,Powertune=%d,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Intensity=%s,Last Share Pool=%d,Last Share Time=%lu,Total MH=%.4f" SEPSTR, @@ -920,6 +1182,10 @@ static void gpustatus(int gpu, bool isjson) (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes); strcat(io_buffer, buf); + */ + root = print_data(root, buf, isjson); + strcat(io_buffer, buf); + strcat(io_buffer, isjson ? BLANK : SEPSTR); } } #endif diff --git a/miner.h b/miner.h index 57fa774f..1be29d6f 100644 --- a/miner.h +++ b/miner.h @@ -791,4 +791,36 @@ extern bool successful_connect; extern void adl(void); extern void app_restart(void); +enum api_data_type { + API_ESCAPE, + API_STRING, + API_INT, + API_UINT, + API_UINT64, + API_ULONG, + API_DOUBLE, + API_BOOL, + API_TIMEVAL, + API_TIME, + API_MHS, + API_MHTOTAL, + API_TEMP, + API_UTILITY, + API_VOLTS, + API_HS +}; + +struct api_data { + enum api_data_type type; + char *name; + void *data; + bool data_was_malloc; + struct api_data *prev; + struct api_data *next; +}; + +extern struct api_data *api_add_data_full(struct api_data *root, char *name, enum api_data_type type, void *data, bool copy_data); +#define api_add_data_copy(r, n, t, d) api_add_data_full((r), (n), (t), (void *)(d), true) +#define api_add_data(r, n, t, d) api_add_data_full((r), (n), (t), (void *)(d), false) + #endif /* __MINER_H__ */