This looks much better than before with typedef chanend and I think a compiler would stand a better chance of type-checking the protocol. Though in motor_controller you persist using the select statement with the control port in two case statements. This resembles PiXC using protocol cases in select statements for channel inputting. But PiXC doesn't describe the use of ports, and it breaks a fundamental in XC: each port and timer may appear in only one of the select case statements. This is because the XMOS architecture restricts each port and timer resource to waiting for just one condition at a time. So, is there a concept you want to express that I'm missing?...playing about with channel ends...
As before I tried an almost-XC-compileable (that gets similar compiler complaints about the chanend resource type) by fixing the select statement, and I also assume your channel broadcast pattern would be implemented using a process since channels are point-to-point resources in the XMOS architecture. And I've optimised use of stack memory a bit further, by receiving into mc member variables:
Code: Select all
/*
* main.xc - project typedef_chanend
*
* 26.june.2010
*
* www.xcore.com, forum:Group Discussion, author:Folknology
*
* The idea is a variation on the protocol, to 'type' channel endpoints using
* C unions, structures and typedef
*/
# include <platform.h>
# include <stdio.h>
typedef enum
{
SYNC
} channel_pattern;
{ chanend, chanend } new_channel( channel_pattern const );
typedef enum
{
START,
STOP
} Signal;
typedef struct {
Signal sig;
unsigned char msg[12];
} Message;
typedef struct {
chanend rx;
chanend tx;
union {
Message M;
Signal S;
} protocol;
} Messenger;
void motor_controller( Messenger mc, in port control ) {
Message motorStart = { START, "Starting " };
Message motorRestart = { START, "Restarting " };
int inp;
mc.tx <: motorStart;
while(1) {
control when pinsneq( 0x3 ):> inp;
{
if( 0x1 & inp ) {
mc.tx <: STOP;
}
else
if( 0x2 & inp ) {
mc.tx <: motorRestart;
}
}
}
}
void motor_driver( Messenger mc, out port motor ) {
while(1) {
select
{
case mc.rx :> mc.protocol :
{
switch( mc.protocol.S )
{
case START :
printf("Motor %s",mc.protocol.M.msg);
motor <: START;
break;
case STOP :
printf("Motor shutdown");
motor <: STOP;
break;
}
}
break;
}
}
}
in port control = XS1_PORT_1K;
out port motor = XS1_PORT_1L;
int main ( void ) {
Messenger mc;
{mc.tx, mc.rx} = new_channel(SYNC);
par {
motor_controller(mc,control);
motor_driver(mc,motor);
}
return( 0 );
}
Code: Select all
/*
* main.xc - project typedef_chanend with transaction
*
* 26.june.2010
*
* www.xcore.com, forum:Group Discussion, author:Folknology
*
* The idea is a variation on the protocol, to 'type' channel endpoints using
* C unions, structures and typedef.
*
*
* A transaction consists of a master thread and a slave thread running
* concurrently. It is used for an exchange of data between the two
* parallel threads.
*
* These master and slave keywords facilitate an asynchronous coupling,
* so that the master is not blocked when sending (up to the buffering
* capacity of a channel) if the slave is not ready to receive.
*
* Each transaction is permitted to communicate on precisely one channel.
* This ensures deadlocks do not arise due to an output on one channel
* blocking as a result of a switch being full with incoming data that
* is not yet ready to be received.
*
*/
# include <platform.h>
# include <stdio.h>
typedef enum
{
SYNC
} channel_pattern;
{ chanend, chanend } new_channel( channel_pattern const );
typedef enum
{
START,
STOP
} Signal;
typedef struct {
Signal sig;
unsigned char msg[12];
} Message;
typedef union {
Message M;
Signal S;
} protocol;
typedef struct {
chanend rx;
chanend tx;
protocol p;
} Messenger;
transaction outProtocol( chanend tx, Message msg )
{
switch( msg.sig )
{
case STOP :
{
tx <: msg.sig;
}
break;
case START :
{
tx <: msg;
}
break;
}
}
void motor_controller( Messenger mc, in port control ) {
Message motorStart = { START, "Starting " };
Message motorRestart = { START, "Restarting " };
Message stop = { STOP, " " };
int inp;
mc.tx <: motorStart;
while(1) {
control when pinsneq( 0x3 ):> inp;
{
if( 0x1 & inp ) {
master outProtocol( mc.tx, stop );
}
else
if( 0x2 & inp ) {
master outProtocol( mc.tx, motorRestart );
}
}
}
}
transaction inProtocol( chanend rx, protocol p )
{
rx :> p.S;
switch( p.S )
{
case START :
{
rx :> p.M;
}
break;
case STOP :
{
}
break;
}
}
void motor_driver( Messenger mc, out port motor ) {
while(1) {
select
{
case slave { inProtocol( mc.rx, mc.p ); } :
{
switch( mc.p.S )
{
case START :
printf("Motor %s",mc.p.M.msg);
motor <: START;
break;
case STOP :
printf("Motor shutdown");
motor <: STOP;
break;
}
}
break;
}
}
}
in port control = XS1_PORT_1K;
out port motor = XS1_PORT_1L;
int main ( void ) {
Messenger mc;
{mc.tx, mc.rx} = new_channel(SYNC);
par {
motor_controller(mc,control);
motor_driver(mc,motor);
}
return( 0 );
}