threading & debugging

New to XMOS and XCore? Get started here.
User avatar
msar
Member++
Posts: 19
Joined: Wed Sep 08, 2010 11:04 am

threading & debugging

Post by msar »

Hi everyone,

I'm stuck on some multithreaded programming, hoping someone can enlighten me. Here's the gist of what I'm trying to do:

- Run two threads - one for listening for input, and another for processing input.
- If no input has arrived when the processing thread finishes, it should just re-do its most recent setting.

I am getting hung up on how to communicate that the processing thread is finished, and thus the listener thread should finish its loop and start the next cycle.

Specifically:
Using the code below, I can't get the XC-1A to register any changes I submit to it. I don't see the return value get transmitted, and I don't see the "shutter" port close. The "debug" loop works properly, so I think the problem is not a deadlock with the "process" thread not sending its signal. Is the pinseq on rxd the wrong approach for the select statement?

Is there a better way to debug what the XC-1A is doing, besides xsim? If xsim is the only tool, how can I simulate user input to it?

Code: Select all


int main(void){
	chan nChan,setChan,processDone;
	char debug;
	configure_clock_rate (clk , 50 , 2);
	configure_out_port (shutter , clk , 0);
	start_clock(clk);
	debug=0;
	par{
		getSettings(nChan,setChan,processDone,debug);
		process(nChan,setChan,processDone);
	}
	return 0;
}

void getSettings(chanend nSetOut, chanend setOut, chanend processDone, char debug){
	unsigned char nSettings;
	timeset settings[100];
	char pDone;
	switch (debug)
	{
		case 1:
		{
			while(1)
			{
				nSettings=2;
				settings[0].nacqs=4;
				settings[0].stime=500;
				settings[0].shutterUnits='m'; //milliseconds
				settings[0].setupDelay=100;
				settings[0].setupUnits='m';
				settings[1].nacqs=2;
				settings[1].stime=2;
				settings[1].shutterUnits='s'; //milliseconds
				settings[1].setupDelay=2;
				settings[1].setupUnits='s';
				nSetOut <: nSettings;
				setOut <: settings[0];
				setOut <: settings[1];
				processDone :> pDone;
			}
			break;
		}

		case 0:
		{
			nSetOut <: 255;  // set the shutter initially open
			while(1)
			{
				select
				{
					case processDone :> pDone: //timeout, process is ready for another round
					{
						nSetOut <: nSettings;
						if (nSettings > 0 && nSettings < 255){
							for (int i = 0; i < nSettings; i += 1) {
								setOut <: settings[i];
								}
						}
						break;
					}
					case rxd when pinseq (0) :> void:
					{
						nSettings=rxByte();
						txByte(255);
						nSetOut <: nSettings;
						if (nSettings > 0 && nSettings < 255)
						{
							for (int i = 0; i < nSettings; i += 1) {
								settings[i].nacqs=rxByte();
								settings[i].setupDelay=rxInt();
								settings[i].setupUnits=rxByte();
								settings[i].stime=rxInt();
								settings[i].shutterUnits=rxByte();
								setOut <: settings[i];
							}
						}
						break;
					}
				}
			}
			break;
		}
	}
}

void process(chanend nSetIn, chanend setIn, chanend processDone){
	timeset settings[100];
	int nSettings;
	char pDone=1;

	while(1){
		nSetIn :> nSettings;
		if (nSettings == 0){
			shutter <: 0;
			wait(50000000);
		}
		else if (nSettings == 255){
			shutter <: 1;
			wait(50000000);
		}
		else
		{
			for (int i = 0; i < nSettings; i+=1){
				setIn :> settings[i];
				for (int j = 0; j < settings[i].nacqs; j += 1){
					setDelay(settings[i].setupDelay,settings[i].setupUnits,0);
					//notscan when pinseq (1) :> void;
					setDelay(settings[i].stime,settings[i].shutterUnits,1);
					//notscan when pinseq (0) :> void;
				}
			}
		}
		processDone <: pDone;
	}
}


User avatar
waluigi
Member++
Posts: 22
Joined: Sun Nov 07, 2010 6:33 pm

Post by waluigi »

Run a debug configuration from the IDE and step through the code?
User avatar
bsmithyman
Experienced Member
Posts: 126
Joined: Fri Feb 12, 2010 10:31 pm

Post by bsmithyman »

Hi msar,

I'm not sure from context whether you were asking this, but as waluigi was saying it is possible to debug the application on the XC-1A itself. You can see what's holding things up in the debug viewer, and that might give you some insight.

