Go Down

Topic: How do we copy a section of a char array that doesn't start at the beginning? (Read 1 time) previous topic - next topic

StuHooper

If I want to split a 140 char array into chars of 21 length  for display on an LCD screen, what command/s do I need to do so?




StuHooper

I have looked through http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html but I can't seem to find anything that will copy from a certain point within the array.

Delta_G

Make a pointer to the element you want to start with and use it as an array name.  It will work just like an array that starts where you pointed to.

bperrybap

IF the goal is really line wrapping there are other ways to handle this.

--- bill

Tom Carpenter

If you are trying to text wrap with the gLCD library, that feature will be built into v3.1 which should be ready tonight or tomorrow.
~Tom~

StuHooper


IF the goal is really line wrapping there are other ways to handle this.

--- bill


Care to elaborate? I have a 140 word tweet that regularly changes. I need to draw it across 6 21 character lines at the bottom of a sparkfun color LCD shield.

Any method you have of doing this will be an education to me.


If you are trying to text wrap with the gLCD library, that feature will be built into v3.1 which should be ready tonight or tomorrow.


That's great news Tom. I'll keep an eye out for it. The more methods I learn, the quicker I'll stop asking questions and be able to help more.

bperrybap



IF the goal is really line wrapping there are other ways to handle this.

--- bill


Care to elaborate? I have a 140 word tweet that regularly changes. I need to draw it across 6 21 character lines at the bottom of a sparkfun color LCD shield.

Any method you have of doing this will be an education to me.

A simplistic way would be printing a single character a time from your string.
When you have printed the number of characters
on a line (21 in this case) drop to the next line

The current gLCD code looks like it support newline processing so when ready to drop to the next line
simply send a newline '\n' before continuing to print the remaining characters.

--- bill


bperrybap


If you are trying to text wrap with the gLCD library, that feature will be built into v3.1 which should be ready tonight or tomorrow.


I'm curious how you will handle this.
There are many little issues and options related to wrapping, newline vs <CR> processing, and how
to handle things when you reach the very last character of a line and the bottom line of a text area.
For example, does <CR> wrap back to column 0?  To allow easy over writing of the line.
If so, you can can't drop the cursor position to the next line until you print the next character *after*
the wrap point.
Otherwise you won't be able to draw a full line of text and overwrite it by using <CR>.

Does the full line of text on the line being wrapped to get fully erased when an auto wrap/newline occurs?

Then there is the issue of how to handle wrapping of the very last line.
Does the text area scroll after that, does the text wrap to the top line or does it just start
throwing away the text.

The most painful to deal with is supporting a single line text area.
Users want and expect to be able to do this:
lcd.println("my new line");
And have each line show up erasing the previous line.
But technically if you process the newline as you see it, and support scrolling, or automatically
erasing a line that is wrapped to, you end up scrolling out the very line that they just printed.

In the big picture, handling this single line case is the same as having to deal with allowing
printing of a full line when you support erasing the line wrapped to.
You have to defer the wrap and newline processing until *after* the next character after the wrap
point is printed.

Lots of little details to think about.

--- bill

MichaelMeissner

#8
Oct 12, 2012, 07:42 pm Last Edit: Oct 12, 2012, 07:45 pm by MichaelMeissner Reason: 1

If I want to split a 140 char array into chars of 21 length  for display on an LCD screen, what command/s do I need to do so?

Memcpy is your friend:

Code: [Select]

#include <string.h>

static const int lcd_width = 20;

void print_large_array (const char *array, size_t len)
{
   char small_array[lcd_width+1];

   if (len == 0)
       len = strlen (array);                // figure out length if not passed

   while (len > 0) {
       // only print 20 characters per line
       size_t len2 = (len > lcd_width) ? lcd_width : len;
       memcpy ((void *)&small_array[0], (void *)array, len2);
       small_array[len2] = '\0';          // add terminating null for println
       lcd.println (small_array);
       array += len2;                        // reset pointer/len for next iteration
       len -= len2;
   }
}


Note, that memcpy assumes the source and destination do not overlap.  If they do overlap, you should use memmove instead.

Alternatively if you are using the raw array and not a pointer to it, you could do it as:

Code: [Select]

#include <string.h>

static const int lcd_width = 20;

