// Bind the master netlink socket for all communication // responses will have to be routed to appropriate bus master GOOD_OR_BAD w1_bind( struct connection_in * in ) { struct port_in * pin = in->pown ; struct sockaddr_nl l_local ; pin->type = ct_netlink ; Test_and_Close( &(pin->file_descriptor) ) ; // just in case // Example from http://lxr.linux.no/linux+v3.0/Documentation/connector/ucon.c#L114 //pin->file_descriptor = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); // pin->file_descriptor = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC , NETLINK_CONNECTOR); pin->file_descriptor = socket(PF_NETLINK, SOCK_RAW , NETLINK_CONNECTOR); if ( FILE_DESCRIPTOR_NOT_VALID( pin->file_descriptor ) ) { ERROR_CONNECT("Netlink (w1) socket (are you root?)"); return gbBAD; } // fcntl (pin->file_descriptor, F_SETFD, FD_CLOEXEC); // for safe forking l_local.nl_pid = in->master.w1_monitor.pid = getpid() ; l_local.nl_pad = 0; l_local.nl_family = AF_NETLINK; l_local.nl_groups = 23; if ( bind( pin->file_descriptor, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl) ) == -1 ) { ERROR_CONNECT("Netlink (w1) bind (are you root?)"); Test_and_Close( &( pin->file_descriptor) ); return gbBAD ; } pin->state = cs_deflowered ; return gbGOOD ; }
/* Called on head of multibus group */ void serial_free(struct connection_in *connection) { FILE_DESCRIPTOR_OR_ERROR fd ; struct port_in * pin = connection->pown ; if ( pin->state == cs_virgin ) { return ; } fd = pin->file_descriptor ; if ( FILE_DESCRIPTOR_NOT_VALID( fd ) ) { // reopen to restore attributes fd = open( pin->init_data, O_RDWR | O_NONBLOCK | O_NOCTTY ) ; } // restore tty settings if ( FILE_DESCRIPTOR_VALID( fd ) ) { LEVEL_DEBUG("COM_close: flush"); tcflush( fd, TCIOFLUSH); LEVEL_DEBUG("COM_close: restore"); if ( tcsetattr( fd, TCSANOW, &(pin->dev.serial.oldSerialTio) ) < 0) { ERROR_CONNECT("Cannot restore port attributes: %s", pin->init_data); } } Test_and_Close( &( pin->file_descriptor) ) ; }
int watchdog_init(struct watchdog_s *w, int inactivity_timeout) { pthread_t thread_id; int error_code; daemon_assert(w != NULL); daemon_assert(inactivity_timeout > 0); _MUTEX_INIT(w->mutex); w->inactivity_timeout = inactivity_timeout; w->oldest = NULL; w->newest = NULL; error_code = pthread_create(&thread_id, DEFAULT_THREAD_ATTR, watcher, w); if (error_code != 0) { errno = error_code; ERROR_CONNECT("Watchdog thread create problem\n"); return 0; } pthread_detach(thread_id); daemon_assert(invariant(w)); return 1; }
/* Re-open a DS2482 */ static GOOD_OR_BAD DS2482_redetect(const struct parsedname *pn) { struct connection_in *head = pn->selected_connection->master.i2c.head; int address = head->master.i2c.i2c_address; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct address_pair ap ; // to get device name from device:address /* open the i2c port */ Parse_Address( DEVICENAME(head), &ap ) ; file_descriptor = open(ap.first.alpha, O_RDWR ); Free_Address( &ap ) ; if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { ERROR_CONNECT("Could not open i2c device %s", DEVICENAME(head)); return gbBAD; } /* address is known */ if (ioctl(file_descriptor, I2C_SLAVE, address) < 0) { ERROR_CONNECT("Cound not set i2c address to %.2X", address); } else { BYTE c; /* write the RESET code */ if (i2c_smbus_write_byte(file_descriptor, DS2482_CMD_RESET) // reset || BAD(DS2482_readstatus(&c, file_descriptor, DS2482_Chip_reset_usec)) // pause .5 usec then read status || (c != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) // make sure status is properly set ) { LEVEL_CONNECT("i2c device at %s address %d cannot be reset. Not a DS2482.", DEVICENAME(head), address); } else { struct connection_in * next ; head->master.i2c.current = 0; head->pown->file_descriptor = file_descriptor; head->pown->state = cs_deflowered ; head->pown->type = ct_i2c ; head->master.i2c.configchip = 0x00; // default configuration register after RESET LEVEL_CONNECT("i2c device at %s address %d reset successfully", DEVICENAME(head), address); for ( next = head->pown->first; next; next = next->next ) { /* loop through devices, matching those that have the same "head" */ /* BUSLOCK also locks the sister channels for this */ next->reconnect_state = reconnect_ok; } return gbGOOD; } } /* fellthough, no device found */ close(file_descriptor); return gbBAD; }
/* return GOOD if any found */ static GOOD_OR_BAD DS2482_detect_sys( int any, enum ds2482_address chip_num, struct port_in *pin_original) { DIR * i2c_list_dir ; struct dirent * i2c_bus ; int found = 0 ; struct port_in * pin_current = pin_original ; // We'll look in this directory for available i2c adapters. // This may be linux 2.6 specific i2c_list_dir = opendir( SYSFS_I2C_Path ) ; if ( i2c_list_dir == NULL ) { ERROR_CONNECT( "Cannot open %d to find available i2c devices",SYSFS_I2C_Path ) ; // Use the cruder approach of trying all possible numbers return DS2482_detect_dir( any, chip_num, pin_original ) ; } /* cycle through entries in /sys/class/i2c-adapter */ while ( (i2c_bus=readdir(i2c_list_dir)) != NULL ) { char dev_name[128] ; // room for /dev/name int sn_ret ; UCLIBCLOCK ; sn_ret = snprintf( dev_name, 128, "/dev/%s", i2c_bus->d_name ) ; UCLIBCUNLOCK ; if ( sn_ret < 0 ) { break ; } // Now look for the ds2482's if ( BAD( DS2482_detect_bus( chip_num, dev_name, pin_current ) ) ) { continue ; // none found on this i2c bus } // at least one found on this i2c bus ++found ; if ( any ) { // found one -- that's enough closedir( i2c_list_dir ) ; return gbGOOD ; } // ALL? then set up a new connection_in slot for the next one pin_current = NewPort(pin_current) ; if ( pin_current == NULL ) { break ; } } closedir( i2c_list_dir ) ; if ( found==0 ) { return gbBAD ; } if ( pin_current != pin_original ) { RemovePort( pin_current ) ; } return gbGOOD ; }
/* All ow library closeup */ void PIDstop(void) { if (pid_created && pid_file) { if (unlink(pid_file)) { ERROR_CONNECT("Cannot remove PID file: %s", pid_file); } owfree(pid_file); pid_file = NULL; } }
/* Puts in 9600 baud */ static GOOD_OR_BAD DS9097_pre_reset(struct connection_in *in ) { struct port_in * pin = in->pown ; RETURN_BAD_IF_BAD( COM_test(in) ) ; /* 8 data bits */ pin->bits = 8 ; pin->baud = B9600 ; if ( BAD( COM_change(in)) ) { ERROR_CONNECT("Cannot set attributes: %s", SAFESTRING(DEVICENAME(in))); DS9097_post_reset( in ) ; return gbBAD; } return gbGOOD; }
void PIDstart(void) { /* store the PID */ pid_t pid_num = getpid(); if (pid_file) { FILE *pid = fopen(pid_file, "w+"); if (pid == NULL) { ERROR_CONNECT("Cannot open PID file: %s", pid_file); owfree(pid_file); pid_file = NULL; } else { fprintf(pid, "%lu", (unsigned long int) pid_num); fclose(pid); pid_created = 1; } } }
/* Usually called with BUS locked, to protect ai settings */ FILE_DESCRIPTOR_OR_ERROR ClientConnect(struct connection_in *in) { struct port_in * pin = in->pown ; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct addrinfo *ai; if ( pin->dev.tcp.ai == NULL) { LEVEL_DEBUG("Client address not yet parsed"); return FILE_DESCRIPTOR_BAD; } /* Can't change ai_ok without locking the in-device. * First try the last working address info, if it fails lock * the in-device and loop through the list until it works. * Not a perfect solution, but it should work at least. */ ai = pin->dev.tcp.ai_ok; if (ai) { file_descriptor = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if ( FILE_DESCRIPTOR_VALID(file_descriptor) ) { if (connect(file_descriptor, ai->ai_addr, ai->ai_addrlen) == 0) { return file_descriptor; } close(file_descriptor); } } ai = pin->dev.tcp.ai; // loop from first address info since it failed. do { file_descriptor = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if ( FILE_DESCRIPTOR_VALID(file_descriptor) ) { if (connect(file_descriptor, ai->ai_addr, ai->ai_addrlen) == 0) { pin->dev.tcp.ai_ok = ai; return file_descriptor; } close(file_descriptor); } } while ((ai = ai->ai_next)); pin->dev.tcp.ai_ok = NULL; ERROR_CONNECT("Socket problem"); STAT_ADD1(NET_connection_errors); return FILE_DESCRIPTOR_BAD; }
static int Get_HA7_response( struct addrinfo *now, char * name ) { struct timeval tv = { 50, 0 }; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct HA7_response ha7_response ; struct sockaddr_in from ; socklen_t fromlen = sizeof(struct sockaddr_in) ; int on = 1; file_descriptor = socket(now->ai_family, now->ai_socktype, now->ai_protocol) ; if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { ERROR_DEBUG("Cannot get socket file descriptor for broadcast."); return 1; } // fcntl (file_descriptor, F_SETFD, FD_CLOEXEC); // for safe forking if (setsockopt(file_descriptor, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) { ERROR_DEBUG("Cannot set socket option for broadcast."); return 1; } if (sendto(file_descriptor, "HA\000\001", 4, 0, now->ai_addr, now->ai_addrlen) != 4) { ERROR_CONNECT("Trouble sending broadcast message"); return 1; } /* now read */ if ( udp_read(file_descriptor, &ha7_response, sizeof(struct HA7_response), &tv, &from, &fromlen) != sizeof(struct HA7_response) ) { LEVEL_CONNECT("HA7 response bad length"); return 1; } if ( Test_HA7_response( &ha7_response ) ) { return 1 ; } UCLIBCLOCK ; snprintf(name,INET_ADDRSTRLEN+20,"%s:%d",inet_ntoa(from.sin_addr),ntohs(ha7_response.port)); UCLIBCUNLOCK ; return 0 ; }
GOOD_OR_BAD W1_detect(struct port_in *pin) { struct connection_in * in = pin->first ; /* Set up low-level routines */ pin->type = ct_none ; W1_setroutines(in); Init_Pipe( in->master.w1.netlink_pipe ) ; if ( pipe( in->master.w1.netlink_pipe ) != 0 ) { ERROR_CONNECT("W1 pipe creation error"); Init_Pipe( in->master.w1.netlink_pipe ) ; return gbBAD ; } in->Adapter = adapter_w1; in->adapter_name = "w1"; pin->busmode = bus_w1; in->master.w1.seq = SEQ_INIT; return gbGOOD; }
//open serial port ( called on head of connection_in group from com_open ) GOOD_OR_BAD serial_open(struct connection_in *connection) { struct port_in * pin = connection->pown ; FILE_DESCRIPTOR_OR_ERROR fd = open( DEVICENAME(connection), O_RDWR | O_NONBLOCK | O_NOCTTY) ; pin->file_descriptor = fd ; if ( FILE_DESCRIPTOR_NOT_VALID( fd ) ) { // state doesn't change ERROR_DEFAULT("Cannot open port: %s Permissions problem?", SAFESTRING(DEVICENAME(connection))); return gbBAD; } if ( pin->state == cs_virgin ) { // valgrind warns about uninitialized memory in tcsetattr(), so clear all. memset( &(pin->dev.serial.oldSerialTio), 0, sizeof(struct termios)); if ((tcgetattr( fd, &(pin->dev.serial.oldSerialTio) ) < 0)) { ERROR_CONNECT("Cannot get old port attributes: %s", SAFESTRING(DEVICENAME(connection))); // proceed anyway } pin->state = cs_deflowered ; } return serial_change( connection ) ; }
// Wait for a resolve, then return. Timeout after 2 minutes static void ResolveWait( DNSServiceRef sref ) { FILE_DESCRIPTOR_OR_ERROR file_descriptor = DNSServiceRefSockFD(sref); if ( FILE_DESCRIPTOR_VALID(file_descriptor) ) { while (1) { fd_set readfd; struct timeval tv = { 120, 0 }; FD_ZERO(&readfd); FD_SET(file_descriptor, &readfd); if (select(file_descriptor + 1, &readfd, NULL, NULL, &tv) > 0) { if (FD_ISSET(file_descriptor, &readfd)) { DNSServiceProcessResult(sref); } } else if (errno == EINTR) { continue; } else { ERROR_CONNECT("Resolve timeout error"); } break; } } }
/* Try to see if there is a DS2482 device on the specified i2c bus */ static GOOD_OR_BAD DS2482_detect_single(int lowindex, int highindex, char * i2c_device, struct port_in *pin) { int test_address[8] = { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, }; // the last 4 are -800 only int i2c_index; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct connection_in * in = pin->first ; /* Sanity check */ if ( lowindex < 0 ) { LEVEL_DEBUG("Bad lower bound"); return gbBAD ; } if ( highindex >= (int) (sizeof(test_address)/sizeof(int)) ) { LEVEL_DEBUG("Bad upper bound"); return gbBAD ; } /* open the i2c port */ file_descriptor = open(i2c_device, O_RDWR); if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { ERROR_CONNECT("Could not open i2c device %s", i2c_device); return gbBAD; } /* Set up low-level routines */ DS2482_setroutines(in); for (i2c_index = lowindex; i2c_index <= highindex; ++i2c_index) { int trial_address = test_address[i2c_index] ; /* set the candidate address */ if (ioctl(file_descriptor, I2C_SLAVE, trial_address) < 0) { ERROR_CONNECT("Cound not set trial i2c address to %.2X", trial_address); } else { BYTE c; LEVEL_CONNECT("Found an i2c device at %s address %.2X", i2c_device, trial_address); /* Provisional setup as a DS2482-100 ( 1 channel ) */ in->pown->file_descriptor = file_descriptor; pin->state = cs_deflowered; pin->type = ct_i2c ; in->master.i2c.i2c_address = trial_address; in->master.i2c.i2c_index = i2c_index; in->master.i2c.index = 0; in->master.i2c.channels = 1; in->master.i2c.current = 0; in->master.i2c.head = in; in->adapter_name = "DS2482-100"; in->master.i2c.configreg = 0x00 ; // default configuration setting desired if ( Globals.i2c_APU ) { in->master.i2c.configreg |= DS2482_REG_CFG_APU ; } if ( Globals.i2c_PPM ) { in->master.i2c.configreg |= DS2482_REG_CFG_PPM ; } in->Adapter = adapter_DS2482_100; /* write the RESET code */ if (i2c_smbus_write_byte(file_descriptor, DS2482_CMD_RESET) // reset || BAD(DS2482_readstatus(&c, file_descriptor, DS2482_Chip_reset_usec)) // pause .5 usec then read status || (c != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) // make sure status is properly set ) { LEVEL_CONNECT("i2c device at %s address %.2X cannot be reset. Not a DS2482.", i2c_device, trial_address); continue; } LEVEL_CONNECT("i2c device at %s address %.2X appears to be DS2482-x00", i2c_device, trial_address); in->master.i2c.configchip = 0x00; // default configuration register after RESET // Note, only the lower nibble of the device config stored // Create name SAFEFREE( DEVICENAME(in) ) ; DEVICENAME(in) = owmalloc( strlen(i2c_device) + 10 ) ; if ( DEVICENAME(in) ) { UCLIBCLOCK; snprintf(DEVICENAME(in), strlen(i2c_device) + 10, "%s:%.2X", i2c_device, trial_address); UCLIBCUNLOCK; } /* Now see if DS2482-100 or DS2482-800 */ return HeadChannel(in); } } /* fell though, no device found */ COM_close( in ) ; return gbBAD; }
//change serial port settings GOOD_OR_BAD serial_change(struct connection_in *connection) { struct port_in * pin = connection->pown ; struct termios newSerialTio; /*new serial port settings */ FILE_DESCRIPTOR_OR_ERROR fd = pin->file_descriptor ; size_t baud = pin->baud ; // read the attribute structure // valgrind warns about uninitialized memory in tcsetattr(), so clear all. memset(&newSerialTio, 0, sizeof(struct termios)); if ((tcgetattr( fd, &newSerialTio) < 0)) { ERROR_CONNECT("Cannot get existing port attributes: %s", SAFESTRING(DEVICENAME(connection))); } // set baud in structure if (cfsetospeed(&newSerialTio, baud) < 0 || cfsetispeed(&newSerialTio, baud) < 0) { ERROR_CONNECT("Trouble setting port speed: %s", SAFESTRING(DEVICENAME(connection))); cfsetospeed(&newSerialTio, B9600) ; cfsetispeed(&newSerialTio, B9600) ; pin->baud = B9600 ; } // Set to non-canonical mode, and no RTS/CTS handshaking newSerialTio.c_iflag &= ~(BRKINT | ICRNL | IGNCR | INLCR | INPCK | ISTRIP | IXON | IXOFF | PARMRK); newSerialTio.c_iflag |= IGNBRK | IGNPAR; newSerialTio.c_oflag &= ~(OPOST); newSerialTio.c_cflag &= ~ HUPCL ; newSerialTio.c_cflag |= (CLOCAL | CREAD); switch( pin->flow ) { case flow_hard: newSerialTio.c_cflag |= CRTSCTS ; break ; case flow_none: newSerialTio.c_cflag &= ~CRTSCTS; break ; case flow_soft: default: LEVEL_DEBUG("Unsupported COM port flow control"); return -ENOTSUP ; } // set bit length newSerialTio.c_cflag &= ~ CSIZE ; switch (pin->bits) { case 5: newSerialTio.c_cflag |= CS5 ; break ; case 6: newSerialTio.c_cflag |= CS6 ; break ; case 7: newSerialTio.c_cflag |= CS7 ; break ; case 8: default: newSerialTio.c_cflag |= CS8 ; break ; } // parity switch (pin->parity) { case parity_none: newSerialTio.c_cflag &= ~PARENB ; break ; case parity_even: newSerialTio.c_cflag |= PARENB ; newSerialTio.c_cflag &= ~( PARODD | CMSPAR ) ; break ; case parity_odd: newSerialTio.c_cflag |= PARENB | PARODD; newSerialTio.c_cflag &= ~CMSPAR ; break ; case parity_mark: newSerialTio.c_cflag |= PARENB | PARODD | CMSPAR; break ; } // stop bits switch (pin->stop) { case stop_15: LEVEL_DEBUG("1.5 Stop bits not supported"); pin->stop = stop_1 ; // fall through case stop_1: newSerialTio.c_cflag &= ~CSTOPB ; break ; case stop_2: newSerialTio.c_cflag |= CSTOPB ; break ; } newSerialTio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN | ISIG); newSerialTio.c_cc[VMIN] = pin->vmin; newSerialTio.c_cc[VTIME] = pin->vtime; if (tcsetattr( fd, TCSAFLUSH, &newSerialTio)) { ERROR_CONNECT("Cannot set port attributes: %s", SAFESTRING(DEVICENAME(connection))); return gbBAD; } tcflush( fd, TCIOFLUSH); return gbGOOD; }