davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

openvg not pthread compatible?

Wed Nov 04, 2015 5:55 pm

Just tried to run my UART communication program with openvg functions in a pthread task, now I get the error

Tx_master008: libshapes.c:571: End: Assertion `vgGetError() == VG_NO_ERROR' failed.

as long the function runs in main in an endless loop it works though -
what do I have to do?
I need the graphic window functionality also in pthread tasks... :!:

Code: Select all

/*     Tx master  
 *     Raspberry Pi 
 *     ============
 *   
 *     ver 0008
 *     Rasbian 8.0
       
 */
 
 
// (C) Helmut Wunder (HaWe) 2015
// freie Verwendung für private Zwecke
// für kommerzielle Zwecke nur nach Genehmigung durch den Autor.
// Programming language: gcc C/C++, Geany IDE
// protected under the friendly Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// http://creativecommons.org/licenses/by-nc-sa/3.0/
 


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <errno.h>
#include <pthread.h>

#include <termios.h>

#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
#include "shapes_plus.h"

#include <wiringPi.h>
#include <wiringSerial.h>

#define  byte  uint8_t

const    uint32_t UARTclock=115200;
char     * uart  =  "/dev/ttyAMA0";
int      Serial1;

 


//=====================================================================================
// C TOOLS
//=====================================================================================

// timer
// millis()
// micros()

//=====================================================================================

int kbhit(void)
{
  struct termios oldt, newt;
  int ch;
  int oldf;
 
  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
 
  ch = getchar();
 
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);
 
  if(ch != EOF)
  {
    ungetc(ch, stdin);
    return 1;
  }
 
  return 0;
}

//=====================================================================================
// openvg + shapes_plus
//=====================================================================================

int _scrwidth_, _scrheight_;

#define vgHidewindow  HideWindow
#define vgShowwindow  End
#define vgcls()       ClearWindowRGB(_scrwidth_, _scrheight_, 0, 0, 0);	
#define vgInit()      init(&_scrwidth_, &_scrheight_)
#define vgStart()     Start(_scrwidth_, _scrheight_)
#define vgCleanup     finish
#define vgSetcolor    Stroke
#define vgFill        Fill

int      _fontsize_ = 10;
Fontinfo _font_     = MonoTypeface;


inline void vgSetfontsize(int size) { _fontsize_ = size; }

inline void vgSetfonttype(Fontinfo myfont) { _font_ = myfont; }

inline void lcdprintxytop(float x, float y, char * buf) {
	Text(x, _scrheight_-y, buf, _font_ , _fontsize_); 
}

inline void lcdprintxy(float x, float y, char * buf) {
	Text(x, y, buf, _font_ , _fontsize_); 
}


void vgInitgraph() {
	vgInit();
    vgStart();
	
    vgcls();	
    
    vgSetcolor(255, 255, 255, 1);  // Set these at the start, no need to    
    vgFill(255,255,255, 1);        // keep calling them if colour hasn't changed
    vgSetfonttype(MonoTypeface);    
    vgSetfontsize(10);
}

//=====================================================================================
// DATA PACKAGES
//=====================================================================================

#define MAXMOTORS           6 // maximum number of encoder motors 
#define MAXANALOG          12 // maximum number of analog sensors 
#define MAXDIGPINS         16 // maximum number of digital pins 


#define OUT_REGSTATE_NUL            0
#define OUT_REGSTATE_COAST          2
#define OUT_REGSTATE_BRAKE          3
#define OUT_REGSTATE_EMERG_STOP     5
#define OUT_REGSTATE_ON             8

#define OUT_REGSTATE_PIDIDLE       15

#define OUT_REGSTATE_PIDACTIVE     16
#define OUT_REGSTATE_PIDRELATIVE   17
#define OUT_REGSTATE_PIDABSOLUTE   18
#define OUT_REGSTATE_PIDHOLD       19
#define OUT_REGSTATE_PIDHOLDCLOSE  20


#define SYNCSLOT      0  // start of this Msg 
#define CKSSLOT       1  // chksum this Msg 
#define DIGSLOT       2  // 2,3: digital Data bitpattern
#define ENCSLOT0      4  // motor 0 -7: 4,8,12,14,16,18,20,22
#define ENCSLOT1      8  // motor 1
#define ENCSLOT2     12  // motor 2
#define ENCSLOT3     14  // motor 3
#define ENCSLOT4     16  // motor 4
#define ENCSLOT5     18  // motor 5
#define ENCSLOT6     20  // motor 6 / optional: float 0
#define FLOATSLOT3   20  // optional: float3
#define ANASLOT0     24  // 24,26,28,30,32,34,36,38,40,42,44,46
#define ANASLOT10    44  // analog 10+11 / optional: float 1
#define FLOATSLOT4   44  // optional: float4

#define PWMSLOT0     24  // 24-39, pwm Dpin: D0-D16
#define MCMDSLOT0    40  // 40-47, motor cmd bytes by master, pwm -100..0..+100, 
                         //        brake -128 emergStop -127
                         //        PID rotate: abs./float 120 /stop 121 rel./float 122 /stop 123 /hold 124
#define MRUNSLOT0    48  // 48-55, motor runstate bytes returned to master
#define LAST8SLOT    55  // custom: float0 or int32
#define LAST4SLOT    59  // custom: float1 or int 32

volatile int8_t  digval[MAXDIGPINS];
volatile int16_t anaval[MAXANALOG];
volatile int32_t motenc[MAXMOTORS]; 

//=====================================================================================
// PARSER
//=====================================================================================

//************************************************************************************
// bit and byte and pin operations
//************************************************************************************
// convert byte arrays to int

inline int16_t  ByteArrayToInt16(uint8_t  array[], uint8_t  slot) {
  return ((array[slot + 1] << 8) + (array[slot]));
}

inline long  ByteArrayToInt32(uint8_t  array[], uint8_t  slot) {
  return ( (array[slot+3]<<24) + (array[slot+2]<<16) + (array[slot+1]<<8) + array[slot] );
}

//************************************************************************************
// convert int to byte arrays

inline void Int16ToByteArray(int16_t  integer, uint8_t  *array, uint8_t  slot) {
  array[slot]   = (integer & 0xFF); // loByte
  array[slot + 1] = (integer >> 8); // hiByte
}

inline void Int32ToByteArray(int32_t  int32, uint8_t  *array, uint8_t  slot) {
  array[slot]     = (int32 & 0xFF);         // loByte 8
  array[slot + 1] = ((int32 >>  8) & 0xFF); // intByte 16
  array[slot + 2] = ((int32 >> 16) & 0xFF); // longloByte 24
  array[slot + 2] = ((int32 >> 24) & 0xFF); // hiByte 32
}

//************************************************************************************
// read+write bits in numbers

#define bitRead(source, bit) ( ((source) >> (bit)) & 0x01 )

#define bitSet (source, bit) ( (source) |= (1UL << (bit)) )

#define bitClear(source, bit) ( (source) &= ~(1UL << (bit)) )

#define bitWrite(source, bit, bitvalue) ( bitvalue ? bitSet(source, bit) : bitClear(source, bit) )


//=====================================================================================

void parsercvbuf(byte * arr) {
	int i;
	
	for( i=0; i<8; ++i) {
		digval[i] = bitRead( arr[DIGSLOT], i);
	}
	for( i=0; i<8; ++i) {
		digval[i+8] = bitRead( arr[DIGSLOT+1], i);
	}
	
	motenc[0] = ByteArrayToInt32(arr, ENCSLOT0);
	motenc[1] = ByteArrayToInt32(arr, ENCSLOT1);
	for( i=2; i<MAXMOTORS; ++i) {
		motenc[i] = ByteArrayToInt16(arr, ENCSLOT3+i-2);
	}
	
	for( i=0; i<MAXANALOG; ++i) {
		anaval[i] = ByteArrayToInt16(arr, ANASLOT0+i);
	}


	
	
}

//=====================================================================================
// DISPLAY
//=====================================================================================

void displayvalues(int line, uint8_t array[]) {
  int cnt;
  char sbuf[128];
  
  vgcls(); 
 
  sprintf(sbuf, "Received:");
  lcdprintxytop(60, line+20, sbuf);     
  //printf(sbuf); printf("\n");
  
  
  for(cnt=0; cnt<16; ++cnt) {
    sprintf(sbuf, "%3d ", cnt);      // print cnt on TFT
    lcdprintxytop( (cnt+1)*60, line+40, sbuf);
    //printf(sbuf); 
  } 
  
  lcdprintxytop(60, line+80, "sync chksum TC bytes");
  for(cnt=0; cnt<2; ++cnt) {
    sprintf(sbuf, "%3d ", array[cnt]);      // print dig bitbytes on TFT
    lcdprintxytop( (cnt+1)*60, line+100, sbuf);
    //printf(sbuf); 
  }   
  
  lcdprintxytop(60, line+140, "digital bits/bytes");
  for(cnt=2; cnt<4; ++cnt) {
    sprintf(sbuf, "%3d ", array[cnt]);        // print dig 0-7 on TFT
    lcdprintxytop( (cnt+1-2)*60, line+160, sbuf);
    //printf(sbuf); 
  }  
  
  for(cnt=0; cnt<16; ++cnt) {
    sprintf(sbuf, "%3d ",  digval[cnt] );     // print dig 8-15 on TFT
    lcdprintxytop( (cnt+1)*60, line+175, sbuf);
    //printf(sbuf); 
  }  
  
  
  
  lcdprintxytop(60, line+200, "encoder bytes #0-2 2x long 1x short // #3-7 5x short");
  for(cnt=4; cnt<14; ++cnt) {
    sprintf(sbuf, "%3d ", array[cnt]);      // print enc bytes  
    lcdprintxytop( (cnt+1-4)*60, line+220, sbuf);
    //printf(sbuf); 
  }     

  for(cnt=14; cnt<24; ++cnt) {
    sprintf(sbuf, "%3d ", array[cnt]);      // print enc bytes  
    lcdprintxytop( (cnt+1-14)*60, line+235, sbuf);
    //printf(sbuf); 
  } 
  
  for(cnt=0; cnt<MAXMOTORS; ++cnt) {
	sprintf(sbuf, "%+010ld ", (long)motenc[cnt]);  // print enc  
    lcdprintxytop( 3+(cnt+1)*120, line+260, sbuf);
    //printf(sbuf);  
  }
  
  lcdprintxytop(60, line+280, "analog bytes #0-5x int // #6-11x int");
  for(cnt=24; cnt<36; ++cnt) {
    sprintf(sbuf, "%3d ", array[cnt]);      // print analog bytes 0-5
    lcdprintxytop( (cnt+1-24)*60, line+300, sbuf);
    //printf(sbuf); 
  } 

  for(cnt=36; cnt<48; ++cnt) {
    sprintf(sbuf, "%3d ", array[cnt]);      // print analog bytes 6-11
    lcdprintxytop( (cnt+1-36)*60, line+315, sbuf);
    //printf(sbuf);     
  } 
  
  for(cnt=0; cnt<MAXANALOG; ++cnt) {
	sprintf(sbuf, "%+06d ", anaval[cnt]);     // print analog values 0-11  
    lcdprintxytop( (cnt+1)*60, line+340, sbuf);
  }

  vgShowwindow();         // Show the graphic screen
  //printf("\n");
 
} 

//=====================================================================================
// SERIAL COMM
//=====================================================================================

const    uint8_t  MSGSIZE = 64;
uint8_t  bsync=255;
uint8_t  sendbuf[MSGSIZE];
uint8_t  recvbuf[MSGSIZE];


uint8_t calcchecksum(uint8_t array[]) {
  int32_t  sum=0;
  for(int i=2; i<MSGSIZE; ++i) sum+=(array[i]);
  return (sum & 0x00ff);
}

bool checksumOK(uint8_t array[]){
return (calcchecksum(array)==array[1]);
}

// ================================================================

bool addToBuffer( uint8_t buf[], uint8_t *cnt, uint16_t timeout){
bool inSync = *cnt>0;
unsigned long start=millis();
while((*cnt<MSGSIZE)&&(millis()-start<timeout)){
  if( serialDataAvail( Serial1 ) ) { // grab new char, test for sync char, if so start adding to buffer
    buf[*cnt] = (uint8_t)serialGetchar( Serial1 );
    if(inSync) *cnt += 1;  // my origional *cnt++ was updating the pointer address, not
                           // the pointed to sendbuffer
    else{
     if(buf[*cnt]==0xFF){
       inSync = true;
       *cnt +=1;
       }
     }
    }
  }
return (*cnt==MSGSIZE);
}


//=====================================================================================

bool receive(uint8_t * buf, uint16_t timeout, uint8_t *cnt){ // by passing cnt in and out,
// i can timeout and still save a partial buffer, so a resync costs less (less data lost)

bool inSync=false;
unsigned long start=millis();
uint8_t * p;  // pointer into buf for reSync operation
bool done=false;

do{
  done = addToBuffer(buf,cnt,timeout); // if this return false, a timeout has occured, and the while will exit.
  if(done){                         // do checksumOK test of buffer;
    done=checksumOK(buf);
    if(!done){                      // checksumOK failed, scan buffer for next sync char
       p = (uint8_t*)memchr((buf+1),0xff,(MSGSIZE-1)); //forgot to skip the current sync at 0
       
       
       if(p){ // found next sync char, shift buffer content, refill buffer
         *cnt = MSGSIZE -(p-buf); // count of characters to salvage from this failure
         memcpy(buf,p,*cnt); //cnt is now where the next character from Serial is stored!
         }
       else *cnt=0; // whole buffer is garbage
       }
    }
   
  } while(!done&&(millis()-start<timeout));

return done; // if done then buf[] contains a sendbufid buffer, else a timeout occurred
}

//=====================================================================================
// TASKS
//=====================================================================================

void* thread1_UART(void *)

{ 
  char     sbuf[128], ch, resOK;   
  static   uint8_t cnt=0; 
  uint8_t  cbuf[MSGSIZE], chk;

  while(1) {
     //   send to Rx slave Arduino
 
     //Serial.println(); 
     sendbuf[0]=bsync;
     sendbuf[1]=calcchecksum(sendbuf);
     
     write( Serial1, sendbuf, MSGSIZE );            // Send values to the Rx Arduino   
        
     //serialFlush( Serial1 );                              // clear output buffer
     
     //displayvalues(20, "Transmitted...: ", sendbuf);  
     //sprintf(sbuf, "%4d %4d", sendbuf[4], sendbuf[6]);
     //printf(sbuf); printf("\n");

 
     //     Receive from Rx slave Arduino

     memset(cbuf, 0, sizeof(cbuf)); 
   
     resOK = receive ( cbuf, 10000, &cnt);
 
     if( resOK ) {                         // byte 0 == syncbyte ?
        cnt=0;

        memcpy(recvbuf, cbuf, sizeof(cbuf));
       parsercvbuf(cbuf);
     
       displayvalues(10, cbuf);
    
 
       // debug: change values to send back!
       memcpy(sendbuf, recvbuf, sizeof(sendbuf));     // copy inbuf to outbuf
       //sendbuf[4]+=1;                                 // change [4] to send back
       
          
     }
     // debug...: careful!  effing slowing down!
     if( kbhit() ) {ch=0; while(ch!='\n') ch=getchar();  }
     //
     
     
   }
}



void* thread2_BUF(void *)
    {
        return NULL;
    }


//=====================================================================================

 
int main() {
    unsigned long timesav;
    char  sbuf[128];
    char  instr[128];
    pthread_t thread1, thread2;
     
    //printf("initializing..."); printf("\n"); 
    
    // UART Serial com port 
    Serial1 = serialOpen (uart, UARTclock); // for Arduino code compatibility reasons 
    
    // graphic screen
    vgInitgraph();    
       
    vgHidewindow();         // Hide the graphic screen     
    // debug
    // lcdprintxytop(50,  50, "press key to proceed");       
    
    // vgShowwindow();         // Show the graphic screen        
    // getchar();
     
    vgcls(); 
    
    pthread_create(&thread1, NULL, thread1_UART, NULL);
    pthread_create(&thread2, NULL, thread2_BUF, NULL);
    
    //wait for threads to join before exiting
     pthread_join(thread1, NULL);
     pthread_join(thread2, NULL);
   
    serialClose( Serial1);
    vgCleanup();
    exit(0);
}

//=====================================================================================
//=====================================================================================

#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

User avatar
Paeryn
Posts: 3171
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: openvg not pthread compatible?

Wed Nov 04, 2015 11:53 pm

An OpenVG context can only be used in the thread it is bound to, and it can only be bound to one thread at a time. You seem to have the context bound in the main thread and then spawn another and attempt to use it in that.

Ideally you'd have all openvg calls (create, use, destroy) in the one thread.

You can share a context between threads but you need to unbind it from the first thread before binding it to another. And since libshapes is handling the context for you, you can't do that because I don't think it gives you access to the needed data. If I get time tomorrow night I'll add a function to my fork of libshapes to do the bind/unbind for you, I don't think it needs much code to do it (famous last words).
She who travels light — forgot something.
Please note that my name doesn't start with the @ character so can people please stop writing it as if it does!

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: openvg not pthread compatible?

Thu Nov 05, 2015 7:59 am

perfect, thank you! :)

BTW: will those bind/unbind procedures cost a lot of cpu time or this perhaps as quick as just writing a few words to the screen?
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

User avatar
Paeryn
Posts: 3171
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: openvg not pthread compatible?

Thu Nov 05, 2015 12:41 pm

As long as you're not doing it constantly then it shouldn't be a problem. I think every time you unbind all pending graphics operations get flushed and possibly stalls the thread until it's done (I'm not too sure where the waiting will happen but the next bind won't take until the unbind has finished). You'll have a problem if you want multiple threads to all access openvg concurrently as that would potentially require lots of binding/unbinding.
She who travels light — forgot something.
Please note that my name doesn't start with the @ character so can people please stop writing it as if it does!

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: openvg not pthread compatible?

Thu Nov 05, 2015 2:25 pm

the program is for an autonomous map and explore robot, the situation is the following:
currently I'm monitoring for UART 64 outgoing bytes and 64 incoming bytes as quick as possible in 1 endless loop (a single display task dedicated for this, about 50 cycles/sec).
Now and then messages by different tasks had to be shown in the moment they are provided, not so quick, but nevertheless a 1-5 times each second, but it's not predictable when they occur as they are environmental, randomly.
A 3rd task is computing the environmental data and is plotting a room map and the driven path to the screen; this is done repetitively about 2 times each second.
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

Return to “C/C++”