Subversion Repositories heizung

Rev

Rev 5 | Rev 8 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 root 1
/*
5 andreas 2
 * (C) Copyright 2010, 2011 by Andreas Theofilu <andreas@theosys.at>
1 root 3
 * All rights reserved!
4
 */
5
 
6
#include <stdio.h>
7
#include <string.h>
8
#include <unistd.h>
9
#include <stdlib.h>
10
#include <math.h>
11
#include <time.h>
12
#include <signal.h>
13
#include <syslog.h>
14
#include <errno.h>
15
#include <pthread.h>
16
#include <sys/stat.h>
17
#include <sys/types.h>
18
#include <sys/socket.h>
19
#include <fcntl.h>
20
#include <netdb.h>
21
#include <netinet/in.h>
22
#include <sys/param.h>
23
#include <sys/ioctl.h>
24
#include <pwd.h>
25
#include <grp.h>
5 andreas 26
#include "sensor.h"
27
#include "usb_comm.h"
28
#include "heizung.h"
1 root 29
 
30
typedef struct
31
{
32
      int wday;
33
      ulong start;
34
      ulong end;
35
      float temp;
36
}HEIZUNG;
37
 
38
typedef struct HEIZINDEX
39
{
40
      HEIZUNG *heizung;
4 andreas 41
      struct HEIZINDEX *next;
1 root 42
}HEIZINDEX;
43
 
44
CONFIGURE configs;
45
HEIZINDEX *HeizFirst;
46
float ActTemperature;
47
float ActPressure;
48
 
5 andreas 49
static pthread_t pthr_pars, pthr_temp_pars;
1 root 50
 
51
// Prototypes
52
void daemon_start(int ignsigcld);
5 andreas 53
void *pthr_temperature(void *pV_data);
1 root 54
void *pthr_parser(void *pV_data);
55
void sig_child(void);
56
int parseCommand(int s1, char *cmd);
4 andreas 57
void changeToUser(char *, char *);
1 root 58
 
59
HEIZINDEX *allocateMemory(void);
4 andreas 60
HEIZINDEX *insertMemory(HEIZINDEX *pos);
1 root 61
void freeMemory(void);
4 andreas 62
HEIZINDEX *freeChainMember(HEIZINDEX *member);
63
void freeDay(int wday);
64
void insertMember(int wday, long endt, float temp);
1 root 65
int readHeizPlan(void);
66
int writeHeizPlan(void);
67
void readConf(void);
68
 
4 andreas 69
char *readLine(int fd, char *buf, int bufLen);
1 root 70
char *trim(char *str);
2 andreas 71
char *remove_string(char *str, char *search, char *ret);
1 root 72
 
73
static pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
5 andreas 74
static pthread_mutex_t fastmutex_ser = PTHREAD_MUTEX_INITIALIZER;
1 root 75
 
76
/*
77
 * The main program, initializing everything and start the daemon.
78
 */
79
int main(int argc, char *argv[])
80
{
81
int fd, index;
82
 
83
	HeizFirst = NULL;
84
	readConf();
5 andreas 85
	// Initialize USB
86
	serialDev.fd = -1;
87
	serialDev.switch_fd = -1;
88
	serialDev.handle = NULL;
1 root 89
	// Now daemonize this application
90
	daemon_start(0);
4 andreas 91
	changeToUser(&configs.User[0], &configs.Grp[0]);
1 root 92
	// Now start our Thread
93
	if (pthread_create(&pthr_pars, NULL, pthr_parser, (void *)0) != 0)
94
	{
95
	   syslog (LOG_DAEMON,"Create of thread \"pthr_parser\" failed!");
96
	   return 1;
97
	}
98
 
5 andreas 99
	// Here we start another thread to read the temperature
100
	if (pthread_create(&pthr_temp_pars, NULL, pthr_temperature, (void *)0) != 0)
101
	{
102
	   syslog(LOG_DAEMON,"Create of thread \"pthr_temperature\" failed!");
103
	   pthread_cancel(pthr_pars);
104
	   return 1;
105
	}
106
 
1 root 107
	while (1)
108
	   sleep(3600);
109
 
5 andreas 110
	pthread_exit(NULL);
1 root 111
	return 0;
112
}
113
 
114
/*
115
 * Detach application from console and make it a daemon.
116
 */
117
void daemon_start (int ignsigcld)
118
{
119
int childpid, fd;
120
 
121
        if (getpid () == 1)
122
           goto out;
123
 
124
#ifdef SIGTTOU
125
        signal (SIGTTOU, SIG_IGN);
126
#endif
127
#ifdef SIGTTIN
128
        signal (SIGTTIN, SIG_IGN);
129
#endif
130
#ifdef SIGTSTP
131
        signal (SIGTSTP, SIG_IGN);
132
#endif
133
 
134
        if ((childpid = fork ()) < 0)
135
           fprintf (stderr, "Can't fork this child\n");
136
        else if (childpid > 0)
137
           exit (0);
138
 
139
        if (setpgrp () == -1)
140
           fprintf (stderr, "Can't change process group\n");
141
 
142
        signal (SIGHUP, SIG_IGN);
143
 
144
        if ((childpid = fork ()) < 0)
145
           syslog (LOG_DAEMON, "Can't fork second child");
146
        else if (childpid > 0)
147
           exit (0);            /* first child */
148
 
149
        /* second child */
150
out:
151
        for (fd = 0; fd < NOFILE; fd++)
152
           close (fd);
153
 
154
        errno = 0;
155
        chdir ("/");
156
        umask (0);
157
 
158
        if (ignsigcld)
159
        {
160
//#ifdef SIGTSTP
161
//           signal (SIGCLD, sig_child);
162
//#else
163
           signal (SIGCLD, SIG_IGN);
164
//#endif
165
        }
166
}
167
 
