Show Posts
|
|
Pages: [1] 2
|
|
1
|
Using Arduino / Audio / Re: toneAC v1.1 - Twice the volume, higher quality, higher frequency, etc.
|
on: May 06, 2013, 11:48:49 am
|
I don't have the code handy - but waaaay back when I was kid, I remember playing around on my TRS-80 Color Computer with the PLAY command; there was a way, via using certain values (I think random notes played with very, very short durations) with a rapidly decreasing volume level (the CoCo had a 6 bit DAC - so there were 64 volume levels) - you could make an "explosion" or "gun" sound of sort...
Nice to see a CoCo reference here... I recently ported a 1983 Extended Color BASIC program I wrote on the CoCo over to Arduino C (line by line, as literally as possible) and I put in a placeholder for the CoCo's SOUND command. It only took tone and duration, though. There was no built in provision to do noise or volume. But the Extended Basic PLAY command did allow volume and some great tricks could be done with it. I have been working on a PLAY command, and finding this thread is helpful as it sounds like it would be better to use than what I was working on.
|
|
|
|
|
3
|
Using Arduino / Programming Questions / Re: Function fails with passed in variable, but works if set manually.
|
on: April 10, 2013, 07:58:01 pm
|
|
westfw, no change on the parens. I really believe it's a compiler issue. It works fine, 100% of the time, with just the call, but place something else around it, and it stops working. When I got down to just doing a "delay(1);" and it broke, I pretty much gave up.
I developed my own routines for handling these items when I ported an old program that expected 21,000 bytes of RAM to work on the Arduino's 2K (just an impractical amount of array storage to be useful), but I really thought I could simplify things once I found that all the Print:: functions were already handling __FlashStringStorage* (so why do it twice).
If I find anything new, I will share it here.
|
|
|
|
|
4
|
Using Arduino / Programming Questions / Re: Function fails with passed in variable, but works if set manually.
|
on: April 10, 2013, 05:25:44 pm
|
Very good find! Thanks. But, I just did some checking, and moving that keyword changes the memory usage by 6 bytes, which is the size of the pointers (three 2 byte pointers). I think placing it there is just placing those pointers in RAM, like not having PROGMEM at all, which explains why it works. (I just did a test. Same free RAM by not using PROGMEM.) But I do believe this is a compiler thing. In my working code, I just retrieve the address using pgm_read_word() and pass that in: Serial.println((__FlashStringHelper*)pgm_read_word(flashArray+i));
But, if this one thing gets fixed to work consistently, I want to go to doing something like this: #ifdef USE_FLASH #define FLASHSTR PROGMEM #define FLASHCAST const __FileStringHelper* #else #define FLASHSTR #define FLASHCAST char * #endif
It's not quite flexible enough yet, but it allows me to have code that conditionally compiles to either put the strings in RAM (using FLASHSTR where we use PROGMEM now) or in Flash just by adding "#define USE_FLASH". If I have the RAM to spare, I'd rather use it and save some clock cycles. But, if I get to the point where RAM is more important, then I can enable that #define and everything magically switches. I am doing that now, but I had to put more code in and #ifdef things that *should* work with the casting alone, so they either use char* or pgm_read_work(). It works, but is a bit more to maintain. Thanks for that thread -- I will bookmark it. And some other tidbit... The prototypes are sometimes required to work around what may be another bug. I had a specific problem with an error saying a function of mine was being redeclared differently, even though it was only used once, and matched parameters exactly with the declaration in the same file. Adding the prototype allowed it to compile. I'm pulling my hair out over these things  But ... it's great stuff, and the tools are free, and I am the last person to complain about free! Thanks so much for the pointers!
|
|
|
|
|
5
|
Using Arduino / Programming Questions / Re: Function fails with passed in variable, but works if set manually.
|
on: April 10, 2013, 04:06:56 pm
|
|
Thanks, SurferTim. I actually have all of this working fine in my production code. I just noticed some very odd things and created this small example to replicate the problem.
With that array in PROGMEM, I have 1839 bytes free on my test program. With PROGMEM removed, it goes to 1833 bytes. The 6 bytes different is because each of those is a 2-byte pointer, so that makes sense. In my production code, I have a much much larger array of strings, and I am down to about 200 bytes free, so every little bit counts, which is what has me converting everything over to Flash storage right now.
It's just a weird thing. Everything works just fine, until code is added around it, then it breaks. I thought it had to do with the function() I was calling, but after I eliminated that I could break it without anything -- just by adding a "delay(1);" or similar around it.
I should probably learn how to read reported bugs, and how to submit ones I can't find already submitted.
|
|
|
|
|
7
|
Using Arduino / Programming Questions / Re: Function fails with passed in variable, but works if set manually.
|
on: April 10, 2013, 03:25:43 pm
|
|
Yes, I actually found that thread before when first researching PROGMEM. It is a very good one.
But this is actually a compiler question, not a PROGMEM question. My question here is what is the compiler doing to change things just by calling a Serial.println(). It's the third issue I have ran in to, with the last two being bugs requiring workarounds, and I am wondering if this is another one.
Looking at the source in Print.cpp, I see it has one that expects a "const __FlashSTringHelper *" and I am specifically casting to that. It looks like something may be trashing the stack or, perhaps, the preprocessor is misreading the source and changing the casting based on what it sees in the source code when that is there. (I am leaning to this second explanation, based on previous issues I have run in to.)
|
|
|
|
|
8
|
Using Arduino / Programming Questions / Re: Function fails with passed in variable, but works if set manually.
|
on: April 10, 2013, 02:32:25 pm
|
Here is a full example. The main for loop works and properly prints the strings. But, if you uncomment the "//Serial.println()" in thisFails(), it starts printing garbage. The duplicate print in "thisFails()" is what I was trying to do, but I have yet to get it to work. Simply having a Serial.println() causing it to not work clues me in that it may just be another oddity with the compiler preprocessor. #include <avr/pgmspace.h> const char string1[] PROGMEM = "This is string #1"; const char string2[] PROGMEM = "This is string #2"; const char string3[] PROGMEM = "This is string #3"; const char *flashArray[] PROGMEM = { string1, string2, string3 }; void thisFails(int i); void setup() { int i; Serial.begin(9600); while(!Serial); for (i=0; i<3; i++) { Serial.println((__FlashStringHelper*)flashArray[i]); thisFails(i); } showFreeRam(); } void loop() { } void thisFails(int i) { // Uncomment out the next line, and it stops working. //Serial.println("Comment this line out and it works."); // This is the line I want to work, but it always fails. BUT, // if you manually pass a number in to the flashArray[0], it // works, or if you set "i=0;" before it, it works. Weird. //Serial.println((__FlashStringHelper*)flashArray[i]); } // End of FlashTest
|
|
|
|
|
9
|
Using Arduino / Programming Questions / Function fails with passed in variable, but works if set manually.
|
on: April 10, 2013, 12:07:23 pm
|
Greetings. I have an array of Flash strings, and I can show them directly like this: Serial.println((_FlashStringHelper*)optCmd[0]);
I can also do that in a function: void thisWorks(byte i) { i = 0; // notice this override Serial.println((_FlashStringHelper*)optCmd[i]); }
...but if I pass in a 0, and even verify it by printing it inside, it prints garbage: void thisFails(byte i) { // i = 0; Serial.println((_FlashStringHelper*)optCmd[i]); }
I assume the preprocessor phase is doing something weird, but I have pruned this down to very simple code and cannot figure it out. Anyone know what is going on?
|
|
|
|
|
10
|
Using Arduino / Networking, Protocols, and Devices / Re: Ethernet showing garabage data available on initial connection to server
|
on: April 09, 2013, 09:30:58 am
|
|
This may be a "nevermind", but I will update the information here.
It seems some of my telnet clients are actually doing some Telnet protocol at the start, while others do not. On the ones I was testing, I see it is indeed sending the "WILL' and "WONT" packets, defining what the telnet client can handle.
So, not garbage. Telnet protocol. I didn't see this being handled in the examples I based my code on, but I will add it to mine and share the results.
|
|
|
|
|
11
|
Using Arduino / Networking, Protocols, and Devices / Ethernet showing garabage data available on initial connection to server
|
on: April 09, 2013, 09:08:14 am
|
|
Greetings. I am working with an UNO R3 and SainSmart Ethernet Shield (Wizpro W5100). I am writting a server, listening on port 23, and I am seeing garbage 24 bytes of data in the client buffer when they initially connect.
For instance, right now, I telnet in, then on the console I dump the data immediately waiting. It seems to follow this pattern:
FF FD 03 FF FB 18 FF FB 1F FF FB 20 FF FB 21 FF FB 22 FF FB 27 FF FD 05
Above, I was reading the data and printing it out to the console, but I see the same pattern again on the next connection.
Anyone know what I am running in to?
|
|
|
|
|
12
|
Using Arduino / Networking, Protocols, and Devices / Re: Ethernet Shield and multiple incoming connections of the same port? (BBS)
|
on: April 08, 2013, 10:14:47 pm
|
The following source contains a server example that *should* work, but does not because of a flaw in the Ethernet library. In the comments after it, I have a few changes you can make to the Ethernet library to allow multiple incoming connections to your server. Right now, the code just allows sending a rejection notice to additional connections, but I have some code I am working on that would allow multiple telnet sessions happening at the same time. Questions: 1. Should my new _dstport variable in EthernetClient.h also be static, like the _srcport? (Whis is _srcport static?) 2. In EthernetServer.cpp, the available() routine serves to establish a new connection, but you only know the connection is there if there is data to read. This requires the new telnet session to have to press Enter or something, which I do not think is proper behavior for telnet. In my "new connection" code, I tried just returning client and it worked like I expected (without needing to press Enter to make data for the server to see). I suspect there should really be a call to accept() or something first, before entering the available() loop. More to come... // MultiServer Demo
#include <SPI.h> #include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(10, 0, 0, 42);
EthernetServer server1(23); EthernetServer server2(23);
void setup() { Serial.begin(9600); while (!Serial);
// start the Ethernet connection and the server: Ethernet.begin(mac, ip); server1.begin(); server2.begin(); Serial.print("\nServer is listening at "); Serial.println(Ethernet.localIP()); }
void loop() { EthernetClient client2; // listen for incoming clients EthernetClient client1 = server1.available(); if (client1) { Serial.println("Client 1 connected."); client1.println("Greetings, program!"); while(client1.available()>0) client1.read(); // Gobble
// Loop while client is connected. while (client1.connected()) { // While we are connected, inform other attempts to connect that we are busy. client2 = server2.available(); if (client2) { Serial.println("Client 2 connected. Getting rid of them..."); client2.println("The system is busy. Try back later."); delay(1); client2.stop(); Serial.println("Client 2 disconnected."); } // Then handle the actual client. // If data is available, just read it and write it back to the user. if (client1.available()) { char c = client1.read(); Serial.write(c); } } // end of while... go back and do it again. // If here, we must no longer be connected. delay(1); // close the connection: client1.stop(); Serial.println("Client 1 disconnected."); } }
/*--------------------------------------------------------------------------*/ // To fix the Ethernet library so it correctly allows multiple connections // to the same port, the following files will need to be modified: // // libraries/Ethernet/Ethernet.h // libraries/Ethernet/Ethernet.cpp // // libraries/Ethernet/EthernetClient.cpp // libraries/Ethernet/EthernetClient.h // // libraries/Ethernet/EthernetServer.cpp
/*
Modify the following files:
1) Ethernet.h: The Ethernet object currently only tracks which Port the socket is listening to. Add the following array to hold the remote Port.
Add this after static "uint16_t _server_port[MAX_SOCK_NUM];"
// ACH - added static uint16_t _client_port[MAX_SOCK_NUM]; // ACH
2) Ethernet.cpp: Add the declaraction of the new array.
Add this after "uint16_t EthernetClass::_server_port[MAX_SOCK_NUM]"
// ACH - added uint16_t EthernetClass::_client_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; // ACH 3) EthernetClient.h: Add prototypes for the new functions, and declare a new local variable that will track the destination port of this client.
Add this in the private: section // ACH - added uint16_t _dstport; // ACH
// ACH - added uint8_t *getRemoteIP(uint8_t remoteIP[]); // ACH uint16_t getRemotePort(); // ACH 4) EthernetClient.cpp: When the Client object is created, it initializes the _server_port to zero. We should probably do this for the new _client_port.
Add after this: EthernetClass::_server_port[_sock] = 0;
// ACH - added EthernetClass::_client_port[_sock] = 0; // ACH
Add these two functions at the bottom of the file:
// ACH - added uint8_t *EthernetClient::getRemoteIP(uint8_t remoteIP[]) // ACH { W5100.readSnDIPR(_sock, remoteIP); return remoteIP; } uint16_t EthernetClient::getRemotePort() // ACH { return W5100.readSnDPORT(_sock); } 5) EthernetServer.cpp: This code has to be modified so when it checks for a connection, it checks both the Port (existing code) AND the remote client's port (new code). If the connection has never been made, it will initialize the remote port varaible correctly.
Add the following code to available()
EthernetClient EthernetServer::available() { accept(); for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { EthernetClient client(sock); if (EthernetClass::_server_port[sock] == _port && (client.status() == SnSR::ESTABLISHED || client.status() == SnSR::CLOSE_WAIT)) { // ACH - added // See if we have identified this one before if (EthernetClass::_client_port[sock] == 0 ) { client._dstport = client.getRemotePort(); EthernetClass::_client_port[sock] = client._dstport; } if (EthernetClass::_client_port[sock] != client._dstport) { // Not us! continue; } // ACH - end of additions if (client.available()) { // XXX: don't always pick the lowest numbered socket. return client; } } } return EthernetClient(MAX_SOCK_NUM); } ...and code to write():
size_t EthernetServer::write(const uint8_t *buffer, size_t size) { size_t n = 0; accept(); for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { EthernetClient client(sock); if (EthernetClass::_server_port[sock] == _port && // ACH - added EthernetClass::_client_port[sock] == client._srcport && // ACH client.status() == SnSR::ESTABLISHED) { n += client.write(buffer, size); } } return n; }
*/ /*--------------------------------------------------------------------------*/
|
|
|
|
|
13
|
Using Arduino / Networking, Protocols, and Devices / Re: Ethernet Shield and multiple incoming connections of the same port? (BBS)
|
on: April 08, 2013, 05:21:26 pm
|
|
Okay, that was a bit easier than I though it would be. I made a few minor additions to the Ethernet library, so now when a server connection is made, it records the remote client's port. Then instead of just snagging the first Wiz ethernet socket that matches the port (useless if you have more than one listening on the same port), it will check to see if it matches.
Now I can telnet in to my system, and it can be handling data, and I insert a second check inside that loop listening for another connection. If it gets one, it can send a "System is busy. Please try back later." message back.
I will clean this up then post it here, and maybe someone can verify that I am doing it the best way.
|
|
|
|
|
14
|
Using Arduino / Networking, Protocols, and Devices / Re: Ethernet Shield and multiple incoming connections of the same port? (BBS)
|
on: April 08, 2013, 02:26:29 pm
|
|
I have been looking through the source code and it seems with the Wiznet chip, all we have access to is 1-n connections and the port they connected on. So, if we listen on (23) and get a connection, we can write to it, but if another socket is also listening on (23), it seems it can indeed connect to it, but the library just finds the first (23) and returns that.
It does not look like this code could support multiple incoming connections unless they are on different ports. If it wasn't for NAT, I would think just tracking the remote IP would suffice, but it seems we would need more than that.
Has anyone done this? If not, I'll try to implement something and post it back.
|
|
|
|
|
15
|
Using Arduino / Storage / Re: Read integers from SD card
|
on: April 08, 2013, 09:22:04 am
|
|
Richard, send me a note if you open up another topic about memory issues and I will take a look. I recently learned quite a bit when I converted an old program that used to take about 21K to run (scaled down) in a 2K Arduino, so I had to use a ton of tricks to maximize what little memory I had.
|
|
|
|
|