Reset Work Time & Work Distance

Post questions and issues with Concept2 PM3 SDK
Post Reply
[old] petor_nl
Posts: 0
Joined: March 18th, 2006, 10:32 pm

Post by [old] petor_nl » November 8th, 2005, 12:53 pm

Hi there, I am working on a rowing game which should make use of two Concept2 Model D Indoor Rowers. For now, there is only one to test with. I am using Delphi 7 and the PM3 API Release 1.24, the PM3 is using beta firmware version 90 (could not find version 89 at the usual BetaUpdate link).<br /><br />With the PM3 Delphi-interface I built upon the PM3 API DLLs it is possible to initialize the PM3, discover the number of units, and read the work time and work distance. However, I do not know how to reset these values whenever a new game should start. I've tried several things, like setting the state to Ready, Finished, or even a Reset, but nothing seems to work. Is it even possible to control the start of a workout by means of the API?<br /><br />Also, the CSAFE state machine is very unclear to me. I have seen several unexpected values, like offline or error when rowing. When the state of the machine is offline I do not succeed in setting it to an other state, other than by resetting the PM3 by pressing the menu/back button on the PM3 for a few seconds. Also, I have somehow managed to cause TKUSB_READ_TIMEOUT_ERR errors which seem to appear at once for commands which worked just fine before. Whenever the PM3 is in this state, it has to be reset manually in order to regain a state in which commands sent by my game (or the demo application) are accepted again by the PM3.<br /><br />For me, the only two things I would like to do in the game I am developing are:<br />- reset time & distance (how?)<br />- get time & distance values (have managed to do this)<br /><br />So, I am having quite some trouble using the SDK and the PM3. I would be very grateful if someone could help me.<br /><br />Thanks in advance for any help.<br /><br />Regards,<br />Peter

[old] malor
Posts: 0
Joined: March 18th, 2006, 10:32 pm

Post by [old] malor » November 9th, 2005, 11:11 am

I've gotten fairly good results by sending the combination CSAFE_GOFINISHED_CMD, CSAFE_GOIDLE_CMD, CSAFE_GOHAVEID_CMD then waiting a second (so the pm3 has time to finish changing states) and then configuring the workout and finishing with CSAFE_SETPROGRAM_CMD & CSAFE_GOINUSE_CMD.<br /><br />This sequence works most of the time, but I don't think it works when the rower has been idle so long during a just row session that the pm3 no longer updates when you continue rowing. So it might not hurt to have the pm3 at the main menu when first starting the game.<br /><br />If anyone knows a better method, I'd also like to know.<br /><br />ps. I also have also found it frustratingly easy to lockup the pm3, so that I have to unplug the usb cable and plug it back in before it will accept commands from my program again.

[old] mlyons

Post by [old] mlyons » November 14th, 2005, 5:53 pm

It is difficult to diagnose the "lock up" behavior without more specific information, but I would offer the following:<br /><br />1. The PM3 does not have an inifinite receiver buffer for USB commands so that sending multiple commands without waiting for responses or associated command processing errors will likely have the effect of erratic (e.g., lock up) behavior.<br />2. If the expected response is not produced (this includes no response) by the PM3, then the error status should be checked (CSAFE_PM_GET_ERRORTYPE, CSAFE_PM_GET_ERRORVALUE) to ascertain what did not work properly.<br /><br />If you can provide me with some more specific description of the "lock up" behavior than I can probably diagnose and potentially fix the issue.<br /><br />Mark

[old] haboustak

Post by [old] haboustak » November 15th, 2005, 1:43 pm