168
void sig_child ()
169
{
170
#if defined(BSD) && !defined(sinix) && !defined(Linux)
171
int pid;
172
union wait status;
173
 
174
        while ((pid = wait3 (&status, WNOHANG, (struct rusage *)0)) > 0)
175
                ;
176
#endif
177
}
178
 
179
void changeToUser(char *usr, char *grp)
180
{
181
gid_t gr_gid;
182
 
183
	if (usr && strlen(usr))
184
	{
185
	   /* get uid */
186
	   struct passwd *userpwd;
187
	   struct group *usergrp;
188
 
189
	   if ((userpwd = getpwnam(usr)) == NULL)
190
	   {
191
	      syslog(LOG_DAEMON,"no such user: %s", usr);
192
	      exit(EXIT_FAILURE);
193
	   }
194
 
195
	   if (!grp || strlen(grp) || (usergrp = getgrnam(grp)) == NULL)
196
	   {
197
	      if (grp && strlen(grp))
198
	         syslog(LOG_WARNING,"no such group: %s", grp);
199
 
200
	      gr_gid = userpwd->pw_gid;
201
	   }
202
	   else
203
	      gr_gid = usergrp->gr_gid;
204
 
205
	   if (setgid(gr_gid) == -1)
206
	   {
207
	      syslog(LOG_DAEMON,"cannot setgid of user %s: %s", usr, strerror(errno));
208
	      exit(EXIT_FAILURE);
209
	   }
210
 
211
#ifdef _BSD_SOURCE
212
	   /* init suplementary groups
213
	    * (must be done before we change our uid)
214
	    */
215
	   if (initgroups(usr, gr_gid) == -1)
216
	      syslog(LOG_DAEMON,"cannot init suplementary groups of user %s: %s", usr, strerror(errno));
217
#endif
218
 
219
	   /* set uid */
220
	   if (setuid(userpwd->pw_uid) == -1)
221
	   {
222
	      syslog(LOG_DAEMON,"cannot change to uid of user %s: %s\n", usr, strerror(errno));
223
	      exit(EXIT_FAILURE);
224
	   }
225
 
226
	   if(userpwd->pw_dir)
227
	      setenv("HOME", userpwd->pw_dir, 1);
228
        }
229
}
230
 
5 andreas 231
void *pthr_temperature(void *pV_data)
232
{
233
time_t t, tstart;
234
struct tm *zeit, sz;
235
int sleep_sec;
236
 
237
	// Initialize the serial port.
238
	serial_set_method((strlen(configs.Device)) ? 1 : 0, configs.VID, configs.PID);
239
 
240
	if (strlen(configs.Device))
241
	   serial_set_device(configs.Device);
242
 
243
	if (!serial_open())
244
	   return NULL;
245
 
246
	if (serialDev.switch_fd == -1)
247
	{
248
	   if (!serial_open())
249
	      return NULL;
250
	}
251
 
252
	pthread_mutex_lock (&fastmutex_ser);
253
 
254
	while(1)
255
	{
256
	   HEIZINDEX *act;
257
 
258
	   ActTemperature = GetTemp();
259
	   sleep_sec = 300;
260
 
261
	   // Compare the actual temperature with the one that should be
262
	   // and switch heating on or off
263
	   if (HeizFirst)
264
	   {
265
	      int wday;
266
	      unsigned long loctm;
267
 
268
	      t = time (NULL);
269
	      sleep_sec = 300 - (int)((t + 300L) % 300L);
270
	      sleep_sec++;
271
	      zeit = localtime (&t);
272
 
273
	      wday = (zeit->tm_wday == 0) ? 7 : zeit->tm_wday;
274
	      memset (&sz, 0, sizeof (struct tm));
275
	      sz.tm_min = 0;
276
	      sz.tm_hour = 0;
277
	      sz.tm_mon = zeit->tm_mon;
278
	      sz.tm_mday = zeit->tm_mday;
279
	      sz.tm_year = zeit->tm_year;
280
	      sz.tm_isdst = zeit->tm_isdst;
281
	      tstart = mktime(&sz);
282
	      loctm = t - tstart;	// Seconds since midnight
283
	      act = HeizFirst;
7 andreas 284
 
5 andreas 285
	      while(act)
286
	      {
287
		 if (act->heizung->wday == wday && loctm >= act->heizung->start && loctm <= act->heizung->end)
288
		 {
289
		    if (ActTemperature == 9999.0)
290
		       SwitchOff();		// No temperature, no heating
291
		    else if (ActTemperature < 5.0)
292
		       SwitchOn();		// Make sure it will not freeze
293
		    else if (ActTemperature > 30.0)
294
		       SwitchOff();		// Don't over heat
295
		    else if (ActTemperature <= (act->heizung->temp - 0.5))
296
		       SwitchOn();
297
		    else if (ActTemperature > act->heizung->temp)
298
		       SwitchOff();
299
		 }
300
 
301
		 act = act->next;
302
	      }
303
	   }
304
	   else
305
	      syslog(LOG_INFO,"Structure not initialized!");
306
 
307
	   sleep(sleep_sec);		// Wait 5 Minutes
308
	}
309
 
310
	pthread_mutex_unlock(&fastmutex_ser);
311
}
312
 
