Pages: 1 ... 26 27 [28]   Go Down
Author Topic: Cosa: An Object-Oriented Platform for Arduino programming  (Read 74073 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@kowalski
Hi Adam. I have push an IOBuffer update that should fix this issue. Please download and test it. There is also an update of the CosaBenchmarkUART to include large IOBuffers and burst write/measure.

You are a star! smiley

It works like a charm, now with the in buffer on faster interface 2048 and out buffer on slower interface 2048 I'm able to send around 4400 characters before it gets garbage. I can't measure exact because my Windows7+putty misbehave and it decides to slow down transmission unless I keep moving fast the mouse pointer within the putty window and I'm not sure if I move it fast enough to keep the transmission at 115200 smiley it's ridiculous I know and it had to happen right now ... (can you fix it as well smiley-wink)

Do you think I would be better leaving the Uart buffers default and create one big IOBuffer as the intermediate buffer or to leave the Uart buffers to deal with the transmission? 4096 is the max buffer size I can use from my understanding of the code, would some SPI RAM be useful in my scenario?
Did you ever think of porting Cosa on to the DUE board?

Kind regards,
Adam
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 434
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@g_ad

Around 4400 characters sound about right. That is the number of characters that would get sent before the large IOBuffers are filled up. For every 10 characters on the fast side one(1) character is sent on the slow side.

The next step is to get a measure on the maximum burst size and the minimum time between bursts to calculate the average bps.  

Using the IOBuffers for the UARTs is the simpler solution and it is possible to modify the IOBuffer to allow "any" size (ie remove the power of 2 restriction). This would allow you to use more of the Mega 1280 8K byte SRAM for the buffers.

Yes, it is possible to use SPI or extended SRAM. Typical size is 32 K byte. The interesting design would be to implement the IOBuffer interface with an IOStream::Device driver for these storage types. The UART requires an implementation of the IOStream::Device interface. It is possible to hook any implementation of the interface directly to the UART. The restriction is that putchar() cannot block as the UART will call that from the ISR and the implementation must not take longer time than the minimum time between received characters. Below is the "simple" Cosa OOP ISR for the RX interrupt.
Code:
void UART::on_rx_interrupt()
{
  m_ibuf->putchar(*UDRn());
}

Once and awhile I get the question of porting Cosa to other processors/boards. This will take some time before it happens. There are several issues. The one that is my greatest concern is adding the necessary components and infra-structure to allow scaling and reuse of libraries.

This implies a different approach with a micro kernel/multi-tasking, interfaces for applications and drivers, build system with libraries, delivery and support, etc. Cosa is moving slowly in this direction with the new build system, multi-tasking, etc, but there is a lot left before considering porting. Then there is the next issue which also goes for any hardware/device drivers added to Cosa; the software must be able to regression test. That implies a lot of hardware for other than my own projects. And suddenly this is not simply sharing any more.

I have done the numbers on software development for Due/Teensy3+/ARM with port and it is in the range of 2-3 man months (400-600 h, excluding the time needed to read up on all the hardware and build the necessary test setups). That is also difficult to motivate without a target application/project/etc of my own.

Cheers!
« Last Edit: July 21, 2014, 02:08:28 am by kowalski » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@kowalski

Thanks for the idea, I updated the sketch, adding the TIMEOUT as suggested - this really helped, as now i can do snmp requests and/or show the basic webpage without any problems.

I then tried to break the thing - opening the webpage in safari and tried to refresh the page as fast as possible.
I came to a state, when the webserver is no longer responding (roughly after 20 quick refreshes - you really need to use keyboard shortcut and hold the keys down). The snmp is working fine, and the arduino itself is ok, just the webserver is fried and does not respond anymore.

I tried to replicate the same thing on the webserver example, but after 100+ refreshes I stopped, this is working just fine.

Its not that big issue really, as in real life there wont be such a heavy traffic. Just wondering about ways to detect that the web is overrun and restart it. I will try to think about it tmrw and post some ideas.

cheers smiley
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 434
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Mispulin

Had another look at the HTTP::Server::run() member function and added an extra timeout after the client socket accept. This will catch client-side socket close before the HTTP message is actually received and gives more robustness. I tried to force the same situation as you described but did not get the web server socket to lock up.

Please give the update a try; https://github.com/mikaelpatel/Cosa/commit/b716ea0f4b3661e85d40d0e34601546c21df5b83

Cheers!
« Last Edit: July 21, 2014, 03:30:35 pm by kowalski » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@kowalski
Once and awhile I get the question of porting Cosa to other processors/boards. This will take some time before it happens. There are several issues. The one that is my greatest concern is adding the necessary components and infra-structure to allow scaling and reuse of libraries.

This implies a different approach with a micro kernel/multi-tasking, interfaces for applications and drivers, build system with libraries, delivery and support, etc. Cosa is moving slowly in this direction with the new build system, multi-tasking, etc, but there is a lot left before considering porting. Then there is the next issue which also goes for any hardware/device drivers added to Cosa; the software must be able to regression test. That implies a lot of hardware for other than my own projects. And suddenly this is not simply sharing any more.

I have done the numbers on software development for Due/Teensy3+/ARM with port and it is in the range of 2-3 man months (400-600 h, excluding the time needed to read up on all the hardware and build the necessary test setups). That is also difficult to motivate without a target application/project/etc of my own.

I'm far from asking or requesting porting, I really appreciate what you do for the community and really respect to your hard work, I was rather asking if this is something that you are actually thinking of ...
I'm rather beginner and rather not soon if at all I will be able to contribute anything myself apart form stress testing smiley-wink due to my professional life being too far from microcontrollers world smiley and family duties after, but I'm trying to mess a little bit every now and then smiley-wink.

I'd like to ask you question - I saw something on github I think about planning to implement some sort of command line interface in Cosa and I can't find it now - is this something that you work on at the moment?

Kind regards,
Adam
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 434
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@g_ad

I should work on shorter answers;-) Yes, I have considered porting to Arduino Due but it will take some time.

