Jump to content



Photo
* * * - - 2 votes

Grander Unified-er DOF R3++


  • Please log in to reply
490 replies to this topic

#181 mjr

mjr

    Pinball Wizard

  • Members
  • PipPipPipPipPip
  • 3,332 posts

  • Flag: United States of America

  • Favorite Pinball: Medieval Madness

Posted 25 April 2018 - 01:03 AM

Wow...its not inn the directoutput directory. And it does not even come up during a system wide search. Figures...thats my luck :)

Now what do I need to do?

 

In order for me to get my log to work, I had to put the direct path to where the log should be..

In the GlobalConfig_B2SServer.xml

 

Yeah, that's the place to check.  The path for that is <direct output install folder>\config. 

 

GlobalConfig_B2SServer.xml is the one that's in effect when running VP, and there's a separate one called GlobalConfig_PinballX.xml that's used when you're running PinballX. 

 

Given that there doesn't seem to a log file anywhere on your disk, you should check to see if you explicitly disabled the log.  You might have saved a version with logging disabled at some point - that was the default in older versions.  Check the XML file for a line like this:

 

<EnableLogging>true</EnableLogging>

 

If it's not there, add it; if it's there, make sure it says "true" and not "false" or some other random string.

 

Hopefully it's something along these lines.  If not, you might have something weirder and harder to debug going on - my first guess would be a file permission issue or the like.



#182 wrd1972

wrd1972

    Authoring Padawan

  • Platinum Supporter
  • 2,265 posts
  • Location:Central KY. USA

  • Flag: United States of America

  • Favorite Pinball: Funhouse

Posted 25 April 2018 - 02:03 AM

It appears to be enabled. Damn it all. I will try to determine if there is a permission issue. Unfortunately, permissions have always drove me mad on Windows.

 

<?xml version="1.0" encoding="utf-8"?>
<!--Global configuration for the DirectOutput framework.-->
<!--Saved by DirectOutput Version 3.1.6656.21457: 2018-04-24 21-54-15-->
<GlobalConfig>
  <LedWizDefaultMinCommandIntervalMs>10</LedWizDefaultMinCommandIntervalMs>
  <LedControlMinimumEffectDurationMs>60</LedControlMinimumEffectDurationMs>
  <LedControlMinimumRGBEffectDurationMs>120</LedControlMinimumRGBEffectDurationMs>
  <PacLedDefaultMinCommandIntervalMs>10</PacLedDefaultMinCommandIntervalMs>
  <IniFilesPath />
  <CabinetConfigFilePattern></CabinetConfigFilePattern>
  <TableConfigFilePatterns />
  <EnableLogging>true</EnableLogging>
  <ClearLogOnSessionStart>true</ClearLogOnSessionStart>
  <LogFilePattern>C:\DirectOutput\DirectOutput.log</LogFilePattern>
</GlobalConfig>


My VP Pincab /MAME Arcade  Specs: Dell T3400 workstation with Core2 Quad core 3.0GHZ (Q9650) CPU - 8GB of RAM - Nvidia  GTX 970

40" PF Sony gaming LED TV, Dual 21" Dell monitors in the backbox - Pinscape dual boards - Full DOF - Full MAME arcade support.


#183 wrd1972

wrd1972

    Authoring Padawan

  • Platinum Supporter
  • 2,265 posts
  • Location:Central KY. USA

  • Flag: United States of America

  • Favorite Pinball: Funhouse

Posted 25 April 2018 - 02:20 AM

Permissions appear to be find. I'm showing full access to the DirectOutput directory. I also dropped in a file called "DirectOutput.log" into the directory...hoping it would get written to. Nothing!

 

I am also now seeing where sometimes only one of the two, Sainsmart relay boards are not working. Other times...both are out. Seems to be very repeatable when it does happen. The issue can easily happen 50% of the time.


My VP Pincab /MAME Arcade  Specs: Dell T3400 workstation with Core2 Quad core 3.0GHZ (Q9650) CPU - 8GB of RAM - Nvidia  GTX 970

40" PF Sony gaming LED TV, Dual 21" Dell monitors in the backbox - Pinscape dual boards - Full DOF - Full MAME arcade support.


#184 wrd1972

wrd1972

    Authoring Padawan

  • Platinum Supporter
  • 2,265 posts
  • Location:Central KY. USA

  • Flag: United States of America

  • Favorite Pinball: Funhouse

Posted 25 April 2018 - 02:52 PM

So to test, I added "DOFSlave.exe" to the white list in my Bitdefender Ransom Ware protection, and the issue might be fixed. I started around 15 or so games this morning and did not notice the problem one time. I will continue to monitor this and will hopefully be able to report that the problem is resolved. Thanks for the assistance guys. :)


