PicoC, \x00 hexadecimal

Einklappen
X
 
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge
  • Jan W.
    Lox Guru
    • 30.08.2015
    • 1366

    #16
    You just have to count the Inputs, so for a program block with 16 inputs, it's this:
    TI1 - Bit 0 in Bitmask 0x01
    Ti2 - Bit 1 in Bitmask 0x02
    TI3 - Bit 2 in Bitmask 0x04
    AI1 - Bit 3 in Bitmask 0x08 - getinput(0)
    AI2 - Bit 4 in Bitmask 0x10 - getinput(1)
    AI3 - Bit 5 in Bitmask 0x20
    AI4 - Bit 6 in Bitmask 0x40
    AI5 - Bit 7 in Bitmask 0x80
    AI6 - Bit 8 in Bitmask 0x0100
    AI7 - Bit 9 in Bitmask 0x0200
    AI8 - Bit 10 in Bitmask 0x0400
    ...

    The overall Mask is the "OR" of all relevant specific inputs, so you should use 0x07f8 for 8 analog inputs. The description on the Loxone website is short, but not too bad:

    getinputevent - Returns a bitmask which contains the changes of inputs (bit 0 = first input of object, starts with text inputs followed by analog inputs).
    getinput - Returns the value of the analog input specified in parameter input. (0 = first analog input)

    The amount of text input varies with the different program blocks (4, 8, or 16), so the bit position in the mask changes for the analog inputs. For a program with 16 inputs the first analog input AI1 - getinput(0) is using 0x08 in the bitmask. You have to adjust the masks in your code.

    Miniserver v14.5.12.7, 2x Ext., 2x Relay Ext., 2x Dimmer Ext., DMX Ext., 1-Wire Ext., Gira KNX Tastsensor 3 Komfort, Gira KNX Präsenzmelder, Fenster- und Türkontakte, Loxone Regen- und Windsensor, Gira Dual Q Rauchmelder vernetzt, 1x Relais-Modul
    Loxberry: SmartMeter, MS Backup, CamConnect, Weather4Lox
    Lüftung: Helios KWL EC 370W ET mit Modbus TCP - via Pico-C
    Heizung: Stiebel Eltron WPF 5 cool (Sole-Wasser WP) mit ISG, FB-Heizung mit 18 Kreisen, Erdsonde - via modbus/TCP
    Node-RED: IKEA Tradfri

    Kommentar

    • K.Clemens
      Smart Home'r
      • 28.08.2015
      • 92

      #17
      Again, thanks for your reply.

      Really sorry, but I do not understand how you come to 0x07f8.

      08 - 0000 1000
      10 - 0001 0000
      20 - 0010 0000
      40 - 0100 0000
      80 - 1000 0000
      0100 - 0000 0001 0000 0000
      0200 - 0000 0010 0000 0000
      0400 - 0000 0100 0000 0000

      OR statement of bytes: 1111 1111 0000 0000, which results in hexadecimal in FF00.

      Furthermore I've found that when I send a certain hex command, I get a response which gives me the ON status of every relais.
      The 7th position tells me which relais are on. If multiple relais are on, than the sum is made of the 7th position.

      I'm thing about something like this:
      // Check status of relais after connection is made
      void checkstatus (char *statusrelais)
      {
      if (isalpha(statusrelais)) {
      // All 8 relais are ON
      }
      if (isdigit (statusrelais)) {
      //
      }
      }

      I was working with if statements to compare the 7th position to set the output of the program, but as if you can imagine the amount possibilities are huge.
      Is there a function to quickly check and correlate position7 with the output of the loxone program?



      niets aan
      // AA 55 00 04 00 8A 00 08 96
      // relais 1 aan
      // AA 55 00 04 00 8A 01 08 97
      // relais 2 aan
      // AA 55 00 04 00 8A 02 08 98
      // relais 3 aan
      // AA 55 00 04 00 8A 04 08 9A
      // relais 4 aan
      // AA 55 00 04 00 8A 08 08 9E
      // relais 5 aan
      // AA 55 00 04 00 8A 10 08 A6
      // relais 6 aan
      // AA 55 00 04 00 8A 20 08 B6
      // relais 7 aan
      // AA 55 00 04 00 8A 40 08 D6
      // relais 8 aan
      // AA 55 00 04 00 8A 80 08 16

      // relais 1 & 2 aan
      // AA 55 00 04 00 8A 03 08 99
      // relais 1 & 3 aan
      // AA 55 00 04 00 8A 05 08 9B
      // relais 2 & 3 aan
      // AA 55 00 04 00 8A 06 08 9C
      // relais 1,2 & 3 aan
      // AA 55 00 04 00 8A 07 08 9
      Zuletzt geändert von K.Clemens; 30.06.2016, 22:57.

      Kommentar

      • Jan W.
        Lox Guru
        • 30.08.2015
        • 1366

        #18
        If you operate with numbers (either binary, hex, decimal), they have to be right-aligned, so you may add zeros at the left side:
        08=0008 - 0000 0000 0000 1000
        10=0010 - 0000 0000 0001 0000
        20=0020 - 0000 0000 0010 0000
        40=0040 - 0000 0000 0100 0000
        80=0080 - 0000 0000 1000 0000
        0100 - 0000 0001 0000 0000
        0200 - 0000 0010 0000 0000
        0400 - 0000 0100 0000 0000
        now it's easy to see that the result of an "OR" is 0x07f8.

        Regarding the output of the board: that make more sense. It's quite easy to get the state for each relais by using similar masking as Loxone for "inputevent". Assuming that relais[8] is the byte array containing the result from the board, e.g. AA 55 00 04 00 8A xx 08 99, so relais[0]=0xAA, ..., relais[6]=xx;

        The following code returns the state (on/off) for relais 1

        // do a binary "OR" with the 7th byte of the response and the mask for a specific relais number, here relais 1 = 0x01
        if (relais[6] & 0x01)
        // relais 1 is on
        else
        // relais 1 is off

        for relais 2 use 0x02, for relais 3 use 0x04, for relais 4 use 0x08, ...

        you may do this in a loop as well:

        mask=0x01;
        for (no=0; no<8; no++ ) {
        if (relais[6] & mask)
        // relais number "no" (counting from 0 to 7!) is on
        else
        // relais number "no" (counting from 0 to 7!) is off
        mask=mask<<1; // left shift. The same result as "mask * 2" or "mask + mask"
        }

        Miniserver v14.5.12.7, 2x Ext., 2x Relay Ext., 2x Dimmer Ext., DMX Ext., 1-Wire Ext., Gira KNX Tastsensor 3 Komfort, Gira KNX Präsenzmelder, Fenster- und Türkontakte, Loxone Regen- und Windsensor, Gira Dual Q Rauchmelder vernetzt, 1x Relais-Modul
        Loxberry: SmartMeter, MS Backup, CamConnect, Weather4Lox
        Lüftung: Helios KWL EC 370W ET mit Modbus TCP - via Pico-C
        Heizung: Stiebel Eltron WPF 5 cool (Sole-Wasser WP) mit ISG, FB-Heizung mit 18 Kreisen, Erdsonde - via modbus/TCP
        Node-RED: IKEA Tradfri

        Kommentar

        • K.Clemens
          Smart Home'r
          • 28.08.2015
          • 92

          #19
          MS crashed already 2 times in 15 minutes.

          What is a good tcp client to test this script?

          Kommentar

          • Jan W.
            Lox Guru
            • 30.08.2015
            • 1366

            #20
            Unfortunately, there is no good Pico C interpreter available to test with! Maybe somebody else has more information.

            I'm using the Pico C interpreter from the same author that is also used by Loxone: https://github.com/zsaleeba/picoc. You have to compile it on your platform, e.g. Windows. I did it on OS-X.

            BUT:
            - I didn't had a problem with two-dimensional arrays with that interpreter.
            - you need to add a "main" function and may have to add libraries (e.g. #include <stdio.h> and #include <string.h>), overall not a big issue
            - the stream functions are NOT available, because they were added by Loxone.
            - the Loxone sprintf has a different result code
            - printf/sprintf do not accept all codes, e.g. "%X" for uppercase hex numbers is not implemented in Loxone
            - getinput, getinputevent and output are specific to Loxone and do not work

            The interpreter may help a bit to test some code, however.

            Regarding the crashes: do you have followed the guidelines from Loxone, e.g. added "sleeps" after a specific amount of statements, e.g. in loops?

            Kind Regards,

            Jan
            Miniserver v14.5.12.7, 2x Ext., 2x Relay Ext., 2x Dimmer Ext., DMX Ext., 1-Wire Ext., Gira KNX Tastsensor 3 Komfort, Gira KNX Präsenzmelder, Fenster- und Türkontakte, Loxone Regen- und Windsensor, Gira Dual Q Rauchmelder vernetzt, 1x Relais-Modul
            Loxberry: SmartMeter, MS Backup, CamConnect, Weather4Lox
            Lüftung: Helios KWL EC 370W ET mit Modbus TCP - via Pico-C
            Heizung: Stiebel Eltron WPF 5 cool (Sole-Wasser WP) mit ISG, FB-Heizung mit 18 Kreisen, Erdsonde - via modbus/TCP
            Node-RED: IKEA Tradfri

            Kommentar

            • K.Clemens
              Smart Home'r
              • 28.08.2015
              • 92

              #21
              Thanks for the info about the pico C interpreter, seems the MS would be the best option..


              mask=mask<<1; seems not to work on the MS. Had to change it to mask = mask + mask;
              I have added a sleep of 500 ms in the for loop and a sleep of 500 ms at the end of the while loop (just before the closing } )

              It seems that the code you provided checks for every relais separated? 0x01, 0x02, 0x04
              So the code is missing the combinations like 0x03 (relais 1 & 2 on) or 0xFF (All relais are on).

              Questions:
              - Which function to use for printing integers in the log file? I just want to print the number (no) of the for loop to check which is on or not.
              - Maybe a good option to keep CPU loads to a minimum would be to only only create a new connection with TCP if this particular one is closed. So not putting the stream_create in the while?
              If a new connection is established, than load in all status from the 8 relais. As long as the connection is still open, wait for a certain "response" of the relay board and set the particular output to ON or OFF. Only problem I see here is like you said earlier that if the "stream_create" and "stream_close" are not in the while, and the connection closes, than the script does not re-open the connection.

              Hmm, it's more difficult than I expected....




              The code of the while so far:

              while(TRUE)
              {
              sprintf(streamname, "/dev/tcp/%s/%s/", IP_ADDRESS, PORT);
              STREAM* TcpStream = stream_create(streamname,0,0);

              if (TcpStream != NULL) {
              //send password
              char relais[7] = {0x61, 0x64, 0x6D, 0x69, 0x6E, 0x0D, 0x0A};
              stream_write(TcpStream, relais, 7);
              stream_flush(TcpStream);

              // check status of relais outputs on connection
              sleep(500);
              char relais2[7] = {0x55, 0xAA, 0x00, 0x02, 0x00, 0x0A, 0x0C};
              stream_write(TcpStream, relais2, 7);
              stream_flush(TcpStream);


              nLen = stream_read(TcpStream,response,9,100);

              if (nLen == 9)
              mask=0x01;
              for (no=0; no<8; no++ ) {
              if (relais2[6] & mask)
              {
              // relais number "no" (counting from 0 to 7!) is on
              sprintf( b, "0x%02x, ",no);

              setlogtext(b);
              }

              else
              {
              // relais number "no" (counting from 0 to 7!) is off
              sprintf(buffer, "relais uit:");
              setlogtext(buffer);
              }
              //mask=mask<<1; // left shift. The same result as "mask * 2" or "mask + mask"
              mask = mask + mask;
              }
              sleep(1000);
              }


              }
              stream_close(TcpStream);
              sleep(500);
              }
              Zuletzt geändert von K.Clemens; 01.07.2016, 21:54.

              Kommentar

              • Jan W.
                Lox Guru
                • 30.08.2015
                • 1366

                #22
                So your program runs now without crashes?

                To print a decimal number with printf/sprintf, use e.g. sprintf(buffer, "relais %d uit", no); There are plenty of good online manuals for the language C on the Internet.

                You only have to check for each relais separately. By looping from 0 to 7 you'll cover each relais and by masking on the specific relais number, you are also handling all combinations. In addition to the printf you may use setoutput to set the outputs of the program. The rest of the logic can be done in Loxone config and you don't have to change your program.

                In post #12 I've already recommended to move the stream create and close into the while loop to handle errors. It does however not reduce CPU load. This program should not put much load on the MS. You are able to watch the CPU load by activating the monitor in Loxone config.

                btw: you'll never go beyond the loop, so the close and sleep at the end of your program are never executed.
                Miniserver v14.5.12.7, 2x Ext., 2x Relay Ext., 2x Dimmer Ext., DMX Ext., 1-Wire Ext., Gira KNX Tastsensor 3 Komfort, Gira KNX Präsenzmelder, Fenster- und Türkontakte, Loxone Regen- und Windsensor, Gira Dual Q Rauchmelder vernetzt, 1x Relais-Modul
                Loxberry: SmartMeter, MS Backup, CamConnect, Weather4Lox
                Lüftung: Helios KWL EC 370W ET mit Modbus TCP - via Pico-C
                Heizung: Stiebel Eltron WPF 5 cool (Sole-Wasser WP) mit ISG, FB-Heizung mit 18 Kreisen, Erdsonde - via modbus/TCP
                Node-RED: IKEA Tradfri

                Kommentar

                • K.Clemens
                  Smart Home'r
                  • 28.08.2015
                  • 92

                  #23
                  I have a script that works now. Big thanks Jan for all of your input. Without your help I could not have done it! Thank you.

                  The script below just works for the first input in Loxone. I still have to adapt the other 7, but that is no issue.

                  Only problem I have is that the time between pressing a button in Loxone and the execution of the action is not always the same.
                  The reaction time is between 0.5 - 3 seconds. Any idea why? A reaction time longer than 1 second is just not usefull.

                  // IP USR-IOT

                  char* IP_ADDRESS = "xxx.xxx.xxx.xxx";

                  // Port (standard port = xxxx)

                  char* PORT = "xxxx";

                  char streamname[100];

                  char buffer[1024];
                  char response[9];
                  char mask;

                  int nLen;
                  int nEvents;
                  int no;



                  while(TRUE)
                  {
                  //create connection with USR IOT
                  sprintf(streamname, "/dev/tcp/%s/%s/", IP_ADDRESS, PORT);
                  STREAM* TcpStream = stream_create(streamname,0,0);

                  //check if connection is OK
                  if (TcpStream != NULL) {
                  //send password
                  char relais[7] = {0x61, 0x64, 0x6D, 0x69, 0x6E, 0x0D, 0x0A};
                  stream_write(TcpStream, relais, 7);
                  stream_flush(TcpStream);
                  sleep(100);

                  // check if input in Loxone has changed status
                  nEvents = getinputevent();
                  if (nEvents & 0x07f8) {
                  // Test bitwise if input 4 was changed (00000100)
                  if (nEvents & 0x08) {
                  if (getinput(0) == 1) {
                  char relaisON[8] = {0x55, 0xAA, 0x00, 0x03, 0x00, 0x02, 0x01, 0x06};
                  stream_write(TcpStream, relaisON, 8);
                  sprintf(buffer, "relais 1 is AANGEZET met loxone");
                  setlogtext(buffer);
                  } else {
                  char relaisOFF[8] = {0x55, 0xAA, 0x00, 0x03, 0x00, 0x01, 0x01, 0x05};
                  stream_write(TcpStream, relaisOFF, 8);
                  sprintf(buffer, "relais 1 is UITGEZET met loxone");
                  setlogtext(buffer);
                  }
                  stream_flush(TcpStream);
                  }
                  // Test bitwise if input 5 is changed (00001000)
                  else if (nEvents & 0x10) {
                  if (getinput(1) == 1) {
                  convertLoxInput(1, 2);
                  } else {
                  convertLoxInput(2, 2);
                  }
                  }
                  // Test bitwise if input 6 is changed (00010000)
                  else if (nEvents & 0x20) {
                  if (getinput(2) == 1) {
                  convertLoxInput(1, 3);
                  } else {
                  convertLoxInput(2, 3);
                  }
                  }
                  // Test bitwise if input 7 is changed (00100000)
                  else if (nEvents & 0x40) {
                  if (getinput(3) == 1) {
                  convertLoxInput(1, 4);
                  } else {
                  convertLoxInput(2, 4);
                  }
                  }
                  // Test bitwise if input 8 is changed (00100000)
                  else if (nEvents & 0x80) {
                  if (getinput(4) == 1) {
                  sconvertLoxInput(1, 5);
                  } else {
                  convertLoxInput(2, 5);
                  }
                  }
                  // Test bitwise if input 9 is changed (00100000)
                  else if (nEvents & 0x0100) {
                  if (getinput(5) == 1) {
                  convertLoxInput(1, 6);
                  } else {
                  convertLoxInput(2, 6);
                  }
                  }
                  // Test bitwise if input 10 is changed (00100000)
                  else if (nEvents & 0x0200) {
                  if (getinput(6) == 1) {
                  convertLoxInput(1, 7);
                  } else {
                  convertLoxInput(2, 7);
                  }
                  }
                  // Test bitwise if input 11 is changed (00100000)
                  else if (nEvents & 0x0400) {
                  if (getinput(7) == 1) {
                  convertLoxInput(1, 8);
                  } else {
                  convertLoxInput(2, 8);
                  }
                  }
                  }
                  else {

                  // check status of relais outputs on connection
                  char relais2[7] = {0x55, 0xAA, 0x00, 0x02, 0x00, 0x0A, 0x0C};
                  stream_write(TcpStream, relais2, 7);
                  stream_flush(TcpStream);

                  //check if the status of the relais is changed on the relais board itself.
                  nLen = stream_read(TcpStream,response,9,200);

                  if (nLen == 9) {


                  // instead of 55 AA 00 04 00 8A "xx" 4F 4F
                  // the sprintf gives in the miniserver
                  // 4F 4B 55 AA 00 04 00 8A "xx"
                  // therefore not response[6] is needed, but response[8]
                  mask = 01;
                  for (no=0; no<8; no++ ) {
                  if (response[8] & mask)
                  {
                  setoutput(no,1);
                  no = no + 1;
                  sprintf(buffer, "relais %d aan", no);
                  setlogtext(buffer);
                  sprintf(buffer, "%02x", response[8] );
                  setlogtext(buffer);
                  no = no - 1;
                  }
                  else
                  {
                  setoutput(no,0);
                  no = no + 1;
                  sprintf(buffer, "relais %d uit", no);
                  setlogtext(buffer);
                  sprintf(buffer, "%02x, ", response[8] );
                  setlogtext(buffer);
                  no = no - 1;
                  }
                  //mask=mask<<1; // left shift. The same result as "mask * 2" or "mask + mask"
                  mask = mask + mask;
                  }
                  //sleep(500);
                  }
                  }
                  }
                  stream_close(TcpStream);
                  sleep(100);
                  }

                  Kommentar

                  • Jan W.
                    Lox Guru
                    • 30.08.2015
                    • 1366

                    #24
                    Welcome! Do you see the same response time in the log window? It sound strange that it takes 3 seconds for the relais to respond. From the amount of code and sleep statement I would say that a response time of 0.5 seconds is expected. Try to remove all parts of the code that are not required, e.g. all code for relais 2..x and reading the response.

                    The code to define and initialize the array char relaisON[8] = {..} and "OFF" may be moved to the top outside of the while loop. This may save save some CPU cycles, but is not the reason for the very long delay.
                    Miniserver v14.5.12.7, 2x Ext., 2x Relay Ext., 2x Dimmer Ext., DMX Ext., 1-Wire Ext., Gira KNX Tastsensor 3 Komfort, Gira KNX Präsenzmelder, Fenster- und Türkontakte, Loxone Regen- und Windsensor, Gira Dual Q Rauchmelder vernetzt, 1x Relais-Modul
                    Loxberry: SmartMeter, MS Backup, CamConnect, Weather4Lox
                    Lüftung: Helios KWL EC 370W ET mit Modbus TCP - via Pico-C
                    Heizung: Stiebel Eltron WPF 5 cool (Sole-Wasser WP) mit ISG, FB-Heizung mit 18 Kreisen, Erdsonde - via modbus/TCP
                    Node-RED: IKEA Tradfri

                    Kommentar

                    • K.Clemens
                      Smart Home'r
                      • 28.08.2015
                      • 92

                      #25
                      Jan W., sorry for the late response.

                      It seems that the delay is related to the loxone miniserver itself, meaning the micro SD card.
                      Replacing by a new one, resulted in fast responses.

                      Kommentar

                      Lädt...