1 root 313
void *pthr_parser( void *pV_data )
314
{
315
int i;
7 andreas 316
char ch, buf[128], str[INET_ADDRSTRLEN];
1 root 317
// socket structure
318
struct sockaddr_in client1, server1;
319
struct servent *serviceInfo;
320
int s1,s;
321
socklen_t length;
322
 
323
	// socket server
324
	if (configs.port > 0)
325
	   server1.sin_port = htons(configs.port);
326
	else if ((serviceInfo = getservbyname ("heizung", "tcp")))
327
	   server1.sin_port = serviceInfo->s_port;
328
	else
329
	{
330
	   syslog(LOG_DAEMON,"Error: No TCP port defined!");
331
	   exit(EXIT_FAILURE);
332
	}
333
 
334
	server1.sin_family = AF_INET;
335
	server1.sin_addr.s_addr = INADDR_ANY;
336
	s = socket(AF_INET,SOCK_STREAM,0);
337
 
338
	if (s < 0)
7 andreas 339
	{
340
	   syslog (LOG_DAEMON, "Error in socket: %s",strerror(errno));
341
	   exit(EXIT_FAILURE);
342
	}
1 root 343
 
344
	if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
7 andreas 345
	{
346
	   syslog (LOG_DAEMON, "Error in bind: %s", strerror(errno));
347
	   exit(EXIT_FAILURE);
348
	}
1 root 349
 
350
	if (listen (s, 5) < 0)
7 andreas 351
	{
352
	   syslog (LOG_DAEMON, "Error in listen: %s", strerror(errno));
353
	   exit(EXIT_FAILURE);
354
	}
1 root 355
 
356
	length = sizeof(client1);
357
        syslog (LOG_DEBUG, "Server ready: %d",s);
358
 
359
	while (1)
360
	{
361
	   // Read time table at every loop, to be sure to have the latest
362
	   // version (User may change it at every time)
363
	   if (!readHeizPlan())
364
	   {
365
	      if (!HeizFirst)
366
	      {
7 andreas 367
	         syslog(LOG_DAEMON, "Error reading table %s with plan!", configs.HeizPath);
368
	         exit(EXIT_FAILURE);
1 root 369
	      }
370
	      else
371
		 syslog(LOG_DAEMON, "Error reading table with plan! Will work with old one.");
372
	   }
373
 
374
	   if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
7 andreas 375
	      syslog (LOG_DAEMON, "Error in accept: %d: %s", s1, strerror(errno));
1 root 376
 
377
	   pthread_mutex_lock (&fastmutex);
7 andreas 378
	   inet_ntop(AF_INET, &(client1.sin_addr), str, INET_ADDRSTRLEN);
379
	   syslog (LOG_INFO, "Connected to client %s", str);
1 root 380
	   memset(&buf[0], 0, sizeof(buf));
381
	   i = 0;
382
 
383
	   while (read(s1,&ch,1) > 0)
384
	   {
385
	      if (i < (sizeof(buf) - 1))
386
	      {
387
		 buf[i] = ch;
388
 
4 andreas 389
		 if (ch == ';' || ch == 0x0d)
1 root 390
		 {
4 andreas 391
		    if (!strncmp(buf, "quit", 4))
392
		       break;
1 root 393
 
394
		    if (!parseCommand(s1,buf))
395
		    {
396
		    char hv0[128];
397
 
398
		       sprintf(&hv0[0],"INVALID COMMAND: %s;",buf);
399
		       write(s1,hv0,strlen(hv0));
400
		    }
401
		    else
402
		       write(s1,"OK;",3);
403
 
404
		    memset(&buf[0], 0, sizeof(buf));
405
		    i = 0;
406
		    continue;
407
		 }
408
	      }
409
 
410
	      i++;
411
	   }
412
 
5 andreas 413
	   close (s1);
1 root 414
	   pthread_mutex_unlock(&fastmutex);
415
	}
416
 
5 andreas 417
	serial_close();
1 root 418
	return NULL;
419
}
420
 
