Subversion Repositories heizung

Rev

Rev 4 | Rev 7 | 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;
284
syslog(LOG_INFO,"wday: %d, loctm: %lu", wday, loctm);
285
	      while(act)
286
	      {
287
		 if (act->heizung->wday == wday && loctm >= act->heizung->start && loctm <= act->heizung->end)
288
		 {
289
syslog(LOG_INFO,"wday: %d, loctm: %lu, endt: %lu, solltemp: %.1f", wday, loctm, act->heizung->start, act->heizung->temp);
290
		    if (ActTemperature == 9999.0)
291
		       SwitchOff();		// No temperature, no heating
292
		    else if (ActTemperature < 5.0)
293
		       SwitchOn();		// Make sure it will not freeze
294
		    else if (ActTemperature > 30.0)
295
		       SwitchOff();		// Don't over heat
296
		    else if (ActTemperature <= (act->heizung->temp - 0.5))
297
		       SwitchOn();
298
		    else if (ActTemperature > act->heizung->temp)
299
		       SwitchOff();
300
		 }
301
 
302
		 act = act->next;
303
	      }
304
	   }
305
	   else
306
	      syslog(LOG_INFO,"Structure not initialized!");
307
 
308
	   sleep(sleep_sec);		// Wait 5 Minutes
309
	}
310
 
311
	pthread_mutex_unlock(&fastmutex_ser);
312
}
313
 
1 root 314
void *pthr_parser( void *pV_data )
315
{
316
int i;
317
char ch, buf[128];
318
// socket structure
319
struct sockaddr_in client1, server1;
320
struct servent *serviceInfo;
321
int s1,s;
322
socklen_t length;
323
 
324
	// socket server
325
	if (configs.port > 0)
326
	   server1.sin_port = htons(configs.port);
327
	else if ((serviceInfo = getservbyname ("heizung", "tcp")))
328
	   server1.sin_port = serviceInfo->s_port;
329
	else
330
	{
331
	   syslog(LOG_DAEMON,"Error: No TCP port defined!");
332
	   exit(EXIT_FAILURE);
333
	}
334
 
335
	server1.sin_family = AF_INET;
336
	server1.sin_addr.s_addr = INADDR_ANY;
337
	s = socket(AF_INET,SOCK_STREAM,0);
338
 
339
	if (s < 0)
340
	   syslog (LOG_DAEMON, "Error in socket");
341
 
342
	if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
343
	   syslog (LOG_DAEMON, "Error in bind");
344
 
345
	if (listen (s, 5) < 0)
346
	   syslog (LOG_DAEMON, "Error in listen");
347
 
348
	length = sizeof(client1);
349
        syslog (LOG_DEBUG, "Server ready: %d",s);
350
 
351
	while (1)
352
	{
353
	   // Read time table at every loop, to be sure to have the latest
354
	   // version (User may change it at every time)
355
	   if (!readHeizPlan())
356
	   {
357
	      if (!HeizFirst)
358
	      {
359
	         syslog(LOG_DAEMON, "Error reading table with plan!");
360
	         return NULL;
361
	      }
362
	      else
363
		 syslog(LOG_DAEMON, "Error reading table with plan! Will work with old one.");
364
	   }
365
 
366
	   if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
367
	      syslog (LOG_DAEMON, "Error in accept: %d", s1);
368
 
369
	   pthread_mutex_lock (&fastmutex);
370
	   syslog (LOG_INFO, "Connected to client");
371
	   memset(&buf[0], 0, sizeof(buf));
372
	   i = 0;
373
 
374
	   while (read(s1,&ch,1) > 0)
375
	   {
376
	      if (i < (sizeof(buf) - 1))
377
	      {
378
		 buf[i] = ch;
379
 
4 andreas 380
		 if (ch == ';' || ch == 0x0d)
1 root 381
		 {
4 andreas 382
		    if (!strncmp(buf, "quit", 4))
383
		       break;
1 root 384
 
385
		    if (!parseCommand(s1,buf))
386
		    {
387
		    char hv0[128];
388
 
389
		       sprintf(&hv0[0],"INVALID COMMAND: %s;",buf);
390
		       write(s1,hv0,strlen(hv0));
391
		    }
392
		    else
393
		       write(s1,"OK;",3);
394
 
395
		    memset(&buf[0], 0, sizeof(buf));
396
		    i = 0;
397
		    continue;
398
		 }
399
	      }
400
 
401
	      i++;
402
	   }
403
 
5 andreas 404
	   close (s1);
1 root 405
	   pthread_mutex_unlock(&fastmutex);
406
	}
407
 
5 andreas 408
	serial_close();
1 root 409
	return NULL;
410
}
411
 
