Wixel Mesh Network?

I’ve been trying to understand how the radio works.
Got stuck on one point:

ISR(RF,0){ … }

what exactly (and where?) generates this interupt? I cannot find any mention of RF variable or procedure anywhere.

The radio hardware that is built into the CC2511F32 generates the interrupt. If you look in cc2511_map.h you can see that

ISR(RF, 0)

expands to:

void ISR_RF() __interrupt(RF_VECTOR) __using(0)

which in turn expands to:

void ISR_RF() __interrupt(16) __using(0)

–David

I see, thank you for the explanation.

2 more wixels arrived today. Will try to sniff the radio_link traffic tonight. As it turned out it doesn’t do much with just one unit.

Hello again. I’m fiddling about with the very simplistic mesh protocol. Need some advice.

in the radio_link library, are there any limits to the packet size?

If there are multiple devices within range of each other, how can I ensure they don’t interfere?

I may’ve just answered my own question. the 0 byte of the packet is the length, would that mean the max size is 255 bytes?

Hello.

The radio_link library is not suitable for making a mesh network unless you heavily modify it. You might want to use the radio_queue library instead.

Yes, there is a limit imposed by the radio_link library. See the documentation of radioLinkTxCurrentPacket for more info. If that limit is a problem, you could easily change the radio_link library to have a different limit in your copy of the Wixel SDK.

One way to avoid interference is to put groups of Wixels on different radio channels (at least 2 channels apart), but of course that defeats the purpose of making a mesh network. One way to help avoid packet collisions it to use some randomness in the timing of your packets. The radio_queue and radio_link libraries both do this.

–David

slowly learning how it all works.

I’m working with 3 wixels at the moment, 1 sniffer and a pair for development.

There is a slight problem: Every time I need to upload a modified app, I first need to shut down the listening console. After upload, the console needs to be reconnected. Also if the wixel gets disconnected from USB and reconnected back, the console needs to be restarted.

Do you know if there’s a way to keep a console in “listening” state? where it would passively listen to a particular port?

That would considerably speed up debugging.

No, I don’t know of any great way to solve those problems. As far as I know, that’s just how Microsoft’s USB-to-serial driver (usbser.sys) behaves. Only one program can have a handle open to the serial port at a time, and if you have a handle open while you are unplugging and replugging the device, bad things happen.

My one suggestion would be to use a terminal program that makes it easy to temporarily disconnect and reconnect. In Tera Term, I just press Ctrl+I to disconnect, but the Tera Term window still stays around. Then I press Alt+N and maybe a few other keystrokes to reconnect.

–David

Thanks, I’ll try that.

I’ve decided to start with discovery mechanism. So far, got the following working:

Master sends broadcast packet (senderID and recipientID are the same), those who hear it, respond and in turn send their own broadcast packet.

I’m modifying the adcRecport structure to make packets easier to manage:

struct adcReport{
uint8 length;
uint8 senderID[4];
uint8 recipientID[4];
} adcReport

the next step is to keep adding fields to the structure:

struct adcReport{
uint8 length;
uint8 senderID[4];
uint8 recipientID[4];
char command;
char data;
} adcReport

This is where the problems start. the data in the command field does not get transmitted correctly. I get garbage on the other end.

What is the correct way to send a string inside a packet?

Could the problem be because I’m creating a txPacket with adcReport type and converting to (uint8) later? (as required by radio_queue library)

You shouldn’t convert an adcReport to a uint8; you probably meant uint8 * which is different.

Basically you just need to make sure that your packet doesn’t exceed the the maximum length allowed by the radio_queue library and ensure that both sides of the transmission agree on the format of the packet. If you want to send a string, then you will need to put an array of chars or uint8s somewhere in the packet; “char data;” will hold a single character, not an entire string.

–David

Sorry, you’re absolutely right, my mistake.

i meant (uint8 *) txPacket;
also in the struct it was supposed to be

char * command;

which should allow me to store a string. I understand I need to put a null at the end.

