Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Webmite V5.07.08 betas : UDP and other stuff
Page 4 of 5 | |||||
Author | Message | ||||
Plasmamac Guru Joined: 31/01/2019 Location: GermanyPosts: 554 |
thanks, works fine now Plasma |
||||
bigfix Senior Member Joined: 20/02/2014 Location: AustriaPosts: 128 |
Many thanks again for implementing static IP addresses ! I just recognized that there is no setup for a DNS/Nameserver ? Is this assumed to be the same as the Gateway/Router address ? About all devices I have ever configured ask for one or multiple DNS Addresses, (besides IP address, Mask, Gateway ) In my network I have a different DNS in use, located not on my main Gateway (mostly for historical reasons...) I wonder if other users also have a different DNS configured (not on their default Gateway) In corporate networks I expect this separation quite often for security reasons |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 9128 |
I presume so. There is no field in any of the function calls to allow you to specify a name server |
||||
homa Guru Joined: 05/11/2021 Location: GermanyPosts: 351 |
NTP server on a MikroTik router with a WebMite causes problems. If the AP has no internet (but the time and internal clock are correct!), the NTP query does not work with the WebMite. A test tool "ntpquery", on the other hand, has no problems (regardless of whether the AP has internet or not!). Is there possibly a bug in the ntp query of the WebMite? Matthias |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 6100 |
@Matthias My uneducated guess is: The pico is 'probably' doing a DNS lookup. It doesn't know if the supplied string is a domain name or ip address. If you can run a packet sniffer on the MikroTik, you should see the DNS lookup requests. Jim Edited 2023-06-22 08:36 by TassyJim VK7JH MMedit MMBasic Help |
||||
homa Guru Joined: 05/11/2021 Location: GermanyPosts: 351 |
Hi Jim, Thanks, that makes sense. I will give it a try while I am on holiday. I have this nice little https://mikrotik.com/product/RBmAPL-2nD So I can set up my own WLAN for all the web sites. Hi Peter: Couldn't the regex ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ tell you that it's an IP address and doesn't need DNS? You've already integrated regex so nicely into a beta, haven't you?Matthias |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 9128 |
The code already identifies numerical IP addresses and doesn't do a DNS lookup on them so this isn't the issue. |
||||
carlschneider Senior Member Joined: 04/08/2023 Location: South AfricaPosts: 158 |
Hi there The following are observations/anomalies I am experiencing with the WebMite running 5.07.08b11. Observation/ Anomaly 1 ————————————— I notice on 5.07.08b11 the OPTION CPUSPEED has a reduced upper limit compared to 5.07.07. WebMite MMBasic Version 5.07.08b11 OPTION AUTORUN ON OPTION COLOURCODE ON OPTION CPUSPEED (KHz) 252000 OPTION DISPLAY 41, 140 OPTION WIFI A*********7, **********, PICO************ OPTION TCP SERVER PORT 80 OPTION TELNET CONSOLE ON > option cpuspeed 378000 Error : 378000 is invalid (valid is 126000 to 252000) > WebMite MMBasic Version 5.07.07 OPTION COLOURCODE ON OPTION CPUSPEED (KHz) 264000 OPTION DISPLAY 41, 80 OPTION WIFI A********7, ********** OPTION TCP SERVER PORT 80 OPTION TELNET CONSOLE ON > option cpuspeed 400000 Error : 400000 is invalid (valid is 64000 to 378000) > Is the reduced upper limit due to beta stability issues or other issues? Will the broader range be made available in RC versions? Observation/ Anomaly 2 ————————————— The SetTick seems to be causing an intermittent problem. I have not yet noticed the sequence of events required to replicate this. Option List as above. Didn’t do this under 5.07.07, but my time on 5.07.07 has probably been slightly less or the same as on 5.07.08b11 by now. The below in response to having the EDIT open and hitting F2 to save and RUN. Saved 5278 bytes 172.16.1.65 ntp address 162.159.200.1 got ntp response: 16/08/2023 14:52:37 [26] SetTick TickPeriod,GetFreq,1:TimeStart=Timer:TimeEnd=0 Error : Unknown command F2 again with no intervention generally results in a launch. Memory listing just in case it is of relevance. > memory Program: 5K ( 5%) Program (194 lines) 75K (95%) Free Saved Variables: 16K (100%) Free RAM: 4K ( 3%) 25 Variables 0K ( 0%) General 102K (97%) Free > Observation/ Anomaly 3 ————————————— I’m running a 13” mid 2012 MacBookPro running Ventura 13.1 through the OpenCore Legacy Patcher. I use the MacOS X Terminal application and Screen to link to the USB port. The hardware is all there, supported by the drivers and the install is stable. The image below with the red arrow is pointing to the command prompt that has come through while in the EDIT mode. This is due to the WEB OPEN CLIENT failing because the ModBus Slave (ModBusPal.jar 1.6c) has been turned off to replicate the problem. To get back into WebMite I up arrow once to load the Screen command at the Terminal prompt and hit enter. This gets me back to the WebMite session and the command screen, without the > prompt. Enter once and the WebMite Starts running again with the following output. This is repeatable by using WEB OPEN TCP CLIENT “ip address”, 502 with no Modbus Slave responding. If I take too long doing this sequence then I have to reset the PicoW to get the USB working again. It would appear that Telnet is also not available, but I have not been able to definitively confirm that yet. Web Open Client failure If I F2 then ^C and wait at the command prompt I get the following Connected XXX.XXX.XXX.XXX Starting TCP server at XXX.XXX.XXX.YYY on port 80 XXX.XXX.XXX.XXX ntp address 216.197.228.230 got ntp response: 17/08/2023 09:13:30 09:13:30 Here we go [123] WEB open tcp client "XXX.XXX.XXX.XXX", 502 Error : TCP client > Carls-MacBook-Pro-5:~ carls$ Observation/ Anomaly 4 ————————————— I’m using a Logitech MX Master mouse, linked through Bluetooth. A rapid spin of the scroll wheel inserts artefacts into the EDIT view. These artefacts are persistent in that these are ascii characters inserted into code. Page up and then Page down does not dislodge them. Recovery is through Esc Y F4 sequence. The image below shows the artefacts, as red arrowed. I was initially thinking this was a USB issue but the mouse is Bluetooth connected. Unless the Bluetooth stack is hanging off the USB Hub? One of the tricky aspects in making OpenCore Legacy work is the USB side of things and the WIFI support. In this instance the chipsets are supported by native Apple drivers, just disabled by Apple in their OS upgrade cycle. Maybe related maybe not. Image of artefacts Observation/ Anomaly 5 ————————————— I notice the WEB OPEN TCP CLIENT “ip address”, 502 reports Connected to the Console. Perhaps a flag to turn this behaviour off? Or am I missing a flag or option associated with this Command set? I’m not seeing it in the WebMite Rev3 manual. There are two ModBus connections, one writes and the other reads, thus the two Connected lines on the console. Each usage of the WEB OPEN CLIENT reports Connected each time the TCP link is established. ntp address 208.81.1.244 got ntp response: 17/08/2023 09:55:09 09:55:09 Here we go Connected Connected I trust these observations/anomalies will be of assistance. Thank you to all the relevant parties, your efforts are appreciated. Cheers Carl Cheers Carl Retirement is tough on Hobbies without a day job |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 9128 |
1. Support for 378MHz required a compile time underclocking of the cyw43. This proved to create intermittent errors in long term operation of the chip so has been withdrawn. 2. More info needed, preferably with a test program that demonstrates the issue. My guess would be some sort of externally initiated TCP interaction happening while in the editor that the Pico can't (be expected?) to handle. 3. Mac issue - can't comment. Haven't had similar reports from anyone on Linux/Windows 4. Mac issue - can't comment. Haven't had similar reports from anyone on Linux/Windows 5. No current mechanism - I'll look at it for the next beta |
||||
carlschneider Senior Member Joined: 04/08/2023 Location: South AfricaPosts: 158 |
Thanks Peter 1. Noted 2. I'll see if I can replicate it more consistently 3. Noted :) 4. Noted :) 5. Thanks. I see its all 'status' messages from WEB OPEN TCP CLIENT by the looks of it. Another post to follow shortly. Many thanks Carl Cheers Carl Retirement is tough on Hobbies without a day job |
||||
carlschneider Senior Member Joined: 04/08/2023 Location: South AfricaPosts: 158 |
Hi there In an attempt to start error trapping I have introduced some ON ERROR SKIP commands with EXIT SUB to avoid the balance of the subroutine. Could there be an EXIT SUB error, possibly similar to the EXIT DO error in earlier versions of PicoMite? Code looks like this ... Print Time$, "Here we go" Dim integer Buff1%(50) WEB TCP INTERRUPT ServiceWebInterrupt AssembleModbusStrings WriteModbus ReadModbus Do 'Port(GP0,10)=&B0101010101 'Pause 100 'Port(GP0,10)=&B1010101010 'Pause 100 'Do nothing 'a=0 'For i=1 To 1000 'a=a+1 'Next 'Print DeltaTime, Loop ... Sub Read ModBus On Error Skip 1 WEB open tcp client "172.16.1.76", 502 If MM.Errno Then Print "RedModBus "; MM.ErrMsg$:Exit Sub test$=ReadModbusRegisters$ ... End Sub Sub Write Modbus On ERROR SKIP 1 WEB open tcp client "172.16.1.76", 502 If MM.Errno Then Print "WriteModBus "; MM.ErrMsg$:Exit Sub test$=WriteModbusMultipleRegisters$ ... End Sub The console result is the following PICO*********** connecting to WiFi... Connected ***.***.***.*** Starting TCP server at ***.***.***.*** on port 80 ***.***.***.*** Error# 0ErrorMsg WATCHDOG 0 ntp address 162.159.200.123 got ntp response: 18/08/2023 06:55:55 06:55:55 Here we go WriteModBus TCP client RedModBus TCP client [50] Loop Error : TCP client > Error : TCP client > > Error : TCP client > > From the code snippet there is no reason for the Exit Sub to end up in the Do Loop. Searching TheBackShed revealed a bug in Exit Do which returned 1 line past where it should have. Grogster overcame this with a dummy line of code dl=dl. I'm assuming the Error: TCP Client is the WEB OPEN TCP CLIENT reporting status messages to the console and see that you confirmed this in your response to my previous post. Based on the dummy line of code approach I tried inserting some dummy lines of code. Code looks like this Print Time$, "Here we go" Dim integer Buff1%(50) WEB TCP INTERRUPT ServiceWebInterrupt AssembleModbusStrings WriteModbus DummyLine=DummyLine ReadModbus DummyLine=DummyLine Do 'Port(GP0,10)=&B0101010101 'Pause 100 'Port(GP0,10)=&B1010101010 'Pause 100 'Do nothing 'a=0 'For i=1 To 1000 'a=a+1 'Next 'Print DeltaTime, Loop ... Sub ReadModbus On Error Skip 1 WEB open tcp client "172.16.1.76", 502 If MM.Errno Then Print "RedModBus "; MM.ErrMsg$:Exit Sub test$=ReadModbusRegisters$ ... End Sub Sub Write Modbus On ERROR SKIP 1 WEB open tcp client "172.16.1.76", 502 If MM.Errno Then Print "WriteModBus "; MM.ErrMsg$:Exit Sub test$=WriteModbusMultipleRegisters$ ... End Sub The console result is the following PICO*********** connecting to WiFi... Connected ***.***.***.*** Starting TCP server at ***.***.***.*** on port 80 ***.***.***.*** Error# 0ErrorMsg WATCHDOG 0 ntp address 162.159.200.1 got ntp response: 18/08/2023 06:58:40 06:58:40 Here we go WriteModBus TCP client RedModBus TCP client [52] Loop Error : TCP client > Error : TCP client > Error : TCP client All the dummy lines seem to do is shift the Loop error by 2 lines. Which could support the argument about EXIT SUB returning to the wrong line of code? However the WEB OPEN TCP CLIENT status messages are still coming through to the console. I then tried closing the unopened TCP connection in the following code having noticed that doing this at the console had suppressed the TCP status messages in the past. Code looks like this Print Time$, "Here we go" Dim integer Buff1%(50) WEB TCP INTERRUPT ServiceWebInterrupt AssembleModbusStrings WriteModbus DummyLine=DummyLine ReadModbus DummyLine=DummyLine Do 'Port(GP0,10)=&B0101010101 'Pause 100 'Port(GP0,10)=&B1010101010 'Pause 100 'Do nothing 'a=0 'For i=1 To 1000 'a=a+1 'Next 'Print DeltaTime, Loop ... Sub ReadModbus On Error Skip 1 WEB open tcp client "172.16.1.76", 502 If MM.Errno Then Print "RedModBus "; MM.ErrMsg$:WEB CLOSE TCP CLIENT :Exit Sub test$=ReadModbusRegisters$ ... End Sub Sub Write Modbus On ERROR SKIP 1 WEB open tcp client "172.16.1.76", 502 If MM.Errno Then Print "WriteModBus "; MM.ErrMsg$:WEB CLOSE TCP CLIENT :Exit Sub test$=WriteModbusMultipleRegisters$ ... End Sub The console result is the following Saved 5533 bytes 172.16.1.65 Error# 0ErrorMsg WATCHDOG 0 ntp address 149.56.47.60 got ntp response: 18/08/2023 07:04:36 07:04:36 Here we go WriteModBus TCP client RedModBus No response from client > RUN 172.16.1.65 Error# 0ErrorMsg WATCHDOG 0 ntp address 132.246.11.237 got ntp response: 18/08/2023 07:05:33 07:05:33 Here we go WriteModBus No response from client RedModBus No response from client Firstly this seems to have solved the Do Loop error. So what does that do to the EXIT SUB returning to the wrong line argument? The continuous status codes appear to have been suppressed by the WEB CLOSE TCP CLIENT command. The read and write Modbus subs have Print statements to indicate that the If MM.errno then has been executed. Interesting how the two runs, one immediately following the other, have generated different TCP status messages-weird :) I then removed the Print MM.ErrMsg$ and now get no Loop errors and no TCP status reporting if the ModBus Slave is not responding. However if the ModBus slave responds then the TCP status messages are coming through, but at least the Connected is not upsetting the do Loop. So in summary it looks as though the TCP Client status messages, particularly the failure to connect, causes a problem with the Exit Sub return line pointer. With regard to the Tick error it's starting look like it occurs with the following sequence of events. From running program at the console ^C F4 Edit some code (possibly looking like delete some code rather than add code) F2 But I'll keep my eye on it and provide more feedback. The only definite consistency is the Tick command failing. So far just another F2 and everything is fine. Cheers Carl Cheers Carl Retirement is tough on Hobbies without a day job |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 9128 |
If MM.Errno Then Print "WriteModBus "; MM.ErrMsg$:Exit Sub I would never recommend this Try If MM.Errno Then Print "WriteModBus "; MM.ErrMsg$ Exit Sub ENDIF |
||||
karlelch Senior Member Joined: 30/10/2014 Location: GermanyPosts: 172 |
Hi, I am experiencing trouble with the latest beta version (5.07.08b11) of the WebMite. I am aware that ideally, I post a short example here, however, I did not yet have time to search for the specific error condition with a respective code snippet. Hence, my question is more if anyone else experienced stability issues with that beta version. My code can be found here on GitHub. It uses MQTT to receive messages about two solar panels. It restarts automatically if the WLAN connection is lost. Also, to recover also from different issues, it uses the new HW watchdog. I went back to 5.07.08b10 and my code seems to run fine. With 5.07.08b11, the firmware seems to crash (?) from time to time - then all the options and any programs in the flash are gone. Drive A: is still fine. The options are: OPTION COLOURCODE ON OPTION DISPLAY 64, 80 OPTION WIFI "Elchland3", "xxx" OPTION TCP SERVER PORT 80 OPTION HEARTBEAT OFF OPTION SYSTEM SPI GP10,GP11,GP12 OPTION SDCARD GP22 OPTION LCDPANEL ST7789_320, LANDSCAPE,GP8,GP15,GP9,GP13 OPTION TOUCH GP16,GP17 Any leads that I could follow? Thanks Thomas |
||||
carlschneider Senior Member Joined: 04/08/2023 Location: South AfricaPosts: 158 |
Thanks for the advice Peter The v3 manual indicates ON ERROR SKIP will ignore an error in a number of commands (specified by the number 'nn') executed following this command. 'nn' is optional, the default if not specified is one. After the number of commands has completed (with an error or not) the behaviour of MMBasic will revert to ON ERROR ABORT. In terms of the ON ERROR SKIP nn and using your example could you please review my walk through the nn in terms of the recommended coding approach? ON ERROR SKIP 1 WEB OPEN TCP CLIENT "ip address", port If MM.Errno Then Print "WriteModBus "; MM.ErrMsg$ Exit Sub ENDIF My understanding, from previous comments (with lots of questions) on TheBackShed, is the following; Effectively a command counter (or is this a line counter?) is set with the SKIP value. In the example above for a SKIP value of 1, the command (line?), which is next command (one line below?) the ON ERROR SKIP command (line?) will not ABORT, so if there is an error raised by the WEB OPEN CLIENT command it does not ABORT, it stores the error no in MM.Errno (at what point is the SKIP counter reset and the ON ERROR reverts to ABORT? Manual says after SKIP nn commands but the IF is still able to Test MM.Errno?). The IF then tests the MM.Errno and if it evaluates to TRUE (<1) the THEN is executed. In the v3 manual Page 25, the recommended NTP setting the RTC approach is the following piece of code is; ON ERROR SKIP 3 WEB NTP -10 IF MM.ERRNO THEN WEB NTP -10 IF MM.ERRNO THEN PRINT "Failure to connect to the Internet" : CPU RESTART In this case I can't wrap my head around the logic of the SKIP counter, whether commands or lines. Are the 3 commands then command 1=WEB NTP -10, command 2= If test and command 3 Then WEB NTP -10. This seems to be more logical than lines, because SKIP 3 would impact the second IF statement. Rewriting the example in the v3 manual on page 25 then yields the following based on your recommendation; ON ERROR SKIP 3 WEB NTP -10 IF MM.ERRNO THEN WEB NTP -10 EndIf IF MM.ERRNO THEN PRINT "Failure to connect to the Internet" CPU RESTART EndIf The last EndIf possibly not required as the CPU RESTART will obviate the need but could possibly cause unexpected code execution. Using the command approach where IF THEN counts as two commands I can get to SKIP 3 commands. The SKIP 3 lines also works out in this example. May I please impose on you to provide a definitive answer, as I see a lot of ON ERROR SKIP nn commands in my future :) Many thanks Carl Cheers Carl Retirement is tough on Hobbies without a day job |
||||
Mixtel90 Guru Joined: 05/10/2019 Location: United KingdomPosts: 6798 |
I'm no expert on error handling, but this is how I read the manual: ON ERROR SKIP 3 'No errors will be recognised during the next 3 statements WEB NTP -10 'no action taken on error but MM.ERRNO may be set to non-zero IF MM.ERRNO THEN 'no action taken on error but MM.ERRNO may be set to non-zero WEB NTP -10 'no action taken on error but MM.ERRNO may be set to non-zero 'if an error occurs in the following statements then it will be printed to the console and the program will be aborted. EndIf 'you will get an ABORT error here unless it is SKIPped IF MM.ERRNO THEN 'if a SKIPped error occurred then... PRINT "Failure to connect to the Internet" CPU RESTART EndIf 'this statement is always required or an abort error will occur if there were no SKIPped errors. Multi-statement lines using IF/THEN are not a good idea generally. You can't always be certain which will be the terminating statement. Always use IF/THEN/ENDIF if there is any doubt. It's a lot easier to read if nothing else. :) Edited 2023-08-19 06:22 by Mixtel90 Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
carlschneider Senior Member Joined: 04/08/2023 Location: South AfricaPosts: 158 |
Thanks for the insights Mick. If one uses the v3 manuals terminology then would you agree your 'statements' are the manual's 'commands'? If this is the case then lines don't feature. I like your comments on the actions, makes a lot of sense, with one caveat *** :) ON ERROR SKIP 3 'No errors will be recognised during the next 3 statements WEB NTP -10 'no action taken on error but MM.ERRNO may be set to non-zero IF MM.ERRNO THEN 'no action taken on error but MM.ERRNO may be set to non-zero WEB NTP -10 'no action taken on error but MM.ERRNO may be set to non-zero 'if an error occurs in the following statements then it will be printed to the console and the program will be aborted. EndIf 'you will get an ABORT error here unless it is SKIPped *** IF MM.ERRNO THEN 'if a SKIPped error occurred then... PRINT "Failure to connect to the Internet" CPU RESTART EndIf 'this statement is always required or an abort error will occur if there were no SKIPped errors. *** If this is the case surely we will never get to the Print command if NTP fails twice? Unless EndIf is not considered a command? Cheers Carl Cheers Carl Retirement is tough on Hobbies without a day job |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 6100 |
I have no experience with MQTT but I do have a Beta11 firmware running in active service. So far it has done 14.5 days without a reset. This is the same hardware that did have a lot of resets with earlier firmware. My options are OPTION CPUSPEED 250000 OPTION SYSTEM SPI 14,15,16 OPTION SDCARD 17 OPTION LCDPANEL VIRTUAL_C option wifi "xxx","xxxx","xxx" OPTION TCP SERVER PORT 80, 10000 OPTION UDP SERVER PORT 6802 OPTION TELNET CONSOLE ON Anything Internet needs long timeouts... Jim VK7JH MMedit MMBasic Help |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 6100 |
Any use of SUBs or IF statements in the middle of an ON ERROR SKIP n range is difficult to predict. I find it much easier to keep control if I stick to single line skips and treat each program branch individually. That saves a lot of head scratching. Jim VK7JH MMedit MMBasic Help |
||||
Mixtel90 Guru Joined: 05/10/2019 Location: United KingdomPosts: 6798 |
IMHO the ENDIF will be looked for from the point that IF is processed. IF <condition> THEN ENDIF is two statements. If <condition> is false then control is passed to the statement following ENDIF, so if you precede the IF statement with ON ERROR SKIP n then n has to skip both the IF and ENDIF in order for the system to work. If IF MM.ERRNO THEN is the statement following ENDIF then ON ERROR SKIP should always land on it. From that point the PRINT statement will be processed if there has been an error. I'm pretty sure that ON ERROR SKIP will be looking for statement ends. That makes it pretty simple to sort out if you are using single line statements but not necessarily if you make them multi-line. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
carlschneider Senior Member Joined: 04/08/2023 Location: South AfricaPosts: 158 |
Some tests then ensued On error skip X If (S$=1%) Then Print "Error Skip 1" S$=1% Print "Should Work" Endif Print "Endif" For Skip X=1 the console output is Error skip 1 [47] s$=1% Error : Expected a string For Skip X=2 Error skip 1 [47] s$=1% Error : Expected a string For Skip X=3 Error skip 1 Should work EndIf So try and explain that :). Looks like its line based... Curious how X=1 and X=2 have the same result though. Just to confuse the issue On error skip X If (S$=1%) Then Print "Error Skip 1" 'S$=1% Print "Should Work" Endif Print "Endif" For Skip X=1 Error skip 1 Should work EndIf For Skip X=2 Error skip 1 Should work EndIf For Skip X=3 Error skip 1 Should work EndIf Which is as one would expect, nes pas. Just to be tenacious how about On error skip X If (S$=1%) Then Print "Error Skip 1":S$=1%:Print "Should Work":Endif:Print "Endif" For Skip X=1 the console output is [45] If (S$=1%) Then Print "Error skip 1":s$=1%:Print "Should work":EndIf ;Print "EndIf" Error : Expected a string For Skip X=2 Should work For Skip X=3 Should work Which are not the results I was expecting. Lesson - use your lines :) Thank you for all your input, but I remain dubious about my ability to apply the ON ERROR SKIP logically and with confidence of the outcome. Cheers Carl Cheers Carl Retirement is tough on Hobbies without a day job |
||||
Page 4 of 5 |
Print this page |