412
int parseCommand(int s1, char *cmd)
413
{
4 andreas 414
char bef[32],par[1024], *p;
415
char hv0[256];
1 root 416
int i,j;
4 andreas 417
HEIZINDEX *act, *last;
1 root 418
 
419
	memset(bef,0,sizeof(bef));
420
	memset(par,0,sizeof(par));
421
 
422
	if ((p = strchr(cmd,':')) != NULL)		// do we have a parameter?
423
	{
4 andreas 424
	   strncpy(bef,cmd,p - cmd);
425
	   strncpy(par,p+1,strlen(p+1));
1 root 426
	}
427
	else
428
	   strncpy(bef,cmd,strlen(cmd)-1);
5 andreas 429
 
4 andreas 430
	if (!strcasecmp(bef, "LIST"))		// Write out current list
1 root 431
	{
5 andreas 432
	   int wday = 1;
1 root 433
 
5 andreas 434
	   i = 1;	// The line counter
435
	   // We will write out the week days in the correct order.
436
	   // So we need 2 loops. The first one is runnung for every week day
437
	   // and the 2nd one will find every entry for the actual week day.
438
	   while (wday <= 7)
1 root 439
	   {
5 andreas 440
	      act = HeizFirst;
441
 
442
	      while (act)
443
	      {
444
		 if (act->heizung->wday == wday)
445
		 {
446
		    sprintf(&hv0[0], "LINE:%d:%d:%lu:%lu:%.1f;", i, act->heizung->wday,
447
			act->heizung->start, act->heizung->end, act->heizung->temp);
448
		    write(s1, &hv0[0], strlen(hv0));
449
		    i++;
450
		 }
451
 
452
		 act = act->next;
453
	      }
454
 
455
	      wday++;
1 root 456
	   }
457
	}
458
 
4 andreas 459
	if (!strcasecmp(bef, "GET WDAY"))		// Write out a particular week day
1 root 460
	{
4 andreas 461
	int wday = atoi(par);
1 root 462
 
463
	   if (wday < 1 || wday > 7)
464
	   {
465
	      strcpy(&hv0[0], "ERROR:Invalid week day");
466
	      write(s1, &hv0[0], strlen(hv0));
467
	      return 0;
468
	   }
469
 
470
	   act = HeizFirst;
471
 
472
	   while (act && act->heizung->wday != wday)
473
	      act = act->next;
474
 
475
	   if (!act)
476
	   {
477
	      sprintf(&hv0[0], "ERROR:No plan for week day %d", wday);
478
	      write(s1, &hv0[0], strlen(hv0));
479
	      return 0;
480
	   }
481
 
482
	   i = 1;
483
 
484
	   while (act && act->heizung->wday == wday)
485
	   {
5 andreas 486
	      sprintf(&hv0[0], "LINE:%d:%d:%lu:%lu:%.1f;", i, act->heizung->wday,
1 root 487
		      act->heizung->start, act->heizung->end, act->heizung->temp);
488
	      write(s1, &hv0[0], strlen(hv0));
489
	      i++;
490
	      act = act->next;
491
	   }
492
	}
493
 
4 andreas 494
	if (!strcasecmp(bef, "GET TEMP"))	// Return actual temperature
1 root 495
	{
5 andreas 496
	   sprintf(&hv0[0], "TEMP:%.1f;", ActTemperature);
1 root 497
	   write(s1, &hv0[0], strlen(hv0));
498
	}
499
 
4 andreas 500
	if (!strcasecmp(bef, "GET PRESSURE"))	// Return the actual air pressure
1 root 501
	{
5 andreas 502
	   sprintf(&hv0[0], "PRESSURE:%.3f;", ActPressure);
1 root 503
	   write(s1, &hv0[0], strlen(hv0));
504
	}
505
 
2 andreas 506
	// SET DAY:<count>:<day>:<end1>:<temp>[:<end2>:<temp>[:...]];
507
	// <count>   number of entries following
508
	// <day>     The day of the week
509
	// <end1>    The end time
510
	// <temp>    The temperature wanted until end time is reached
511
	//
4 andreas 512
	if (!strcasecmp(bef, "SET DAY"))		// Set the plan for a particular day
1 root 513
	{
2 andreas 514
	int count, wday, i;
515
	long endt;
516
	float temp;
517
 
4 andreas 518
	   count = atoi(par);
519
	   remove_string(par, ":", &hv0[0]);
520
	   wday = atoi(par);
521
	   freeDay(wday);
522
	   last = NULL;
2 andreas 523
 
524
	   if (count > 0)
525
	   {
526
	      for (i = 0; i < count; i++)
527
	      {
4 andreas 528
		 remove_string(par, ":", &hv0[0]);
529
		 endt = atol(par);
530
		 remove_string(par, ":", &hv0[0]);
531
		 temp = atof(par);
2 andreas 532
 
4 andreas 533
		 if ((act = allocateMemory()) == NULL)
534
		 {
535
		    syslog(LOG_DAEMON,"Error allocating memory for a temperature line.");
536
		    sprintf(&hv0[0], "ERROR:Not enough memory!");
537
		    write(s1, &hv0[0], strlen(hv0));
538
		    return 0;
539
		 }
2 andreas 540
 
4 andreas 541
		 act->heizung->wday = wday;
542
		 act->heizung->end = endt;
543
		 act->heizung->temp = temp;
544
 
545
		 if (last)
5 andreas 546
		    act->heizung->start = last->heizung->end;
4 andreas 547
		 else
548
		    act->heizung->start = 0L;
549
 
550
		 last = act;
2 andreas 551
	      }
5 andreas 552
 
553
	      writeHeizPlan();
2 andreas 554
	   }
1 root 555
	}
556
 
2 andreas 557
	// SET TEMP:<wday>:<end>:<temp>;
5 andreas 558
	if (!strcasecmp(bef, "SET TEMP"))	// Set the temperature for a particular day and line
1 root 559
	{
4 andreas 560
	int wday;
561
	unsigned long endt;
1 root 562
	float tmp;
563
 
4 andreas 564
	   wday = atoi(par);
565
	   remove_string(par, ":", &hv0[0]);
566
	   endt = atol(par);
567
	   remove_string(par, ":", &hv0[0]);
568
	   tmp = atof(par);
569
	   insertMember(wday, endt, tmp);
5 andreas 570
	   writeHeizPlan();
1 root 571
	}
572
 
573
	return 1;
574
}
575
 