421
int parseCommand(int s1, char *cmd)
422
{
4 andreas 423
char bef[32],par[1024], *p;
424
char hv0[256];
1 root 425
int i,j;
4 andreas 426
HEIZINDEX *act, *last;
1 root 427
 
428
	memset(bef,0,sizeof(bef));
429
	memset(par,0,sizeof(par));
430
 
431
	if ((p = strchr(cmd,':')) != NULL)		// do we have a parameter?
432
	{
4 andreas 433
	   strncpy(bef,cmd,p - cmd);
434
	   strncpy(par,p+1,strlen(p+1));
1 root 435
	}
436
	else
437
	   strncpy(bef,cmd,strlen(cmd)-1);
5 andreas 438
 
4 andreas 439
	if (!strcasecmp(bef, "LIST"))		// Write out current list
1 root 440
	{
5 andreas 441
	   int wday = 1;
1 root 442
 
5 andreas 443
	   i = 1;	// The line counter
444
	   // We will write out the week days in the correct order.
445
	   // So we need 2 loops. The first one is runnung for every week day
446
	   // and the 2nd one will find every entry for the actual week day.
447
	   while (wday <= 7)
1 root 448
	   {
5 andreas 449
	      act = HeizFirst;
450
 
451
	      while (act)
452
	      {
453
		 if (act->heizung->wday == wday)
454
		 {
455
		    sprintf(&hv0[0], "LINE:%d:%d:%lu:%lu:%.1f;", i, act->heizung->wday,
456
			act->heizung->start, act->heizung->end, act->heizung->temp);
457
		    write(s1, &hv0[0], strlen(hv0));
458
		    i++;
459
		 }
460
 
461
		 act = act->next;
462
	      }
463
 
464
	      wday++;
1 root 465
	   }
466
	}
467
 
4 andreas 468
	if (!strcasecmp(bef, "GET WDAY"))		// Write out a particular week day
1 root 469
	{
4 andreas 470
	int wday = atoi(par);
1 root 471
 
472
	   if (wday < 1 || wday > 7)
473
	   {
474
	      strcpy(&hv0[0], "ERROR:Invalid week day");
475
	      write(s1, &hv0[0], strlen(hv0));
476
	      return 0;
477
	   }
478
 
479
	   act = HeizFirst;
480
 
481
	   while (act && act->heizung->wday != wday)
482
	      act = act->next;
483
 
484
	   if (!act)
485
	   {
486
	      sprintf(&hv0[0], "ERROR:No plan for week day %d", wday);
487
	      write(s1, &hv0[0], strlen(hv0));
488
	      return 0;
489
	   }
490
 
491
	   i = 1;
492
 
493
	   while (act && act->heizung->wday == wday)
494
	   {
5 andreas 495
	      sprintf(&hv0[0], "LINE:%d:%d:%lu:%lu:%.1f;", i, act->heizung->wday,
1 root 496
		      act->heizung->start, act->heizung->end, act->heizung->temp);
497
	      write(s1, &hv0[0], strlen(hv0));
498
	      i++;
499
	      act = act->next;
500
	   }
501
	}
502
 
4 andreas 503
	if (!strcasecmp(bef, "GET TEMP"))	// Return actual temperature
1 root 504
	{
5 andreas 505
	   sprintf(&hv0[0], "TEMP:%.1f;", ActTemperature);
1 root 506
	   write(s1, &hv0[0], strlen(hv0));
507
	}
508
 
4 andreas 509
	if (!strcasecmp(bef, "GET PRESSURE"))	// Return the actual air pressure
1 root 510
	{
7 andreas 511
	   sprintf(&hv0[0], "PRESSURE:%.1f;", ActPressure);
1 root 512
	   write(s1, &hv0[0], strlen(hv0));
513
	}
514
 
2 andreas 515
	// SET DAY:<count>:<day>:<end1>:<temp>[:<end2>:<temp>[:...]];
516
	// <count>   number of entries following
517
	// <day>     The day of the week
518
	// <end1>    The end time
519
	// <temp>    The temperature wanted until end time is reached
520
	//
4 andreas 521
	if (!strcasecmp(bef, "SET DAY"))		// Set the plan for a particular day
1 root 522
	{
2 andreas 523
	int count, wday, i;
524
	long endt;
525
	float temp;
526
 
4 andreas 527
	   count = atoi(par);
528
	   remove_string(par, ":", &hv0[0]);
529
	   wday = atoi(par);
530
	   freeDay(wday);
531
	   last = NULL;
2 andreas 532
 
533
	   if (count > 0)
534
	   {
535
	      for (i = 0; i < count; i++)
536
	      {
4 andreas 537
		 remove_string(par, ":", &hv0[0]);
538
		 endt = atol(par);
539
		 remove_string(par, ":", &hv0[0]);
540
		 temp = atof(par);
2 andreas 541
 
4 andreas 542
		 if ((act = allocateMemory()) == NULL)
543
		 {
544
		    syslog(LOG_DAEMON,"Error allocating memory for a temperature line.");
545
		    sprintf(&hv0[0], "ERROR:Not enough memory!");
546
		    write(s1, &hv0[0], strlen(hv0));
547
		    return 0;
548
		 }
2 andreas 549
 
4 andreas 550
		 act->heizung->wday = wday;
551
		 act->heizung->end = endt;
552
		 act->heizung->temp = temp;
553
 
554
		 if (last)
5 andreas 555
		    act->heizung->start = last->heizung->end;
4 andreas 556
		 else
557
		    act->heizung->start = 0L;
558
 
559
		 last = act;
2 andreas 560
	      }
5 andreas 561
 
562
	      writeHeizPlan();
2 andreas 563
	   }
1 root 564
	}
565
 
2 andreas 566
	// SET TEMP:<wday>:<end>:<temp>;
5 andreas 567
	if (!strcasecmp(bef, "SET TEMP"))	// Set the temperature for a particular day and line
1 root 568
	{
4 andreas 569
	int wday;
570
	unsigned long endt;
1 root 571
	float tmp;
572
 
4 andreas 573
	   wday = atoi(par);
574
	   remove_string(par, ":", &hv0[0]);
575
	   endt = atol(par);
576
	   remove_string(par, ":", &hv0[0]);
577
	   tmp = atof(par);
578
	   insertMember(wday, endt, tmp);
5 andreas 579
	   writeHeizPlan();
1 root 580
	}
581
 
582
	return 1;
583
}
584
 