My VP Pincab /MAME Arcade  Specs: Dell T3400 workstation with Core2 Quad core 3.0GHZ (Q9650) CPU - 8GB of RAM - Nvidia  GTX 970

40" PF Sony gaming LED TV, Dual 21" Dell monitors in the backbox - Pinscape dual boards - Full DOF - Full MAME arcade support.


#185 mjr

mjr

    Pinball Wizard

  • Members
  • PipPipPipPipPip
  • 3,332 posts

  • Flag: United States of America

  • Favorite Pinball: Medieval Madness

Posted 25 April 2018 - 06:15 PM

So to test, I added "DOFSlave.exe" to the white list in my Bitdefender Ransom Ware protection, and the issue might be fixed. I started around 15 or so games this morning and did not notice the problem one time. I will continue to monitor this and will hopefully be able to report that the problem is resolved. Thanks for the assistance guys. :)

 

Great - glad that seems to have fixed it.  It didn't occur to me to suggest fiddling with antivirus/antimalware software, since most cab builders delete all of that stuff when first setting up.  But this is a good thing to keep in mind for anyone else having config problems - try disabling or uninstalling all of your security software.  (It shouldn't be necessary to disable the basic Windows stuff like UAC, though, unless you're getting explicit error boxes from Windows telling you that UAC is blocking something.)

 

Did that help with the missing DOF log file, by the way?  If not, one more thing you might want to try is changing the absolute path you have set (D:\DirectOutput\DirectOutput.log) to a relative path (.\DirectOutput.log).


Edited by mjr, 25 April 2018 - 06:16 PM.


#186 wrd1972

wrd1972

    Authoring Padawan

  • Platinum Supporter
  • 2,265 posts
  • Location:Central KY. USA

  • Flag: United States of America

  • Favorite Pinball: Funhouse

Posted 26 April 2018 - 10:12 PM

Nope, I still dont have a log. But I have not searched to see if it might be placed somewhere weird.


My VP Pincab /MAME Arcade  Specs: Dell T3400 workstation with Core2 Quad core 3.0GHZ (Q9650) CPU - 8GB of RAM - Nvidia  GTX 970

40" PF Sony gaming LED TV, Dual 21" Dell monitors in the backbox - Pinscape dual boards - Full DOF - Full MAME arcade support.


#187 wrd1972

wrd1972

    Authoring Padawan

  • Platinum Supporter
  • 2,265 posts
  • Location:Central KY. USA

  • Flag: United States of America

  • Favorite Pinball: Funhouse

Posted 09 May 2018 - 04:09 PM

New question regarding DOF, and I am not sure if this is a new concern with 3+, or if it has always been around.

 

So on any given table and specifically when the ball is very rapidly bouncing around in a cluster of pop-bumpers, it seems that the solenoid feedback falls out of sync with the ball contacting the bumpers. I dont think its a lag issue, but rather that the bumper hits are just too quick for the DOF controller,  to keep up with. Another way of saying it, if the ball hits the bumpers maybe 8 times in a second, I might hear 4 solenoid feedbacks. I dont really see this issue anywhere else on the table, just in a cluster of pops.

 

Is this normal for DOF? Or do I have something configured wrong. Its noticeable enough that it detracts from the overall experience.

 

Thanks


My VP Pincab /MAME Arcade  Specs: Dell T3400 workstation with Core2 Quad core 3.0GHZ (Q9650) CPU - 8GB of RAM - Nvidia  GTX 970

40" PF Sony gaming LED TV, Dual 21" Dell monitors in the backbox - Pinscape dual boards - Full DOF - Full MAME arcade support.


#188 mjr

mjr

    Pinball Wizard

  • Members
  • PipPipPipPipPip
  • 3,332 posts

  • Flag: United States of America

  • Favorite Pinball: Medieval Madness

Posted 09 May 2018 - 05:09 PM

So on any given table and specifically when the ball is very rapidly bouncing around in a cluster of pop-bumpers, it seems that the solenoid feedback falls out of sync with the ball contacting the bumpers. I dont think its a lag issue, but rather that the bumper hits are just too quick for the DOF controller,  to keep up with. Another way of saying it, if the ball hits the bumpers maybe 8 times in a second, I might hear 4 solenoid feedbacks. I dont really see this issue anywhere else on the table, just in a cluster of pops.

 

My guess is that the physical travel time of your solenoids is the limiting factor.

 

You might want to capture some high-speed video of the game action in question to get the exact timing, because it can be hard to precisely judge short time frames like this by eye.  The diagnosis will be different if you're talking 1/8 second intervals between events vs 1/80 second intervals.

 

If "8 times a second" is accurate, you're talking about an average of 125ms between events.  But let's say that the 8 bumper hits over the 1-second period aren't perfectly evenly distributed in time, and it's really more like 30ms between the closest pair of bumper hits.  In terms of DOF events, one bumper hit is actually two events, an ON and an OFF command for the solenoid.  So we might be down to a shortest interval of around 15ms.

 