576
/*
2 andreas 577
 * Remove a complete day
578
 */
579
void freeDay(int wday)
580
{
581
HEIZINDEX *act, *next, *prev;
582
 
583
	act = HeizFirst;
584
	prev = NULL;
585
 
586
	while(act)
587
	{
588
	   if (act->heizung->wday == wday)
589
	      act = freeChainMember(act);
590
 
591
	   act = act->next;
592
	}  
593
}
594
 
595
/*
596
 * Insert a new entry
597
 */
598
void insertMember(int wday, long endt, float temp)
599
{
600
HEIZINDEX *act;
601
 
602
	act = HeizFirst;
603
 
604
	while(act)
605
	{
606
	   if (act->heizung->wday == wday && act->heizung->end == endt)
607
	   {
608
	      act->heizung->temp = temp;
609
	      return;
610
	   }
611
 
612
	   act = act->next;
613
	}
614
 
615
	if ((act = allocateMemory()) != NULL)
616
	{
617
	   act->heizung->wday = wday;
618
	   act->heizung->end = endt;
619
	   act->heizung->temp = temp;
620
	}
621
}
622
 
623
/*
1 root 624
 * Free the memory for the actual heizung plan.
625
 */
626
void freeMemory()
627
{
628
HEIZINDEX *act, *next;
629
 
630
	act = HeizFirst;
631
 
632
	while(act)
633
	{
634
	   if (act->heizung)
635
	   {
636
	      free(act->heizung);
637
	      act->heizung = NULL;
638
	   }
639
 
640
	   next = act->next;
641
	   free(act);
642
	   act = next;
643
	}
5 andreas 644
 
645
	HeizFirst = NULL;
1 root 646
}
647
 
648
/*
649
 * Free only one entry in the chain
650
 */