585
/*
2 andreas 586
 * Remove a complete day
587
 */
588
void freeDay(int wday)
589
{
590
HEIZINDEX *act, *next, *prev;
591
 
592
	act = HeizFirst;
593
	prev = NULL;
594
 
595
	while(act)
596
	{
597
	   if (act->heizung->wday == wday)
598
	      act = freeChainMember(act);
599
 
600
	   act = act->next;
601
	}  
602
}
603
 
604
/*
605
 * Insert a new entry
606
 */
607
void insertMember(int wday, long endt, float temp)
608
{
609
HEIZINDEX *act;
610
 
611
	act = HeizFirst;
612
 
613
	while(act)
614
	{
615
	   if (act->heizung->wday == wday && act->heizung->end == endt)
616
	   {
617
	      act->heizung->temp = temp;
618
	      return;
619
	   }
620
 
621
	   act = act->next;
622
	}
623
 
624
	if ((act = allocateMemory()) != NULL)
625
	{
626
	   act->heizung->wday = wday;
627
	   act->heizung->end = endt;
628
	   act->heizung->temp = temp;
629
	}
630
}
631
 
632
/*
1 root 633
 * Free the memory for the actual heizung plan.
634
 */
635
void freeMemory()
636
{
637
HEIZINDEX *act, *next;
638
 
639
	act = HeizFirst;
640
 
641
	while(act)
642
	{
643
	   if (act->heizung)
644
	   {
645
	      free(act->heizung);
646
	      act->heizung = NULL;
647
	   }
648
 
649
	   next = act->next;
650
	   free(act);
651
	   act = next;
652
	}
5 andreas 653
 
654
	HeizFirst = NULL;
1 root 655
}
656
 
657
/*
658
 * Free only one entry in the chain
659
 */
2 andreas 660
HEIZINDEX *freeChainMember(HEIZINDEX *member)
1 root 661
{
662
HEIZINDEX *act,*prev;
663
 
664
	act = HeizFirst;
665
	prev = NULL;
666
 
667
	while(act != member)
668
	{
669
	   prev = act;
670
	   act = act->next;
671
	}
672
 
673
	if (act == member)
674
	{
675
	   if (prev)
2 andreas 676
	      prev->next = act->next;
4 andreas 677
	   else
678
	   {
679
	      prev = act->next;
1 root 680
 
4 andreas 681
	      if (act == HeizFirst)
682
		 HeizFirst = act->next;
683
	   }
684
 
1 root 685
	   if (act->heizung)
686
	      free(act->heizung);
687
 
688
	   free(act);
4 andreas 689
	   return prev;
1 root 690
	}
2 andreas 691
 
692
	return NULL;
1 root 693
}
694
 
695
/*
4 andreas 696
 * Allocate the memory for the actual heizung plan.
697
 * This function appends an element to the end of the chain.
1 root 698
 */
699
HEIZINDEX *allocateMemory()
700
{
701
HEIZINDEX *act, *last;
702
 
703
	if (!HeizFirst)
704
	{
705
	   HeizFirst = malloc(sizeof(HEIZINDEX));
706
 
707
	   if (HeizFirst)
708
	   {
709
	      HeizFirst->heizung = malloc(sizeof(HEIZUNG));
710
	      HeizFirst->next = NULL;
711
	   }
712
	   else
713
	      return NULL;
714
 
715
	   return HeizFirst;
716
	}
717
	else
718
	{
719
	   // Find last element
720
	   last = HeizFirst;
721
 
722
	   while(last->next)
723
	      last = last->next;
724
 
725
	   act = malloc(sizeof(HEIZINDEX));
726
 
727
	   if (act)
728
	   {
729
	      act->heizung = malloc(sizeof(HEIZUNG));
730
	      act->next = NULL;
731
	      last->next = act;
732
	   }
733
	   else
734
	      return NULL;
735
 
736
	   return act;
737
	}
738
 
739
	return NULL;
740
}
741
 
