Shop OBEX P1 Docs P2 Docs Learn Events
C: Testing Serial Protocol And Simulating Inter-Propeller Communication - Page 2 — Parallax Forums

C: Testing Serial Protocol And Simulating Inter-Propeller Communication

2»

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-21 18:46
    Are you sure that the struct doesn't contain any bytes with a value of 62? Your loop terminates when a 62 is encountered.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-21 18:56
    Dave

    I have tried other terminators besides '>', such as ';', and ':', but the results are the same. I believe one of the memcpy(s) is screwing up the data, but I could be wrong :)
  • idbruceidbruce Posts: 6,197
    edited 2015-04-21 19:12
    Or perhaps it may be the lack of null termination like David said earlier.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-21 19:26
    You are also sure that none of your struct bytes contain a zero, right? That will cause your loop to terminate also.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-21 19:56
    idbruce wrote: »
    Dave

    I have tried other terminators besides '>', such as ';', and ':', but the results are the same. I believe one of the memcpy(s) is screwing up the data, but I could be wrong :)
    Instead of using a terminating character, why not apply a header of a known size, that gives the transmission length???
  • idbruceidbruce Posts: 6,197
    edited 2015-04-21 22:10
    @Dave
    You are also sure that none of your struct bytes contain a zero, right? That will cause your loop to terminate also.

    There are plenty of zeros, but to my knowledge, the are no "null" characters, but I am not certain. I am a little out of my playground. How would that terminate my loop?

    @David
    Instead of using a terminating character, why not apply a header of a known size, that gives the transmission length???

    At least for the moment, I do not believe the terminator is the problem. If it is determined that any terminator will be a problem, well then of course I would explore that option. Right now, I am proceeding the struct with a '<' for STX and following the struct with a '>' for ETX. I believe it should work, but I also believe the data is getting screwed up somewhere, perhaps with all this "volatile" mumbo jumbo.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-22 05:03
    idbruce wrote: »
    There are plenty of zeros, but to my knowledge, the are no "null" characters, but I am not certain. I am a little out of my playground.
    Bruce, what do you think a "null" character is? It's just a byte with a zero value. Get out a magnifying glass and look closely at your loop.
    while((Char = fdserial_rxChar(processor)) && (Char != '>'))
    {
        received_struct_array[index] = Char;
        index++;
    }
    
    Do you see it now? If not, look closely at this line:
    while((Char = fdserial_rxChar(processor)) && (Char != '>'))
    
    Now do you see it? How about if I write it this way:
    while(((Char = fdserial_rxChar(processor)) != 0) && (Char != '>'))
    
    Or how about this?
    while(((Char = fdserial_rxChar(processor)) != NULL) && (Char != '>'))
    
    Or let's get rid of the test for '>' for now since it doesn't seem to make a difference.
    while((Char = fdserial_rxChar(processor)) != NULL))
    
    Now do you see it? What you really need is a loop that terminates after reading all the bytes, such as.
    for (index = 0; index < sizeof(GCODE_STRUCT); index++)
        received_struct_array[index] = fdserial_rxChar(processor);
    
    So what happens if you don't receive all of the bytes. Your code get's stuck. So you need a timeout to get out of that stupid loop. What you need is a rxChar that times out have a certain period of time, such as 100 msec. I don't want to do all of your homework, so I'll let you figure that out on your own.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 05:22
    Dave

    Yes, I get the point :)

    Last night, after you asked the question:
    You are also sure that none of your struct bytes contain a zero, right?

    I altered my test code within StructTest.c to include:
    	for(int i = 0; i < sizeof(GCODE_STRUCT); i++)
    	{
    		print("%d\n", send_struct_array[i]);
    	}
    

    The output from this included many zeros. How do I combat the zeros or is there another way around it?
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-22 05:25
    Dave Hein wrote: »
    What you really need is a loop that terminates after reading all the bytes, such as.
    for (index = 0; index < sizeof(GCODE_STRUCT); index++)
        received_struct_array[index] = fdserial_rxChar(processor);
    
    So what happens if you don't receive all of the bytes. Your code get's stuck. So you need a timeout to get out of that stupid loop. What you need is a rxChar that times out have a certain period of time, such as 100 msec. I don't want to do all of your homework, so I'll let you figure that out on your own.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 05:31
    On a further note, while trying to resolve the problem of sending a structure serially with differing data types, I came across several references that indicated that the structure should be byte aligned with "#pragma pack(n)" and in some instance may need "push" or "pop".
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-22 05:35
    NOOOOOOOOOOOOOOOOOOOO!!! Don't mess around with that. Just do what I said.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 05:49
    Dave

    Okay, I will see what kind of concoction I can come up with :)
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 06:54
    Houston... We have a lift off :):):)

    Thank you Dave and Steve for pointing me in the right direction.

    For all others, you now have a working example of passing a struct serially from one cog to another cog, thus simulating the passing of a struct serially from one Propeller to another Propeller :)

    I hope it is of good use to you :) As for me, NOW I can move forward with my project :)

    EDIT: I have updated the original upload to include a few extra additional comments.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 07:53
    For those of you who downloaded my previous upload, I forgot to add a few comments to StructTest.c and to processor.c. These comments are just friendly reminders that STX and ETX should be the same on both the transmitting and receiving end of the serial connections. So I have updated that upload, for those that like friendly reminders :)
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 08:51
    After looking the project over just one more time, I decided to rearrange some things and remove some things. There was an extra GCODE_STRUCT that wasn't needed, which added an extra memcpy and an extra memset, etc... so on... so forth...

    So the following attachment, is the final draft, at least for now :)
  • jazzedjazzed Posts: 11,803
    edited 2015-04-22 10:18
    Bruce,

    Try this generic packet code which does a loopback but could be used between boards. Byte receive timeout, packet length, and primitive checksum are included. Other packet items are left to the imagination.

    This can be used for a ASCII byte oriented transport layer. Making marshalling layer code like XDR is left as an exercise.

    Output:
    Packet Test
    Send packets
    Dequeue received packets:
    -> Hello
    -> Packet
    -> Tester
    
    /**
     * This is the main PacketTest program file.
     * @file PacketTest.c
     * 
     * Add wire between P0 and P1
     */
    
    
    #include <string.h>
    #include "simpletext.h"
    #include "fdserial.h"
    #include "packet.h"
    
    
    fdserial *pktport;
    packet_st g_packet;
    
    
    char *msg[] = { "Hello", "Packet", "Tester", 0 };    
    
    
    int main(void)
    {
        int n = 0;
        pktport = fdserial_open(PROD_RX, PROD_TX, PROD_MODE, PROD_BAUD);
        
        printi("Packet Test\n");
        packet_start(pktport);
        
        printi("Send packets\n");
        
        for (n = 0; msg[n]; n++) {
            packet_make(&g_packet, msg[n], strlen(msg[n])+1);
            packet_send(pktport, &g_packet);
        }        
    
    
        printi("Dequeue received packets:\n");
        
        for (;;) { // for (ever)
            // if packet available
            if (packet_ready()) {
                packet_read(&g_packet);
                // print packet contents
                //packet_print(&mypacket);
                printi("-> %s\n",g_packet.data);
            }
        }                    
        
        return 0;
    }
    
    
    
    
    

    /**
     * @file packet.c
     * Packet utilities.
     */
    
    
    #include <stdio.h>
    #include "packet.h"
    
    
    static volatile packet_st queue[PACKET_QLEN];
    static volatile int qhead = 0;
    static volatile int qtail = 0;
    static volatile int qcount = 0;
    
    
    static volatile fdserial *grec;
    static char packet_stack[sizeof(_thread_state_t)+20*sizeof(int)];
    
    
    static int gcog;
    
    
    //#define LED1 (1 << 26)
    //#define LED2 (1 << 27)
    
    
    void packet_cog(void *parm);
    
    
    void packet_start(fdserial *rec)
    {
        grec = rec;
        gcog = cogstart(packet_cog, 0, packet_stack, sizeof(packet_stack));
        //debug("packet_start %d cog %d\n", sizeof(packet_stack), gcog);
    }
    
    
    void packet_stop(void)
    {
        if (gcog > 0) {
            //debug("packet_stop %d\n", gcog);
            cogstop(gcog);
            gcog = 0;
        }    
    }
            
    void packet_cog(void *parm)
    {
        int len = 0;
        int byte = 0;
        int n = 0;
        int sum = 0;
        
        volatile packet_st *pkt = 0;
        
        //DIRA |= LED1 | LED2;
        
        for (;;) { // for (ever)
            //OUTA |= LED1;
            // got a char?
            if (fdserial_rxReady((fdserial*)grec)) {
                // read length
                len = fdserial_rxChar((fdserial*)grec);
                if (len > -1) {
                    //OUTA |= LED2;
                    // read into packet packet
                    pkt = &queue[qhead];
                    pkt->length = len;
                    sum = 0;
      
                    // wait for packet              
                    waitcnt(CNT+CNT/100);
                    // get bytes while valid
                    for (n = 0; n < len; n++) {
                        byte = fdserial_rxTime((fdserial*)grec,10);
                        //byte = fdserial_rxCheck((fdserial*)grec);
                        if (byte < 0) break;
                        if (n < len-1) sum += byte;
                        pkt->data[n] = byte; // last byte is sum
                    }
                    
                    sum  &= 0xff;
                    byte &= 0xff;
                    
                    // if valid length and sum increment queue head
                    // otherwise recycle queue entry.
                    if (n > len-2) {
                        if (sum == byte)
                        {
                            //OUTA &= ~LED2;
                            qhead++;
                            qhead &= PACKET_QMASK;
                            qcount++;
                        }                    
                    }                    
                }               
            }            
        }        
        // don't exit function
    }
    
    
    int packet_make(packet_st *pkt, char *s, int len)
    {
        int n = 0;
        int sum = 0;
        
        pkt->length = len+1;
        
        for (n = 0; n < len && n < PACKET_DLEN; n++) {
            pkt->data[n] = s[n];
            if (n < len-1) sum += s[n];
        }        
        sum &= 0xff;
        pkt->data[n] = sum;
        //packet_print(pkt);
        return n;
    }
    
    
    int packet_send(fdserial *port, packet_st *pkt)
    {
        int n;
        //packet_print(pkt);
        writeChar(port, pkt->length);
        for (n = 0; n < pkt->length; n++) {
            writeChar(port, pkt->data[n]);
        }
        return 0;        
    }
    
    
    int packet_ready(void)
    {
        int rc = 0;
        if (qhead != qtail) rc = 1;
        return rc; 
    }
    
    
    int packet_read(packet_st *rxpkt)
    {
        packet_st *pkt = (packet_st*) &queue[qtail];
        memcpy((void*)rxpkt, (void*)pkt, sizeof(packet_st));
        qtail++;
        qtail &= PACKET_QMASK;
        return pkt->length;
    }
    
    
    int packet_print(packet_st *pkt)
    {
        int n;
        int len = pkt->length;
        printi("\npacket len %d : ", len);
        for (n = 0; n < len; n++) {
            printi(" %02x", pkt->data[n]);
        }
        printi("\n");
        return 0;
    }
    

    /**
     * @file packet.h
     */
    
    
    #ifndef __PACKET_H__
    #define __PACKET_H__
    
    
    #define CONS_RX 0
    #define CONS_TX 1
    #define CONS_MODE 0
    #define CONS_BAUD 115200
    
    
    #define PROD_RX 1
    #define PROD_TX 0
    #define PROD_MODE 0
    #define PROD_BAUD CONS_BAUD
    
    
    #define PACKET_DLEN 30
    
    
    #define PACKET_QLEN 16 // power of 2 for queue
    #define PACKET_QMASK (PACKET_QLEN-1)
    
    
    #include <stdint.h>
    #include "simpletext.h"
    #include "fdserial.h"
    
    
    typedef struct packet_struct {
        uint8_t length; // total packet length including length and checksum byte
        uint8_t data[PACKET_DLEN+1]; // add 1 for checksum
    } packet_st;
        
    void packet_start(fdserial *rec);
    void packet_stop(void);
        
    int packet_make(packet_st *pkt, char *s, int len);
    int packet_send(text_t *port, packet_st *pkt);
    int packet_ready(void);
    int packet_read(packet_st *pkt);
    int packet_print(packet_st *pkt);
    
    
    #endif
    
    
    
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 11:12
    Steve
    Try this generic packet code which does a loopback but could be used between boards. Byte receive timeout, packet length, and primitive checksum are included. Other packet items are left to the imagination.

    This can be used for a ASCII byte oriented transport layer. Making marshalling layer code like XDR is left as an exercise.

    Thanks, it looks very interesting and useful :) Of course I will have to study it for a while, just to be able to understand it, but I will study it. I am very curious about your use of:
    static volatile packet_st queue[PACKET_QLEN];
    static volatile int qhead = 0;
    static volatile int qtail = 0;
    static volatile int qcount = 0;
    

    Like I said, it will be very interesting to see how it all works.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 11:20
    Steve

    Thank you very much!!!!

    (void*) <- Key to removing all my warnings for volatile memcpy(s) and memset(s). Those warnings were annoying the bejeezers out of me.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-22 11:48
    For what it is worth.....

    Using a Propeller BOE for the attached code of Post #46 and using 470 ohm resistors for the serial connections, the baud rate can be increased to 230400 from the current 115200 full duplex serial settings.
Sign In or Register to comment.