for me it is very often useful to send and receive a single byte using VirtualWire.
Thus I am trying to write a wrapper around the vw_send, vw_get_message function
void vw_send_byte(byte b)
{
vw_send((uint8_t *)b, 1);
vw_wait_tx();
}
boolean vw_get_byte(byte& b)
{
uint8_t buf[1];
uint8_t buflen = 1;
boolean result = vw_get_message(buf, &buflen);
if (result)
b = buf[0];
return result;
}
However, it is not realiably working and sometimes has wrong output.
I don't know where the reason for this is, so maybe because of the difficulty in debugging wirelessly, there is also some other error source.
Maybe someone can help me to optimize a byte sending / receiving wrapper function for VirtualWire ?!
Anyone interested I have been working on a solution with partial success.
Feel free to optimize it
VirtualWire.cpp to be added beginning l.558
//////////////////////// MOD, >Pascal; 9.11.2012
void vw_send_string(String s)
{
char msg[99];
s.toCharArray(msg, 99);
vw_send((uint8_t *)msg, s.length());
vw_wait_tx();
/*
// 15 nov 13
// following code sends the variable as STRING (using sprintf is being formatted to string)
char buff[30];
sprintf(buff,"%i",b);
const char *msg0 = buff;
//const char *msg0 = b;
vw_send((uint8_t *)msg0, strlen(msg0));
vw_wait_tx(); // Wait until the whole message is gone
*/
}
boolean vw_get_string(String& str_out)
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
String r = "";
boolean result = vw_get_message(buf, &buflen);
// buflen now contains the actual received length
if (result)
{
for (int i = 0; i < buflen; i++)
{
char x = buf[i];
r.concat(x);
}
}
str_out = r;
return result;
}
void vw_send_byte(byte b)
{
/*
String s = "";
s.concat(char(b));
vw_send_string(s);
*/
/*
// 24feb13
vw_send((uint8_t *)b, 1); // wrong! needs to point to an array to be sent
vw_wait_tx();
*/
// 15 nov 13
byte tmp[1];
tmp[0] = b;
vw_send((uint8_t *)tmp, 1); // point to the array containing one octet
vw_wait_tx();
}
boolean vw_get_byte(byte& b)
{
/*
uint8_t buf[1]; //VW_MAX_MESSAGE_LEN];
uint8_t buflen = 1; //VW_MAX_MESSAGE_LEN;
*/
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
boolean result = vw_get_message(buf, &buflen);
if (result)
b = buf[0];
return result;
}
boolean vw_check_rxtx(byte b, unsigned int maxwait/* =500 */) //03Mar13-4NOV2013
{
byte r = 0;
vw_send_byte(b);
vw_wait_rx_max(maxwait);
return (vw_get_byte(r)) && (r == b);
/* other end:
if (vw_get_byte(b))
{
delay(50); //wait ca. <50ms because other end has to wait after waittx
vw_send_byte(b);
...
*/
}
// MOD: 03.JAN.2013
void vw_start_rx(int rxpin)
{
// do NOT use pin10 as RX because it is defined as ptt pin and output,
// alternatively change ptt_pin (unnecessary anyway)
// solved -> vw_set_ptt_pin(txpin)
vw_set_rx_pin(rxpin); // important! 24.FEB.13, first set pins THEN vw_setup!
vw_setup(2000);
vw_rx_start();
}
void vw_start_tx(int txpin, boolean dosetup/*=true*/)
{
vw_set_tx_pin(txpin); // first set pins then vw_setup !!!
vw_set_ptt_pin(txpin);
if (dosetup) vw_setup(2000);
}
void vw_start_rxtx(int rxpin, int txpin) // 03mar13
{
vw_start_tx(txpin,false); // do NOT vw_setup twice !
vw_start_rx(rxpin);
}
///////////////////// Mod, end //////
Get rid of support for Strings. There is no need to piss away resources uselessly. The VirtualWire class has a limit on the length of a message. C strings (NULL terminated array of chars) can be statically sized to match that limit, and are a much better way to send ASCII data.
Hello,
do you mean the maximal length of the receivebuffer is VW_MAX_MESSAGE_LEN.
So for receiving a string I initialize a buffer
uint8_t buf[VW_MAX_MESSAGE_LEN];
and actually in this buffer, the message is saved, but how do I modify the function header to
a char array instead of a String.
By statically sizing them, you mean
char result[VW_MAX_MESSAGE_LEN];
And as far as I know by regarding the code, the "&" sign after the data type and in fron of the variable name in a function header specifies the variable to be changed by the function.
What does the "*" (asterisk) sign stands for?
do you mean the maximal length of the receivebuffer is VW_MAX_MESSAGE_LEN.
Yes.
and actually in this buffer, the message is saved
Yes.
but how do I modify the function header to a char array instead of a String.
Change "String" to "char *".
By statically sizing them, you mean
char result[VW_MAX_MESSAGE_LEN];
Yes.
And as far as I know by regarding the code, the "&" sign after the data type and in fron of the variable name in a function header specifies the variable to be changed by the function.
Yes. It means "pass by reference" instead of "pass by value". The address of the variable is passed to the function, rather than the value in the variable. Since the function has the address, it can write to that address. Therefore, the changes that the function makes are persisted when the function ends.
What does the "*" (asterisk) sign stands for?
It means that the variable is a pointer. A pointer variable holds an address, rather than a value. When a pointer is dereferenced, the value that the pointer points to is obtained/replaced. Arrays and pointers are very closely related. Using an array name as an argument means the address of the first element, which is a what a pointer is.
Thank you very much for your detailed answer and I am glad to see you are also very familiar with VirtualWire.
Concerning your last answer:
I now understand very well how to use the ampersand like
get_byte(byte& b)
Where is the difference in using this and the asterisk?
So, when using the ampersand the address is sent and the function is able to change the passed variable.
For instance
function increase_value_by_999(int**&** x)
{ x += 999 }
int somevalue = 1;
increase_value_by_999(somevalue); Serial.print(somevalue); // should send 1000 to Serial monitor
And the asterisk also sends the address of the variable? Sorry to ask again, but this is not clear yet for me.
And the asterisk also sends the address of the variable?
Not exactly. The * defines the variable as a pointer (the value is an address). When you pass a pointer to a function, pass by value is still used, but the value is an address.
When you use a reference variable, pass by reference (passing the address of the variable, not the value of the variable) is used.
In either case, the called function has a address to work with, rather than a value, but the mechanism for working with the address is quite different. In the case of a reference variable, dereferencing is done automatically. You just treat the variable as a value. In the case of a pointer, you must manage the dereferencing (getting the value at the address/changing the value at the address).
You can't (easily) do pointer arithmetic on references so they are safer to work with. Most
bugs in C programs are due to erroneous pointer arithmetic and lack of array bounds
checks I think.
Concerning the function void "vw_send_string" I want a char array (C string) to be sent instead of a String.
I know that "vw_send" expects a pointer to be passed and a length of bytes beginning at this address to be sent.
I want a function call somehow like this:
char somestring[] = "Hello"; // automatically sets the size to 6 (5+1 for null termination)
vw_send_string(somestring); // call with variable passed
vw_send_string("World"); // call with string passed
It should be able to simply send a string.
Thus I have to define a function somehow like this:
void vw_send_string(char string[])
But why should it be sufficient to
PaulS:
but how do I modify the function header to a char array instead of a String.
Change "String" to "char *".
I should have to send an array and I was explained that array has often to do with asterisk usage.
So is your recommendation to use the asterisk to point to that array instead of passing an array?
I should have to send an array and I was explained that array has often to do with asterisk usage.
So is your recommendation to use the asterisk to point to that array instead of passing an array?
Re-read the part I wrote about arrays and pointers being very closely related. The function should take a pointer. You can pass an array, instead, and everyone's happy.
Of course, wrapping a function that takes a pointer to byte with one that takes a pointer to char is a waste of time. Just use the function that takes a pointer to byte, casting the char pointer/array:
char *stuffToSend = "Send this";
vw_send((byte *)stuffToSend, strlen(stuffToSend));
char moreStuff[32];
strcpy(moreStuff, "Send me to mars");
vw_send((byte *)moreStuff, strlen(moreStuff));
Do you mean, i could directly call this function when sending a message instead of using a wrapper whose only difference is to accept char instead of byte?
Do you mean, i could directly call this function when sending a message instead of using a wrapper whose only difference is to accept char instead of byte?
passes the address of "tmp" as read-only value as the first paramter to "vw_send"
And in the function header of "vw_send", there is written:
uint8_t vw_send(uint8_t* buf, uint8_t len)
after the data type of the first paramter, there is an asterisk, that means the first paramter is accessed via its address.
Additionally, it is expressed that buf is a unit8_t. However, later it is accessed as array like buf[i]
So don't I have to declare that buf is actually an array of uint8_t ? What is the advantage of passing its address?
I am trying to write a function sending 2 bytes at once.
This is my approach:
So don't I have to declare that buf is actually an array of uint8_t ?
What, exactly, is an array? It is a collection of contiguous memory locations (how many depends on the type and the size of the array). If you know where the first address is, you can access all the elements of the array.
That is why arrays and pointers are almost interchangeable.
Is there a possibility to simplify the process to split a 2 byte value into 2 one-byte values
Yes. The MSB and the LSB of the int are always stored in adjacent memory locations. So, you don't need to separate them into an array.
On the receiving end, you simply reverse the process. Pass the address of an int to the function that expects the memory location to store the bytes in. The bytes are stored in adjacent memory locations, in the order received (which matches the order sent).