742
/*
4 andreas 743
 * Allocate the memory for the actual heizung plan.
744
 * This function inserts an element into the chain.
745
 */
746
HEIZINDEX *insertMemory(HEIZINDEX *pos)
747
{
748
HEIZINDEX *act;
749
 
750
	if (!HeizFirst)
751
	{
752
	   HeizFirst = malloc(sizeof(HEIZINDEX));
753
 
754
	   if (HeizFirst)
755
	   {
756
	      HeizFirst->heizung = malloc(sizeof(HEIZUNG));
757
	      HeizFirst->next = NULL;
758
	   }
759
	   else
760
	      return NULL;
761
 
762
	   return HeizFirst;
763
	}
764
	else
765
	{
766
	   act = malloc(sizeof(HEIZINDEX));
767
 
768
	   if (act)
769
	   {
770
	      act->heizung = malloc(sizeof(HEIZUNG));
771
	      act->next = pos->next;
772
	      pos->next = act;
773
	   }
774
	   else
775
	      return NULL;
776
 
777
	   return act;
778
	}
779
 
780
	return NULL;
781
}
782
 
783
/*
1 root 784
 * The following functions read a config file and put the
785
 * contents into a structure.
786
 */
787
void readConf(void)
788
{
789
int fd;
790
char confFile[512], line[512];
791
char *home, *p;
792
char hv0[64], hv1[128];
793
 
794
	home = getenv("HOME");
795
	fd = -1;
796
 
797
	if (!access("/etc/heizung.conf",R_OK))
798
	   strcpy(confFile,"/etc/heizung.conf");
799
	else if (!access("/etc/heizung/heizung.conf",R_OK))
800
	   strcpy(confFile,"/etc/heizung/heizung.conf");
801
	else if (!access("/usr/etc/heizung.conf",R_OK))
802
	   strcpy(confFile,"/usr/etc/heizung.conf");
803
	else if (home)
804
	{
805
	   strcpy(confFile,home);
806
	   strcat(confFile,"/.heizung.conf");
807
 
808
	   if (access(confFile,R_OK))
4 andreas 809
	   {
810
	      syslog(LOG_WARNING,"Even config file %s was not found!", confFile);
1 root 811
	      confFile[0] = 0;
4 andreas 812
	   }
1 root 813
	}
814
	else
815
	   confFile[0] = 0;
816
 
5 andreas 817
	memset(&configs, 0, sizeof(configs));
818
	strcpy(configs.User,"nobody");
819
	strcpy(configs.Grp,"nobody");
820
	strcpy(configs.HeizPath, "/var/www/.HeizPlan.conf");
821
	strcpy(configs.Werte, "/var/log/werte.dat");
822
	strcpy(configs.Device, "/dev/ttyS1");
823
	configs.port = 11001;
1 root 824
 
4 andreas 825
	if (!confFile[0] || (fd = open(confFile,O_RDONLY)) == -1)
1 root 826
	{
4 andreas 827
	   if (confFile[0])
828
	      syslog(LOG_WARNING,"Error opening the config file %s! Using built in defaults. (%s)", confFile, strerror(errno));
829
	   else
830
	      syslog(LOG_WARNING,"Error opening the config file! Using built in defaults.");
831
 
1 root 832
	   return;
833
	}
834
 
4 andreas 835
	while (readLine(fd, &line[0], sizeof(line)) != NULL)
1 root 836
	{
837
	   int len;
838
 
839
	   trim (&line[0]);
840
 
4 andreas 841
	   if (line[0] == '#' || !strlen(line))
1 root 842
	      continue;
843
 
844
	   if ((p = strchr (line, '=')) == NULL)
845
	      continue;
846
 
847
	   *p = 0;
848
	   p++;
849
	   len = strlen(line);
850
 
851
	   if (len > sizeof(hv0))
852
	      len = sizeof(hv0) - 1;
853
 
854
	   strncpy (hv0, line, len);
4 andreas 855
	   hv0[len] = 0;
1 root 856
	   trim (hv0);
857
	   len = strlen(p);
858
 
859
	   if (len > sizeof(hv1))
860
	      len = sizeof(hv0) - 1;
861
 
862
	   strncpy (hv1, p, len);
4 andreas 863
	   hv1[len] = 0;
1 root 864
	   trim (hv1);
865
 
866
	   if (!strcasecmp(hv0, "user"))
4 andreas 867
	   {
868
	      syslog(LOG_INFO,"Found \"user\": %s", hv1);
1 root 869
	      strncpy (configs.User, hv1, sizeof(configs.User));
4 andreas 870
	   }
1 root 871
 
872
	   if (!strcasecmp(hv0, "group"))
4 andreas 873
	   {
874
	      syslog(LOG_INFO,"Found \"group\": %s", hv1);
1 root 875
	      strncpy (configs.Grp, hv1, sizeof(configs.Grp));
4 andreas 876
	   }
1 root 877
 
878
	   if (!strcasecmp(hv0, "port"))
4 andreas 879
	   {
880
	      syslog(LOG_INFO,"Found \"port\": %s", hv1);
1 root 881
	      configs.port = atoi (hv1);
4 andreas 882
	   }
1 root 883
 
884
	   if (!strcasecmp(hv0, "heizpath"))
4 andreas 885
	   {
886
	      syslog(LOG_INFO,"Found \"heizpath\": %s", hv1);
1 root 887
	      strncpy (configs.HeizPath, hv1, sizeof(configs.HeizPath));
4 andreas 888
	   }
5 andreas 889
 
890
	   if (!strcasecmp(hv0, "Werte"))
891
	   {
892
	      syslog(LOG_INFO,"Found \"Werte\": %s", hv1);
893
	      strncpy (configs.Werte, hv1, sizeof(configs.Werte));
894
	   }
895
 
896
	   if (!strcasecmp(hv0, "Device"))
897
	   {
898
	      syslog(LOG_INFO,"Found \"Device\": %s", hv1);
899
	      strncpy (configs.Device, hv1, sizeof(configs.Device));
900
	   }
901
 
902
	   if (!strcasecmp(hv0, "VID"))
903
	   {
904
	      syslog(LOG_INFO,"Found VendorID: %04x", atoi(hv1));
905
	      configs.VID = atoi(hv1);
906
	   }
907
 
908
	   if (!strcasecmp(hv0, "PID"))
909
	   {
910
	      syslog(LOG_INFO,"Found ProductID: %04x", atoi(hv1));
911
	      configs.PID = atoi(hv1);
912
	   }
1 root 913
	}
914
 
915
	close (fd);
916
}
917
 