I just recently updated with a command line interface (Cosa/Shell.hh). That has been on the backlog for a long time, https://github.com/mikaelpatel/Cosa/issues/64. The example sketch is a simple shell with the basic file system commands (for Cosa Flash File System, CFFS, and the S25FL127S 16 Mbyte flash memory). Below is a snippet of some interaction with the example sketch. The "arduino$" is the prompt from the Anarduino Mini-Wireless http://www.anarduino.com/miniwireless/ that I am using for these tests.
Code:
user@host:~/Projects/Cosa/examples/Sandbox/CosaCFFSshell$ cosa miniwireless monitor
...
arduino:$ ls
.. Kalle Folder User
arduino:$ cat Kalle
0:A0 = 282
440876:A0 = 289
440868:A0 = 281
440852:A0 = 277
440844:A0 = 287
...
arduino:$ od Kalle
30 3a 41 30 20 3d 20 32 38 32 0a 34 34 30 38 37
36 3a 41 30 20 3d 20 32 38 39 0a 34 34 30 38 36
38 3a 41 30 20 3d 20 32 38 31 0a 34 34 30 38 35
32 3a 41 30 20 3d 20 32 37 37 0a 34 34 30 38 34
34 3a 41 30 20 3d 20 32 38 37 0a 34 34 30 38 33
...
arduino:$ cd User
arduino:$ ls
.. Nisse
arduino:$ cd Nisse
arduino:$ ls
..
arduino:$ date
2000-01-01 00:02:54
The command line handler will parse the command line into the typical main() function argument vector and count, do a table lookup and call the action function. To use the command line handler you have to define a string for the name of the command, a help string and the action function.  Below is the definition of the command "ls".
Code:
static const char LS_NAME[] __PROGMEM = "ls";
static const char LS_HELP[] __PROGMEM = "ls [--verbose] -- list files";
static int ls_action(int argc, char* argv[])
{
  bool verbose = false;
  if (argc == 2) {
    if (strcmp_P(argv[1], PSTR("--verbose")) == 0)
      verbose = true;
    else return (-1);
  }
  return (CFFS::ls(cout, verbose));
}
All the commands are collected in a table which is then used to drive the command line handler (shell). All data is in program memory. The __PROGMEM is defined in Cosa/Types.h and used to avoid compiler warnings in Arduino 1.0.X.
Code:
static const Shell::command_t command_vec[] __PROGMEM = {
  { 2, CAT_NAME, cat_action, CAT_HELP },
  { 2, CD_NAME, cd_action, CD_HELP },
  { 2, DATE_NAME, date_action, DATE_HELP },
  { 2, LS_NAME, ls_action, LS_HELP },
  { 2, MKDIR_NAME, mkdir_action, MKDIR_HELP },
  { 2, OD_NAME, od_action, OD_HELP },
  { 2, RM_NAME, rm_action, RM_HELP }
};
Shell shell(membersof(command_vec), command_vec);
The typical shell sketch has the following structure:
Code:
IOStream cout;
IOStream cin;

