madleech / ArduinoCMRI

Arduino library for connecting your computer to your model railroad.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Errors in the JMRI console?

k4kfh opened this issue · comments

Whenever I close a JMRI turnout that's assigned to a CMRI bit, the console gives an error like these:

2016-07-07 16:21:27,084 jmrix.AbstractMRTrafficController     ERROR - reply complete in unexpected state: 10 was 41 52 00 00 00 [Receive]
2016-07-07 16:21:27,089 jmrix.AbstractMRTrafficController     ERROR - reply complete in unexpected state: 10 was 41 52 00 00 00 [Receive]
2016-07-07 16:21:33,494 jmrix.AbstractMRTrafficController     ERROR - reply complete in unexpected state: 15 was 41 52 00 00 00 [Receive]
2016-07-07 16:21:33,498 jmrix.AbstractMRTrafficController     ERROR - reply complete in unexpected state: 15 was 41 52 00 00 00 [Receive]
2016-07-07 16:21:33,554 jmrix.AbstractMRTrafficController     ERROR - reply complete in unexpected state: 15 was 41 52 00 00 00 [Receive]

I've also run into some issues where the Arduino seems to be "imagining" bits. It will act on some random bit being set even if I don't have that bit set up to do anything in JMRI. I may be posting this in the wrong place; it very well could be a bug with JMRI, but I wanted to check here first.

Thanks for your patience. I know I've posted a ton of issues, so I appreciate your help.

Thanks for the report. I have attempted to debug the issue but can't recreate it. Can you give me some details, such as:

  • JMRI version
  • JMRI panel file / screenshots of the sensors, signals, turnouts, etc in the tables menu
  • Arduino model being used
  • What version of Arduino software
  • OS
  • Where you are seeing the error messages
  • Steps to recreate the issue
  • How the turnout causing the error is set up

As for imaginary bits, could you post the sketch that is exhibiting this behaviour? I haven't come across this issue before, so I'd be keen to get to the bottom of it.

Update: According to the JMRI devs, those console errors mean that JMRI is expecting a reply, but didn't receive it in time. The use case for this is a homemade indexing system for an Atlas turntable (you know, the one that's been around forever and is a total pain to DCC) so I suspect the problem is that the Arduino is waiting on the turntable to finish rotating when it should be handling CMRI stuff. I'll post the full sketch/JMRI information shortly, but I wouldn't be surprised to find out that's where the "imaginary bits" are coming from and that it's not an inherent fault in your library.

Arduino Sketch

The Arduino sketch can be found on my turningTables Repository. I am using Arduino IDE 1.6.7 with an official Arduino Uno (on a USB 2.0 port, if that matters) on Ubuntu GNOME 16.04 amd64.

Most of the sketch has to do with hardware/motor stuff, so here is a "condensed" version:

void setup() {
  //set all the pins to the correct mode
  pinMode(motor_cw_pin, OUTPUT); //motor clockwise
  pinMode(motor_ccw_pin, OUTPUT); //motor counterclockwise
  pinMode(hall_pin, INPUT); //hall effect sensor input (used as a tachometer)
  pinMode(service_btn_cw_pin, INPUT_PULLUP); //these buttons are for calibrating the turntable
  pinMode(service_btn_ccw_pin, INPUT_PULLUP);

  //read EEPROM for last position
  EEPROM.get(0, currentPosition);

  //making hall effect sensor interrupt
  attachInterrupt(digitalPinToInterrupt(hall_pin), hallTrigger, FALLING);

  //start Serial connection for CMRI
  Serial.begin(9600, SERIAL_8N2);

  //set last bit states initially - this is part of my hacked together system for detecting if a bit changes
  for (int i=0;i < 47;i++) {
    lastBitStates[i] = cmri.get_bit(i);
  }

  //play startup noise - this is just so I know when the turntable is ready, it plays on a little piezo speaker. it does use delay()
  startup_beep();
}