918
int readHeizPlan(void)
919
{
920
int fd, i, wday;
921
ulong tim;
922
char line[512];
923
char *p, *xp;
924
char hv0[64], hv1[128];
925
float temperature;
7 andreas 926
int counter = 0;
4 andreas 927
HEIZINDEX *act, *prev;
1 root 928
 
929
	fd = -1;
930
 
4 andreas 931
	if (access(configs.HeizPath, R_OK))
932
	{
933
	   syslog(LOG_DAEMON,"Access to file %s denied: %s", configs.HeizPath, strerror(errno));
1 root 934
	   return 0;
4 andreas 935
	}
1 root 936
 
937
	if ((fd = open(configs.HeizPath, O_RDONLY)) == -1)
4 andreas 938
	{
939
	   syslog(LOG_DAEMON,"Error opening file %s: %s", configs.HeizPath, strerror(errno));
1 root 940
	   return 0;
4 andreas 941
	}
1 root 942
 
4 andreas 943
	act = prev = NULL;
944
	freeMemory();
945
 
946
	while (readLine(fd, &line[0], sizeof(line)) != NULL)
1 root 947
	{
948
	   int len;
949
 
950
	   trim (&line[0]);
951
 
5 andreas 952
	   if (line[0] == '#' || !strlen(line) || strchr(line, ',') == NULL)
1 root 953
	      continue;
954
 
4 andreas 955
	   // We need a place to store the information
956
	   prev = act;
957
 
958
	   if ((act = allocateMemory()) == NULL)
959
	   {
960
	      close(fd);
961
	      syslog(LOG_DAEMON,"Error allocating memory for a temperature line! Stopped reading file %s.", configs.HeizPath);
962
	      return 0;
963
	   }
964
 
7 andreas 965
	   counter++;
4 andreas 966
	   memset(act->heizung, 0, sizeof(HEIZUNG));
1 root 967
	   // Parse a line. The line has the format:
968
	   // <wday>,<end>,<temperature>
4 andreas 969
	   p = strtok(line, ",");
1 root 970
	   i = 1;
971
 
972
	   while(p)
973
	   {
974
	      switch(i)
975
	      {
976
		 case 1:	// Week day
977
		    wday = atoi(p);
978
 
979
		    if (wday < 1 || wday > 7)	// valid line?
980
		    {
4 andreas 981
		       if (prev)
982
			  wday = prev->heizung->wday;
1 root 983
 
4 andreas 984
		       if (wday < 1 || wday > 7)
985
		       {
986
			  p = strtok(NULL, ",");
987
			  i++;
988
			  continue;
989
		       }
1 root 990
		    }
991
 
992
		    act->heizung->wday = wday;
993
		    act->heizung->start = 0;
994
		 break;
995
 
996
		 case 2:	// start/end time
997
		    if ((xp = strchr(p, ':')) != NULL)
998
		    {
999
		    int hour, min;
1000
 
1001
		       hour = atoi(p);
1002
		       min = atoi(xp+1);
1003
 
1004
		       if (hour >= 0 && hour <= 23 && min >= 0 && min <= 59)
1005
		       {
5 andreas 1006
			  act->heizung->end = hour * 3600 + min * 60 + 59;
1 root 1007
 
4 andreas 1008
			  if (prev && prev->heizung->wday == act->heizung->wday)
1009
			     act->heizung->start = prev->heizung->end;
1 root 1010
		       }
1011
		    }
1012
		 break;
1013
 
1014
		 case 3:	// temperature
1015
		    temperature = atof(p);
1016
 
1017
		    if (temperature < 5.0 || temperature > 30.0)
1018
		    {
4 andreas 1019
		       p = strtok(NULL,",");
1020
		       i++;
1 root 1021
		       continue;
1022
		    }
1023
 
1024
		    act->heizung->temp = temperature;
1025
		 break;
1026
	      }
1027
 
4 andreas 1028
	      p = strtok(NULL, ",");
1029
	      i++;
1 root 1030
	   }
1031
	}
1032
 
7 andreas 1033
	syslog(LOG_INFO,"Found %d entries in %s", counter, configs.HeizPath);
1 root 1034
	close (fd);
1035
	return 1;
1036
}
1037
 