2 andreas 651
HEIZINDEX *freeChainMember(HEIZINDEX *member)
1 root 652
{
653
HEIZINDEX *act,*prev;
654
 
655
	act = HeizFirst;
656
	prev = NULL;
657
 
658
	while(act != member)
659
	{
660
	   prev = act;
661
	   act = act->next;
662
	}
663
 
664
	if (act == member)
665
	{
666
	   if (prev)
2 andreas 667
	      prev->next = act->next;
4 andreas 668
	   else
669
	   {
670
	      prev = act->next;
1 root 671
 
4 andreas 672
	      if (act == HeizFirst)
673
		 HeizFirst = act->next;
674
	   }
675
 
1 root 676
	   if (act->heizung)
677
	      free(act->heizung);
678
 
679
	   free(act);
4 andreas 680
	   return prev;
1 root 681
	}
2 andreas 682
 
683
	return NULL;
1 root 684
}
685
 
686
/*
4 andreas 687
 * Allocate the memory for the actual heizung plan.
688
 * This function appends an element to the end of the chain.
1 root 689
 */
690
HEIZINDEX *allocateMemory()
691
{
692
HEIZINDEX *act, *last;
693
 
694
	if (!HeizFirst)
695
	{
696
	   HeizFirst = malloc(sizeof(HEIZINDEX));
697
 
698
	   if (HeizFirst)
699
	   {
700
	      HeizFirst->heizung = malloc(sizeof(HEIZUNG));
701
	      HeizFirst->next = NULL;
702
	   }
703
	   else
704
	      return NULL;
705
 
706
	   return HeizFirst;
707
	}
708
	else
709
	{
710
	   // Find last element
711
	   last = HeizFirst;
712
 
713
	   while(last->next)
714
	      last = last->next;
715
 
716
	   act = malloc(sizeof(HEIZINDEX));
717
 
718
	   if (act)
719
	   {
720
	      act->heizung = malloc(sizeof(HEIZUNG));
721
	      act->next = NULL;
722
	      last->next = act;
723
	   }
724
	   else
725
	      return NULL;
726
 
727
	   return act;
728
	}
729
 
730
	return NULL;
731
}
732
 
733
/*
4 andreas 734
 * Allocate the memory for the actual heizung plan.
735
 * This function inserts an element into the chain.
736
 */
737
HEIZINDEX *insertMemory(HEIZINDEX *pos)
738
{
739
HEIZINDEX *act;
740
 
741
	if (!HeizFirst)
742
	{
743
	   HeizFirst = malloc(sizeof(HEIZINDEX));
744
 
745
	   if (HeizFirst)
746
	   {
747
	      HeizFirst->heizung = malloc(sizeof(HEIZUNG));
748
	      HeizFirst->next = NULL;
749
	   }
750
	   else
751
	      return NULL;
752
 
753
	   return HeizFirst;
754
	}
755
	else
756
	{
757
	   act = malloc(sizeof(HEIZINDEX));
758
 
759
	   if (act)
760
	   {
761
	      act->heizung = malloc(sizeof(HEIZUNG));
762
	      act->next = pos->next;
763
	      pos->next = act;
764
	   }
765
	   else
766
	      return NULL;
767
 
768
	   return act;
769
	}
770
 
771
	return NULL;
772
}
773
 
774
/*
1 root 775
 * The following functions read a config file and put the
776
 * contents into a structure.
777
 */