I’ll check if the packet size is set correctly. I have to do it manually as, for some odd reason, sizeof(rfPacket) does not return the correct value of packet size.

As I said before, you should put a char array in your packet. You should NOT put a pointer to a char (char *) in the packet. That won’t work. A pointer is just the memory address of some data in the Wixel. Because different Wixels have different memories, the receiver Wixel can’t really do anything with a pointer that it gets from the transmitter Wixel. Instead you should transmit the actual data. For now, you should just set a maximum length for your strings and make a char array of that size.

struct mypacket
{
  char command[6];
}

–David

Hello again,

I’m trying to decide on the routing algorithm. One option is to have each node store the whole routing table. But it may grow rather large.

The spec sheet states that wixels have 4k of RAM and 29KB program memory size.

Is it possible to store data in the program memory area?

Hello, Armon.

Yes, you can read and write data from the flash (program) memory. Writing to flash is a lot harder than writing to RAM but it can be done. You can read about it in the “Flash Controller” section of the CC2511F32 datasheet.

–David

Encountered another problem.

After I tested broadcast->response mechanic with 4 wixels, I continued developing with only 2.

Right now, only 1 wixel can reply to broadcast. Powering on more than 1 will result either in no packets recieved or recieving packet from one of them, usually one with strongest signal.

I do not understand where I have gone wrong:

typedef struct header
{
    uint8 length;
    char type;
    uint8 senderID[4]; //
    uint8 recipientID[4];
    uint8 hops;
} header;

void transmitService()
{

    header XDATA * txPacket;
    static uint16 lastTx = 0;

    if ((uint16)(getMs() - lastTx) >= param_report_period_ms && (txPacket = (header XDATA *) radioQueueTxCurrentPacket()))
    {
        lastTx = getMs();
        memcpy(txPacket->senderID,serialNumber,4);
        memcpy(txPacket->recipientID,serialNumber,4);
        txPacket->length = sizeof(*txPacket);
  
        printf("sending packet from:%02X-%02X-%02X-%02X to:%02X-%02X-%02X-%02X %5u",
        		txPacket->senderID[3],
        		txPacket->senderID[2],
        		txPacket->senderID[1],
        		txPacket->senderID[0],
        		txPacket->recipientID[3],
        		txPacket->recipientID[2],
        		txPacket->recipientID[1],
        		txPacket->recipientID[0],
                   (uint16)getMs()
                   );
        (uint8) txPacket;
        radioQueueTxSendPacket();
    }
}

void respondToDiscovery(header XDATA * rxPacket)
{
		static uint16 lastTx = 0;
	    header XDATA * txPacket;
	    // We recieved discovery packet.
	    // respond with our serial number
	    if (txPacket = (header XDATA *) radioQueueTxCurrentPacket())
	      {
	        lastTx = getMs();
	        memcpy(txPacket->senderID,serialNumber,4);
	        memcpy(txPacket->recipientID,rxPacket->senderID,4);
	        txPacket->type = 'i';

	        txPacket->length = sizeof(*txPacket);
, sizeof(uint8),sizeof(int));
	        printf("command: %c, length: %d, full length: %d \n\r",txPacket->type, 1, txPacket->length);
	        (uint8) txPacket;
	        radioQueueTxSendPacket();
	      }


}

uint8 compareID(uint8 * id1, uint8 * id2){
	uint8 i;
 	for (i = 0; i < 4; i++)
 	{
 		if(id1[i] != id2[i])
 		{
 			return 0;
 		}
 	}
 	return 1;
}

