File: PWMPortFS

Details

File: PWMPortFS.cs
Date: Thu, Mar 7, 2019
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;

/// +------------------------------------------------------------------------------------------------------------------------------+
/// |                                                   TERMS OF USE: MIT License                                                  |
/// +------------------------------------------------------------------------------------------------------------------------------|
/// |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    |
/// |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    |
/// |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
/// |is furnished to do so, subject to the following conditions:                                                                   |
/// |                                                                                                                              |
/// |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
/// |                                                                                                                              |
/// |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          |
/// |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         |
/// |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   |
/// |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         |
/// +------------------------------------------------------------------------------------------------------------------------------+

namespace BBBCSIO
{
    /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
    /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
    /// <summary>
    /// Provides the Pulse Width Modulation Port functionality for a BeagleBone Black
    /// This is the SYSFS version
    /// 
    /// Be aware that you need to ensure the PWM port is configured in the Device
    /// Tree before this code will work. Usually this is done by adding the 
    /// overlay to the uEnv.txt file. The Beaglebone Black and Device Tree Overlays
    /// technical note has more information.
    /// 
    /// http://www.ofitselfso.com/BeagleNotes/Beaglebone_Black_And_Device_Tree_Overlays.php
    ///
    /// Any of the entries below placed in the /boot/uEnv.txt file will enable the 
    /// specified PWM ports. You may need to edit the .dts source if you only want A and 
    /// not B etc.
    /// uboot_overlay_addr4=/lib/firmware/BB-PWM0-00A0.dtbo (PWM0_A & PWM0_B)
    /// uboot_overlay_addr5=/lib/firmware/BB-PWM1-00A0.dtbo (PWM1_A & PWM1_B)
    /// uboot_overlay_addr6=/lib/firmware/BB-PWM2-00A0.dtbo (PWM2_A & PWM2_B)
    /// 
    /// </summary>
    /// <history>
    ///    07 Mar 19  Cynic - Originally written
    /// </history>
    public class PWMPortFS : PortFS
    {