778
void readConf(void)
779
{
780
int fd;
781
char confFile[512], line[512];
782
char *home, *p;
783
char hv0[64], hv1[128];
784
 
785
	home = getenv("HOME");
786
	fd = -1;
787
 
788
	if (!access("/etc/heizung.conf",R_OK))
789
	   strcpy(confFile,"/etc/heizung.conf");
790
	else if (!access("/etc/heizung/heizung.conf",R_OK))
791
	   strcpy(confFile,"/etc/heizung/heizung.conf");
792
	else if (!access("/usr/etc/heizung.conf",R_OK))
793
	   strcpy(confFile,"/usr/etc/heizung.conf");
794
	else if (home)
795
	{
796
	   strcpy(confFile,home);
797
	   strcat(confFile,"/.heizung.conf");
798
 
799
	   if (access(confFile,R_OK))
4 andreas 800
	   {
801
	      syslog(LOG_WARNING,"Even config file %s was not found!", confFile);
1 root 802
	      confFile[0] = 0;
4 andreas 803
	   }
1 root 804
	}
805
	else
806
	   confFile[0] = 0;
807
 
5 andreas 808
	memset(&configs, 0, sizeof(configs));
809
	strcpy(configs.User,"nobody");
810
	strcpy(configs.Grp,"nobody");
811
	strcpy(configs.HeizPath, "/var/www/.HeizPlan.conf");
812
	strcpy(configs.Werte, "/var/log/werte.dat");
813
	strcpy(configs.Device, "/dev/ttyS1");
814
	configs.port = 11001;
1 root 815
 
4 andreas 816
	if (!confFile[0] || (fd = open(confFile,O_RDONLY)) == -1)
1 root 817
	{
4 andreas 818
	   if (confFile[0])
819
	      syslog(LOG_WARNING,"Error opening the config file %s! Using built in defaults. (%s)", confFile, strerror(errno));
820
	   else
821
	      syslog(LOG_WARNING,"Error opening the config file! Using built in defaults.");
822
 
1 root 823
	   return;
824
	}
825
 
4 andreas 826
	while (readLine(fd, &line[0], sizeof(line)) != NULL)
1 root 827
	{
828
	   int len;
829
 
830
	   trim (&line[0]);
831
 
4 andreas 832
	   if (line[0] == '#' || !strlen(line))
1 root 833
	      continue;
834
 
835
	   if ((p = strchr (line, '=')) == NULL)
836
	      continue;
837
 
838
	   *p = 0;
839
	   p++;
840
	   len = strlen(line);
841
 
842
	   if (len > sizeof(hv0))
843
	      len = sizeof(hv0) - 1;
844
 
845
	   strncpy (hv0, line, len);
4 andreas 846
	   hv0[len] = 0;
1 root 847
	   trim (hv0);
848
	   len = strlen(p);
849
 
850
	   if (len > sizeof(hv1))
851
	      len = sizeof(hv0) - 1;
852
 
853
	   strncpy (hv1, p, len);
4 andreas 854
	   hv1[len] = 0;
1 root 855
	   trim (hv1);
856
 
857
	   if (!strcasecmp(hv0, "user"))
4 andreas 858
	   {
859
	      syslog(LOG_INFO,"Found \"user\": %s", hv1);
1 root 860
	      strncpy (configs.User, hv1, sizeof(configs.User));
4 andreas 861
	   }
1 root 862
 
863
	   if (!strcasecmp(hv0, "group"))
4 andreas 864
	   {
865
	      syslog(LOG_INFO,"Found \"group\": %s", hv1);
1 root 866
	      strncpy (configs.Grp, hv1, sizeof(configs.Grp));
4 andreas 867
	   }
1 root 868
 
869
	   if (!strcasecmp(hv0, "port"))
4 andreas 870
	   {
871
	      syslog(LOG_INFO,"Found \"port\": %s", hv1);
1 root 872
	      configs.port = atoi (hv1);
4 andreas 873
	   }
1 root 874
 
875
	   if (!strcasecmp(hv0, "heizpath"))
4 andreas 876
	   {
877
	      syslog(LOG_INFO,"Found \"heizpath\": %s", hv1);
1 root 878
	      strncpy (configs.HeizPath, hv1, sizeof(configs.HeizPath));
4 andreas 879
	   }
5 andreas 880
 
881
	   if (!strcasecmp(hv0, "Werte"))
882
	   {
883
	      syslog(LOG_INFO,"Found \"Werte\": %s", hv1);
884
	      strncpy (configs.Werte, hv1, sizeof(configs.Werte));
885
	   }
886
 
887
	   if (!strcasecmp(hv0, "Device"))
888
	   {
889
	      syslog(LOG_INFO,"Found \"Device\": %s", hv1);
890
	      strncpy (configs.Device, hv1, sizeof(configs.Device));
891
	   }
892
 
893
	   if (!strcasecmp(hv0, "VID"))
894
	   {
895
	      syslog(LOG_INFO,"Found VendorID: %04x", atoi(hv1));
896
	      configs.VID = atoi(hv1);
897
	   }
898
 
899
	   if (!strcasecmp(hv0, "PID"))
900
	   {
901
	      syslog(LOG_INFO,"Found ProductID: %04x", atoi(hv1));
902
	      configs.PID = atoi(hv1);
903
	   }
1 root 904
	}
905
 
906
	close (fd);
907
}
908
 