void setup()
{
  ...
  // Initiate UART for blocked read line
  uart.begin(9600);
  uart.set_blocking(SLEEP_MODE_IDLE);
  cin.set_device(&uart);
  cout.set_device(&uart);
  ...
}

void loop()
{
  // The shell command handler will do the top loop
  if (!shell.run(&cin, &cout)) return;
  cout << PSTR("illegal command") << endl;
}
Some links to further details. First the example sketch:
https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaCFFSshell/CosaCFFSshell.ino
https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaCFFSshell/CFFSshell.cpp
The interface and implementation of the command line handler:
https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/Shell.hh
https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/Shell.cpp

Cheers!
« Last Edit: July 22, 2014, 02:39:39 am by kowalski » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just recently updated with a command line interface (Cosa/Shell.hh). That has been on the backlog for a long time, https://github.com/mikaelpatel/Cosa/issues/64. The example sketch is a simple shell with the basic file system commands (for Cosa Flash File System, CFFS, and the S25FL127S 16 Mbyte flash memory). Below is a snippet of some interaction with the example sketch. The "arduino$" is the prompt from the Anarduino Mini-Wireless http://www.anarduino.com/miniwireless/ that I am using for these tests.
...

@kowalski

Thank you very much I'll have a look at it and try to learn something from the code.
Before I dig to get the answer myself, may I ask if the current implementation allow to use the command like:
"set terminal 1 baud 19200"?
or that would be far too complicated command line?

And one more from the code you've shared:
Code:
IOStream cout;
IOStream cin;

void setup()
{
  ...
  cin.set_device(&uart);
  cout.set_device(&uart);
  ...
}

of course that might be clear when I dig into the code but what hits me looking at it is that you declare two IOStreams - cout and cin and somehow for both you do the same set_device(&uart) so they kind of look the same to me ... sorry if this is one of the stupid questions.

Kind regards,
Adam
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 434
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Before I dig to get the answer myself, may I ask if the current implementation allow to use the command like:
"set terminal 1 baud 19200"?
or that would be far too complicated command line?
@g_ad

No problem using that command style. The parser will break it into the different elements and the action function will have to check and do any conversions (such as text to number). The linux command is "stty -F /dev/ttyS0 19200" http://pubs.opengroup.org/onlinepubs/007904975/utilities/stty.html or "setserial /dev/ttyS0 19200" if you would like to use that format. I would use something like "stty uart2 19200". Snippet of the action function for this command is:
Code:
static int stty_action(int argc, char* argv[])
{
  uint32_t baudrate = strtoul(argv[2], NULL, 10);
  if (baudrate < MIN_BAUDRATE || baudrate > MAX_BAUDRATE) return (-1);
  if (strcmp_P(argv[1], PSTR("uart1")) == 0) uart1.begin(baudrate);
  else if (strcmp_P(argv[1], PSTR("uart2")) == 0) uart2.begin(baudrate);
  else return (-1);
  return (0);
}
The function strtoul() is available in the AVR library http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#gaea44aa48bda8261f794dcb2d1e7ab2b2
And one more from the code you've shared:
Code:
IOStream cout;
IOStream cin;