        // the PWM port we use
        private PWMPortEnum pwmPort = PWMPortEnum.PWM_NONE;      

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="pwmPortIn">The PWM port we use</param>
        /// <history>
        ///    07 Mar 19  Cynic - Originally written
        /// </history>
        public PWMPortFS(PWMPortEnum pwmPortIn) : base(GpioEnum.GPIO_NONE)
        {
            pwmPort = pwmPortIn;
            //Console.WriteLine("PWMPort Starts");
            // open the port
            OpenPort();
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets/Sets the period of the PWM output square wave form
        /// 
        /// </summary>
        /// <value>the period (1/Freq) in nano seconds</value>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public uint PeriodNS
        { 
            get
            {
                if(portIsOpen != true) throw new Exception("Port "+ PWMPort.ToString() + " is not open");

                // read the contents of the file
                string pwmFileName = BBBDefinitions.PWM_FILENAME_PERIOD.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
                string outStr = System.IO.File.ReadAllText(pwmFileName);

                // return the contents as a UINT
                return Convert.ToUInt32(outStr);
            }
            set
            {
                //Console.WriteLine("Set PeriodNS : " + value.ToString());
                if(portIsOpen != true) throw new Exception("Port "+ PWMPort.ToString() + " is not open");

                // set the period
                string pwmFileName = BBBDefinitions.PWM_FILENAME_PERIOD.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
                Console.WriteLine("Set PeriodNS pwmFileName=: " + pwmFileName +", value="+ value.ToString());
                System.IO.File.WriteAllText(pwmFileName, value.ToString());
            }
        }
       
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets/Sets the frequency of the PWM output square wave form
        /// 
        /// </summary>
        /// <value>frequency in Hz</value>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public uint FrequencyHz
        { 
            get
            {
                UInt64 freqInHz = 1000000000/PeriodNS;
                return (uint)freqInHz;
            }
            set
            {
                UInt64 periodInNs = 1000000000/value;
                PeriodNS = (uint)periodInNs;
            }
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets/Sets the duty cycle of the PWM output square wave form as a percent
        /// 
        /// </summary>
        /// <value>percentage of the input value. Must be between 0 and 100 </value>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public double DutyPercent
        { 
            get
            {
                return (( float)DutyNS/(float)PeriodNS)*100;
            }
            set
            {
                DutyNS = (uint)((float)PeriodNS*(value/100));
            }
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets/Sets the duty cycle of the PWM output square wave form in nanoseconds
        /// 
        /// NOTE: the duty cycle is the part of the wave form devoted to a high state
        /// (if polarity is PWM_POLARITY_NORMAL) or the percent of the wave form devoted to
        /// the low state (if polarity is PWM_POLARITY_INVERTED)
        /// 
        /// </summary>
        /// <value>the duty cycle of the PWM output in nanoseconds. This should always
        /// be less than the PeriodNS</value>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public uint DutyNS
        { 
            get
            {
                if(portIsOpen != true) throw new Exception("Port "+ PWMPort.ToString() + " is not open");

                // read the contents of the file
                string pwmFileName = BBBDefinitions.PWM_FILENAME_DUTY.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
                string outStr = System.IO.File.ReadAllText(pwmFileName);

                // return the contents as a UINT
                return Convert.ToUInt32(outStr);
            }
            set
            {
                //Console.WriteLine("Set DutyNS : " + value.ToString());
                if(portIsOpen != true) throw new Exception("Port "+ PWMPort.ToString() + " is not open");

                // set the duty
                string pwmFileName = BBBDefinitions.PWM_FILENAME_DUTY.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
                System.IO.File.WriteAllText(pwmFileName, value.ToString());
            }
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets/Sets the run state of the PWM output square wave
        /// 
        /// </summary>
        /// <value>true - begin running, false - stop running</value>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public bool RunState
        { 
            get
            {
                if(portIsOpen != true) throw new Exception("Port "+ PWMPort.ToString() + " is not open");

                // read the contents of the file
                string pwmFileName = BBBDefinitions.PWM_FILENAME_ENABLE.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
                string outStr = System.IO.File.ReadAllText(pwmFileName);
                //Console.WriteLine("Get Run State : outStr=" + outStr);

                // return the contents as a UINT
                if (outStr.Trim() == "1") return true;
                else return false;
            }
            set
            {
                // Console.WriteLine("Set Run State : " + value.ToString());
                if(portIsOpen != true) throw new Exception("Port "+ PWMPort.ToString() + " is not open");

                // set the run state
                string outVal = "0";
                if (value == true) outVal = "1";
                string pwmFileName = BBBDefinitions.PWM_FILENAME_ENABLE.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
                System.IO.File.WriteAllText(pwmFileName, outVal);
            }
        }            

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Opens the port. Throws an exception on failure
        /// 
        /// </summary>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        protected override void OpenPort()
        {

            string outfileName = BBBDefinitions.PWM_FILENAME_EXPORT.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
            Console.WriteLine("PWMPort Port Opening: "+ outfileName + ", " + ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());

            // do the export
            System.IO.File.WriteAllText(outfileName, ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
            portIsOpen = true;

            // the act of writing the PortExportNumber to the export file
            // will create a directory /sys/class/pwm/pwm<PortExportNumber> 
            // This directory contains files which we can use to enable the PWM
            // and set the pulse widths etc

            Console.WriteLine("PWMPort Port Opened: "+ PWMPort.ToString());
        }


        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Closes the port. 
        /// 
        /// </summary>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public override void ClosePort()
        {

            string outfileName = BBBDefinitions.PWM_FILENAME_UNEXPORT.Replace("%chipNum%", ConvertPWMPortEnumToChipNumber(PWMPort).ToString()).Replace("%deviceNum%", ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
            Console.WriteLine("PWMPort Port Closing: " + outfileName + ", " + ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());

            // do the unexport
            System.IO.File.WriteAllText(outfileName, ConvertPWMPortEnumToDeviceNumber(PWMPort).ToString());
            portIsOpen = false;

            // the act of writing the PortExportNumber to the unexport file
            // will remove the directory /sys/class/pwm/pwm<PortExportNumber>:
    
            Console.WriteLine("PWMPort Port Closed: "+ PWMPort.ToString());

        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets the PWM Port. There is no Set accessor this is set in the constructor
        /// </summary>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public PWMPortEnum PWMPort
        {
            get
            {
                return pwmPort;
            }
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Gets the PortDirection
        /// </summary>
        /// <history>
        ///    07 Mar 19 Cynic - Originally written
        /// </history>
        public override PortDirectionEnum PortDirection()
        {
            return PortDirectionEnum.PORTDIR_OUTPUT;
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// The sysfs system requires a number to be used in order to 
        /// specify the EHRPWM chip in use
        /// </summary>
        /// <param name="pwmPortIn">The PWM port we use</param>
        /// <returns>the export number</returns>
        /// <history>
        ///    03 Mar 19  Cynic - Originally written
        /// </history>
        public uint ConvertPWMPortEnumToChipNumber(PWMPortEnum pwmPortIn)
        {
            if (pwmPortIn == PWMPortEnum.PWM0_A) return 0; // 0 - EHRPWM0A
            if (pwmPortIn == PWMPortEnum.PWM0_B) return 0; // 1 - EHRPWM0B    
            if (pwmPortIn == PWMPortEnum.PWM1_A) return 2; // 3 - EHRPWM1A
            if (pwmPortIn == PWMPortEnum.PWM1_B) return 2; // 4 - EHRPWM1B
            if (pwmPortIn == PWMPortEnum.PWM2_A) return 4; // 5 - EHRPWM2A
            if (pwmPortIn == PWMPortEnum.PWM2_B) return 4; // 6 - EHRPWM2B
            throw new Exception("Unknown PWM Port: "+ pwmPortIn.ToString());
        }

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// The sysfs system requires a number to be used in order to 
        /// specify a specific PWM device on a EHRPWM chip This function 
        /// converts the PWMPortEnum value to that number
        /// </summary>
        /// <param name="pwmPortIn">The PWM port we use</param>
        /// <returns>the export number</returns>
        /// <history>
        ///    07 Mar 19  Cynic - Originally written
        ///    03 Mar 19  Cynic - Converted to new PWM Port Enum names
        /// </history>
        public uint ConvertPWMPortEnumToDeviceNumber(PWMPortEnum pwmPortIn)
        {
            if (pwmPortIn == PWMPortEnum.PWM0_A) return 0; // 0 - EHRPWM0A
            if (pwmPortIn == PWMPortEnum.PWM0_B) return 1; // 1 - EHRPWM0B    
            if (pwmPortIn == PWMPortEnum.PWM1_A) return 0; // 3 - EHRPWM1A
            if (pwmPortIn == PWMPortEnum.PWM1_B) return 1; // 4 - EHRPWM1B
            if (pwmPortIn == PWMPortEnum.PWM2_A) return 0; // 5 - EHRPWM2A
            if (pwmPortIn == PWMPortEnum.PWM2_B) return 1; // 6 - EHRPWM2B
            throw new Exception("Unknown PWM Port: " + pwmPortIn.ToString());
        }

        // #########################################################################
        // ### Dispose Code
        // #########################################################################
        #region

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Implement IDisposable. 
        /// Dispose(bool disposing) executes in two distinct scenarios. 
        /// 
        ///    If disposing equals true, the method has been called directly 
        ///    or indirectly by a user's code. Managed and unmanaged resources 
        ///    can be disposed.
        ///  
        ///    If disposing equals false, the method has been called by the 
        ///    runtime from inside the finalizer and you should not reference 
        ///    other objects. Only unmanaged resources can be disposed. 
        /// 
        ///  see: http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28v=vs.110%29.aspx
        /// 
        /// </summary>
        /// <history>
        ///    28 Aug 14 Cynic - Originally written
        /// </history>
        protected override void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(Disposed==false)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing==true)
                {
                    // Dispose managed resources.
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. If disposing is false, 
                // only the following code is executed.

                // Clean up our code
                //  Console.WriteLine("Disposing PWMPORT");
         
                // call the base to dispose there
                base.Dispose(disposing);

            }
        }
        #endregion

    }
}

HTML Code Generated by CoDocker v00.90 Beta