It seems like the two threads have a few places where they might deadlock. For example, if the UART is faster than the shutter and there's a delay on one of the channel writes, you may miss information on the UART. I'm not sure if you have flow control implemented separately. If not, with the way things are set up there's no real room for error - if it misses a bit it's likely the command thread will get stuck in the UART reads while waiting for a larger datatype than is coming across the line. I'd try to separate things a bit more. One option would be to read in all of the instructions over UART, dump them all across to the other thread, and then start the shutter process from the cached list, rather than the current interactive process. You could still include a way to interrupt it, but that would give you a much coarser-grained parallelism that might be easier to debug.

Hopefully this helps :)
User avatar
msar
Member++
Posts: 19
Joined: Wed Sep 08, 2010 11:04 am

Post by msar »

Bsmithyman and waluigi, thanks for your replies. The debugger in the IDE actually runs the code on the card? It was running at a speed more like the simulator, so I assumed it was running on the simulator.

The cached input method is exactly what I was aiming to do. I guess I'm not clear on how to achieve that, but I'll spend some more time pondering it and reading up.
User avatar
waluigi
Member++
Posts: 22
Joined: Sun Nov 07, 2010 6:33 pm

Post by waluigi »

On the "debug configurations" page you can select simulator or hardware.
User avatar
msar
Member++
Posts: 19
Joined: Wed Sep 08, 2010 11:04 am

Post by msar »

nice! thanks! This makes debugging my silly delay loops much better.
User avatar
msar
Member++
Posts: 19
Joined: Wed Sep 08, 2010 11:04 am

Post by msar »

Hi guys,

I hope I'm getting closer here. Compared to before, I have tried to change the code to cache any settings, rather than transmitting them each time. I'm still hung up, though - when my process thread sends it's "I'm done here" signal over process_ch, I get an 'ET_ILLEGAL_RESOURCE' error that suspends my getSettings thread.

Any ideas on what could be causing this?

New code below:

Code: Select all

void getSettings(chanend out_ch, chanend process_ch, char debug){
	unsigned char nSettings;
	timeset settings[255];
	char pDone;
		while(1)
		{
			select
			{
				case process_ch :> pDone: //timeout, process is ready for another round
				{
					out_ch <: 0;
					break;
				}
				case rxd when pinseq (0) :> void:
				{
					// wait for process to finish
					process_ch :> pDone;
					// tell process to wait for new input
					out_ch <: 1;
					// tell computer you're ready for data
					txByte(255);
					nSettings=rxByte();
					out_ch <: nSettings;
					if (nSettings > 0 && nSettings < 255)
					{
						for (int i = 0; i < nSettings; i += 1) {
							settings[i].nacqs=rxByte();
							settings[i].setupDelay=rxInt();
							settings[i].setupUnits=rxByte();
							settings[i].stime=rxInt();
							settings[i].shutterUnits=rxByte();
							out_ch <: settings[i];
						}
					}
					break;
				}
			}
		}
}


void process(chanend in_ch, chanend process_ch){
	timeset settings[255];
	int nSettings;
	char stop;

	nSettings=255;

	while(1){
		if (nSettings == 0){
			shutter <: 0;
			setDelay(750,'m',0,0);
		}
		else if (nSettings == 255){
			shutter <: 1;
			setDelay(750,'m',1,1);
		}
		else
		{
			for (int i = 0; i < nSettings; i+=1){
				for (int j = 0; j < settings[i].nacqs; j += 1){
					setDelay(settings[i].setupDelay,settings[i].setupUnits,0,0);
					//notscan when pinseq (1) :> void;
					setDelay(settings[i].stime,settings[i].shutterUnits,1,0);
					//notscan when pinseq (0) :> void;
				}
			}
		}
		// is one of these blocking?  Does the receiver function have to first synchronously receive process_ch before it can send the in_ch?
		process_ch <: 1;
		in_ch :> stop;
		if (stop == 1) {
			in_ch :> nSettings;
			if (nSettings > 0 && nSettings < 255) {
				for (int i = 0; i < nSettings; i+=1){
					in_ch :> settings[i];
				}
			}
		}

	}
}
User avatar
msar
Member++
Posts: 19
Joined: Wed Sep 08, 2010 11:04 am

Post by msar »

never mind. It was an error in types. I had created the receiving variables in each function as chars. However, when I output a value, it was an integer.

I fixed it by defining char values. Like this:
replace this:

Code: Select all

out_ch <: 1;
with this:

Code: Select all

char GO=1;
out_ch <: GO;
works fine now.