15ms is relatively slow by DOF standards, but it's really fast in terms of physical motion of solenoids.  DOF can reliably handle updates at intervals of 10ms or less, in practice, considering the whole chain of things in the system - VP/VPM/B2S, DOF, USB, LedWiz.   But for your solenoids, 15ms is probably much too fast for them to reset.  I have some actual timing data on this courtesy of scottacus, who hooked his chime box up to a signal generator to figure out exactly how fast it could run.  His testing came up with about 150ms cycle time for his chime coils.  Most of that is just the time it takes for the plunger to make the full round trip and get back to its starting position - if you feed it pulses faster than that, the pulses will catch the plunger in mid-travel and pull it back rather than forward, so that it doesn't hit the target on that cycle.  I'm sure you're using something completely different from chime coils for your bumpers, so the exact timing will be different, but probably not that different.  So my guess is that they're the source of the problem.



#189 DJRobX

DJRobX

    Pinball Fan

  • VP Dev Team
  • PipPipPipPip
  • 941 posts
  • Location:Valencia, CA

  • Flag: United States of America

  • Favorite Pinball: F14 Tomcat

Posted 10 May 2018 - 09:46 PM

Another thing I brought up too is that DOF bumpers are generally configured to work off of MAME solenoid numbers, but are actually activated immediately in VP.  VP then sends the signal to the ROM with PulseSw, which is a queueing mechanism processed by a timer.    So between the switch signal triggering, it actually getting to VPM, VPM responding to the switch by firing a solenoid, and that solenoid signal being received by DOF, there's quite a bit of opportunity for lag and lag accumulation.

 

Might be worthwhile trying a custom Exxx DOF event, and firing it directly on the bumper hit sub to see if the situation improves at all.


Edited by DJRobX, 10 May 2018 - 09:51 PM.


#190 gtxjoe

gtxjoe

    VPF Veteran

  • VIP
  • 5,153 posts

  • Flag: United States of America

  • Favorite Pinball: Medieval Madness, AbraCadabra



Contributor

Posted 10 May 2018 - 10:56 PM

Also most likely one solenoid is being used to cover the 3 bumpers

Maybe as a test, map each bumper to a unique solenoid in your cabinet

#191 Aetios

Aetios

    Neophyte

  • Members
  • Pip
  • 6 posts

  • Flag: France

  • Favorite Pinball: Jurassic Park

  • PS3 Gamer Tag: Aetios
  • 360 Gamer Tag: Aetios

Posted 12 May 2018 - 07:19 PM

Hi guys,

 

thx to @mjr and @DJRobX for this update. 

 

Could it be possible to modify TeensyStripController.cs from the code source to integrate the compatibility with the WEMOS D1 Mini Pro which actually can do the same work as the Teensy for our Virtual Pinball.

 

Here is the modded code :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;

namespace DirectOutput.Cab.Out.AdressableLedStrip
{
    /// <summary>
    /// The TeensyStripController is used to control up to 8 WS2811/WS2812 based ledstrips with up to 1100 leds per strip which are connected to a Teensy 3.1, 3.2 or later.
    /// 
    /// \image html TeensyOctoWS2811.jpg
    /// 
    /// The best place to get the hardware is probably the <a target="_blank" href="http://pjrc.com/teensy/">website</a> of the Teennsy inventor, where you can buy the <a target="_blank" href="http://pjrc.com/store/teensy32_pins.html">Teensy boards</a> (check if newer versions are available) and also a <a target="_blank" href="http://pjrc.com/store/octo28_adaptor.html">adapter board</a> which allows for easy connection of up to 8 led strips. There are also numerous other vendors of Teensy hardware (just ask Google).
    /// 
    /// The firmware for the Teensy based ledstrip controller is based on a slightly hacked version of Paul Stoffregens excellent OctoWS2811 LED Library which can easily drive up to 1100leds per channel on a Teensy 3.1 or later. More information on the OctoWS2811 lib can be found on the Teensy website, on Github and many other places on the internet.
    /// 
    /// Ready to use, compiled firmware files can be downloaded from the <a target="_blank" href="http://github.com/DirectOutput/TeensyStripController/releases/">Github page</a> for the TeensyStripController, the source code for the firmware is available on Github as well.
    /// 
    /// </summary>
    public class TeensyStripController : OutputControllerCompleteBase
    {
        private int[] NumberOfLedsPerStrip = new int[8];

        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 1 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 1 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip1
        {
            get
            {
                return NumberOfLedsPerStrip[0];
            }
            set
            {
                NumberOfLedsPerStrip[0] = value;
                base.SetupOutputs();
            }
        }
        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 2 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 2 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip2
        {
            get
            {
                return NumberOfLedsPerStrip[1];
            }
            set
            {
                NumberOfLedsPerStrip[1] = value;
                base.SetupOutputs();
            }
        }

        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 3 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 3 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip3
        {
            get
            {
                return NumberOfLedsPerStrip[2];
            }
            set
            {
                NumberOfLedsPerStrip[2] = value;
                base.SetupOutputs();
            }
        }
        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 4 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 4 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip4
        {
            get
            {
                return NumberOfLedsPerStrip[3];
            }
            set
            {
                NumberOfLedsPerStrip[3] = value;
                base.SetupOutputs();
            }
        }
        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 5 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 5 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip5
        {
            get
            {
                return NumberOfLedsPerStrip[4];
            }
            set
            {
                NumberOfLedsPerStrip[4] = value;
                base.SetupOutputs();
            }
        }

        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 6 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 6 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip6
        {
            get
            {
                return NumberOfLedsPerStrip[5];
            }
            set
            {
                NumberOfLedsPerStrip[5] = value;
                base.SetupOutputs();
            }
        }
        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 7 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 7 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip7
        {
            get
            {
                return NumberOfLedsPerStrip[6];
            }
            set
            {
                NumberOfLedsPerStrip[6] = value;
                base.SetupOutputs();
            }
        }
        /// <summary>
        /// Gets or sets the number of leds of ledstrip connected to channel 8 of the Teensy.
        /// </summary>
        /// <value>
        /// The number of leds on the ledstrip connected to channel 8 of the Teensy.
        /// </value>
        public int NumberOfLedsStrip8
        {
            get
            {
                return NumberOfLedsPerStrip[7];
            }
            set
            {
                NumberOfLedsPerStrip[7] = value;
                base.SetupOutputs();
            }
        }