909
int readHeizPlan(void)
910
{
911
int fd, i, wday;
912
ulong tim;
913
char line[512];
914
char *p, *xp;
915
char hv0[64], hv1[128];
916
float temperature;
917
long offset = 0;
4 andreas 918
HEIZINDEX *act, *prev;
1 root 919
 
920
	fd = -1;
921
 
4 andreas 922
	if (access(configs.HeizPath, R_OK))
923
	{
924
	   syslog(LOG_DAEMON,"Access to file %s denied: %s", configs.HeizPath, strerror(errno));
1 root 925
	   return 0;
4 andreas 926
	}
1 root 927
 
928
	if ((fd = open(configs.HeizPath, O_RDONLY)) == -1)
4 andreas 929
	{
930
	   syslog(LOG_DAEMON,"Error opening file %s: %s", configs.HeizPath, strerror(errno));
1 root 931
	   return 0;
4 andreas 932
	}
1 root 933
 
4 andreas 934
	act = prev = NULL;
935
	freeMemory();
936
 
937
	while (readLine(fd, &line[0], sizeof(line)) != NULL)
1 root 938
	{
939
	   int len;
940
 
941
	   trim (&line[0]);
942
 
5 andreas 943
	   if (line[0] == '#' || !strlen(line) || strchr(line, ',') == NULL)
1 root 944
	      continue;
945
 
4 andreas 946
	   // We need a place to store the information
947
	   prev = act;
948
 
949
	   if ((act = allocateMemory()) == NULL)
950
	   {
951
	      close(fd);
952
	      syslog(LOG_DAEMON,"Error allocating memory for a temperature line! Stopped reading file %s.", configs.HeizPath);
953
	      return 0;
954
	   }
955
 
956
	   memset(act->heizung, 0, sizeof(HEIZUNG));
1 root 957
	   // Parse a line. The line has the format:
958
	   // <wday>,<end>,<temperature>
4 andreas 959
	   p = strtok(line, ",");
1 root 960
	   i = 1;
961
 
962
	   while(p)
963
	   {
964
	      switch(i)
965
	      {
966
		 case 1:	// Week day
967
		    wday = atoi(p);
968
 
969
		    if (wday < 1 || wday > 7)	// valid line?
970
		    {
4 andreas 971
		       if (prev)
972
			  wday = prev->heizung->wday;
1 root 973
 
4 andreas 974
		       if (wday < 1 || wday > 7)
975
		       {
976
			  p = strtok(NULL, ",");
977
			  i++;
978
			  continue;
979
		       }
1 root 980
		    }
981
 
982
		    act->heizung->wday = wday;
983
		    act->heizung->start = 0;
984
		 break;
985
 
986
		 case 2:	// start/end time
987
		    if ((xp = strchr(p, ':')) != NULL)
988
		    {
989
		    int hour, min;
990
 
991
		       hour = atoi(p);
992
		       min = atoi(xp+1);
993
 
994
		       if (hour >= 0 && hour <= 23 && min >= 0 && min <= 59)
995
		       {
5 andreas 996
			  act->heizung->end = hour * 3600 + min * 60 + 59;
1 root 997
 
4 andreas 998
			  if (prev && prev->heizung->wday == act->heizung->wday)
999
			     act->heizung->start = prev->heizung->end;
1 root 1000
		       }
1001
		    }
1002
		 break;
1003
 
1004
		 case 3:	// temperature
1005
		    temperature = atof(p);
1006
 
1007
		    if (temperature < 5.0 || temperature > 30.0)
1008
		    {
4 andreas 1009
		       p = strtok(NULL,",");
1010
		       i++;
1 root 1011
		       continue;
1012
		    }
1013
 
1014
		    act->heizung->temp = temperature;
1015
		 break;
1016
	      }
1017
 
4 andreas 1018
	      p = strtok(NULL, ",");
1019
	      i++;
1 root 1020
	   }
1021
	}
1022
 
1023
	close (fd);
1024
	return 1;
1025
}
1026
 
1027
/*
1028
 * write the (may be) altered plan.
1029
 * This function allways writes whole plan.
1030
 */
