BeagleBoneBlack + L4686SDK. Monitoring the bTicino SCS bus. The SCS bus is the way chosen by bticino to realize the rail where all informations are sent and received from all present appliances in a domotic wired system.This article provides a way to monitor the SCS bus of bticino  using an hardware interface provided from bticino, the L4686SDK,  and using a Beagle Bone Black to drive it.  The hardware modules. Why do I choose these elements ? The BeagleBoneBlack is the state of art, the best single board computer, from my point of view, for cpu power, number of pins (great board for prototyping), several electronic buses (see CAN, I2C, SPI ), cheap and finally linux based.The CPU in revision C is the TI SITARA AM3359, ARM CORTEX A8: a digital beast. From the initial distro, the distro on sbc (single board computer) when exited from factory,  I migrated to linux ubuntu distro, with arm hf; you can download it from http://www.armhf.com. A distro with HF(hard float ) feature is adapt to run binary files developed with an external linux os, external ide tool (eclipse), and then, external toolchain.  Even if, personally, I adopted the old way: I wrote all my code using Xcode(this time I didn’t use linux specific header), sent all files by means of FileZilla, compiled these files on board, launched the binary.  If you like an arm HF distro and want install that see this link: http://www.armhf.com/boards/beaglebone-black/bbb-sd-install/ Don’t  waste your time following other wrong instructions.
Following the wiring and the architectures hardware and software.
The L4686SDK little black box. This one is a little black box, really a black box, you can use to interface the bticino SCS bus. It has three connectors. One is used to join the box to the bus by means of a proprietary cable, the second is a 9 pin serial connector and the the last is a usb port; therefore you can connect to the L4686SDK using either a usb cable or a serial cable. The L4686SDK is just a hardware driver capable of managing the SCS bus; You will able to connect to box a pc, your macbook, a SBC etc. It has made by bTicino for development goal. The bus SCS is based on a twisted flexible cable without shield and insulated until to 300/500V - according to  indications CEI 46-5 e CEI. The bus can have star or free cabling configuration; it can be chosen according to wiring requirements. Through SCS bus 4 types of signals are sent. Power(27V cc)Physical data similar to the KNX standard TP1, with RZ coding (9600 bit per second), eight bits each symbol, with 1 start bit and 1 stop bit .The zero is implemented with an interrupt of 34μs (obtained applying a load to the bus) , followed by a 70μs of silence, the one is obtained with 104μs of silence. The start bit is zero, the  stop bit is  one (opposing to the serial traditional coding). The frames can be shorts (seven symbols) or  longs (eleven symbols); they are bounded from a starting symbol (0xA8) and from an ending symbol (0xA3). Within the frame no symbol can be upper than  0x7F. Every frame is ended with a check code obtained by  XORing all frame symbols but delimitators.VideoAudio
written by Ivan Cerrato
LINUX  BeagleBoneBlack L4686SDK SCS bus domotic
next
back to home
Architecture-hardware. The system architecture has 3 elements: the BBB , the L4686SDK and  the plug of the bus. The wiring between the BBB and the box is realized by using a smple USB - mini USB cable. Deeper.This time no configuration has to be made for the BBB, but before starting the devices, follow these step:1 - join the scs bus to the the L4686SDK; 2 - join the L4686SDK to the BBB (the BBB must be switched off)3 - join BBB to the net (this is my favorite manner to use the BBB) 4 - empower to the BBB. Now you have to check if all went ok and the L4686SDK has been accepted as serial peripehral.Open a connection toward the BBB and check it exporing the /dev directory; cd /dev  ls -la tty*you’ d see a device  like ttyUSB0 or similar. That’s the door for the SCS bus. ubuntu@ubuntu-armhf:/dev$ ll ttyUS* crw-rw---- 1 root dialout 188, 0 Dec 11 19:40 ttyUSB0 ubuntu@ubuntu-armhf:/dev$  Our example is tailored  for a two floors home, with several appliances scattered among them. For that You’ll see some C structure in the source code where we refer to the peripherals. Why those strange string for every device? Every appliance must have a unique identifier in the bus. This way you can request or mange the device, sending it a string upon the bus. The unique address for every device is obtained, with the bticno bus, plugging some little configurators in components distributed along the bus. Configurators.        //lower floor     strcpy(bticino_status.row[0].address, "*11##");     bticino_status.row[0].value=0;     strcpy(bticino_status.row[0].description, "kitchen_dimmer");          strcpy(bticino_status.row[1].address, "*16##");     bticino_status.row[1].value=0;     strcpy(bticino_status.row[1].description, "curtain_kitchen");          strcpy(bticino_status.row[2].address, "*17##");     bticino_status.row[2].value=0;     strcpy(bticino_status.row[2].description, "curtain_door");          strcpy(bticino_status.row[3].address, "*24##");     bticino_status.row[3].value=0;     strcpy(bticino_status.row[3].description, "boiler");          strcpy(bticino_status.row[4].address, "*25##");     bticino_status.row[4].value=0;     strcpy(bticino_status.row[4].description, "light_1");          strcpy(bticino_status.row[5].address, "*26##");     bticino_status.row[5].value=0;     strcpy(bticino_status.row[5].description, "light_2");          strcpy(bticino_status.row[6].address, "*27##");     bticino_status.row[6].value=0;     strcpy(bticino_status.row[6].description, "light_3");          //upper floor     strcpy(bticino_status.row[7].address, "*33##");     bticino_status.row[7].value=0;     strcpy(bticino_status.row[7].description, "mosquito_plug");          strcpy(bticino_status.row[8].address, "*35##");     bticino_status.row[8].value=0;     strcpy(bticino_status.row[8].description, "curtain_upper_floor");          strcpy(bticino_status.row[9].address, "*36##");     bticino_status.row[9].value=0;     strcpy(bticino_status.row[9].description, "rolling_shutter_upper_floor");
back
Architecture-software. In this simplified version, it ’s  a simple c program, with just a file. The simple macros, you can see at beginning of the file, are used along the code. The main function is so structured : int main() {          init();          char devices_status_l[32];     _zm1(devices_status_l)     fd_bTicino_bus = tty_open(SERIAL_DEVICE);     if (fd_bTicino_bus == -1) {         perror(PROCESS_NAME" opening serial device");         return APPLICATION_FAILURE;     }               get_bTicino_bus_all_device_status(fd_bTicino_bus, STRING_ALL_DEVICES);     printf(PROCESS_NAME", raw status bus: %s\n", tty_rxbuffer);     _zm1(devices_status_l)     memcpy(devices_status_l,  devices_status, STATUS_ROW_NUMBER);          tty_close(fd_bTicino_bus);              return EXIT_SUCCESS; } The init() function reset the status structure array and load the configuration relative to each device (as previously seen). After the serial port is opened and the principal function is called: get_bTicino_bus_all_device_status; In this version of code I made use of Posix select system call. Programming the serial port, is tipically realized with simple writing and  simple reading. In general you send some command to the port, wait for some while and finally you read the data. To the contary, select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform the corresponding I/O operation without blocking.In other words, this time, we program the serial asynchronuously. Why that? It’s faster….So at beginning of the function you can find  long iOut = tty_write(fd, bticino_string); printf(PROCESS_NAME", wrote %ld bytes on the bus .\n", iOut ); where we send on the bus the command to see all devices status: // string to ask status of all devices on the bus #define STRING_ALL_DEVICES "*#1*0##" after that, it starts an infinite loop that monitors the bus. What happens in the loop? Beginning the file descriptor readfs is reset and the FD_SET macro associates it to fd_bTicino_bus; after the select function is  called; if the fd_bTicino_bus has some data, we start analyzing these bits.By means of the function int get_n_readable_bytes(int fd) we check how many bytes can be read; after that we read all available bytes and put it in the tty_rxbuffer buffer. At the end of the reading the buffer is zero terminated and the status array of structure is filled by fill_status_structure(tty_rxbuffer);     while(true)     {         struct timeval timeout;         timeout.tv_sec = TIMEOUT_SELECT_SEC;  //seconds         timeout.tv_usec = 0;                  //microseconds                  _zm1(rx_buffer)                  FD_ZERO( &readfs );         FD_SET( fd_bTicino_bus, &readfs);                  int ret_value = select( fd_bTicino_bus+1, &readfs, NULL, NULL, &timeout );                  if( ret_value > 0 )         {              //printf(PROCESS_NAME", data received...\n");                          if( FD_ISSET(fd_bTicino_bus, &readfs) )             {                                                   //char rx_char;                 //                 //if( read( fd_bTicino_bus, &rx_char, 1 ) )                 //{                 //    tty_rxbuffer[counter++] = rx_char;                 //    //printf(PROCESS_NAME", %c", rx_char );                 //} else {                 //    tty_rxbuffer[counter] = '\0';                 //}                                                   if(0<(bytes_to_read = get_n_readable_bytes(fd_bTicino_bus))) {                                          if( read( fd_bTicino_bus, &rx_buffer, bytes_to_read ) )                     {                         memcpy((tty_rxbuffer + counter), rx_buffer, bytes_to_read);                         counter += bytes_to_read;                         //printf(PROCESS_NAME", partial read, bytes_to_read: %d\n", bytes_to_read );                         //printf(PROCESS_NAME", rx_buffer: %s\n", rx_buffer);                                              } else {                         printf(PROCESS_NAME", no read to do... \n" );                     }                 } else {                     tty_rxbuffer[counter] = '\0';                 }                          }                      } else if( ret_value == 0 ) {              printf(PROCESS_NAME", timeout, ret_value = 0 \n" );             break;         } else {              printf(PROCESS_NAME", select failed with error: %d.\n", errno );             break;         }              }          fill_status_structure(tty_rxbuffer); Following, an extract from console, after launching the binary. ubuntu@ubuntu-armhf:~/serial_asyncrhonous_1$ ./d_master_01  D_MASTER_01, opening sPort=/dev/ttyUSB0 D_MASTER_01, wrote 7 chars: *#1*0## D_MASTER_01, wrote 7 bytes on the bus . D_MASTER_01, timeout, ret_value = 0  D_MASTER_01,  a: 0 D_MASTER_01, bticino_status.row[a].address: *11## D_MASTER_01, bticino_status.row[a].description: kitchen_dimmer D_MASTER_01, (position-2)[0]: 1 D_MASTER_01, (position-1)[0]: 9 D_MASTER_01, position[0]: * D_MASTER_01,  a: 1 D_MASTER_01, bticino_status.row[a].address: *16## D_MASTER_01, bticino_status.row[a].description: curtain_kitchen D_MASTER_01, (position-1)[0]: 0 D_MASTER_01, position[0]: * D_MASTER_01,  a: 2 … … … D_MASTER_01,  a: 7 D_MASTER_01, bticino_status.row[a].address: *33## D_MASTER_01, bticino_status.row[a].description: mosquito_plug D_MASTER_01, (position-1)[0]: 0 D_MASTER_01, position[0]: * D_MASTER_01,  a: 8 D_MASTER_01, bticino_status.row[a].address: *35## D_MASTER_01, bticino_status.row[a].description: curtain_upper_floor D_MASTER_01, (position-1)[0]: 0 D_MASTER_01, position[0]: * D_MASTER_01,  a: 9 D_MASTER_01, bticino_status.row[a].address: *36## D_MASTER_01, bticino_status.row[a].description: rolling_shutter_upper_floor D_MASTER_01, (position-1)[0]: 0 D_MASTER_01, position[0]: * D_MASTER_01, raw status bus: *#*1##*1*19*11##*1*0*21##*1*0*22##*1*0*31##*1*0*23##*1*0*24##*1*0*32##*1*0*33##*1*0*34##*1*0*12##*1*0*13##*1*0*14##*1*0*15##*1*0*25##*1*1*26##*2*0*35##*1*1*27##*1*0*28##*2*0*36##*2*0*16##*2*0*17##*1*0*37##*1*0*38##*1*0*39## ubuntu@ubuntu-armhf:~/serial_asyncrhonous_1$ 
The next section will describe in detail the managing of the port.
Serial port managing. First of all, open the port, let’s examine the tty_open port: int tty_open( const char* sPort ) At start of the function we have a system call, to instruct the program to ignore the SIGIO signal; that because  we use the select call, that is in charge of managing the that signaling.     //We are ignoring SIGIO signal since we are using "select" instead     signal( SIGIO, SIG_IGN ); after,  we open the serial port in read-write way, non blocking  and with the option that this program doesn't want to be the "controlling terminal" for that port:     fd = open(SERIAL_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK );     if (fd == -1) {         printf(PROCESS_NAME" error, opening serial device\n");         exit(APPLICATION_FAILURE);     } after we set the file descriptor with O_ASYNC flag     int ret_value  = fcntl(fd, F_SETFL,  O_ASYNC );     if( ret_value != 0 )     {         printf(PROCESS_NAME" fcntl F_SETFL O_ASYNC on new port[%s] failed with error[%d].\n", SERIAL_DEVICE, errno );         exit(APPLICATION_FAILURE);     } After we get the old configuration and set the port with the new configuration, where we fix the BAUDRATE,  ignore modem status lines with CLOCAL, 8 bits every symbol CS8, we ignore (discard) parity errors IGNPAR and  we map CR to NL (ala CRMOD) ICRNL; also the port can be read after a character is load in the buffer port, we don’t  wait for any while ( newtio.c_cc[VMIN]=1;  newtio.c_cc[VTIME]=0;) At the end we make the flush of port and set the new configuration:     tcgetattr(fd, &oldtio);          if( memset( &newtio, 0, sizeof(newtio) ) < (void *)1 ) {         printf(PROCESS_NAME" clearing up new port[%s] failed with error[%d].\n", SERIAL_DEVICE, errno);     }     //CRTSCTS Hardware Flow Control     newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;     newtio.c_iflag = ( IGNPAR | ICRNL );     newtio.c_oflag = 0;     newtio.c_lflag = 0; //~(ICANON | ECHO | ECHOE | ISIG);               //Constant Description Key     //-------------------------------------------------------------     //VINTR     Interrupt CTRL-C     //VQUIT     Quit CTRL-Z     //VERASE Erase Backspace (BS)     //VKILL     Kill-line CTRL-U     //VEOF      End-of-file CTRL-D     //VEOL      End-of-line Carriage return (CR)     //VEOL2     Second end-of-line Line feed (LF)     //VMIN      Minimum number of characters to read     //VTIME     Time to wait for data (tenths of seconds)          newtio.c_cc[VMIN]=1;     newtio.c_cc[VTIME]=0;          tcflush(fd, TCIFLUSH);     tcsetattr(fd,TCSANOW,&newtio); The functions  long tty_write(int fd, const char* psOutput) long tty_read(int fd, char* psResponse, int iMax)  simply writes and reads from serial. The function tty_close closes the port file descriptor; void tty_close(int fd){     if( fd > 0 ){         close(fd);     } else {         printf(PROCESS_NAME", error file descriptor %d not open.\n", fd );     }      } In the download section you can download the zip of the project. Remember that, you’ll find a Xcode project to examine it in a mac environment but you’ll also find the makefile to compile it under BBB.
bbb_bTicino_serial_asyncrhonous.zip
[if gte mso 9]> 0 0 1 40 232 extech 1 1 271 14.0 Normal 0 false false false EN-US JA X-NONE