Rather difficult question to ask but bare with me please. This is also my first post.
I have a setup which involves a Raspberry Pi, PC and Zigbee comms. Coding language i'm using is Java.
Ok, so my design involves my Pi taking a photo with the Pi camera and transmitting it to PC through zigbee comms.
My problem is when I run the code the first time, it works no problem and jpg image is transmitted and saved to PC. But when I go to execute the code again (without restarting the execution of the code) basically I want to be able to have the code running on the Pi indefinitely and let the PC send a signal at any moment in time to tell it to begin transmission.
So, I have an event handler on the Pi side in a method called connect() that if it receives a certain string it is to execute a method. There are 3 methods getImage,getSize and run. There strings are "" ":|" and "" respectively.
So PC sends "" to Pi which is in connect method until told otherwise, reads in string from port and triggers if loop for that string which for now is getImage. Then sends back a string "Image cropped successfully" which is read by the PC in a while loop, once it gets this string it then sends ":|" to the Pi to get the filesize. Once filesize is received at PC it then sends "" to begin transfer of image.
This all works fine and dandy for first execution, but on second execution the PC sends "" to getImage, does its stuff and Pi sends back "Image cropped successfully". The minute that is returned a random "" appears on the Pi side and begins to execute the getImage method again which in turn messes up the whole sequence of events.
The code for PC and Pi is attached, I'm relatively new to Java so please understand if my code is rough. Suggestions for improvement are welcome. Any help on this issue is appreciated as I have exhausted my debugging ideas. As you can see in code I have println thrown around alot to see the different steps.
Welcome to CodeRanch!
That's a lot of code which makes it difficult to provide comments on. One approach to troubleshooting is to create a SSCCE. Can you try making the code shorter/simpler to illustrate the problem? You may find the problem goes away in which case you put back that step and post here with the troublesome step. Or you may wind up with a small test example.
Yes, sorry for the length of code posted, but at present i'm unsure of where the issue is. So its difficult to decide which piece of code is relevant. But saying that, there is only one area on the PC code side that has the "" string in order to write it to the port (below). That string is acknowledged on the Pi side and the assigned method is initiated.
I was thinking today, that it maybe the fact that I am using a thread in my GUI class to run the program, which at the moment I don't think is being closed after each transmission (should it be closed?). So possibly when the code runs again, it starts a new thread, so then 2 threads are running the same code at same time?
If so, how do I close the thread, there's warnings all over the internet about not using Thread.close(); or Thread.destroy();
My GUI method to start thread
My suggestion would be to look at every variable you declare as a member variable and see if you can either move it into a method local scope or make it final. For example, in Piport you have public boolean wait. Where is that used? Does it make sense to have that flag last longer than a single method? Can you move it to the method which uses it? How about int BufferSize = 64; When is that value used? Does it ever change? Could you use private static final BUFFER_SIZE = 64; instead? The variables blockSize, bytesToRead, and bytesRemaining seem like they will be used in a particular IO loop to read bytes from the port, should they be member variables lasting the lifetime of the object or should they be member-local, only existing when you are actually reading from the port? This is probably most particular for the FileInput/OutputStreams, and the ack, size, input, sizeBuffer variables. You don't want any one of those things spilling from one request to the next. you should be ruthless with this stuff. Define no variables you don't need. If you need a variable in multiple methods, you should check to see if you can pass it as a parameter from one method to another, rather than storing it the instance scope. i.e. does it really need to last longer than a single call chain through the class. If Piport 'starts' from the connect() method, does the variable need to be used in connect() and one or more methods connect() calls (or those methods call)? Or does it need to exist between separate calls to connect() - and therefore multiple 'requests'? If the former, then you can take it out of the instance scope (member variable) and put it in the method scope and pass it as argument(s) to the methods that need it.
Don't forget to also check if the variable changes, if it does not, make it final.
Like I said, my guess is that you have some state which is being preserved from one execution cycle to the next. I can't see it in your code, but I didn't look at it too thoroughly (as others said, on the one hand there is too much of it but on the other hand it doesn't seem complete either). So treat the above as a hint as to where the problem might be and as a guideline that will help prevent this sort of thing happening in the future.
I tried letting the thread terminate end naturally by adding a return; statement, but it hasn't changed the outcome.
Thanks for the detailed post. Yes I have a lot of variables. A lot of which are not used anymore e.g public boolean wait; but never removed them, (my laziness and frustration) sorry. I have now moved around the these variables and declared in the appropriate methods.
If Piport 'starts' from the connect() method, does the variable need to be used in connect() and one or more methods connect() calls (or those methods call)? Or does it need to exist between separate calls to connect() - and therefore multiple 'requests'? If the former, then you can take it out of the instance scope (member variable) and put it in the method scope and pass it as argument(s) to the methods that need it.
Yes Piport begins in connect method and depending on incoming string the assigned method is called from there and then reverts back to connect method after file transfer has been successful by being called in the run method @
There is only one variable in connect method and that's String input; which is set to null each time connect(); is called and this variable is not used in any other method so I don't need to pass it?
For the problem I'm having (a repeated "" string). I cant see where it could possibly be preserved on either end of the transfer. But I do agree that it is probably whats causing it. I've single stepped through the code on the PC and used System.out.println(); all over the Pi code where "" could possibly be getting repeated, but with no success. I'm pretty stumped to be honest.
My plan is to be able to let this code run for 24 hours taking an image and saving to file each hour so I need it to be able to loop until I tell it otherwise.
Thanks for the input so far.
- X 2
If you are having problems isolating which side the problem is coming from, remove one side. Stop using the PC side code and build a super simple GUI which has a button which does nothing but sends ":)". Then see if you trigger multiple reads on the Pi side of things when you press it multiple times. If it doesn't reproduce or you can't just send :) over and over again without breaking the Pi side, then make the PC side do the entire sequence one time:
Trigger that from a simple, single button GUI with no extras (no threads or timers or whatever...).
If the problem reproduces, it is on the Pi side. If not then reverse it. Install the initial PC side and replace the Pi side with something that does nothing but takes the request and sends back pre-defined responses and spits out logging. If the problem reproduces you know it is on the Client side.
Ya, that code you wrote is a lot neater than mine, thanks for that. much appreciated. Should make it easier to find the fault.
Apologies for delayed response, but currently where I live (Ireland) we are having very bad storms and electricity has been cut off, so I will hopefully get to run that code in the next day or 2 and see if I can find the fault.
I will let you know how I get on.
Okay after taking your advice Steve I took your code (thanks) and ran it on PC, due to its layout, it was A LOT easier to work with. Firstly just sending "" repeatedly and it worked no problem. Then ":|" (filesize) was introduced and it still worked ok.
When "" was introduced, it then started repeating. So my first assumption was that it was the run() method on the Pi side. So I created a new file (so at least i could go back to square one if ended up getting worse). Commented out connect();
And it didn't change the output, I then got rid of most of the code on the Pi side and just had it printing "", filesize of 1 and transmitting a small string. When this was executed, Strings displaying information that I had removed from the file were appearing. So this opened another can of worms. Spent a bit of time trying to figure that out, as the right file was being compiled and executed.
Took a break, came back and noticed in my main method:
although the file name and class name was changed (otherwise it wouldn't compile), the main method was still running the other file. So that was changed to the correct class and it then started to work.
The timers and threads were re-introduced and they now work and it's transmitting every 3 minutes.
Apart from the wrong file in "main" was being executed. The main issue in the Pi code was the connect(); in the run(); Commenting this out allowed for it to function correctly.
I'm not sure why, as I had assumed once the run(); method had finished, the program would need to start at connect() again hence call connect() at the end of the run() method. If anyone can clear that up i'd appreciate it
Again, thanks to all for you help, especially Steve