Example #1
0
int main(int argc, char* argv[]) {
    sqlite3_stmt *stmt;   
    pid_t pid;
	char debug[300];
	int init_jobno = 1;
	int c;
	long starttime=time(0);
	uint8_t radiochannel=RADIOCHANNEL;
	// check if started as root
	if ( getuid()!=0 ) {
           fprintf(stdout, "sensorhubd has to be startet as user root\n");
          exit(1);
        }
	// processing argc and argv[]
	while (1) {
		static struct option long_options[] =
			{	{"daemon",  no_argument, 0, 'd'},
				{"verbose",  required_argument, 0, 'v'},
				{"radiochannel", required_argument, 0, 'r'},
				{"logfile",    required_argument, 0, 'l'},
				{"hostname",    required_argument, 0, 'n'},
				{"port",    required_argument, 0, 'p'},
				{"help", no_argument, 0, 'h'},
				{0, 0, 0, 0} };
           /* getopt_long stores the option index here. */
		int option_index = 0;
		c = getopt_long (argc, argv, "?dhv:r:l:n:p:",long_options, &option_index);
		/* Detect the end of the options. */
		if (c == -1) break;
		switch (c) {
			case 'd':
            			start_daemon = true;
			break;
           		case 'v':
				verboselevel = (optarg[0] - '0') * 1;
			break;
			case 'r':
				radiochannel = atoi(optarg);
			break;
			case 'l':
				strcpy(logfilename, optarg);
				use_logfile=true;
			break;
			case 'n':
				sprintf(tn_hostname, "%s", optarg);
				host_set = true;
			break;
			case 'p':
				sprintf(tn_portno, "%s", optarg);
				port_set = true;
			break;
			case 'h':
			case '?':
				usage(argv[0]);
				exit (0);
			break;
			default:
				usage (argv[0]);
				abort ();
		}
	}
       /* Print any remaining command line arguments (not options). */
	if (optind < argc) {
		printf ("non-option ARGV-elements: ");
		while (optind < argc) printf ("%s ", argv[optind++]);
		putchar ('\n');
	}
	// END processing argc and argv[]


	order_t order[7]; // we do not handle more than 6 orders (one per subnode 1...6) at one time
	for (int i=1; i<7; i++) { // init order array
		order[i].Job = 0;
		order[i].seq = 0;
		order[i].to_node  = ' ';
		order[i].channel  = 0;
		order[i].value = 0;
	}
	if( access( PIDFILE, F_OK ) != -1 ) {
    // PIDFILE exists => terminate !!!
	    fprintf(stdout, "PIDFILE exists, terminating\n\n");
		exit(1);
	}
	signal(SIGTERM, sighandler);
	signal(SIGINT, sighandler);
	logmode=interactive;
	if ( use_logfile ) {
	// log to logfile
		logmode = logfile;
		logfile_ptr = fopen (logfilename,"a");
		if (logfile_ptr==NULL) {
			fprintf(stdout,"Could not open %s for writing\n", argv[2]);
		    exit (1);
		}
		fclose(logfile_ptr);
	}
    if (start_daemon) {
    // starts sensorhub as a deamon
		pid = fork ();
		if (pid == 0) {
		// Child prozess
		chdir ("/");
		umask (0);
//		for (i = sysconf (_SC_OPEN_MAX); i > 0; i--) close (i);
		if ( ! use_logfile ) logmode=systemlog;
		sprintf(debug, "Starting up ....");
		logmsg(1,debug);
		} else if (pid > 0) { 
		// Parentprozess -> exit and return to shell
			// write a message to the console
			sprintf(debug, "Starting sensorhubd as daemon...");
			fprintf(stdout, debug);
			// and exit
			exit (0);
		} else {   
		// nagativ is an error
			exit (1);
		}
	}
	if ( ! (start_daemon || use_logfile) ) {
		sprintf(debug,"Using interactive mode ....\n");
		logmsg(1, debug);
	}
	// save own pid tp pidfile
	pid=getpid();
	pidfile_ptr = fopen (PIDFILE,"w");
	if (pidfile_ptr==NULL) {
		sprintf(debug,"Can't write PIDFILE! Exit programm ....\n");
		fprintf(stdout, debug);
		exit (1);
	}
	fprintf (pidfile_ptr, "%d", pid );
	fclose(pidfile_ptr);
	sprintf(debug, "sensorhub running with PID: %d\n", pid);
	logmsg(1, debug);
	if ( port_set && host_set ) {
		telnet_active = true;
		sprintf(debug, "telnet session started: Host: %s Port: %s \n", tn_hostname, tn_portno);
		logmsg(1, debug);	
	}	
    // set up message queue
	key = ftok("/var/www/index.html", 'S');
    if((msqid = msgget(key, 0666 | IPC_CREAT)) == -1) {
        sprintf(debug, "Failed to open messagequeue");
		logmsg(1, debug);
        exit(1);
    }
	sleep(2);
	sprintf(debug, "starting radio... \n");
	logmsg(1, debug);
	radio.begin();
	delay(5);
	sprintf(debug, "starting network on channel %d ... \n", radiochannel);
	logmsg(1, debug);
	network.begin( radiochannel, 0);
	radio.setDataRate(RF24_250KBPS);
    if (verboselevel > 5) {
		sprintf(debug,"\n\n");
		logmsg(1, debug);
		radio.printDetails();
	}
	sprintf(debug, "open database... \n");
	char sql_stmt[300];
	int rc = sqlite3_open(DBFILE, &db);
	if (rc) { logmsg (1, err_opendb);  exit(99); }
    // Start Cleanup
    sprintf (sql_stmt, "delete from JobBuffer "); 
	logmsg(9, sql_stmt);        
    do_sql(sql_stmt);
    // End Cleanup	
    long int dispatch_time=0;
	long int sent_time=0;
	long int akt_time;
    while(1) {
		// check for external messages
		if (msgrcv(msqid, &mesg_buf, sizeof(mesg_buf.mesg)-1, 0, IPC_NOWAIT) > 0) {
			sprintf(debug, "MESG: received Message: Type: %ld Mesg: %s", mesg_buf.mtype, mesg_buf.mesg);
			logmsg(7,debug);
//			if ( mesg_buf.mesg == 1 ) {
				ordersqlrefresh = true;
//			}
		}
		network.update();
		if ( network.available() ) {
//
// Receive loop: react on the message from the nodes
//
			bool goodSignal = radio.testRPD();    
			network.read(rxheader,&payload,sizeof(payload));
            store_node_signal_quality(rxheader.from_node, goodSignal);
			sprintf(debug, DEBUGSTR "Received: Channel: %u from Node: %o to Node: %o Job %d Seq %d Value %f "
						, rxheader.type, rxheader.from_node, rxheader.to_node, payload.Job, payload.seq, payload.value);
			logmsg(7, debug);
			uint16_t sendernode=rxheader.from_node;
			switch (rxheader.type) {

				case 1 ... 20: {
				// Sensor 
					if (is_jobbuffer_entry(payload.Job, payload.seq)) {
						store_sensor_value(payload.Job, payload.seq, payload.value); 
						sprintf(debug, DEBUGSTR "Value of sensor %u on Node: %o is %f ", rxheader.type, sendernode, payload.value);
						logmsg(7, debug);        
						del_jobbuffer_entry(payload.Job, payload.seq);
					}
				break; }
 
				case 21 ... 99: {
				// Actor 
					if (is_jobbuffer_entry(payload.Job, payload.seq)) {
						store_actor_value(payload.Job, payload.seq, payload.value); 
						sprintf(debug, DEBUGSTR "Value of sensor %u on Node: %o is %f ", rxheader.type, sendernode, payload.value);
						logmsg(7, debug);        
						del_jobbuffer_entry(payload.Job, payload.seq);
					}
				break; }

				case 101: {
				// battery voltage
					if (is_jobbuffer_entry(payload.Job, payload.seq)) {
						store_sensor_value(payload.Job, payload.seq, payload.value); 
						sprintf(debug, DEBUGSTR "Voltage of Node: %o is %f ", sendernode, payload.value);
						logmsg(7, debug);        
						sprintf(sql_stmt,"update node set U_Batt = %f where Node_ID = '0%o'", payload.value, sendernode);
						do_sql(sql_stmt);
						del_jobbuffer_entry(payload.Job, payload.seq);
					}
				break; }
				
				case 111: { // Init Sleeptime 1
					sprintf(debug, DEBUGSTR "Node: %o: Sleeptime1 set to %f ", sendernode, payload.value);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break; }
				
				case 112: { // Init Sleeptime 2
					sprintf(debug, DEBUGSTR "Node: %o: Sleeptime2 set to %f ", sendernode, payload.value);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break; }

				case 113: { // Init Sleeptime 3
					sprintf(debug, DEBUGSTR "Node: %o: Sleeptime3 set to %f ", sendernode, payload.value);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break; }

				case 114: { // Init Sleeptime 4
					sprintf(debug, DEBUGSTR "Node: %o: Sleeptime4 set to %f ", sendernode, payload.value);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break; }

				case 115: { // Init Radiobuffer
                    bool radio_always_on = (payload.value >0.5);
					if ( radio_always_on ) sprintf(debug, "Node: %o: Radio allways on", sendernode);
					else sprintf(debug, "Node: %o: Radio allways off", sendernode);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break;  } 
				
				case 116: { // Init Voltagedivider
					sprintf(debug, "Node: %o: Set Voltagedivider to: %f.", sendernode, payload.value);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break;  } 
				
				case 118: {
					sprintf(debug, DEBUGSTR "Node: %o Init finished.", sendernode);
					logmsg(7, debug);        
					del_jobbuffer_entry(payload.Job, payload.seq);  
				break; }
				
				case 119: {
				// Init via JobBuffer
				// we do only one init at one time
					uint16_t sendernode = rxheader.from_node;
					int init_seq = 10;
					// check th jobbuffer if there is still an init job remaining
					int init_waiting_jobs; 
					sprintf(sql_stmt,"select count(*) from JobBuffer where channel in (111,112,113,114,115,116,117,118,119) and priority = 1 and node_id = '0%o' ", sendernode);
					rc = sqlite3_prepare(db, sql_stmt, -1, &stmt, 0 ); 
					if ( rc != SQLITE_OK) log_db_err(rc, err_prepare, sql_stmt);
				    if (sqlite3_step(stmt) == SQLITE_ROW) {
						init_waiting_jobs = sqlite3_column_int (stmt, 0);
					} else {
						init_waiting_jobs = 0;
					}
					rc=sqlite3_finalize(stmt);
					if ( rc != SQLITE_OK) log_db_err(rc, err_finalize, sql_stmt);
					if ( init_waiting_jobs == 0) { 
						sprintf (sql_stmt, "select sleeptime1, sleeptime2, sleeptime3, sleeptime4, radiomode, voltagedivider from node where node_id = '0%o' LIMIT 1 ",sendernode);
						rc = sqlite3_prepare(db, sql_stmt, -1, &stmt, 0 ); 
						if ( rc != SQLITE_OK) log_db_err(rc, err_prepare, sql_stmt);
						double sleeptime1=60; // set defaults
						double sleeptime2=60; // set defaults
						double sleeptime3=1; // set defaults
						double sleeptime4=1; // set defaults
						double radiomode=0;
						double voltagedivider=1;
						if (sqlite3_step(stmt) == SQLITE_ROW) {
							sleeptime1 = sqlite3_column_double (stmt, 0);
							sleeptime2 = sqlite3_column_double (stmt, 1);
							sleeptime3 = sqlite3_column_double (stmt, 2);
							sleeptime4 = sqlite3_column_double (stmt, 3);
							// radiomode not implemented yet ==> still use default !!!!!
							radiomode = sqlite3_column_double (stmt, 4);			
							voltagedivider = sqlite3_column_double (stmt, 5);			
						}
						rc=sqlite3_finalize(stmt);
						if ( rc != SQLITE_OK) log_db_err(rc, err_finalize, sql_stmt);
						// Channel 111 sets sleeptime1 
						sprintf(sql_stmt,"insert into JobBuffer(job_ID,Seq,Node_ID,Channel,Value, Type, Priority) values (%d,1,'0%o',111,%f,2,1)",init_jobno, sendernode, sleeptime1);
						do_sql(sql_stmt);
						// Channel 112 sets sleeptime2 
						sprintf(sql_stmt,"insert into JobBuffer(job_ID,Seq,Node_ID,Channel,Value, Type, Priority) values (%d,2,'0%o',112,%f,2,1)",init_jobno, sendernode, sleeptime2);
						do_sql(sql_stmt);
						// Channel 113 sets sleeptime3 
						sprintf(sql_stmt,"insert into JobBuffer(job_ID,Seq,Node_ID,Channel,Value, Type, Priority) values (%d,3,'0%o',113,%f,2,1)",init_jobno, sendernode, sleeptime3);
						do_sql(sql_stmt);
						// Channel 114 sets sleeptime4 
						sprintf(sql_stmt,"insert into JobBuffer(job_ID,Seq,Node_ID,Channel,Value, Type, Priority) values (%d,4,'0%o',114,%f,2,1)",init_jobno, sendernode, sleeptime4);
						do_sql(sql_stmt);
						// Channel 115 sets radiomode
						sprintf(sql_stmt,"insert into JobBuffer(job_ID,Seq,Node_ID,Channel,Value, Type, Priority) values (%d,5,'0%o',115,%f,2,1)",init_jobno, sendernode, radiomode);
						do_sql(sql_stmt);
						// Channel 116 sets voltagedivider
						sprintf(sql_stmt,"insert into JobBuffer(job_ID,Seq,Node_ID,Channel,Value, Type, Priority) values (%d,6,'0%o',116,%f,2,1)",init_jobno, sendernode, voltagedivider);
						do_sql(sql_stmt);
						// Channel 118 sets init is finished
						sprintf(sql_stmt,"insert into jobbuffer(job_ID,seq,Node_ID,channel,value, Type, priority) values (%d,8,'0%o',118,1,2,1)",init_jobno, sendernode);
						do_sql(sql_stmt);
						// Set the actors to its last known value
						float last_val;
						int mychannel;
						sprintf(sql_stmt, " select channel, value from actor where node_id = '0%o' ",	sendernode);				
						int rc = sqlite3_prepare(db, sql_stmt, -1, &stmt, 0 ); 
						if ( rc != SQLITE_OK) log_db_err(rc, err_prepare, sql_stmt);
						while (sqlite3_step(stmt) == SQLITE_ROW) {
							mychannel  = sqlite3_column_int (stmt, 0);
							last_val = sqlite3_column_double (stmt, 1);
							char sql_stmt1[300];
							sprintf(sql_stmt1, "insert into jobbuffer(job_id, seq , node_id, channel, value, type, priority) values (%d, %d, '0%o', %d, %f, 2, 5)" 
											,init_jobno, init_seq, sendernode, mychannel, last_val);
							do_sql(sql_stmt1);
							init_seq++;
						}
						rc=sqlite3_finalize(stmt);
						if ( rc != SQLITE_OK) log_db_err(rc, err_finalize, sql_stmt);
						init_jobno++;
						if ( init_jobno > 99 ) init_jobno = 1;
						ordersqlrefresh=true;
					}
				break; }
				default: { // By default just delete this job from the jobbuffer
					del_jobbuffer_entry(payload.Job, payload.seq);  				
				}
			}
		} // network.available
//
// Dispatcher: Look if the is anything to schedule
//
		if ( time(0) > dispatch_time + 59 ) {  // check every minute if we have jobs to schedule
			dispatch_time = time(0);
//
// Cleanup old jobs that have not been executed during the last 10 minutes
//
			sprintf (sql_stmt, "delete from jobbuffer"
                 " where strftime('%%s','now') - utime > 600 " );
			do_sql(sql_stmt);
//
// Case 1: Jobs that run frequently - increment "start" by "interval" minutes 
//
			sprintf (sql_stmt, "insert into Scheduled_Jobs (Job_ID)"
							   " select Job_ID from schedule"
							   "  where utime <= strftime('%%s','now') and interval > 0 and Triggered_By = 't' ");
			do_sql(sql_stmt);
			sprintf (sql_stmt, "update schedule set utime =  utime+(1+((strftime('%%s','now')-utime)/interval))*interval "
							   "where utime < strftime('%%s','now') and interval > 0 and Triggered_By = 't' "); 
			do_sql(sql_stmt); 
//
// Case 2: Jobs that run  immeadeately (utime = 0) and run only once (interval = 0)
//
			sprintf (sql_stmt, "insert into Scheduled_Jobs (Job_ID)"
							   " select Job_ID from schedule "
							   "  where utime = 0 and interval = 0  and Triggered_By = 't' ");
			do_sql(sql_stmt);
			sprintf (sql_stmt, "delete from schedule where utime = 0 and interval = 0 and Triggered_By = 't' "); 
			do_sql(sql_stmt);
//
// Case 3: Jobs that run at a scheduled time (utime) and run only once (interval = 0)
//
			sprintf (sql_stmt, "insert into Scheduled_Jobs (Job_ID)"
							   " select Job_ID from schedule "
							   "  where utime <= strftime('%%s','now') and interval = 0 and Triggered_By = 't' ");
			do_sql(sql_stmt);
			sprintf (sql_stmt, "delete from schedule where utime <= strftime('%%s','now') and interval = 0 and Triggered_By = 't' "); 
			do_sql(sql_stmt);
//
// Case 4: Jobs that start immeadeately (utime = 0) and run every <interval> minutes
// 
			sprintf (sql_stmt, "insert into Scheduled_Jobs (Job_ID)"
							   " select Job_ID from schedule "
							   " where utime = 0 and interval > 0 and Triggered_By = 't' ");
			do_sql(sql_stmt);
			sprintf (sql_stmt, "update schedule set utime = strftime('%%s','now') + interval where utime = 0 and interval > 0 and Triggered_By = 't' "); 
			do_sql(sql_stmt);
// Prepare the orders
			ordersqlrefresh=true;
       }
// Orders can come from the dispatcher above or from outside by inserting a jobnumber into the table scheduled_jobs and sending a message to execute immedeatly	   
	   if (ordersqlrefresh) {
// Put all Jobentries into jobbuffer
			sprintf (sql_stmt, 	"insert into jobbuffer (Job_ID, Seq, Node_ID, Channel, Type, Value, Sensor_ID, Priority, Utime)"
								" select Job_ID, Seq, Node_ID, Channel, Type, Value, Sensor_ID, Priority, strftime('%%s','now') from Job2Jobbuffer ");
			do_sql(sql_stmt);
// Delete all entries in Scheduled_Jobs, we dont need them any more
			sprintf (sql_stmt, " delete from Scheduled_Jobs ");
			do_sql(sql_stmt);
//
// End Dispatcher
//
		}
//
// Orderloop: Tell the nodes what they have to do
//
		akt_time=runtime(starttime);
		if ( akt_time > sent_time + 499 ) {  // send every 500 milliseconds
			sent_time=akt_time;
			if ( ordersqlrefresh ) { // if we got new jobs refresh the order array first
				for (int i=1; i<7; i++) {
					sprintf (sql_stmt, "select Job_ID, Seq, Node_ID, Channel, Value from jobbuffer2order where substr(Node_ID,length(Node_ID),1) = '%d' order by CAST(Node_ID as integer), priority, seq LIMIT 1 ",i);
					logmsg(9,sql_stmt);					
					rc = sqlite3_prepare(db, sql_stmt, -1, &stmt, 0 ); 
					if ( rc != SQLITE_OK) log_db_err(rc, err_prepare, sql_stmt);
					order[i].Job = 0;
					if(sqlite3_step(stmt) == SQLITE_ROW) {
						order[i].Job = sqlite3_column_int (stmt, 0);
						order[i].seq = sqlite3_column_int (stmt, 1);
						char nodebuf[10];
						sprintf(nodebuf,"%s",sqlite3_column_text (stmt, 2));
						order[i].to_node  = getnodeadr(nodebuf);
						order[i].channel  = sqlite3_column_int (stmt, 3);
						order[i].value = sqlite3_column_double (stmt, 4);
					}
					rc=sqlite3_finalize(stmt);
					if ( rc != SQLITE_OK) log_db_err(rc, err_finalize, sql_stmt);
					ordersqlrefresh=false;
				}
			}
			if ( (order[1].Job || order[2].Job || order[3].Job || order[4].Job || order[5].Job || order[6].Job)) {
				int i=1;
				while (i<7) {
					if (order[i].Job) {
						txheader.from_node = 0;
						payload.Job = order[i].Job;
						payload.seq = order[i].seq;
						txheader.to_node  = order[i].to_node;
						txheader.type  = order[i].channel;
						payload.value = order[i].value;
						if (network.write(txheader,&payload,sizeof(payload))) {
							sprintf(debug, DEBUGSTR "Send: Channel: %u from Node: %o to Node: %o Job %d Seq %d Value %f "
									, txheader.type, txheader.from_node, txheader.to_node, payload.Job, payload.seq, payload.value);
							logmsg(7, debug); 
						} else {		
							sprintf(debug, DEBUGSTR "Failed: Send: Channel: %u from Node: %o to Node: %o Job %d Seq %d Value %f "
									, txheader.type, txheader.from_node, txheader.to_node, payload.Job, payload.seq, payload.value);
							logmsg(7, debug); 
						}  
					}
					i++; 
				}
			}
		} 
		usleep(10000); 
//
//  end orderloop 
//
	} // while(1)