Subversion Repositories heizung

Rev

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