malor:<br />I'm pretty sure you can bypass the CSAFE Idle state entirely. The CSAFE state flowchart on page 22 in the Interface Definition Rev 010 (the latest version I have handy) has an arrow between Ready and InUse. I seem to remember testing the following successfully:<br /><br />[Ready] > [SetProgram]<br />[Ready] > [GoInUse]<br />[InUse]<br /><br />Then waiting on the Finished state. You can bypass the Idle/HaveID states. You do have to start from READY though. Also, interrupting a workout with GoFinished followed by GoReady may not reset the screen presented to the rower. I seem to remember having my PM3 get stuck at the workout completed screen when trying to abort a workout via machine control. I haven't tested these things using Rev 90 though.<br /><br /><br />petor_nl:<br />It might help if you add a polling loop to your code that retrieves the PM3's status/state and display it somewhere on the screen. When the rower is in JustRow mode, the PM3 is in the OFFLINE state. When the user is in a workout they selected from the menus (or if they've bypassed entering an ID during the Idle state) the PM3 is in the MANUAL state. I've tested this fairly extensively in FW88 and it seems to work correctly (state follows screen follows button presses)<br /><br />If the PM3 is OFFLINE or MANUAL you can't do anything to interrupt it. As far as the PM3 is concerned, the user has taken action to bypass computer control. You can't interrupt their workout and have to wait until the state returns to READY. Which should happen after they hit MENU/BACK or the appropriate timeout expires (see the diagram page 22 -- there's no timeout for JustRows).<br /><br />So the answer to your question is -- You can't reset a JustRow because the PM3 is OFFLINE and ignoring you . You'll have to go through the process of setting up a workout and getting the PM3 into the proper state before the user starts rowing (or, playing as the case may be). <br /><br />Mike

[old] petor_nl
Posts: 0
Joined: March 18th, 2006, 10:32 pm

Post by [old] petor_nl » November 18th, 2005, 3:37 am

By using Malor's startup sequence I was able to reset the PM3. Fortunately, up to now I haven't had any lockups described by Malor, instead I experienced somewhat inconsistent behaviour. Running the startup sequence sometimes brought the PM3 in the HaveID state, or some kind of JustRow state, but that may just be what Haboustak described.<br /><br />At the moment I am not monitoring the PM3's state yet, because last time I tried (that was before the use of the startup sequence) it kept returning OFFLINE. I will add a polling loop and monitor/log the state during the game. Also, I will try to shorten the startup sequence by leaving out the Idle/HaveID states.<br /><br />Thanks for all replies.<br /><br />Peter

[old] haboustak

Post by [old] haboustak » November 18th, 2005, 10:50 am

I'm glad you're having some success. I think polling the state will make things a lot clearer for you, I know it did for me. Before I started polling, the PM3 would appear stuck in a certain state, or it would seem to transition at odd times.<br /><br />I suspect the reason that you haven't had any lockup issues like Malor is because you haven't been polling. The current PM3 SDK has a bug that can cause re-entry into the CSafe send/recv functions. If you're implementing a polling loop on Windows, be sure to use a thread rather than a timer object. I've described this in an earlier post here: <a href='http://concept2.ipbhost.com/index.php?s ... st&p=25416' target='_blank'>http://concept2.ipbhost.com/index.php?s ... 416</a><br /><br /><br />Normally, you'd think sending timer messages would help prevent threading issues, but in this case the only way to synchronize your packets to the PM3 is to use a second thread.<br /><br /><br />Mike<br /><br />

[old] petor_nl
Posts: 0
Joined: March 18th, 2006, 10:32 pm

Post by [old] petor_nl » December 16th, 2005, 11:41 am

Thanks Mike for the link to the earlier post about threads and timers.<br /><br />I have implemented two threads in the game: one for polling the state, and one for polling the workout data. Each thread is executed only when needed, and the two threads never execute at the same time (which should not be a problem if they did, though). <br /><br />The state poll thread polls the state of the machine every 150 ms (timers are not involved here, just a call to the sleep() function). When the game starts, it initializes the Concept2 machine by sending the appropriate commands based on the state diagram in the Concept2 documentation. This initialization phase should always end in the 'In Use' state, ready for the player to start the programmed workout of 2 km.<br /><br />After the initialization, the state poll thread is suspended and the work poll thread is resumed. For a minute, every 500 ms the workout data is polled. When the game is finished, the work poll thread is suspended again.<br /><br />Now, it all seems to work quite well, but... the machines still get locked or stuck after a while. The display shows an hourglass and the state poller receives nothing but 'unknown' states. The only way to get the machine out of this state is by pressing the menu/back button on the PM3 itself. Both machines have been built into a custom made casing, so this is quite awkward.<br /><br />Am I still doing something wrong, and/or is this a known problem? Can it be solved?<br /><br />Again, thanks in advance for any advice on this subject.<br /><br />Regards,<br />Peter

