Announcement

Collapse
No announcement yet.

Magic Object and host string troubles

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Magic Object and host string troubles

    I'm using a Magic Object to receive a string from the host MCU and display it in a dynamic string object.
    (The reason for this is that I have more than 256 dynamic strings - once this works I'll make the object index two bytes wide.)

    I'm sending a Write Magic Bytes command with this payload: 0,5,"HELLO WORLD!"
    0 (cmd) is the command byte (0=write dynamic string)
    5 (obj_idx) is the string object index (Strings5)

    I'm getting no change to the string object.
    However, if I omit the 0 and 5 from the host send and the MagicObject code, here's what I get:
    with Dstring:=str_Ptr(&ptr[0]); Strings5="H"
    with Dstring:=str_Ptr(&ptr[1]); Strings5="ELLO WORLD!"

    In summary: it appears the pointer indices are wrong. Please help!!


    Below is the analyzer output of the message from the host to the LCD:
    Click image for larger version

Name:	Capture 1.JPG
Views:	243
Size:	14.0 KB
ID:	69284

    Here's the code:
    Code:
    // MagicObject0
    
    // action  READ_OBJ, WRITE_OBJ, WRITE_MAGIC_BYTES or WRITE_MAGIC_DBYTES
    // object  Usually the object number, but since you can call this routing inside your code you could change this
    // newVal  New value for WRITE_OBJ. Length for WRITE_MAGIC_BYTES and WRITE_MAGIC_DBYTES
    // ptr     poiinter to data for WRITE_MAGIC_BYTES and WRITE_MAGIC_DBYTES, otherwise N/A
    
    #CONST
        DSTRING_WRITE    // write to dynamic string object
    #END
    
    func rMagicObject0(var action, var object, var newVal, var *ptr)
        var Dstring, cmd, obj_idx, i, j;
    
        if (action == WRITE_MAGIC_BYTES)
            for (i := 1; i < newVal; i++)           // change endianness
                j := i*2 ;
                ptr[i] := (ptr[j] << 8) + ptr[j-1] ;
            next
    
            cmd := ptr[0] ;                         // extract command
            obj_idx := ptr[1] ;                     // extract string object index
            Dstring := str_Ptr(&ptr[2]) ;           // build string pointer
    
    //        print(cmd," ") ;
    //        str_Printf(&Dstring, "%s\n");             // Dstring will need resetting afterwards
    //        Dstring := str_Ptr(&ptr[1]) ;             // to reset
    
            switch (cmd)
                case DSTRING_WRITE:                     // write dynamic string
                    ANSI2Uni(Dstring,strUni);           // convert to unicode
                    PrintStrings(obj_idx,strUni,1);     // display string
                    break ;
            endswitch
    
        endif   // end WRITE_MAGIC_BYTES
    
        serout(ACK) ;    // send back an ACK to command, do this last, otherwise the master may send the
                        // next command which is cannot be started until this is finished.
    
    endfunc

    Code:
    func ANSI2Uni(var *ansi, var *uni)
        var i, ch ;
        repeat
        ch := str_GetByte(ansi++) ;
        uni[i++] := ch ;
        until (!ch) ;
    endfunc

  • #2
    Hi Jeremy,

    I'm sending a Write Magic Bytes command with this payload: 0,5,"HELLO WORLD!"
    I am quite lost with what you mentioned here.
    Based on ViSi-Genie-Reference Manual, the command: Write_Magic_Bytes is composed of Code(0x08), Parameter1(Object Index), Parameter2(Length), ParameterN(Array - 1 byte values), Checksum

    Correct me if I am wrong, but do you intend to extract the 2nd byte of the message to act as the string object index?
    I think it should be written like this:
    Code:
    cmd := ptr[0] ;
    obj_idx := ptr[1] - 48; //convert ASCII to Int
    Using the ViSi-Genie-Arduino Library, I send this command on the display:
    Code:
    genie.WriteMagicBytes(0,"00Hello World",13);

    On the MagicObjectCode, you could try to simply print the message, by storing it on a buffer.
    Code:
       var buffer[20];
       pointer:=str_Ptr(buffer);
    
       cmd := ptr[0] ;
       obj_idx := ptr[1] - 48; //convert ASCII to Int
    
       for(i:=2; i<newVal;i++)
            str_PutByte(pointer + j,ptr[i]);
            j+=1;
        next
    
       putstr(buffer);
    If you want to print it on a String Object:
    Code:
    ANSI2Uni(str_Ptr(buffer), strUni);
    PrintStrings(obj_idx,strUni,1);
    However, for your convenience, you can also use the WriteStr command:

    Code:
    genie.WriteStr(0,"Hello World");

    Best Regards,
    Kevin
    Last edited by John Kevin; 14 August 2019, 07:59 PM.

    Comment


    • #3
      I am quite lost with what you mentioned here.
      Based on ViSi-Genie-Reference Manual, the command: Write_Magic_Bytes is composed of Code(0x08), Parameter1(Object Index), Parameter2(Length), ParameterN(Array - 1 byte values), Checksum
      Click image for larger version  Name:	Capture 2.jpg Views:	0 Size:	40.8 KB ID:	69300
      Correct me if I am wrong, but do you intend to extract the 2nd byte of the message to act as the string object index?
      I think it should be written like this:
      Yes, however the first byte ('0') and second byte ('5') of the payload are not ASCII. (in picture above, numbers in ' ' are decimal values)

      My code comes from "FileAccess.4DGENIE", where (it appears that) cmd is the first byte of the payload and is not ASCII:

      Code:
      // MagicObject - FileAccess
      // action  READ_OBJ, WRITE_OBJ, WRITE_MAGIC_BYTES or WRITE_MAGIC_DBYTES
      // object  Usually the object number, but since you can call this routing inside your code you could change this
      // newVal  New value for WRITE_OBJ. Length for WRITE_MAGIC_BYTES and WRITE_MAGIC_DBYTES
      // ptr     poiinter to data for WRITE_MAGIC_BYTES and WRITE_MAGIC_DBYTES, otherwise N/A
      //
      #CONST
          MFILE_READ
          MFILE_WRITE
          MFILE_APPEND
          MFILE_ERASE
          MFILE_DIR
          MFILE_SCREEN_CAPTURE
          MFILE_SIZE
      #END
      //
      
      func rMagicObject0(var action, var object, var newVal, var *ptr)
          var fname, cmd, i, j, k, myhndl, szh, szl, szlo, fdata[7] ;
          if (action == WRITE_MAGIC_BYTES)
              for (i := 1; i < newVal; i++)           // change endianness
                  j := i*2 ;
                  ptr[i] := (ptr[j] << 8) + ptr[j-1] ;
              next
              cmd := ptr[0] ;                              // extract command
              fname := str_Ptr(&ptr[1]) ;             // build string pointer
              seroutCS(REPORT_MAGIC_EVENT_BYTES) ;    // we report in bytes
              seroutCS(object) ;
              switch (cmd)
                  case MFILE_READ :


      genie.WriteStr(0,"Hello World");
      I don't have any problems with host writing to dynamic strings like this. But this only allows me to address 256 string objects. Therefore, I'm using MagicObject to address more than 256 strings (will change obj_idx to two bytes once this routine works).

      I did come across some other posts where they had to offset their pointer by adding 4800, etc... because of memory bank reasons???

      It's clear that the pointers aren't working (not reading cmd as 0 or obj_idx as 5). Pointer to string not working because I either get "H" or "ELLO WORLD!" (ptr[0], ptr[1])


      UPDATE:

      for debugging: I have the host sending cmd (0) & obj_idx (5) (image above), but I have the LCD code intentionally ignore them:

      using Dstring := str_Ptr(&ptr[1]) ; gives me the whole "HELLO WORLD!"


      Why doesn't "HELLO WORLD!" start at ptr[2] (the third byte in the payload) ?

      Shouldn't cmd be at ptr[0] and obj_idx at ptr[1] ?

      How do I read cmd and obj_idx ?
      Last edited by jeremywilson; 15 August 2019, 08:02 AM.

      Comment


      • #4
        Hello,

        Thank you for your explanation.
        As you may know, there is only one variable data type in 4DGL - var data type, which is a 16 bit signed integer variable. A var variable is a word which holds 2 bytes.

        You may refer to this application note which explains how string characters are stored in and accessed from memory.
        AN-00193 Designer or ViSi Strings and Character Arrays:
        https://4dsystems.com.au/blog/4d-an-00193/

        Have you tried to make a simple program to print each character you received?

        For a demonstration, let's say you will send this message = '00Hello World'
        Code:
        func rMagicObject0(var action, var object, var newVal, var *ptr)
            if (action == WRITE_MAGIC_BYTES)
                print([HEX]ptr[0]); //Output = 0030 -> '0'
                print([HEX]ptr[1]); //Output = 0030 -> '0'
                print([HEX]ptr[2]); //Output = 0048 -> 'H'
                print([HEX]ptr[3]); //Output = 0065 -> 'e'
                print([HEX]ptr[4]); //Output = 006C -> 'l'
                print([HEX]ptr[5]); //Output = 006C -> 'l'
                print([HEX]ptr[0]); //Output = 006F -> 'o'          
            endif
        endfunc
        As you can see each address can hold up to 2 bytes, thus producing the output.


        Why doesn't "HELLO WORLD!" start at ptr[2] (the third byte in the payload) ?

        Shouldn't cmd be at ptr[0] and obj_idx at ptr[1] ?

        How do I read cmd and obj_idx ?

        In the example program 'FileAccess', each byte is addressed and stored. Using the function you used for changing the endianess, the output you received is correct.
        Code:
        func rMagicObject0(var action, var object, var newVal, var *ptr)
            if (action == WRITE_MAGIC_BYTES)
                for (i := 1; i < newVal; i++)           // change endianness
                        j := i*2 ;
                        ptr[i] := (ptr[j] << 8) + ptr[j-1] ;
                next    
            endif
        endfunc
        You can try to substitute the value you received, on the function.

        On first iteration, ptr[1]:=4830 -> 'H''0'
        On second iteration, ptr[2]:=6C65 -> 'l' 'e'
        and so on....

        When you print it on the display
        Code:
         Dstring := str_Ptr(&ptr[1]) ; 
         str_Printf(&Dstring, "%s\n"); //Output = '0Hello World'
        
         Dstring := str_Ptr(&ptr[2]) ; 
         str_Printf(&Dstring, "%s\n"); //Output = 'ello World'
        
         Dstring := str_Ptr(&ptr[2]) ; 
         str_Printf(&Dstring, "%s\n"); //Output = 'lo World'
        
        and so on....
        I hope this helps.

        Best Regards,
        Kevin






        Comment


        • #5
          Kevin:
          Thanks for the reply!
          I forgot that the message bytes are 2 bytes wide !!!
          Unfortunately, I've spent most of the day trying to get this to work to no avail.


          Code:
          func rMagicObject0(var action, var object, var newVal, var *ptr)
              var Dstring, cmd, obj_idx, i, j, pntr;
              var StringID;
          
              if (action == WRITE_MAGIC_BYTES)
                  for (i := 1; i < newVal; i++)           // change endianness
                      j := i*2 ;
                      ptr[i] := (ptr[j] << 8) + ptr[j-1] ;
                  next
          
          // Ref A:
                  //print([HEX]ptr[0]);       doesn't print anything
          
          //Ref B:
                  //cmd:=0;                // ignore cmd
                  //obj_idx:=ptr[0];     // obj_idx 2 bytes wide
          
          //Ref C:                                            // based on 4D-AN-00193 page 7
                  //cmd := ptr[0]>>8 ;                       
                  //obj_idx := ptr[0] & 0x00FF ;
          
           //Ref D:                                             // based on 4D-AN-00193 page 8
                  pntr:=str_Ptr(&ptr[0]);
                  cmd:=str_GetByte(pntr);
                  obj_idx:=str_GetByte(pntr+1);
          
                  Dstring := str_Ptr(&ptr[1]) ;           // build string pointer
          
                  switch (cmd)
                      case DSTRING_WRITE:                     // write dynamic string
                          StringID := oStringss[1+obj_idx] ;
                          gfx_RectangleFilled(*(StringID + Ofs_String_x1), *(StringID + Ofs_String_y1), *(StringID + Ofs_String_x2), *(StringID + Ofs_String_y2), *(StringID + Ofs_String_BGColor));
                          ANSI2Uni(Dstring,strUni);           // convert to unicode
                          PrintStrings(obj_idx,strUni,1);     // display string
                          break ;
                  endswitch
          
              endif   // end WRITE_MAGIC_BYTES
          
              serout(ACK) ;    // send back an ACK to command, do this last, otherwise the master may send the
                              // next command which is cannot be started until this is finished.
          
          endfunc



          I'm at a total loss !!!

          Comment


          • #6
            So I appended a null terminating '0' to the serial message (before checksum) and changed code to this: (ignoring cmd)

            Code:
                    cmd:=DSTRING_WRITE;
                    obj_idx:=ptr[0];
                    Dstring := str_Ptr(&ptr[1]) ;
            This works. Tomorrow I will try putting cmd back in but as 16-bits wide.

            Comment


            • #7
              Hi Jeremy,

              Sure, no problem. Keep me updated.
              Alternatively, you can also check the .cpp file in the ViSi-Genie-Arduino library for the list of commands available and how it is implemented.
              Have fun in your project.

              Best Regards,
              Kevin

              Comment

              Working...
              X