diff --git a/uno-stats-monitor/unomond/gather_stats.c b/uno-stats-monitor/unomond/gather_stats.c new file mode 100644 index 0000000..f3d61a5 --- /dev/null +++ b/uno-stats-monitor/unomond/gather_stats.c @@ -0,0 +1,261 @@ +/* + * UNO Monitor Daemon + * Kidacro + * + * gather_stats.c - retrieves stats from system + * + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_ENTRIES 10 + +// from monitor_daemon.c +void send_stats(); + +// local function prototypes +void get_stats(); +char *trim(char *str); +static void get_cpu_load(); +static void get_cpu_temp(); +static void get_free_mem(); +static void get_free_space(); + +// external vars (monitor_daemon.c) +extern const char *cpu_temp_file; +extern const char *cpu_fanspeed_file; +extern char *drive_free_space[MAX_ENTRIES]; +extern int drive_free_space_count; +extern FILE *log_stream; +extern int debug; +extern int line_length; +extern int line_count; + +// stats vars +// TODO: make the character sizes dynamic based on line_length +// src/gather_stats.c:43:6: error: variably modified ‘freespace’ at file scope <-- damn C +// so we have to make a concession and either #define a max or.... no clue... go back to PHP? +char cpuload[4]; // line 1 +char cputemp[6]; // line 1 +char freemem[6]; // line 1 +char freespace[16]; // line 2 + +// sysinfo vars +int sysinfo(struct sysinfo *info); + +// proto: +// struct sysinfo { +// long uptime; /* Seconds since boot */ +// unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ +// unsigned long totalram; /* Total usable main memory size */ +// unsigned long freeram; /* Available memory size */ +// unsigned long sharedram; /* Amount of shared memory */ +// unsigned long bufferram; /* Memory used by buffers */ +// unsigned long totalswap; /* Total swap space size */ +// unsigned long freeswap; /* swap space still available */ +// unsigned short procs; /* Number of current processes */ +// unsigned long totalhigh; /* Total high memory size */ +// unsigned long freehigh; /* Available high memory size */ +// unsigned int mem_unit; /* Memory unit size in bytes */ +// char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */ +//}; + +// trims end of strings +char *trim(char *str) +{ + size_t len = 0; + char *frontp = str; + char *endp = NULL; + + if( str == NULL ) { return NULL; } + if( str[0] == '\0' ) { return str; } + + len = strlen(str); + endp = str + len; + + /* Move the front and back pointers to address the first non-whitespace + * characters from each end. + */ + while(isspace((unsigned char) *frontp)) { ++frontp; } + if(endp != frontp) { + while(isspace((unsigned char) *(--endp)) && endp != frontp) {} + } + + if(frontp != str && endp == frontp) { + *str = '\0'; + } + else if(str + len - 1 != endp) { + *(endp + 1) = '\0'; + } + + /* Shift the string so that it starts at str so that if it's dynamically + * allocated, we can still free it on the returned pointer. Note the reuse + * of endp to mean the front of the string buffer now. + */ + endp = str; + if(frontp != str) { + while(*frontp) { *endp++ = *frontp++; } + *endp = '\0'; + } + + return str; +} + +// get stats (retreive, combine, and send stats) +// TODO: force trunication for each line to line_length +// no reason to hardcode '24' below when we know the exact line_length +void get_stats() +{ + char line_1[24], line_2[24], line_3[24]; + + get_cpu_load(); + get_cpu_temp(); + get_free_mem(); + get_free_space(); + + snprintf(line_1,sizeof(line_1),"#1%s%% %sC %sM@",cpuload,cputemp,freemem); + snprintf(line_2,sizeof(line_2),"#2%s@",trim(freespace)); + snprintf(line_3,sizeof(line_3),"#3%s@",cpuload); + + send_stats(line_1,line_2,line_3); + + return; +} + +static void get_cpu_load() +{ + //static unsigned int lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle; + static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle; + float percent; + static float lastPercent; + int intPercent, read_result = 0; + FILE* file; + unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total; + + file = fopen("/proc/stat", "r"); + read_result = fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow, &totalSys, &totalIdle); + fclose(file); + + // if result cannot be read, set to 0 + if(read_result < 0) { + snprintf(&*cpuload, sizeof(0), "%d", 0); + return; + } + + // we dont have a good value, use old value + if(totalUser < lastTotalUser || totalUserLow < lastTotalUserLow || + totalSys < lastTotalSys || totalIdle < lastTotalIdle) + { + //percent = -1.0; + percent = lastPercent; + } + + // we have a good value, save it and process it + else + { + total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) + (totalSys - lastTotalSys); + percent = total * 100; + total += (totalIdle - lastTotalIdle); + percent /= total; + lastPercent = percent; + } + + lastTotalUser = totalUser; + lastTotalUserLow = totalUserLow; + lastTotalSys = totalSys; + lastTotalIdle = totalIdle; + intPercent = percent; + + snprintf(&*cpuload, sizeof(intPercent), "%d", intPercent); + + return; +} + +static void get_cpu_temp() +{ + FILE* ptr; + char str[10]; + + // opening file in readonly mode + ptr = fopen(&*cpu_temp_file, "r"); + + if(NULL == ptr) { + fprintf(log_stream,"File %s can't be opened!\n",cpu_temp_file); + return; + } + + while(fgets(str, 10, ptr) != NULL) { + if(debug) { + fprintf(log_stream,"Raw CPU temp: %s\n", str); + } + } + + /* + 1 decimal place + char a = str[0]; + char b = str[1]; + char c = str[2]; + snprintf(&*cputemp,6,"%c%c.%c",a,b,c);*/ + + // no decimals + char a = str[0]; + char b = str[1]; + snprintf(&*cputemp,6,"%c%c",a,b); + + fclose(ptr); + + return; +} + +static void get_free_mem() +{ + struct sysinfo info; + int myfreemem; + + if(sysinfo(&info) < 0) { + return; + } + + if(debug) { + fprintf(log_stream,"RAW free mem: %ld\n",info.freeram); + } + + myfreemem = info.freeram / 1024 / 1024; + snprintf(&*freemem,sizeof(freemem),"%d",myfreemem); + + return; +} + +static void get_free_space() +{ + struct statfs info; + int n = 0; + char *mydrive; + char myfree_string[line_length]; + long unsigned int mytmpfree; + + for(n = 0; n < drive_free_space_count; n++) { + mydrive = drive_free_space[n]; + statfs(mydrive, &info); + mytmpfree = ((info.f_bavail*4) / 1024 / 1024) + 1; + snprintf(myfree_string,line_length,"%ldG ",mytmpfree); + strcat(freespace,myfree_string); + + if(debug) { + fprintf(log_stream, "My Drive: %s\n" +" block size : %ld," +" total data blocks : %ld," +" free blocks for root: %ld," +" free blocks for user: %ld," +" free space in G: %ld\n\n", +mydrive, info.f_bsize, info.f_blocks, info.f_bfree, info.f_bavail, mytmpfree); + } + } + + return; +} diff --git a/uno-stats-monitor/unomond/monitor_daemon.c b/uno-stats-monitor/unomond/monitor_daemon.c new file mode 100644 index 0000000..2f0bfd2 --- /dev/null +++ b/uno-stats-monitor/unomond/monitor_daemon.c @@ -0,0 +1,700 @@ +/* + * UNO Monitor Daemon + * Kidacro + * + * monitor_daemon.c - Sends and Receives commands to UNO Monitor over serial connection + * + * Input Schema: + * Start char is: '#' + * End char is: '@' + * 2nd char denotes which line number/mode to use + * + * Example: + * Line 1: #1Archamedis Status@ + * Line 2: #299% free / etc.@ + * LAVG 3: #324@ + * + * Output Schema: + * Multimedia Controls use single characters to denote which button was pressed + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_ENTRIES 10 + +// global variables +int debug = 0; +int running = 0; +char *conf_file_name = "unomond.conf"; +char *pid_file_name = NULL; +int pid_fd = -1; +const char *app_name = "UnomonD"; +FILE *log_stream; +char *log_file_name = NULL; +int serial_port; +struct termios tty; +struct timeval __millis_start; + +// config file settings +int delay = 10000; +int line_length = 16; +int line_count = 2; +const char *cpu_temp_file = ""; +const char *cpu_fanspeed_file; +char *drive_free_space[MAX_ENTRIES]; +int drive_free_space_count; +const char *ttydevice = "/dev/ttyACM0"; +const char *logfile = ""; +const char *ircmd_P = ""; // power +const char *ircmd_M = ""; // mute +const char *ircmd_m = ""; // mode +const char *ircmd_p = ""; // pause/play +const char *ircmd_b = ""; // back +const char *ircmd_f = ""; // forward +const char *ircmd_e = ""; // eq +const char *ircmd_minus = ""; // vol down +const char *ircmd_plus = ""; // vol up +const char *ircmd_r = ""; // return +const char *ircmd_u = ""; // usb scan +const char *ircmd_0 = ""; // number 0 +const char *ircmd_1 = ""; // number 1 +const char *ircmd_2 = ""; // number 2 +const char *ircmd_3 = ""; // number 3 +const char *ircmd_4 = ""; // number 4 +const char *ircmd_5 = ""; // number 5 +const char *ircmd_6 = ""; // number 6 +const char *ircmd_7 = ""; // number 7 +const char *ircmd_8 = ""; // number 8 +const char *ircmd_9 = ""; // number 9 +const char *ircmd_R = ""; // repeat +const char *ircmd_Z = ""; // other button pressed + +// function prototypes +void init_millis(); +unsigned long int millis(); +int read_conf_file(int reload); +void handle_signal(int sig); +static void daemonize(); +void print_help(void); +int serial_open_port(); +int listen_server(); +void send_stats(); + +// from gather_stats.c +void get_stats(); + +// local functions +void init_millis() { + gettimeofday(&__millis_start, NULL); +} + +unsigned long int millis() { + long mtime, seconds, useconds; + struct timeval end; + gettimeofday(&end, NULL); + seconds = end.tv_sec - __millis_start.tv_sec; + useconds = end.tv_usec - __millis_start.tv_usec; + + mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5; + return mtime; +} + +// read from config file +int read_conf_file(int reload) { + int ret = -1, n = 0; + config_t cfg; + config_setting_t *drive_free_space_entries; + char *mydrive; + const char *myttydevice; + const char *mylogfile; + const char *mycpu_temp_file; + const char *mycpu_fanspeed_file; + const char *myircmd_P; + const char *myircmd_M; + const char *myircmd_m; + const char *myircmd_p; + const char *myircmd_b; + const char *myircmd_f; + const char *myircmd_e; + const char *myircmd_minus; + const char *myircmd_plus; + const char *myircmd_r; + const char *myircmd_u; + const char *myircmd_0; + const char *myircmd_1; + const char *myircmd_2; + const char *myircmd_3; + const char *myircmd_4; + const char *myircmd_5; + const char *myircmd_6; + const char *myircmd_7; + const char *myircmd_8; + const char *myircmd_9; + const char *myircmd_R; + const char *myircmd_Z; + + config_init(&cfg); + if(conf_file_name == NULL) { + fprintf(log_stream, "Can not open configuration file!\n"); + syslog(LOG_INFO, "Can not open configuration file %s, exiting.",conf_file_name); + return(EXIT_FAILURE); + } + + // read the file. if there is an error, report it and exit + if(!config_read_file(&cfg, conf_file_name)) { + fprintf(log_stream, "%s:%d - %s\n", config_error_file(&cfg), + config_error_line(&cfg), config_error_text(&cfg)); + config_destroy(&cfg); + syslog(LOG_INFO, "Can not open configuration file %s, exiting.",conf_file_name); + return(EXIT_FAILURE); + } + + if(debug) { + fprintf(log_stream, "in load/reload config file\n"); + } + + // load the base config + // delay + if(config_lookup_int(&cfg, "delay", &delay)) { + fprintf(log_stream, "Config: Using 'delay': %i\n",delay); + } + else { + fprintf(log_stream, "No 'delay' setting in configuration file, using default delay of %i.\n",delay); + } + + // ttydevice + if(config_lookup_string(&cfg, "tty", &myttydevice)) { + ttydevice = strdup(myttydevice); + fprintf(log_stream, "Config: Using 'TTY': %s\n",ttydevice); + } + else { + fprintf(log_stream, "No 'tty' setting in configuration file, using default tty of %s.\n",ttydevice); + } + + // logfile + if(config_lookup_string(&cfg, "logfile", &mylogfile)) { + logfile = strdup(mylogfile); + fprintf(log_stream, "Config: Using 'logfile': %s\n",logfile); + } + else { + fprintf(log_stream, "No 'logfile' setting in configuration file, using default stderr output.\n"); + } + + // line_length + if(config_lookup_int(&cfg, "line_length", &line_length)) { + fprintf(log_stream, "Config: Using 'line_length': %i\n",line_length); + } + else { + fprintf(log_stream, "No 'line_length' setting in configuration file, using default line_length of %i.\n",line_length); + } + + // line_count + if(config_lookup_int(&cfg, "line_count", &line_count)) { + fprintf(log_stream, "Config: Using 'line_count': %i\n",line_count); + } + else { + fprintf(log_stream, "No 'line_count' setting in configuration file, using default line_count of %i.\n",line_count); + } + + // cpu stats settings + if(config_lookup_string(&cfg, "cpu_temp_file", &mycpu_temp_file)) { + cpu_temp_file = strdup(mycpu_temp_file); + } + + if(config_lookup_string(&cfg, "cpu_fanspeed_file", &mycpu_fanspeed_file)) { + cpu_fanspeed_file = strdup(mycpu_fanspeed_file); + } + + // IR commands + if(config_lookup_string(&cfg, "ircmd_P", &myircmd_P)) { ircmd_P = strdup(myircmd_P); } + if(config_lookup_string(&cfg, "ircmd_M", &myircmd_M)) { ircmd_M = strdup(myircmd_M); } + if(config_lookup_string(&cfg, "ircmd_m", &myircmd_m)) { ircmd_m = strdup(myircmd_m); } + if(config_lookup_string(&cfg, "ircmd_p", &myircmd_p)) { ircmd_p = strdup(myircmd_p); } + if(config_lookup_string(&cfg, "ircmd_b", &myircmd_b)) { ircmd_b = strdup(myircmd_b); } + if(config_lookup_string(&cfg, "ircmd_f", &myircmd_f)) { ircmd_f = strdup(myircmd_f); } + if(config_lookup_string(&cfg, "ircmd_e", &myircmd_e)) { ircmd_e = strdup(myircmd_e); } + if(config_lookup_string(&cfg, "ircmd_minus", &myircmd_minus)) { ircmd_minus = strdup(myircmd_minus); } + if(config_lookup_string(&cfg, "ircmd_plus", &myircmd_plus)) { ircmd_plus = strdup(myircmd_plus); } + if(config_lookup_string(&cfg, "ircmd_r", &myircmd_r)) { ircmd_r = strdup(myircmd_r); } + if(config_lookup_string(&cfg, "ircmd_u", &myircmd_u)) { ircmd_u = strdup(myircmd_u); } + if(config_lookup_string(&cfg, "ircmd_0", &myircmd_0)) { ircmd_0 = strdup(myircmd_0); } + if(config_lookup_string(&cfg, "ircmd_1", &myircmd_1)) { ircmd_1 = strdup(myircmd_1); } + if(config_lookup_string(&cfg, "ircmd_2", &myircmd_2)) { ircmd_2 = strdup(myircmd_2); } + if(config_lookup_string(&cfg, "ircmd_3", &myircmd_3)) { ircmd_3 = strdup(myircmd_3); } + if(config_lookup_string(&cfg, "ircmd_4", &myircmd_4)) { ircmd_4 = strdup(myircmd_4); } + if(config_lookup_string(&cfg, "ircmd_5", &myircmd_5)) { ircmd_5 = strdup(myircmd_5); } + if(config_lookup_string(&cfg, "ircmd_6", &myircmd_6)) { ircmd_6 = strdup(myircmd_6); } + if(config_lookup_string(&cfg, "ircmd_7", &myircmd_7)) { ircmd_7 = strdup(myircmd_7); } + if(config_lookup_string(&cfg, "ircmd_8", &myircmd_8)) { ircmd_8 = strdup(myircmd_8); } + if(config_lookup_string(&cfg, "ircmd_9", &myircmd_9)) { ircmd_9 = strdup(myircmd_9); } + if(config_lookup_string(&cfg, "ircmd_0", &myircmd_0)) { ircmd_0 = strdup(myircmd_0); } + if(config_lookup_string(&cfg, "ircmd_R", &myircmd_R)) { ircmd_R = strdup(myircmd_R); } + if(config_lookup_string(&cfg, "ircmd_Z", &myircmd_Z)) { ircmd_Z = strdup(myircmd_Z); } + + // free drive space settings + drive_free_space_entries = config_lookup(&cfg, "drive_free_space"); + drive_free_space_count = config_setting_length(drive_free_space_entries); + fprintf(log_stream,"Config: I have %d free drive space entries:\n", drive_free_space_count); + + for(n = 0; n < drive_free_space_count; n++) { + mydrive = strdup(config_setting_get_string_elem(drive_free_space_entries, n)); + drive_free_space[n] = strdup(mydrive); + + fprintf(log_stream,"\t#%d. %s\n", n + 1, + config_setting_get_string_elem(drive_free_space_entries, n)); + } + + // report to syslog + if(reload == 1) { + syslog(LOG_INFO, "Reloaded configuration file %s of %s", conf_file_name, app_name); + } + else { + syslog(LOG_INFO, "Configuration of %s read from file %s", app_name, conf_file_name); + } + + config_destroy(&cfg); + return ret; +} + +void handle_signal(int sig) +{ + int lock_result = 0; + + if(sig == SIGINT) { + fprintf(log_stream, "Stopping daemon ...\n"); + + /* Unlock and close lockfile */ + if(pid_fd != -1) { + lock_result = lockf(pid_fd, F_ULOCK, 0); + if(lock_result < 0) { + fprintf(log_stream,"Lockfile could not be unlocked.\n"); + syslog(LOG_INFO, "Lockfile could not be unlocked."); + } + close(pid_fd); + } + + /* Try to delete lockfile */ + if(pid_file_name != NULL) { + unlink(pid_file_name); + } + running = 0; + + /* Reset signal handling to default behavior */ + signal(SIGINT, SIG_DFL); + + running = 0; + return; + } + else if (sig == SIGHUP) { + //fprintf(log_stream, "Reloading daemon config file ...\n"); + syslog(LOG_INFO, "Reloading daemon config file ..."); + read_conf_file(1); + } + else if (sig == SIGCHLD) { + //fprintf(log_stream, "Received SIGCHLD signal\n"); + syslog(LOG_INFO, "Received SIGCHLD signal"); + } +} + +static void daemonize() +{ + pid_t pid = 0; + int myfd = -1; + int chdir_result = 0; + int write_result = 0; + + /* Fork off the parent process */ + pid = fork(); + + /* An error occurred */ + if (pid < 0) { + exit(EXIT_FAILURE); + } + + /* Success: Let the parent terminate */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* On success: The child process becomes session leader */ + if (setsid() < 0) { + exit(EXIT_FAILURE); + } + + /* Ignore signal sent from child to parent process */ + signal(SIGCHLD, SIG_IGN); + + /* Fork off for the second time*/ + pid = fork(); + + /* An error occurred */ + if (pid < 0) { + exit(EXIT_FAILURE); + } + + /* Success: Let the parent terminate */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Set new file permissions */ + umask(0); + + /* Change the working directory to the root directory */ + /* or another appropriated directory */ + chdir_result = chdir("/"); + if(chdir_result <0) { + //fprintf(log_stream,"Could not change to our working directory.\n"); + syslog(LOG_INFO, "Could not change to our working directory."); + } + + /* Close all open file descriptors */ + for(myfd = sysconf(_SC_OPEN_MAX); myfd > 0; myfd--) { + close(myfd); + } + + /* Reopen stdin (myfd = 0), stdout (myfd = 1), stderr (myfd = 2) */ + stdin = fopen("/dev/null", "r"); + stdout = fopen("/dev/null", "w+"); + stderr = fopen("/dev/null", "w+"); + + /* Try to write PID of daemon to lockfile */ + if(pid_file_name != NULL) { + char str[256]; + pid_fd = open(pid_file_name, O_RDWR|O_CREAT, 0640); + if(pid_fd < 0) { + /* Can't open lockfile */ + exit(EXIT_FAILURE); + } + + if(lockf(pid_fd, F_TLOCK, 0) < 0) { + /* Can't lock file */ + exit(EXIT_FAILURE); + } + + /* Get current PID */ + sprintf(str, "%d\n", getpid()); + + /* Write PID to lockfile */ + write_result = write(pid_fd, str, strlen(str)); + if(write_result < 0) { + //fprintf(log_stream,"PID could not be written to lockfile.\n"); + syslog(LOG_INFO, "PID could not be written to lockfile."); + } + + } +} + +void print_help(void) +{ + printf("\n Usage: %s [OPTIONS]\n\n", app_name); + printf(" Options:\n"); + printf(" -h --help Print this help\n"); + printf(" -c --conf_file filename Read configuration from the file\n"); + printf(" -l --log_file filename Write logs to the file\n"); + printf(" -d --daemon Daemonize this application\n"); + printf(" -D --debug Debug this application\n"); + printf(" -n --tty /dev/tty* TTY device to connect to\n"); + printf(" -p --pid_file filename PID file used by daemonized app\n"); + printf("\n"); +} + +/* Open Serial Port */ +int serial_open_port() +{ + serial_port = open(ttydevice, O_RDWR); + + // Read in existing settings, and handle any error + if(tcgetattr(serial_port, &tty) != 0) { + fprintf(log_stream, "Error %i from tcgetattr in open ttydevice: %s\n", errno, strerror(errno)); + syslog(LOG_INFO, "Could not open serial port! Exiting."); + exit(EXIT_FAILURE); + } + + tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common) + tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common) + tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size + tty.c_cflag |= CS8; // 8 bits per byte (most common) + tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common) + tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) + + tty.c_lflag &= ~ICANON; + tty.c_lflag &= ~ECHO; // Disable echo + tty.c_lflag &= ~ECHOE; // Disable erasure + tty.c_lflag &= ~ECHONL; // Disable new-line echo + tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes + + tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) + tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed + // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX) + // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX) + + tty.c_cc[VTIME] = 10; // Wait for up to 1s (10 deciseconds), returning as soon as any data is received. + tty.c_cc[VMIN] = 0; + + // Set in/out baud rate to 9600 + cfsetispeed(&tty, B9600); + cfsetospeed(&tty, B9600); + + // Save tty settings, also checking for error + if(tcsetattr(serial_port, TCSANOW, &tty) != 0) { + fprintf(log_stream, "Error %i from tcsetattr in save tty settings: %s\n", errno, strerror(errno)); + syslog(LOG_INFO, "Could not save serial port settings! Exiting."); + exit(EXIT_FAILURE); + } + + return 1; +} + +/* Server */ +int listen_server() +{ + // Allocate memory for read buffer, set size according to your needs + char read_buf [2]; + + // Normally you wouldn't do this memset() call, but since we will just receive + // ASCII data for this example, we'll set everything to 0 so we can + // call printf() easily. + memset(&read_buf, '\0', sizeof(read_buf)); + + // Read bytes. The behaviour of read() (e.g. does it block?, + // how long does it block for?) depends on the configuration + // settings above, specifically VMIN and VTIME + int num_bytes = read(serial_port, &read_buf, sizeof(read_buf)); + + // n is the number of bytes read. n may be 0 if no bytes were received, and can also be -1 to signal an error. + if(num_bytes < 0) { + fprintf(log_stream, "Error reading: %s\n", strerror(errno)); + return 1; + } + + int exec_result = 0; + + // do stuff goes here + // switch on read_buf + // input proto: PMmpbfe-+ru0123456789RZ + if(strcmp(read_buf,"P") == 0) { exec_result = system(ircmd_P); } + if(strcmp(read_buf,"M") == 0) { exec_result = system(ircmd_M); } + if(strcmp(read_buf,"m") == 0) { exec_result = system(ircmd_m); } + if(strcmp(read_buf,"p") == 0) { exec_result = system(ircmd_p); } + if(strcmp(read_buf,"b") == 0) { exec_result = system(ircmd_b); } + if(strcmp(read_buf,"f") == 0) { exec_result = system(ircmd_f); } + if(strcmp(read_buf,"e") == 0) { exec_result = system(ircmd_e); } + if(strcmp(read_buf,"-") == 0) { exec_result = system(ircmd_minus); } + if(strcmp(read_buf,"+") == 0) { exec_result = system(ircmd_plus); } + if(strcmp(read_buf,"r") == 0) { exec_result = system(ircmd_r); } + if(strcmp(read_buf,"u") == 0) { exec_result = system(ircmd_u); } + if(strcmp(read_buf,"0") == 0) { exec_result = system(ircmd_0); } + if(strcmp(read_buf,"1") == 0) { exec_result = system(ircmd_1); } + if(strcmp(read_buf,"2") == 0) { exec_result = system(ircmd_2); } + if(strcmp(read_buf,"3") == 0) { exec_result = system(ircmd_3); } + if(strcmp(read_buf,"4") == 0) { exec_result = system(ircmd_4); } + if(strcmp(read_buf,"5") == 0) { exec_result = system(ircmd_5); } + if(strcmp(read_buf,"6") == 0) { exec_result = system(ircmd_6); } + if(strcmp(read_buf,"7") == 0) { exec_result = system(ircmd_7); } + if(strcmp(read_buf,"8") == 0) { exec_result = system(ircmd_8); } + if(strcmp(read_buf,"9") == 0) { exec_result = system(ircmd_9); } + if(strcmp(read_buf,"R") == 0) { exec_result = system(ircmd_R); } + if(strcmp(read_buf,"Z") == 0) { exec_result = system(ircmd_Z); } + + if(exec_result != 0) { + fprintf(log_stream, "Command for %s failed with %i bytes. Received message: %s\n", read_buf, num_bytes, read_buf); + syslog(LOG_INFO, "Command for %s failed.",read_buf); + } + + if(debug) { + fprintf(log_stream, "Read %i bytes. Received message: %s\n", num_bytes, read_buf); + } + + return 0; +} + +// send stats +void send_stats(char *line_1, char *line_2, char *line_3) +{ + int write_result = 0; + unsigned int mylen_1 = 0; + unsigned int mylen_2 = 0; + unsigned int mylen_3 = 0; + + // Line 1 + mylen_1 = strlen(line_1); + write_result = write(serial_port, line_1, mylen_1); + + if(write_result < 0) { + fprintf(log_stream, "Writing stats to serial report resulted in %i error. Size of message: %i\n", write_result, mylen_1); + syslog(LOG_INFO, "Writing stats to serial report resulted in %i error.",write_result); + } + + // Line 2 + mylen_2 = strlen(line_2); + write_result = write(serial_port, line_2, mylen_2); + + if(write_result < 0) { + fprintf(log_stream, "Writing stats to serial report resulted in %i error. Size of message: %i\n", write_result, mylen_2); + syslog(LOG_INFO, "Writing stats to serial report resulted in %i error.",write_result); + } + + // Line 3 + mylen_3 = strlen(line_3); + write_result = write(serial_port, line_3, mylen_3); + + if(write_result < 0) { + fprintf(log_stream, "Writing stats to serial report resulted in %i error. Size of message: %i\n", write_result, mylen_3); + syslog(LOG_INFO, "Writing stats to serial report resulted in %i error.",write_result); + } + + return; +} + +/* Daemon log method */ +void log_method() { + // command line logfile takes precedence + if(log_file_name != NULL) { + log_stream = fopen(log_file_name, "a+"); + if(log_stream == NULL) { + syslog(LOG_ERR, "Can not open log file: %s, error: %s", log_file_name, strerror(errno)); + log_stream = stderr; // stdout; + } + } + + // config logfile + else if(logfile != NULL) { + log_stream = fopen(logfile, "a+"); + if(log_stream == NULL) { + syslog(LOG_ERR, "Can not open log file: %s, error: %s", logfile, strerror(errno)); + log_stream = stderr; // stdout; + } + } + + // use stderr as failback + else { + log_stream = stderr; // stdout; + } + + return; +} + +/* Main function */ +int main(int argc, char *argv[]) +{ + static struct option long_options[] = { + {"conf_file", required_argument, 0, 'c'}, + {"log_file", required_argument, 0, 'l'}, + {"help", no_argument, 0, 'h'}, + {"debug", no_argument, 0, 'D'}, + {"daemon", no_argument, 0, 'd'}, + {"pid_file", required_argument, 0, 'p'}, + {"tty", required_argument, 0, 'n'}, + {NULL, 0, 0, 0} + }; + int value, option_index = 0; + char *mytty = NULL; + int start_daemonized = 0; + + /* Open system log and write startup message to it */ + openlog(argv[0], LOG_PID|LOG_CONS, LOG_DAEMON); + syslog(LOG_INFO, "Started %s", app_name); + + /* Daemon will handle two signals */ + signal(SIGINT, handle_signal); + signal(SIGHUP, handle_signal); + + // define default log method + log_method(); + + /* Read configuration from config file + * dev: keep this b4 command line arguments so below takes precedence + */ + read_conf_file(0); + + /* Try to process all command line arguments */ + while((value = getopt_long(argc, argv, "c:l:p:n:dDh", long_options, &option_index)) != -1) { + switch (value) { + case 'c': + conf_file_name = strdup(optarg); + read_conf_file(0); + fprintf(log_stream, "Command Line: Using 'conffile': %s\n",conf_file_name); + break; + case 'l': + log_file_name = strdup(optarg); + log_method(); + fprintf(log_stream, "Command Line: Using 'logfile': %s\n",log_file_name); + break; + case 'p': + pid_file_name = strdup(optarg); + fprintf(log_stream, "Command Line: Using 'pidfile': %s\n",pid_file_name); + break; + case 'n': + mytty = strdup(optarg); + ttydevice = mytty; + fprintf(log_stream, "Command Line: Using 'TTY': %s\n",ttydevice); + break; + case 'd': + start_daemonized = 1; + fprintf(log_stream, "Command Line: Daemonizing..."); + break; + case 'D': + debug = 1; + fprintf(log_stream, "Command Line: Using Debugging\n"); + break; + case 'h' | '?': + print_help(); + return EXIT_SUCCESS; + default: + break; + } + } + + /* When daemonizing is requested at command line. */ + if(start_daemonized == 1) { + daemonize(); + } + + /* This global variable can be changed in function handling signal */ + running = 1; + + /* Main loop */ + serial_open_port(); + init_millis(); + while(running == 1) { + listen_server(); // listen for IR events (blocks for 1 second at a time) + + if(debug) { + fprintf(log_stream,"Elapsed time: %ld milliseconds\n", millis()); + } + + if(millis() >= (unsigned long)delay) { + get_stats(); // get and send stats if its time to do so (non blocking timer) + init_millis(); // reset timer + } + } + close(serial_port); + + /* Close log file, when it is used. */ + if(log_stream != stderr) { + fclose(log_stream); + } + + /* Write system log and close it. */ + syslog(LOG_INFO, "Stopped %s\n", app_name); + closelog(); + + return EXIT_SUCCESS; +} diff --git a/uno-stats-monitor/unomond/unomond.conf b/uno-stats-monitor/unomond/unomond.conf new file mode 100644 index 0000000..51a7b34 --- /dev/null +++ b/uno-stats-monitor/unomond/unomond.conf @@ -0,0 +1,38 @@ +// Daemon config +delay = 10000; // in ms (1 second = 1000 ms) - do not set too low or the systat calls will return junk +tty = "/dev/ttyACM0"; // tty device to use (most common for arduino based boards on *nix) +logfile = ""; // logfile - leave undefined for console output (syslog is always used if possible for hard errors) +line_length = 16; // unused but will be needed +line_count = 2; // unused but will be needed + +// readings +cpu_temp_file = "/sys/class/hwmon/hwmon1/temp11_input"; // doesnt have to be cpu, any temperature reading in C will do +cpu_fanspeed_file = "/sys/class/hwmon/hwmon1/temp11_input"; + +// drives (free space stats) +// dev note: for a 16 line display, 3 drives will barely fit depending on the GB available so choose wisely +drive_free_space = [ "/", "/mnt/local", "/mnt/store" ] // list of mountpoints - NOT devices! + +// IR command config +// TODO: lookup xf86 and/or dbus commands for multimedia control +ircmd_P = "echo Power Pressed"; // P power +ircmd_M = ""; // mute +ircmd_m = ""; // mode +ircmd_p = ""; // back +ircmd_f = ""; // forward +ircmd_e = ""; // eq +ircmd_minus = ""; // vol down +ircmd_plus = ""; // vol up +ircmd_r = ""; // return +ircmd_u = ""; // usb scan +ircmd_0 = ""; // number 1 +ircmd_2 = ""; // number 2 +ircmd_3 = ""; // number 3 +ircmd_4 = ""; // number 4 +ircmd_5 = ""; // number 5 +ircmd_6 = ""; // number 6 +ircmd_7 = ""; // number 7 +ircmd_8 = ""; // number 8 +ircmd_9 = ""; // number 9 +ircmd_R = ""; // repeat +ircmd_Z = "echo Unknown Pressed"; // other button pressed