void parse()
{
	header XDATA * rxPacket;
	if ((rxPacket = (header XDATA *)radioQueueRxCurrentPacket()) && usbComTxAvailable() >= 64)
	    {
		printf("\n\rnew packet: \r\n from:%02X-%02X-%02X-%02X to:%02X-%02X-%02X-%02X\n\r length: %i type: %c \n\r =========================\n\r",
					rxPacket->senderID[3],
	               rxPacket->senderID[2],
	               rxPacket->senderID[1],
	               rxPacket->senderID[0],
	               rxPacket->recipientID[3],
				   rxPacket->recipientID[2],
				   rxPacket->recipientID[1],
				   rxPacket->recipientID[0],
				   rxPacket->length,
				   rxPacket->type);
		(uint8) rxPacket;
			radioQueueRxDoneWithPacket();

		if(compareID(rxPacket->senderID,rxPacket->recipientID) == 1){
			printf("recieved broadcast\n\r");
			// respond to a broadcast
		      printf("\n\r responding to: %02X-%02X-%02X-%02X \n\r",
				               rxPacket->senderID[3],
				               rxPacket->senderID[2],
				               rxPacket->senderID[1],
				               rxPacket->senderID[0]
				               );
			  respondToDiscovery(rxPacket);
		}else if((compareID(rxPacket->recipientID,serialNumber) == 1)) {
			printf("recieved broadcast packet");

	    }else{
		      printf("recieved responce from: %02X-%02X-%02X-%02X",
		               rxPacket->senderID[3],
		               rxPacket->senderID[2],
		               rxPacket->senderID[1],
		               rxPacket->senderID[0]
		               );
		}
		putchar('\r');
		putchar('\n');
	    }
void getUSB(void)
{
	if(usbComRxAvailable())
    {
	uint8 usbCommand = usbComRxReceiveByte();

	switch(usbCommand){
		case 'm':
			toggleMasterMode();
			if(global_master_mode == 1)
				printf("mastermode activated, %i \n\r", global_master_mode);
			else
				printf("mastermode disabled, %i \n\r", global_master_mode);

			//toggle mastermode
			break;
		case 'b':
			initiateDiscovery();
			break;
		case 's':
			printStatus();
			break;
		case 'p':
			printRoutingTable();
			break;
		default:
			break;
	}
    }
}
void main(void)
{
    systemInit();
    usbInit();
    radioQueueInit();

    while(1)
    {
        updateLeds();
        boardService();
        usbComService();
        getUSB();
        parse();
        transmitService();
    }
}

}

or pastebin for some easier to read highlighting: http://pastebin.com/kT6g1MmB

Am I not using the TxQueue correctly? It was my understanding that it should check the channel is open before transmitting. Or am I not processing the packets fast enough?

The exact behaviour is this:

1 remote wixel: perfect, 100% responce
2 remote wixesl: 30-40% of responce from 1, 60% no responce at all.

I think i found the problem.

radio_queue.c

This layer does not transmit packets as quickly as possible; instead, it listens for incoming packets for a random interval of 1-4 ms between sending packets.

I have misunderstood what you said about the interval delay earlier. The delay is implemented between packets, so the radio can receive new ones and not before each individual packet.

In my app, the wixels respond to the broadcast at exactly same time, interfering with each other.
A short delay just before sending the packet should solve that.

Could you advice me on the best way to check if the channel is free after the delay?

Thanks!

You could try reading the RSSI register to see how strong the signal currently is, or check (PKTSTATUS & (1<<3)) like we do in radio_mac.c to see if the radio is in the middle of receiving a packet. I’m not sure how well either of those strategies will work. The basic problem is that it takes some time for the Wixel’s radio to change from RX to TX, and during that time its possible that another Wixel will start transmitting.

–David

Hello all,
This is a great thread! there is a lot of useful information here, but it seems like it died long time ago.

Have anyone finally figured out how to create a real Mesh network with the Wixels?

Thanks!

While I enjoyed programming the Wixels, I have since moved on to the Xbee Series 1 modules. You might want to look into these. Similar price, much better range and built in network that supports any node talking to any other node.

As far as the Wixel however, they don’t have a good range but are some tough little widgets. I’ve implemented a master/slave set of apps for them, if you would like some more example code to peruse there is a free download here:

http://servowidget.com/

Martin

While it reaches into the next room no problem, it will not cover the whole house.