void print_large_array (const char *array, size_t len)
{
    char small_array[lcd_width+1];
    size_t start = 0;

    if (len == 0)
        len = strlen (array);                // figure out length if not passed

    while (len > 0) {
        // only print 20 characters per line
        size_t len2 = (len > lcd_width) ? lcd_width : len;
        memcpy ((void *)&small_array[0], (void *)&array[start], len2);
        small_array[len2] = '\0';          // add terminating null for println
        lcd.println (small_array);
        start += len2;                        // reset pointer/len for next iteration
        len -= len2;
    }
}


This program logically does:

Code: [Select]

static const int lcd_width = 20;

void print_large_array (const char *array, size_t len)
{
   size_t i;
   char small_array[21];

   if (len == 0)
       len = strlen (array);                // figure out length if not passed

   while (len > 0) {
       size_t len2 = (len > lcd_width) ? lcd_width : len;
       for (i = 0; i < len2; i++)
           small_array[i] = array[i];

       small_array[len2] = '\0';
       lcd.println (small_array);
       array += len2;                        // reset pointer/len for next iteration
       len -= len2;
   }
}

Tom Carpenter



If you are trying to text wrap with the gLCD library, that feature will be built into v3.1 which should be ready tonight or tomorrow.


I'm curious how you will handle this.
There are many little issues and options related to wrapping, newline vs <CR> processing, and how
to handle things when you reach the very last character of a line and the bottom line of a text area.
For example, does <CR> wrap back to column 0?  To allow easy over writing of the line.
If so, you can can't drop the cursor position to the next line until you print the next character *after*
the wrap point.
Otherwise you won't be able to draw a full line of text and overwrite it by using <CR>.

Does the full line of text on the line being wrapped to get fully erased when an auto wrap/newline occurs?

Then there is the issue of how to handle wrapping of the very last line.
Does the text area scroll after that, does the text wrap to the top line or does it just start
throwing away the text.

The most painful to deal with is supporting a single line text area.
Users want and expect to be able to do this:
lcd.println("my new line");
And have each line show up erasing the previous line.
But technically if you process the newline as you see it, and support scrolling, or automatically
erasing a line that is wrapped to, you end up scrolling out the very line that they just printed.

In the big picture, handling this single line case is the same as having to deal with allowing
printing of a full line when you support erasing the line wrapped to.
You have to defer the wrap and newline processing until *after* the next character after the wrap
point is printed.

Lots of little details to think about.

--- bill


Basically text wrapping is part of the font. In order to have compatibility with older programs that don't expect wrapping:
setFont(someFont);
prints the font with text wrapping disabled.

To turn it on, you would use this:
setFont(someFont, WrapText);
Where wrapText is a #defined constant. It will automatically turn off again next time you set the font.


If the text goes beyond the bottom of the screen, in the current version it is just truncated. The size returned from the write() function in arduino 1.0+ is reduced to the number of characters actually printed.
When the end of a line is reached, if there is not enough space on the line for another character, the rest of the line from the end of the prior character to the edge of the screen is filled with the background colour (unless the background is transparent), and the character is printed just below on the next line.
Conversely if a '\n' is used to drop to a new line, the end of the line (from the end of the last character on the line to the edge of the screen) is not filled in the background colour.

At the moment it doesn't account for whole words, so it just chops the string mid word. In future versions I may add the ability to wrap in a way which keeps whole words together, but to keep printing as fast as possible, this is not yet implemented.

Furthermore, the last line of a wrapped string does not currently blank the full line, only what is needed. I might add an option to allow the bounding box of the printed text to be set to the background colour.
~Tom~

Tom Carpenter

I'm afraid you may have to wait until Monday or Tuesday for version 3.1 as I had to work Saturday, so didn't get a chance to finish writing the new examples.
~Tom~

StuHooper



If I want to split a 140 char array into chars of 21 length  for display on an LCD screen, what command/s do I need to do so?


This program logically does:

Code: [Select]

static const int lcd_width = 20;

void print_large_array (const char *array, size_t len)
{
   size_t i;
   char small_array[21];

   if (len == 0)
       len = strlen (array);                // figure out length if not passed

   while (len > 0) {
       size_t len2 = (len > lcd_width) ? lcd_width : len;
       for (i = 0; i < len2; i++)
           small_array[i] = array[i];

       small_array[len2] = '\0';
       lcd.println (small_array);
       array += len2;                        // reset pointer/len for next iteration
       len -= len2;
   }
}



Thanks. I found this works, although due to having to draw a graphic.box to the screen before each line of code, I can't have it scrolling very fast. This seems to be interfering with my Ethernet connection as it's holding up my loop();

Go Up