        private string _ComPortName;

        /// <summary>
        /// Gets or sets the name (typicaly COM{Number}) of the virtual Com port the Teensy board is using.
        /// </summary>
        /// <value>
        /// The name of the Com port (typicaly COM{Number}) the Teensy board is using.
        /// </value>
        public string ComPortName
        {
            get { return _ComPortName; }
            set { _ComPortName = value; }
        }


        private int _ComPortTimeOutMs = 200;

        /// <summary>
        /// Gets or sets the COM port timeout in milliseconds.
        /// This properties accepts values between 1 and 5000 milliseconds (default 200ms). If a value outside this range is specified, the properties value reverts to the default value of 200ms.
        /// </summary>
        /// <value>
        /// The COM port timeout in milliseconds (Valid range 1-5000ms, default: 200ms).
        /// </value>
        public int ComPortTimeOutMs
        {
            get { return _ComPortTimeOutMs; }
            set
            {
                if (value.IsBetween(1, 5000))
                {
                    _ComPortTimeOutMs = value;
                }
                else
                {
                    _ComPortTimeOutMs = 200;
                    Log.Warning("The specified value {0} for the ComPortTimeOutMs is outside the valid range of 1 to 5000. Will use the default value of 200ms.".Build(value));
                }
            }
        }



        /// <summary>
        /// This method returns the sum of the number of leds configured for the 8 output channels of the Teensy board.
        /// </summary>
        /// <returns>
        /// The sum of the number of leds configured for the 8 output channels of the Teensy board.
        /// </returns>
        protected override int GetNumberOfConfiguredOutputs()
        {
            return NumberOfLedsPerStrip.Sum() * 3;
        }

        /// <summary>
        /// Verifies if a valid ComPortName has been set and if the number of outputs per channel is >=0.
        /// </summary>
        /// <returns>
        ///   <c>true</c> if the verification is OK, otherwise <c>false</c>
        /// </returns>
        protected override bool VerifySettings()
        {
            if (ComPortName.IsNullOrWhiteSpace())
            {
                Log.Warning("The ComPortName has not been specified");
                return false;
            }

            if (!SerialPort.GetPortNames().Any(PN => PN == ComPortName))
            {
                Log.Warning("The specified Com-Port {0} was not found. Available com-ports: {1}".Build(ComPortName, string.Join(", ", SerialPort.GetPortNames())));
                return false;
            }

            if (NumberOfLedsPerStrip.Any(Nr => Nr < 0))
            {
                Log.Warning("At least one ledstrip has a invalid number of leds specified (<0).");
                return false;
            }
            return true;
        }


        SerialPort ComPort = null;
        int NumberOfLedsPerChannel = -1;

        protected override void UpdateOutputs(byte[] OutputValues)
        {
            if (ComPort == null)
            {
                throw new Exception("Comport is not initialized");
            }
            byte[] CommandData;
            byte[] AnswerData;
            int BytesRead;
            int SourcePosition = 0;
            for (int i = 0; i < 8; i++)
            {
                int NrOfLedsOnStrip = NumberOfLedsPerStrip[i];
                if (NrOfLedsOnStrip > 0)
                {
                    int TargetPosition = i * NumberOfLedsPerChannel;
                    CommandData = new byte[5] { (byte)'R', (byte)(TargetPosition >> 8), (byte)(TargetPosition & 255), (byte)(NrOfLedsOnStrip >> 8), (byte)(NrOfLedsOnStrip & 255) };

                    ComPort.Write(CommandData, 0, 5);
                    ComPort.Write(OutputValues, SourcePosition * 3, NrOfLedsOnStrip * 3);

                    BytesRead = -1;

                    AnswerData = new byte[1];

                    try
                    {
                        BytesRead = ComPort.Read(AnswerData, 0, 1);
                    }
                    catch (Exception E)
                    {
                        throw new Exception("A exception occured while waiting for the ACK after sending the data for channel {0} of the TeensyStripController.".Build(i + 1), E);
                    }
                    if (BytesRead != 1 || AnswerData[0] != (byte)'A')
                    {
                        throw new Exception("Received no answer or a unexpected answer while waiting for the ACK after sending the data for channel {0} of the TeensyStripController.".Build(i + 1));
                    }
                    SourcePosition += NrOfLedsOnStrip;
                }
            }

            CommandData = new byte[1] { (byte)'O' };
            ComPort.Write(CommandData, 0, 1);

            BytesRead = -1;
            AnswerData = new byte[1];

            try
            {
                BytesRead = ComPort.Read(AnswerData, 0, 1);
            }
            catch (Exception E)
            {
                throw new Exception("A exception occured while waiting for the ACK after sending the output command (O) to the TeensyStripController", E);
            }
            if (BytesRead != 1 || AnswerData[0] != (byte)'A')
            {
                throw new Exception("Received no answer or a unexpected answer while waiting for the ACK after sending the output command (O) to the TeensyStripController");
            }


        }


        //private byte[] PackData(byte[] OutputValues, int FirstLed, int NumberOfLeds)
        //{
        //    int OutputPosition = FirstLed * 3;
        //    int LedNr = 0;

        //    if (NumberOfLeds > 0)
        //    {
        //        while (LedNr < NumberOfLeds)
        //        {
        //            if (OutputValues[OutputPosition] == OutputValues[OutputPosition + 3] && OutputValues[OutputPosition + 1] == OutputValues[OutputPosition + 4] && OutputValues[OutputPosition + 2] == OutputValues[OutputPosition + 5])
        //            {
        //                //
        //            }
        //            else
        //            {

        //            }




        //        }



        //    }
        //    else
        //    {
        //        //No data to pack
        //        return new byte[1] { 0 };
        //    }


        //}


        /// <summary>
        /// This method is called when DOF wants to connect to the controller.
        /// </summary>
        protected override void ConnectToController()
        {
            DisconnectFromController();

            string[] PortNames = SerialPort.GetPortNames();
            if (!PortNames.Any(PN => PN == ComPortName))
            {
                throw new Exception("The specified Com-Port '{0}' does not exist. Found the following Com-Ports: {1}. Will not send data to the controller.".Build(ComPortName, string.Join(", ", PortNames)));
            }

            //ComPort = new SerialPort();
            ComPort = new SerialPort(ComPortName, 921600, Parity.None, 8, StopBits.One);
            ComPort.ReadTimeout = ComPortTimeOutMs;
            ComPort.WriteTimeout = ComPortTimeOutMs;

            try
            {
                ComPort.PortName = ComPortName;
            }
            catch (Exception E)
            {
                throw new Exception("A exception occured while setting the name of the Com-port '{0}'. Found the following Com-Ports: {1}.  Will not send data to the controller.".Build(ComPortName, string.Join(", ", PortNames)), E);
            }

            try
            {
                ComPort.Open();
                Thread.Sleep(5000);
            }
            catch (Exception E)
            {
                throw new Exception("A exception occured while trying to open the Com-port '{0}'. Found the following Com-Ports: {1}.  Will not send data to the controller.".Build(ComPortName, string.Join(", ", PortNames)), E);
            }



            //Make sure, the controller is in the expected state (ready to receive commands)
            Thread.Sleep(50);
            ComPort.ReadExisting();

            bool CommandModeOK = false;
            for (int AttemptNr = 0; AttemptNr < 20; AttemptNr++)
            {

                ComPort.Write(new byte[] { 0 }, 0, 1);
                Thread.Sleep(200);
                if (ComPort.BytesToRead > 0)
                {
                    int Ret = ComPort.ReadByte();
                    if (Ret == (int)'A')
                    {
                        //Got a Ack, controller is ready for more commands
                        CommandModeOK = true;
                        break;
                    }
                    else if (Ret == (int)'N')
                    {
                        //Got a NACK. Controller is ready for more commands
                        CommandModeOK = true;
                        break;
                    }
                    else
                    {
                        //Must be the answer of a previous command. Just ignore.
                    }

                    //Got no anwser from com port. Mostly likely we are still inside a command which is expecting more data. Send a lot of 0 bytes to get out of this situation.
                    ComPort.Write(new byte[3 * 1000], 0, 3 * 1000);

                    Thread.Sleep(50);
                    //Get rid of all returned data and try again
                    ComPort.ReadExisting();
                }
            };
            if (!CommandModeOK)
            {
                Log.Exception("Could not put the controller on com-port {0} into the commandmode. Will not send data to the controller.".Build(ComPortName));
                DisconnectFromController();
                return;
            }


            //If we reach this point, we know that the controller is ready to accept commands.

            //Check max number of leds per channel
            ComPort.Write(new byte[] { (byte)'M' }, 0, 1);
            byte[] ReceiveData = new byte[3];
            int BytesRead = -1;

            try
            {
                BytesRead = ReadPortWait(ReceiveData, 0, 3);
            }
            catch (Exception E)
            {
                throw new Exception("Expected 3 bytes containing data on the max number of leds per channel, but the read operation resulted in a exception. Will not send data to the controller", E);
            }


            if (BytesRead != 3)
            {
                throw new Exception("The TeensyStripController did not send the expected 3 bytes containing the data on the max number of leds per channel. Received only {0} bytes. Will not send data to the controller".Build(BytesRead));
            }
            if (ReceiveData[2] != 'A')
            {
                throw new Exception("The TeensyStripController did not send a ACK after the data containing the max number of leds per channel. Will not send data to the controller");
            }
            int MaxNumberOfLedsPerChannel = ReceiveData[0] * 256 + ReceiveData[1];

            if (NumberOfLedsPerStrip.Any(Nr => Nr > MaxNumberOfLedsPerChannel))
            {
                throw new Exception("The TeensyStripController boards supports up to {0}} leds per channel, but you have defined up to {1} leds per channel. Will not send data to the controller.".Build(MaxNumberOfLedsPerChannel, NumberOfLedsPerStrip.Max()));
            }



            //Set number of leds per channel
            NumberOfLedsPerChannel = NumberOfLedsPerStrip.Max();
            ushort NrOfLeds = (ushort)NumberOfLedsPerChannel;
            byte[] CommandData = new byte[3] { (byte)'L', (byte)(NrOfLeds >> 8), (byte)(NrOfLeds & 255) };
            ComPort.Write(CommandData, 0, 3);
            ReceiveData = new byte[1];
            BytesRead = -1;
            try
            {
                BytesRead = ReadPortWait(ReceiveData, 0, 1);
            }
            catch (Exception E)
            {
                throw new Exception("Expected 1 bytes after setting the number of leds per channel, but the read operation resulted in a exception. Will not send data to the controller.", E);
            }

            if (BytesRead != 1 || ReceiveData[0] != (byte)'A')
            {
                throw new Exception("Expected a Ack (A) after setting the number of leds per channel, but received no answer or a unexpected answer. Will not send data to the controller.");

            }

            //Clear the buffer and turn off the leds.
            CommandData = new byte[1] { (byte)'C' };
            ComPort.Write(CommandData, 0, 1);
            ReceiveData = new byte[1];
            BytesRead = -1;
            try
            {
                BytesRead = ReadPortWait(ReceiveData, 0, 1);
            }
            catch (Exception E)
            {
                throw new Exception("Expected 1 bytes after clearing the buffer of the TeensyStripController, but the read operation resulted in a exception. Will not send data to the controller.", E);
            }

            if (BytesRead != 1 || ReceiveData[0] != (byte)'A')
            {
                throw new Exception("Expected a Ack (A) after clearing the buffer of the TeensyStripController, but received no answer or a unexpected answer. Will not send data to the controller.");
            }

            CommandData = new byte[1] { (byte)'O' };
            ComPort.Write(CommandData, 0, 1);
            ReceiveData = new byte[1];
            BytesRead = -1;
            try
            {
                BytesRead = ReadPortWait(ReceiveData, 0, 1);
            }
            catch (Exception E)
            {
                throw new Exception("Expected 1 bytes after outputing the buffer of the TeensyStripController to the ledstrips, but the read operation resulted in a exception. Will not send data to the controller.", E);
            }

            if (BytesRead != 1 || ReceiveData[0] != (byte)'A')
            {
                throw new Exception("Expected a Ack (A) after outputing the buffer of the TeensyStripController to the ledstrips, but received no answer or a unexpected answer. Will not send data to the controller.");
            }
        }




        /// <summary>
        /// Disconnects from the controller.
        /// </summary>
        protected override void DisconnectFromController()
        {
            if (ComPort != null)
            {
                try
                {
                    ComPort.Close();

                }
                finally
                {
                    ComPort = null;
                }
            }

        }


        /// <summary>
        /// Reads reads the specifed number of bytes into the given buffer.
        /// Waits until the specified number of bytes has been received or until the read timeout of the comport occurs.
        /// </summary>
        /// <param name="Buffer">The buffer.</param>
        /// <param name="BufferOffset">The buffer offset.</param>
        /// <param name="NumberOfBytes">The number of bytes.</param>
        /// <returns>Number of bytes read.</returns>
        private int ReadPortWait(byte[] Buffer, int BufferOffset, int NumberOfBytes)
        {

            byte[] ReadBuffer = new byte[1];
            for (int ByteNumber = 0; ByteNumber < NumberOfBytes; ByteNumber++)
            {
                int BytesRead = -1;

                try
                {
                    BytesRead = ComPort.Read(ReadBuffer, 0, 1);

                }
                catch (TimeoutException TE)
                {
                    throw new Exception("A TimeoutException occured while trying to read byte {0} of {1} from Com-Port {2}.".Build(ByteNumber + 1, NumberOfBytes, ComPort.PortName), TE);
                }
                catch (Exception E)
                {
                    throw new Exception("A exception occured while trying to read byte {0} of {1} from Com-Port {2}.".Build(ByteNumber + 1, NumberOfBytes, ComPort.PortName), E);
                }

                if (BytesRead != 1)
                {
                    throw new Exception("A exception occured while trying to read byte {0} of {1} from Com-Port {2}. Tried to read 1 byte, but received {3} bytes.".Build(new object[] { ByteNumber + 1, NumberOfBytes, ComPort.PortName, BytesRead }));
                }

                Buffer[BufferOffset + ByteNumber] = ReadBuffer[0];

            }

            return NumberOfBytes;

        }



    }
}

This modification would be really appreciate because for the moment we have to modify your code at each update.

 

Thx a lot,

 

Byebye



#192 mjr

mjr

    Pinball Wizard

  • Members
  • PipPipPipPipPip
  • 3,332 posts

  • Flag: United States of America

  • Favorite Pinball: Medieval Madness

Posted 14 May 2018 - 06:40 PM

Could it be possible to modify TeensyStripController.cs from the code source to integrate the compatibility with the WEMOS D1 Mini Pro which actually can do the same work as the Teensy for our Virtual Pinball.

 

Okay, I'll take a look at merging that when I get a chance - I'll let you know how it goes.

 

(Just FYI and for future reference, GitHub provides a more formal way to convey code updates like this, called a "pull request".  The basic procedure is like this:  (1) you create your own fork of the DOF repository on GitHub, branching off from my DOF repos (which is easy - one button click on the GitHub web site), (2) you make your edits to the file or files in your forked copy (which you can also do purely on the GitHub web site - no need to install any Git tools on your PC for this), (3) you commit your changes in your forked repos, and (4) you click the Create Pull Request button to send me a request to merge the changes back into my fork.  It's no problem for me to merge back ad hoc changes to a file or two like the one you posted here, but the Pull Request mechanism is easier for you and me both if there's more than one file involved since everything is handled on the GitHub site; you don't have to keep track of a bunch of separate copies of the files.)



#193 bord

bord

    Pinball Fan

  • Members
  • PipPipPipPip
  • 603 posts

  • Flag: ---------

  • Favorite Pinball: Star Gazer, Whirlwind, Frontier

Posted 20 May 2018 - 07:50 PM

Thought I'd chime (haha) in and give a success story. Just finished setting up a set of Pinscape boards (main, power, chime) in Windows 10 and this tool had me up and running with almost no work. Sure beats the last time I tried to set up a Sainsmart device manually. I'm honestly still in shock at how much faster this was. Thanks, mjr!



#194 BorgDog

BorgDog

    We come in peace.. shoot to kill.. shoot to kill.

  • Members
  • PipPipPipPip
  • 1,427 posts
  • Location:Leavenworth, WA

  • Flag: United States of America

  • Favorite Pinball: Alien Star, TNA



Posted 21 May 2018 - 01:42 PM

I'm about to start putting my boards together (main and 2 chime) and one thing I haven't seen but may have missed is high res images of fully populated boards (not wired up).  I know I don't need them to build mine, but would like just as a reality check and for planning order of construction...

 

edit: oops, should have put in other thread


Edited by BorgDog, 21 May 2018 - 01:43 PM.


#195 marc9

marc9

    Hobbyist

  • Members
  • PipPip
  • 17 posts

  • Flag: ---------

  • Favorite Pinball: RFM

Posted 23 May 2018 - 01:54 PM

Here are high res pictures of the main and power board: http://www.dallasliv....php#uebersicht and a video:

 



#196 BorgDog

BorgDog

    We come in peace.. shoot to kill.. shoot to kill.

  • Members
  • PipPipPipPip
  • 1,427 posts
  • Location:Leavenworth, WA

  • Flag: United States of America

  • Favorite Pinball: Alien Star, TNA



Posted 23 May 2018 - 05:30 PM

thanks, I like being able to see what it is supposed to look like in the end.



#197 Rappelbox

Rappelbox

    Enthusiast

  • Banned
  • PipPipPip
  • 88 posts

  • Flag: Germany

  • Favorite Pinball: Creature fr...... ;)