void setup()
{
  ...
  cin.set_device(&uart);
  cout.set_device(&uart);
  ...
}
of course that might be clear when I dig into the code but what hits me looking at it is that you declare two IOStreams - cout and cin and somehow for both you do the same set_device(&uart) so they kind of look the same to me.

Might have been clearer to use two device, for instance, cin on uart and cout on lcd. The more important for the example was that the shell.run() is called with the IOStreams as parameters and that a prompt is written to the IOStream cout (if provided).

Cheers!
« Last Edit: July 22, 2014, 06:08:18 pm by kowalski » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No problem using that command style. The parser will break it into the different elements and the action function will have to check and do any conversions (such as text to number). The linux command is "stty -F /dev/ttyS0 19200" http://pubs.opengroup.org/onlinepubs/007904975/utilities/stty.html or "setserial /dev/ttyS0 19200" if you would like to use that format. I would use something like "stty uart2 19200". Snippet of the action function for this command is:
...
@kowalski

Thank you for all the advices, you have really great knowledge, I'm a bit jealous smiley-wink.
I already looked at the code and have to say that I'm a bit overwhelmed but not giving up - time to code some examples.

I couldn't find how to understand the "Required number of parameters" in the table:
Code:
static const Shell::command_t command_vec[] __PROGMEM = {
  { 2, CAT_NAME, cat_action, CAT_HELP },
  { 2, CD_NAME, cd_action, CD_HELP },
  { 2, DATE_NAME, date_action, DATE_HELP },
  { 2, LS_NAME, ls_action, LS_HELP },
  { 2, MKDIR_NAME, mkdir_action, MKDIR_HELP },
  { 2, OD_NAME, od_action, OD_HELP },
  { 2, RM_NAME, rm_action, RM_HELP }
};
Shell shell(membersof(command_vec), command_vec);
above you have declared 2 for every command but does it mean that every command can have one argument or has to have one argument? From above example it doesn't look like so I'm puzzled how to deal with this value. My real question is - if I would have commands:
terminal 1 name device1
terminal 1 baud 9600
terminal 1 start
terminal 1 stop
how would I deal with different number of options for the command: terminal?
This is just example, I still didn't figure out how exactly the commands will look like but I suppose I will have to stick to what I can actually code.

I looked at the function strtoul() and there is one potentially very dangerous problem - from the description "If no conversion could be performed, 0 is returned" so it looks like I would need to check if the converted argument contains only valid digit characters before conversion because I could ended up with function returning 0 after unsuccessful conversion and that would be big problem when 0 would be acceptable option - did I get it right?

Sorry for making you more busy that you already are and greatly appreciate your help.

Kind regards,
Adam

Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 434
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@g_ad

Hi Adam. Lets just say I have had a few more years to work on my programming skills. A lot of trail and error, teaching at university, building large software system, telecom systems and many-core operating systems for base-stations, and other frameworks.

Interesting questions you can back with. Actually the parameter and the options handling was something that I started refactoring after my last answer. Describing how to use something often has that effect :-)

The result after the refactoring is that 1) the expected argument count has been removed. The command action function is always responsible for checking the arguments, 2) there is a new member function that will parse options; shell.get(option, value). Below is a command action function from the update example sketch. It demonstrates the usage:
Code:
static const char ARGS_NAME[] __PROGMEM = "args";
static const char ARGS_HELP[] __PROGMEM = "args OPTS ARGS -- display options and arguments";
static int args_action(int argc, char* argv[])
{
  char* option;
  char* value;
  int i;
  while ((i = shell.get(option, value)) == 0)
    cout << PSTR("option: ") << option << PSTR(" value: ") << value << endl;
  while (i < argc)
    cout << PSTR("argument: ") << argv[i++] << endl;
  return (0);
}
The option syntax is a modified version of the standard getopt() function (and HTTP GET options); 1) -X single character option, 2) -XVALUE with value, 3) OPTION=VALUE option string with value. Below is example of interaction:
Code:
arduino:$ args -x -y10 -zabc a=10 b=nisse c=1.10 arg1 arg2
option: x value:
option: y value: 10
option: z value: abc
option: a value: 10
option: b value: nisse
option: c value: 1.10
argument: arg1
argument: arg2
To sum up the answer of your first question; The expected argument count is removed.