void loop() {
  //This code handles reading the alignment buttons. The buttons move the turntable not one track position, but one rotation of the measured gear, which is useful if the mechanism gets a few turns out of alignment.
  buttonState_cw = digitalRead(service_btn_cw_pin);
  if (buttonState_cw != lastButtonState_cw) {
    if (buttonState_cw == LOW) {
      click_cw();
    }
  }
  lastButtonState_cw = buttonState_cw;

  buttonState_ccw = digitalRead(service_btn_ccw_pin);
  if (buttonState_ccw != lastButtonState_ccw) {
    if (buttonState_ccw == LOW) {
      click_ccw();
    }
  }
  lastButtonState_ccw = buttonState_ccw;
  //end button handling code

  //CMRI interface code
  cmri.process();

  //all the bits for the stalls - there are 24 stall tracks so we read all those bits here
  for (int i=0; i < num_tracks; i++) {
    int currentBit = cmri.get_bit(i);
    if (currentBit == 1) {
      if (currentBit != lastBitStates[i]) {
        rotate(i,0); //this is the tricky part. this function does not complete until the turntable is done rotating, so you can imagine this can take a little bit.
      }
    }
  }

  //bit 25 is supposed to rotate the turntable 180 degrees. This is also a problem area as this function often gets called several times (I think because of the time it takes to complete screwing up the timing of the CMRI data tx/rx) which is useless because then  the turntable just does a full 360 (or more) instead of a 180.
  if (cmri.get_bit(25) == 1) {
    if (cmri.get_bit(25) != lastBitStates[25]) {
      turn_ccw(12);
    }
  }

  //set last bit states at the end of the "cycle".
  //this goes along with my makeshift "is this bit changed?" system.
  for (int i=0;i < 47;i++) {
    lastBitStates[i] = cmri.get_bit(i);
  }
}

If you need more information about any of that I can answer questions. I'm new to C in general so my commenting/organizational skills are probably a little lacking.


JMRI/PC Info

PC Specs:

  • Ubuntu 16.04LTS amd64
  • GNOME Desktop

I do not have a panel set up for this project yet, so I just included screenshots of the turnouts table and the JMRI version info.

The turnouts are set up as steady-state output, 1-bit turnouts. There are no Logix set up for them.

If I throw the "Turn 180 degrees" turnout, sometimes it will be called 1 time, sometimes several times. This doesn't make a difference with the other turnouts because once it's at that position, the rotate() function in the Arduino code simply finds that 0 moves are required to get to the desired position, and it does nothing. But with the "turn 180 degrees" turnout, it can just keep running over and over again. I haven't narrowed down the "imagining bits" issue to specific steps (yet) but it frequently will turn to a stall track that corresponds to a bit that isn't even configured with JMRI as a turnout, and this happens randomly, but especially frequently after throwing the "turn 180 degrees" turnout.

I'll do some tests tonight, but I believe the issue might be due to the turn_cw and turn_ccw functions being blocking. So while the turntable is turning, it is so busy checking its position that no CMRI messages are processed. Once it finishes turning, the queued up messages (sitting in the Arduino's serial buffer) get processed. These messages are almost certainly POLL requests, resulting in a bunch of GET replies being sent out (41 52 ...) when JMRI isn't expecting any; it only expects a single GET message in response to each POLL message that it sends out.

While these unexpected messages won't hurt JMRI, it will cause it to complain. Do you have any sensors set up? Can you show the output of C/MRI > List Assignments?

Just seen your earlier message; seems the JMRI devs came to the same conclusion as me. You'll need to convert your code to set a target value for the motor, and then check that each time through the main loop. It's not too complicated to do, just requires a different way of looking at the logic.

The other option is to not have any CMRI sensors set up; then JMRI won't send out POLL requests for it.

Okay, sounds good, I'll try that and let you know if that fixes it. Out of curiosity, how long does it typically take to run cmri.process()?

It varies depending on whether there is a POLL message that needs responding to or not. If there is no data to process, it is near enough to instant. If it needs to send out a poll response, then it'll take fractionally longer, but it shouldn't be significant.

I just finished rewriting the rotation system to be non-blocking. After some tinkering (which had less to do with your library and more to do with my limited C experience) I was able to get it working with JMRI. The only blocking thing in the program now is the initial startup_beep() function that runs at the very end of setup(), and plays a quick series of notes on a piezo speaker to let me know the controller just booted up. Everything seems to work! A couple times I have gotten one of those errors in JMRI immediately after the board starts, so I think that's due to the startup_beep() function being blocking. In an hour or so of testing I was not able to reproduce any of those errors by throwing/closing turnout bits, which is what caused them before.

So in short, this was my fault for not writing everything to be non-blocking. Thank you so much for your patience and for your help with this program. I really appreciate it!

Awesome glad to help. So the random toggling of lines has gone away too?

Seems to. The only thing that I have not gotten totally working is the "turn 180 degrees" function, which sometimes gets called twice, but if I do it in a strange way it works fine. I'm pretty sure that's issues in my programming.