[old] mlyons

Post by [old] mlyons » December 16th, 2005, 12:30 pm

Peter,<br /><br />If you look at the state machine closely, the Master is supposed to issue the GoIdle command after completing the collection of results at the workout conclusion (in Finished state). There are two notes under the Finished state in the state diagram which you should reference as well.<br /><br />Mark

[old] haboustak

Post by [old] haboustak » December 16th, 2005, 1:26 pm

<!--QuoteBegin-petor_nl+Dec 16 2005, 10:41 AM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(petor_nl @ Dec 16 2005, 10:41 AM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin-->I have implemented two threads in the game: one for polling the state, and one for polling the workout data.<br /> </td></tr></table><br />I'm not sure what platform you're running on, but suspending and resuming threads might give you headaches in the long-run. I don't think it's the source of your current problem, but you might consider using only a single thread and creating a 'poll mode' variable. The value of this variable (e.g. POLL_NONE, POLL_STATUS, or POLL_WORK) would control the CSAFE packet sent to the PM3. You can even make these binary flags so that the loop can pick up multiple items of data per loop. This way, the run() loop of the thread stays the same and it's execution is never interrupted. Let me know if you'd be interested in seeing a code example.<br /><br /><!--QuoteBegin-petor_nl+Dec 16 2005, 10:41 AM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(petor_nl @ Dec 16 2005, 10:41 AM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin-->The display shows an hourglass and the state poller receives nothing but 'unknown' states. [right] <br /> </td></tr></table><br />'Unknown' isn't a valid status code response from the PM3 -- I've listed the valid status values below. Is the API command returning an error? Are you checking the value of the returned ERRCODE_T? Any error values might help narrow down the problem.<br /><br />How does your software know the workout is over? By comparing the distance/time rowed value? What does your code do when it decides the workout ends? Does it send any commands to the PM3?<br /><br />Mike<br /><br />From PM3CSafe.h and FitLinxx Web site <br />------------------------------------------------------<br />0:STATE_ERROR<br />1:STATE_READY<br />2:STATE_IDLE<br />3:STATE_HAVEID<br /> (note "4" is unused)<br />5:STATE_INUSE<br />6:STATE_PAUSED<br />7:STATE_FINISHED<br />8:STATE_MANUAL<br />9:STATE_OFFLINE<br />------------------------------------------------------

[old] petor_nl
Posts: 0
Joined: March 18th, 2006, 10:32 pm

Post by [old] petor_nl » December 19th, 2005, 12:56 pm

I think the problem might very well have been caused by the state the machine was left in after the game, i.e. 'finished'. Now I make sure that the machine is always left in the 'idle' state. Unfortunately, because the game -and what's more important: the Concept2 machines- are about 140 km away, I cannot check the outcome of this modification to the code myself. For this, I have to wait until the client does not detect the sleep state any longer.<br /><br /><!--QuoteBegin--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin--><b>Haboustak</b>: 'Unknown' isn't a valid status code response from the PM3 -- I've listed the valid status values below. Is the API command returning an error? </td></tr></table><br /><br />Yes, you are completely right, 'unknown' is the value I give to the state whenever the API returned an error. And this error is the effect of the impenetrable state the PM3 is in at that time. Just now I detected that I failed to log the exact error code... <br /><br /><!--QuoteBegin--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin--><b>Haboustak</b>: How does your software know the workout is over? By comparing the distance/time rowed value? What does your code do when it decides the workout ends? Does it send any commands to the PM3? </td></tr></table><br /><br />The duration of the game is just one minute, so one has to do their very best to achieve 2 km in that short period of time. I compute the speed by means of a work poller thread, that's the only (computed) variable that is used. So the game decides that the workout is over and (now) resets the rowing machines to the idle state by sending commands to the PM3.<br /><br />Thanks for the advice on the threads. Because I do not suspect this mechanism to do any harm at the moment, and because I do not want to modify too much of the code that can only be tested on location, I will probably leave that for later.

[old] haboustak

Post by [old] haboustak » December 19th, 2005, 1:49 pm

<!--QuoteBegin-petor_nl+Dec 19 2005, 11:56 AM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(petor_nl @ Dec 19 2005, 11:56 AM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin-->I think the problem might very well have been caused by the state the machine was left in after the game, i.e. 'finished'. Now I make sure that the machine is always left in the 'idle' state.<br /> </td></tr></table><br />I can't think of any PM3 state that would cause GET_STATUS to return an error code -- but we'll see what it is when you're able to log it. The PM3 might return error codes to workout or state transition requests while in FINISHED, but GET_STATUS should always be able to report the current state, unless communication has been corrupted.<br /><br />I'm not sure how your suspend/resume thread code works. But if you suspend the Work poll thread while it's inside of tkcmdsetCSAFE_command() you might get strange communication problems that are quite intermittent. Does your thread suspend happen instantly or does it wait for control to return to the Run() loop before suspending?<br /><br />If it suspends instantly, what happens if you suspend a thread while it's waiting on an IO response from the PM3? It might not release mutex/semaphore objects and might cause deadlocks. It also might cause a PM3 response to be stranded in the input queue. Or you might have race conditions between when the Work thread stops and the Status thread starts (I would hope the PM3 API would be able to sort out those races, though) The PM3 doesn't know you've aborted the most recent transaction. It's going to try and process it to completion.<br /><br />The API does seem to be fairly isolated from these kinds of faults, and I've never been able to cause a comm. error using threads. But if you're stepping out mid-transaction you might see problems.<br /><br /><!--QuoteBegin-petor_nl+Dec 19 2005, 11:56 AM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(petor_nl @ Dec 19 2005, 11:56 AM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin-->The duration of the game is just one minute, so one has to do their very best to achieve 2 km in that short period of time.<br /> </td></tr></table><br />Watchout for rowing over-shoot here. Where the PC detects the end of the trial and ends the workout, but the rower keeps stroking. With the PM3 in READY mode, it might push the user into JustRow mode. This probably isn't a problem, because I think the FINISHED and IDLE states are safe from this JustRow transition. But it's something worth testing for.<br /><br />I can imagine that it's VERY difficult to do any real testing while you're far from the erg.<br /><br />Mike

[old] haboustak

Post by [old] haboustak » December 19th, 2005, 2:04 pm

<!--QuoteBegin-petor_nl+Dec 19 2005, 11:56 AM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(petor_nl @ Dec 19 2005, 11:56 AM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin-->Unfortunately, because the game -and what's more important: the Concept2 machines- are about 140 km away, <br /> </td></tr></table><br />I can also offer that I'm rarely more than 14 meters from a PM3. So if it's something that can be used on a standard C2 and you're able to release a test version -- just let me know. I'd be glad to connect it up to my machine.<br /><br />Mike

[old] petor_nl
Posts: 0
Joined: March 18th, 2006, 10:32 pm

Post by [old] petor_nl » December 22nd, 2005, 7:54 am

<!--QuoteBegin-haboustak+Dec 19 2005, 07:04 PM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(haboustak @ Dec 19 2005, 07:04 PM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin--><!--QuoteBegin-petor_nl+Dec 19 2005, 11:56 AM--><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><div class='genmed'><b>QUOTE(petor_nl @ Dec 19 2005, 11:56 AM)</b></div></td></tr><tr><td class='quote'><!--QuoteEBegin-->Unfortunately, because the game -and what's more important: the Concept2 machines- are about 140 km away, <br /> </td></tr></table><br />I can also offer that I'm rarely more than 14 meters from a PM3. So if it's something that can be used on a standard C2 and you're able to release a test version -- just let me know. I'd be glad to connect it up to my machine. <br /> </td></tr></table><br /><br />Thanks for the offer Mike, but both the client and the company I work for do not want the software to be copied. So I have to wait for the client to test the modified software.<br /><br />By the way, I implemented the poll thread the way you suggested (1 thread having 3 poll modes) in order to prevent communication problems caused by immediate suspension of my previous threads.

Post Reply