The next one; "potential danger with strtoul". Yes, you have to handle scan errors from the function. I took a short cut to show the principle. There are a lot more details to get robust code. The parameter that was NULL should be used to capture the end of scan and check that the whole string was parsed by strtoul. The slightly more robust version would be:
Code:
static int stty_action(int argc, char* argv[])
{
  if (argc != 2) return (-1);
  char* sp;
  uint32_t baudrate = strtoul(argv[2], &sp, 10);
  if (*sp != 0) return (-1);
  if (baudrate < MIN_BAUDRATE || baudrate > MAX_BAUDRATE) return (-1);
  if (strcmp_P(argv[1], PSTR("uart1")) == 0) return (uart1.begin(baudrate) ? 0 : -1);
  if (strcmp_P(argv[1], PSTR("uart2")) == 0) return (uart2.begin(baudrate) ? 0 : -1);
  ...
  return (-1);
}
Please see the latest update; https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/Shell.hh and https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaCFFSshell/CFFSshell.cpp

The next step of the command shell support will add simple scripting (i.e. reading commands from program memory or eemem). The will actually give two new interesting implementations of the Cosa IOStream::Device interface.  

Cheers!
« Last Edit: Today at 02:23:03 pm by kowalski » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@kowalski

Hi Adam. Lets just say I have had a few more years to work on my programming skills. A lot of trail and error, teaching at university, building large software system, telecom systems and many-core operating systems for base-stations, and other frameworks.
Wow, now I'm really jealous smiley-wink
Let's say I have bit less experience  smiley-lol - got kind of affected by the microcontrollers when I was learning in university, back when the 8051 was a king, I liked a lot the assembler and the only other coding they taught us was turbo pascal smiley, any way I didn't even have my own computer and couldn't afford it not mentioning any development board. Years past I was working and tried to reconnect with the 8051 but working for a living didn't really left time for anything else. Then was the time for AVR, trying to build my own board on atmega8, got the developmend board based on mega16 and trying .. assembler it smiley-wink. Then was the discovery of AVR-libc and learning C, then big changes in life, moving abroad ... always time was big issue. but somehow never gave up the passive passion smiley so recently I try again and have couple of real projects in mind - from house automation to some monitoring equipment for my work smiley.

Interesting questions you can back with. Actually the parameter and the options handling was something that I started refactoring after my last answer. Describing how to use something often has that effect :-)
I'm very happy to be at least some catalyser smiley-wink

The next one; "potential danger with strtoul". Yes, you have to handle scan errors from the function. I took a short cut to show the principle. There are a lot more details to get robust code. The parameter that was NULL should be used to capture the end of scan and check that the whole string was parsed by strtoul. The slightly more robust version would be:
Code:
static int stty_action(int argc, char* argv[])
{
  if (argc != 2) return (-1);
  char* sp;
  uint32_t baudrate = strtoul(argv[2], &sp, 10);
  if (*sp != 0) return (-1);
  ...
Thank you very much, got it. I wouldn't get the idea to check the pointers and would rather go the hard way and scan the string to check if it contains the digits  smiley-grin, so glad that you have sorted it in two lines of code smiley.

Thank you a lot for your input, I'll learn from the code and start experimenting.
The whole Cosa library is definitely the best thing I've found over the years of looking and planning - I really hope that it will help me actually do something finally smiley

Kind regards,
Adam
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 434
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@g_ad

Hi Adam. I have added a somewhat better example sketch to show how to use the Shell support; Below is a screenshot.



The command shell example CosaCFFSshell has been one of my test programs for the flash memory file system. Not very good to show how to use the Shell class, especially as it is evolving.

The new example sketch is a tiny Arduino command language with a small blink boot script. Hopefully this will give a better "introduction".

https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaShell/CosaShell.ino
https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaShell/Commands.cpp

Cheers!
« Last Edit: Today at 06:14:29 pm by kowalski » Logged

Pages: 1 ... 26 27 [28]   Go Up
Jump to: