softpwm.bmx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. ' Copyright (c) .NET Foundation and Contributors
  2. ' Copyright (c) 2019 Bruce A Henderson
  3. '
  4. ' All rights reserved.
  5. '
  6. ' Permission is hereby granted, free of charge, to any person obtaining a copy
  7. ' of this software and associated documentation files (the "Software"), to deal
  8. ' in the Software without restriction, including without limitation the rights
  9. ' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. ' copies of the Software, and to permit persons to whom the Software is
  11. ' furnished to do so, subject to the following conditions:
  12. '
  13. ' The above copyright notice and this permission notice shall be included in all
  14. ' copies or substantial portions of the Software.
  15. '
  16. ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. ' SOFTWARE.
  23. '
  24. SuperStrict
  25. Rem
  26. bbdoc: Software PWM channel.
  27. End Rem
  28. Module iot.SoftPwm
  29. Import iot.core
  30. Import brl.timer
  31. Rem
  32. bbdoc: Software PWM channel implementation
  33. End Rem
  34. Type TSoftwarePwmChannel Extends TPwmChannel
  35. Field currentPulseWidth:Double
  36. Field pulseFrequency:Double
  37. Field frequency:Int
  38. Field percentage:Double
  39. Field usePrecisionTimer:Int
  40. Field isRunning:Int
  41. Field isStopped:Int = True
  42. Field servoPin:Int = -1
  43. Field runningThread:TThread
  44. Field controller:TGpioController
  45. Field runThread:Int = True
  46. Field shouldDispose:Int
  47. Field chrono:TChrono = TChrono.Create()
  48. Method New(pinNumber:Int, frequency:Int = 400, dutyCycle:Double = 0.5, usePrecisionTimer:Int = False, controller:TGpioController = Null, shouldDispose:Int = True)
  49. If Not controller Then
  50. Self.controller = New TGpioController()
  51. Self.shouldDispose = True
  52. Else
  53. Self.controller = controller
  54. Self.shouldDispose = shouldDispose
  55. End If
  56. If Not controller Then
  57. Print "GPIO does not exist on the current system."
  58. Return
  59. End If
  60. servoPin = pinNumber
  61. controller.OpenPin(servoPin, EPinMode.Output)
  62. Self.usePrecisionTimer = usePrecisionTimer
  63. isRunning = False
  64. runningThread = TThread.Create(_RunSoftPWM, Self)
  65. Self.frequency = frequency
  66. If frequency > 0 Then
  67. pulseFrequency = 1.0 / frequency * 1000.0
  68. End If
  69. SetDutyCycle(dutyCycle)
  70. End Method
  71. Rem
  72. bbdoc: Gets the frequency in hertz.
  73. End Rem
  74. Method GetFrequency:Int()
  75. Return frequency
  76. End Method
  77. Rem
  78. bbdoc: Sets the frequency in hertz.
  79. End Rem
  80. Method SetFrequency(value:Int)
  81. If value < 0 Then
  82. Throw New TArgumentOutOfRangeException("Value must note be negative.")
  83. End If
  84. frequency = value
  85. If frequency > 0 Then
  86. pulseFrequency = 1 / frequency * 1000.0
  87. Else
  88. pulseFrequency = 0.0
  89. End If
  90. UpdateRange()
  91. End Method
  92. Rem
  93. bbdoc: Gets the duty cycle percentage represented as a value between 0.0 and 1.0.
  94. End Rem
  95. Method GetDutyCycle:Double()
  96. Return percentage
  97. End Method
  98. Rem
  99. bbdoc: Sets the duty cycle percentage represented as a value between 0.0 and 1.0.
  100. End Rem
  101. Method SetDutyCycle(value:Double)
  102. If value < 0.0 Or value > 1.0 Then
  103. Throw New TArgumentOutOfRangeException("Value must be between 0.0 and 1.0.")
  104. End If
  105. percentage = value
  106. UpdateRange()
  107. End Method
  108. Private
  109. Method UpdateRange()
  110. currentPulseWidth = percentage * pulseFrequency
  111. End Method
  112. Function _RunSoftPWM:Object(data:Object)
  113. TSoftwarePwmChannel(data).RunSoftPWM()
  114. End Function
  115. Method RunSoftPWM()
  116. While runThread
  117. ' Write the pin high for the appropriate length of time
  118. If isRunning Then
  119. If currentPulseWidth <> 0 Then
  120. controller.Write(servoPin, EPinValue.High)
  121. isStopped = False
  122. End If
  123. ' Use the wait helper method to wait for the length of the pulse
  124. Wait(currentPulseWidth)
  125. ' The pulse if over and so set the pin to low and then wait until it's time for the next pulse
  126. controller.Write(servoPin, EPinValue.Low)
  127. Wait(pulseFrequency - currentPulseWidth)
  128. Else
  129. If Not isStopped Then
  130. controller.Write(servoPin, EPinValue.Low)
  131. isStopped = True
  132. End If
  133. End If
  134. Wend
  135. End Method
  136. Method Wait(milliseconds:Double)
  137. Local initialTick:ULong = chrono.GetElapsedTicks()
  138. Local initialElapsed:ULong = chrono.GetElapsedMilliseconds()
  139. Local desiredTicks:Double = milliseconds / 1000.0 * TChrono.frequency
  140. Local finalTick:Double = initialTick + desiredTicks
  141. While chrono.GetElapsedTicks() < finalTick
  142. Wend
  143. End Method
  144. Public
  145. Rem
  146. bbdoc: Starts the PWM channel.
  147. End Rem
  148. Method Start()
  149. isRunning = True
  150. End Method
  151. Rem
  152. bbdoc: Stops the PWM channel.
  153. End Rem
  154. Method Stop()
  155. isRunning = False
  156. End Method
  157. Method Dispose()
  158. isRunning = False
  159. runThread = False
  160. If runningThread Then
  161. runningThread.Wait()
  162. End If
  163. If shouldDispose Then
  164. If controller Then
  165. controller.Dispose()
  166. controller = Null
  167. End If
  168. End If
  169. End Method
  170. End Type