1038
/*
1039
 * write the (may be) altered plan.
1040
 * This function allways writes whole plan.
1041
 */
1042
int writeHeizPlan()
1043
{
1044
int fd;
1045
char hv0[512];
1046
HEIZINDEX *act;
1047
 
1048
	fd = -1;
1049
 
5 andreas 1050
	if (access(configs.HeizPath, R_OK))
1 root 1051
	   return 0;
1052
 
1053
	if ((fd = open(configs.HeizPath, O_RDWR | O_TRUNC)) == -1)
1054
	   return 0;
1055
 
1056
	act = HeizFirst;
1057
 
1058
	while(act)
1059
	{
5 andreas 1060
	   if (act->heizung->wday)
1061
	   {
1062
	      int hour, min;
1063
 
1064
	      hour = act->heizung->end / 3600;
1065
	      min = (act->heizung->end - (hour * 3600)) / 60;
1066
 
1067
	      if (hour > 23)
1068
	      {
1069
		 hour = 23;
1070
		 min = 59;
1071
	      }
1072
 
1073
	      sprintf(&hv0[0], "%d,%02d:%02d,%.1f\n",
1074
		   act->heizung->wday, hour, min,
1 root 1075
		   act->heizung->temp);
5 andreas 1076
	      write(fd, &hv0[0], strlen(hv0));
1077
	   }
1078
 
1 root 1079
	   act = act->next;
1080
	}
1081
 
1082
	close(fd);
1083
	return 1;
1084
}
1085
 
4 andreas 1086
char *readLine(int fd, char *buf, int bufLen)
1 root 1087
{
4 andreas 1088
int i, end;
1 root 1089
char ch, *p;
1090
 
1091
        if (fd <= 0)
4 andreas 1092
	{
1093
	   syslog(LOG_DAEMON,"Function readLine was called with an invalid file descriptor of %d!", fd);
1094
           return NULL;
1095
	}
1 root 1096
 
4 andreas 1097
        i = end = 0;
1098
        p = buf;
1 root 1099
 
4 andreas 1100
        while (read(fd, &ch, 1) > 0)
1101
        {
1102
           end = 1;
1 root 1103
 
4 andreas 1104
           if (ch == 0x0a)
1105
           {
1106
             *p = 0;
1107
             return buf;
1108
           }
1 root 1109
 
4 andreas 1110
           if (ch == 0x0d)      // ignore this!
1111
              continue;
1 root 1112
 
4 andreas 1113
           if (i < (bufLen - 1))
1114
           {
1115
              *p = ch;
1116
              p++;
1117
              i++;
1118
           }
1119
        }
1 root 1120
 
4 andreas 1121
        *p = 0;
1122
 
1123
        if (end)
1124
           return buf;
1125
        else
1126
           return NULL;
1 root 1127
}
1128
 
1129
char *trim(char *str)
1130
{
1131
char *p1, *p2, *p;
1132
 
1133
	if (!str)
1134
	   return NULL;
1135
 
4 andreas 1136
	if (!strlen(str))
1137
	   return str;
1138
 
1 root 1139
	p = str;
1140
	p1 = p2 = NULL;
1141
 
1142
	while (*p)
1143
	{
1144
	   if (!p1 && *p != ' ')
1145
	   {
1146
	      p1 = p;
1147
	      break;
1148
	   }
1149
 
1150
	   p++;
1151
	}
1152
 
1153
	p2 = str + (strlen(str) - 1);
1154
 
1155
	while (p2 > str && *p2 == ' ')
1156
	   p2--;
1157
 
1158
	if (p2)
1159
	   *(p2+1) = 0;
1160
 
1161
	if (p1)
1162
	{
1163
	   char *buf = strdup (p1);
1164
	   strcpy (str, buf);
1165
	   free (buf);
1166
	}
1167
 
1168
	return str;
1169
}
2 andreas 1170
 
1171
char *remove_string(char *str, char *search, char *ret)
1172
{
1173
char *p;
1174
 
1175
	if (!strlen(str) || !strlen(search))
1176
	   return NULL;
1177
 
1178
	if ((p = strstr(str, search)) != NULL)
1179
	{
1180
	int len = strlen(search);
1181
 
4 andreas 1182
	   strncpy(ret, str, p - str + len);
5 andreas 1183
	   ret[p - str + len] = 0;
1184
	   memmove(str, p + len, strlen(p+len));
1185
	   str[strlen(p+len)] = 0;
2 andreas 1186
	   return ret;
1187
	}
1188
 
1189
	return NULL;
4 andreas 1190
}