1031
int writeHeizPlan()
1032
{
1033
int fd;
1034
char hv0[512];
1035
HEIZINDEX *act;
1036
 
1037
	fd = -1;
1038
 
5 andreas 1039
	if (access(configs.HeizPath, R_OK))
1 root 1040
	   return 0;
1041
 
1042
	if ((fd = open(configs.HeizPath, O_RDWR | O_TRUNC)) == -1)
1043
	   return 0;
1044
 
1045
	act = HeizFirst;
1046
 
1047
	while(act)
1048
	{
5 andreas 1049
	   if (act->heizung->wday)
1050
	   {
1051
	      int hour, min;
1052
 
1053
	      hour = act->heizung->end / 3600;
1054
	      min = (act->heizung->end - (hour * 3600)) / 60;
1055
 
1056
	      if (hour > 23)
1057
	      {
1058
		 hour = 23;
1059
		 min = 59;
1060
	      }
1061
 
1062
	      sprintf(&hv0[0], "%d,%02d:%02d,%.1f\n",
1063
		   act->heizung->wday, hour, min,
1 root 1064
		   act->heizung->temp);
5 andreas 1065
	      write(fd, &hv0[0], strlen(hv0));
1066
	   }
1067
 
1 root 1068
	   act = act->next;
1069
	}
1070
 
1071
	close(fd);
1072
	return 1;
1073
}
1074
 
4 andreas 1075
char *readLine(int fd, char *buf, int bufLen)
1 root 1076
{
4 andreas 1077
int i, end;
1 root 1078
char ch, *p;
1079
 
1080
        if (fd <= 0)
4 andreas 1081
	{
1082
	   syslog(LOG_DAEMON,"Function readLine was called with an invalid file descriptor of %d!", fd);
1083
           return NULL;
1084
	}
1 root 1085
 
4 andreas 1086
        i = end = 0;
1087
        p = buf;
1 root 1088
 
4 andreas 1089
        while (read(fd, &ch, 1) > 0)
1090
        {
1091
           end = 1;
1 root 1092
 
4 andreas 1093
           if (ch == 0x0a)
1094
           {
1095
             *p = 0;
1096
             return buf;
1097
           }
1 root 1098
 
4 andreas 1099
           if (ch == 0x0d)      // ignore this!
1100
              continue;
1 root 1101
 
4 andreas 1102
           if (i < (bufLen - 1))
1103
           {
1104
              *p = ch;
1105
              p++;
1106
              i++;
1107
           }
1108
        }
1 root 1109
 
4 andreas 1110
        *p = 0;
1111
 
1112
        if (end)
1113
           return buf;
1114
        else
1115
           return NULL;
1 root 1116
}
1117
 
1118
char *trim(char *str)
1119
{
1120
char *p1, *p2, *p;
1121
 
1122
	if (!str)
1123
	   return NULL;
1124
 
4 andreas 1125
	if (!strlen(str))
1126
	   return str;
1127
 
1 root 1128
	p = str;
1129
	p1 = p2 = NULL;
1130
 
1131
	while (*p)
1132
	{
1133
	   if (!p1 && *p != ' ')
1134
	   {
1135
	      p1 = p;
1136
	      break;
1137
	   }
1138
 
1139
	   p++;
1140
	}
1141
 
1142
	p2 = str + (strlen(str) - 1);
1143
 
1144
	while (p2 > str && *p2 == ' ')
1145
	   p2--;
1146
 
1147
	if (p2)
1148
	   *(p2+1) = 0;
1149
 
1150
	if (p1)
1151
	{
1152
	   char *buf = strdup (p1);
1153
	   strcpy (str, buf);
1154
	   free (buf);
1155
	}
1156
 
1157
	return str;
1158
}
2 andreas 1159
 
1160
char *remove_string(char *str, char *search, char *ret)
1161
{
1162
char *p;
1163
 
1164
	if (!strlen(str) || !strlen(search))
1165
	   return NULL;
1166
 
1167
	if ((p = strstr(str, search)) != NULL)
1168
	{
1169
	int len = strlen(search);
1170
 
4 andreas 1171
	   strncpy(ret, str, p - str + len);
5 andreas 1172
	   ret[p - str + len] = 0;
1173
	   memmove(str, p + len, strlen(p+len));
1174
	   str[strlen(p+len)] = 0;
2 andreas 1175
	   return ret;
1176
	}
1177
 
1178
	return NULL;
4 andreas 1179
}