Posted 23 May 2018 - 05:37 PM

Chime board for you ;)

509f6964e2b52d00302e91b8d6f5444d.jpgeb39d70ef67cba9868a8bc39f4ccaa56.jpge04e1c9efbe366efddd220b19c7bdbfd.jpg2326dd95f6195d25f9000a8707a3bed8.jpg


Gesendet von iPhone mit Tapatalk
www.GermanGamingSupplies.com - European Virtual Pinball Supplies and ready assembled Pinscape Boards, PIN²DMDs, Virtual Pins

Visual Pinball Addicts - the BIGGEST Visual and Virtual Pinball Group worldwide... Newest table releases, tutorials, videos, chat... all that fancy stuff

#198 NailBuster

NailBuster

    Enthusiast

  • Members
  • PipPipPip
  • 300 posts

  • Flag: Canada

  • Favorite Pinball: YES

Posted 01 June 2018 - 03:28 AM

Hi guys,

 

thx to @mjr and @DJRobX for this update. 

 

Could it be possible to modify TeensyStripController.cs from the code source to integrate the compatibility with the WEMOS D1 Mini Pro which actually can do the same work as the Teensy for our Virtual Pinball.

 

Here is the modded code :et + ByteNumber] = ReadBuffer[0];



This modification would be really appreciate because for the moment we have to modify your code at each update.

 

Thx a lot,

 

Byebye

 

IMO,  these code changes shouldn't be applied to the working Teensy working class.  What i did is just create a new class called WeMosStripController with the needed changes.  Keeps it separate and allows some better fine tuning with the esp8266 interface code without messing with the teensycontroller driver.

 

I can send the PR if you want....but i just did the changes now, so I'll be testing it a bit to get those sleep times a bit lower.



#199 mjr

mjr

    Pinball Wizard

  • Members
  • PipPipPipPipPip
  • 3,332 posts

  • Flag: United States of America

  • Favorite Pinball: Medieval Madness

Posted 01 June 2018 - 04:27 AM

IMO,  these code changes shouldn't be applied to the working Teensy working class.  What i did is just create a new class called WeMosStripController with the needed changes.  Keeps it separate and allows some better fine tuning with the esp8266 interface code without messing with the teensycontroller driver.

 

Agreed - that seems like the right way to do it.

 

 

I can send the PR if you want....but i just did the changes now, so I'll be testing it a bit to get those sleep times a bit lower.

 

I'd say hold off on the pull request until you're satisfied with the testing/tuning, and then send it my way and I'll merge it with my branch.  It sounds like Aetios doesn't need the merged version urgently as he already has his own manual merged version - what I got is that he just wants to avoid having to do it again on each update (correct me if I'm wrong, Aetios!).  I don't have any pending updates in the works right now so there's no immediate rush.



#200 Aetios

Aetios

    Neophyte

  • Members
  • Pip
  • 6 posts

  • Flag: France

  • Favorite Pinball: Jurassic Park

  • PS3 Gamer Tag: Aetios
  • 360 Gamer Tag: Aetios

Posted 01 June 2018 - 07:26 AM

Thx guys for your return.

 

@NailBuster

 

Normally, the changed code works with both teensy and wemos. My friend @kakou could explain it better because he's in charge with this modification.

But if you added a new controller for wemos, it should be perfect too. Just tell me where I can find the link to download the source and we will test it soon (may I search a forked one on GitHub ?)

 

@mjr

 

I will try to pull a request on your github. I've never used it. I hope I won't broke something lol

 

And just for your information, here is the code working on wemos to use Teensy DOF. : https://github.com/a.../PincabLedStrip

 

Thx again for your interest

 

 

 

EDIT : the easiest way should to keep the teensy code and to add a "if -- then" to activate the modification of the wemos via the cabinet.XML.. @kakou just told me this idea, he will try to make it soon. We will test it and share it by pulling a request to your code.

 

EDIT2 : Peskopat from PincabPassion has just confirmed me that the moddified code works with both Teensy and Wemos. So I'll send the request to your GitHub @mjr. thx ;)

 

EDIT3 : Request pulled ! ;)


Edited by Aetios, 01 June 2018 - 09:59 AM.