diff --git a/Ev3LangScala/src/ev3dev4s/Ev3System.scala b/Ev3LangScala/src/ev3dev4s/Ev3System.scala index 0e80ea5..8e3bbc4 100644 --- a/Ev3LangScala/src/ev3dev4s/Ev3System.scala +++ b/Ev3LangScala/src/ev3dev4s/Ev3System.scala @@ -21,4 +21,4 @@ object Ev3System { lazy val portsToMotors: Map[MotorPort, Motor] = MotorPortScanner.scanMotors lazy val portsToSensors: Map[SensorPort, Sensor[_]] = SensorPortScanner.scanSensors -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/JarRunner.scala b/Ev3LangScala/src/ev3dev4s/JarRunner.scala index 7c718a3..5f04ab4 100644 --- a/Ev3LangScala/src/ev3dev4s/JarRunner.scala +++ b/Ev3LangScala/src/ev3dev4s/JarRunner.scala @@ -41,7 +41,7 @@ object JarRunner { } @tailrec - def runIt(jarFile:Path,className:String):Unit = { + def runIt(jarFile: Path, className: String): Unit = { try { Log.log(s"Start run() of $className from $jarFile") val classLoader = new URLClassLoader(Array(jarFile.toUri.toURL)) @@ -49,14 +49,14 @@ object JarRunner { } catch { case x: Throwable => - Log.log("Caught in top-level",x) + Log.log("Caught in top-level", x) MotorPortScanner.stopAllMotors() Ev3Led.writeBothRed() Lcd.clear() x.getMessage.grouped(11).take(3).zipWithIndex.foreach { chunk => Lcd.set(chunk._2, chunk._1) } - Lcd.set(3,"Push Button") + Lcd.set(3, "Push Button") Lcd.flush() Sound.playTone(55.Hz, 200.milliseconds) Ev3KeyPad.blockUntilAnyKey() @@ -68,4 +68,4 @@ object JarRunner { } runIt(jarFile, className) } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/Log.scala b/Ev3LangScala/src/ev3dev4s/Log.scala index 739e614..2252df2 100644 --- a/Ev3LangScala/src/ev3dev4s/Log.scala +++ b/Ev3LangScala/src/ev3dev4s/Log.scala @@ -11,10 +11,11 @@ import java.io.PrintStream object Log { private val logStream: PrintStream = Option(System.getProperty("logFile")).map(new PrintStream(_)).getOrElse(System.out) - def log(text: String): Unit = logStream.println(s"${System.currentTimeMillis()} $text") + def log(text: String): Unit = logStream.println(s"${System.currentTimeMillis()} $text") def log(text: String, x: Throwable): Unit = { logStream.println(s"${System.currentTimeMillis()} $text") x.printStackTrace(logStream) } + } diff --git a/Ev3LangScala/src/ev3dev4s/actuators/Ev3Led.scala b/Ev3LangScala/src/ev3dev4s/actuators/Ev3Led.scala index 5b64cdd..47f1d7f 100644 --- a/Ev3LangScala/src/ev3dev4s/actuators/Ev3Led.scala +++ b/Ev3LangScala/src/ev3dev4s/actuators/Ev3Led.scala @@ -1,10 +1,10 @@ package ev3dev4s.actuators +import ev3dev4s.scala2measure.Conversions._ +import ev3dev4s.scala2measure.LedIntensity import ev3dev4s.sysfs.ChannelRewriter import java.nio.file.Path -import ev3dev4s.scala2measure.LedIntensity -import ev3dev4s.scala2measure.Conversions._ /** * @@ -12,8 +12,9 @@ import ev3dev4s.scala2measure.Conversions._ * @author David Walend */ -sealed case class Ev3Led(side:Int) extends AutoCloseable { - import ev3dev4s.actuators.Ev3Led.{Color,brightest, darkest,Off,Red,Green,Yellow} +sealed case class Ev3Led(side: Int) extends AutoCloseable { + + import ev3dev4s.actuators.Ev3Led.{Color, Off, Red, Green, Yellow} // brightest, darkest val rootName = "/sys/class" //noinspection SpellCheckingInspection @@ -21,31 +22,34 @@ sealed case class Ev3Led(side:Int) extends AutoCloseable { //noinspection SpellCheckingInspection val greenName = s"leds/led$side:green:brick-status/brightness" - private val redPath = Path.of (rootName, redName) - private val greenPath = Path.of (rootName, greenName) + private val redPath = Path.of(rootName, redName) + private val greenPath = Path.of(rootName, greenName) - private val redWriter: ChannelRewriter = ChannelRewriter (redPath) - private val greenWriter: ChannelRewriter = ChannelRewriter (greenPath) + private val redWriter: ChannelRewriter = ChannelRewriter(redPath) + private val greenWriter: ChannelRewriter = ChannelRewriter(greenPath) //todo add readers to read brightness from the same paths maybe someday - it will work, not sure if it has any value - def writeBrightness (red: LedIntensity, green: LedIntensity): Unit = this.synchronized { - redWriter.writeAsciiInt (red.round) - greenWriter.writeAsciiInt (green.round) + def writeBrightness(red: LedIntensity, green: LedIntensity): Unit = this.synchronized { + redWriter.writeAsciiInt(red.round) + greenWriter.writeAsciiInt(green.round) } - override def close (): Unit = this.synchronized { - redWriter.close () - greenWriter.close () + override def close(): Unit = this.synchronized { + redWriter.close() + greenWriter.close() } - def writeColor(color:Color) = { - writeBrightness(color.red,color.green) + def writeColor(color: Color): Unit = { + writeBrightness(color.red, color.green) } - def writeOff (): Unit = writeColor(Off) - def writeRed (): Unit = writeColor(Red) - def writeGreen (): Unit = writeColor(Green) - def writeYellow (): Unit = writeColor(Yellow) + def writeOff(): Unit = writeColor(Off) + + def writeRed(): Unit = writeColor(Red) + + def writeGreen(): Unit = writeColor(Green) + + def writeYellow(): Unit = writeColor(Yellow) } object Ev3Led { @@ -57,10 +61,10 @@ object Ev3Led { case class Color(red: LedIntensity, green: LedIntensity) - val Red: Color = Color(brightest,darkest) - val Yellow: Color = Color(brightest,brightest) - val Green: Color = Color(darkest,brightest) - val Off: Color = Color(darkest,darkest) + val Red: Color = Color(brightest, darkest) + val Yellow: Color = Color(brightest, brightest) + val Green: Color = Color(darkest, brightest) + val Off: Color = Color(darkest, darkest) def writeBothGreen(): Unit = writeBothColor(Green) @@ -81,17 +85,17 @@ object Ev3Led { * Yellow Red * Yellow Off * */ - def writeBothColor(leftColor:Color,rightColor:Color):Unit = { + def writeBothColor(leftColor: Color, rightColor: Color): Unit = { Left.writeColor(leftColor) Right.writeColor(rightColor) } - def writeBothColor(colors:(Color,Color)): Unit = { + def writeBothColor(colors: (Color, Color)): Unit = { Left.writeColor(colors._1) Right.writeColor(colors._2) } - def writeBothColor(color:Color):Unit = { - writeBothColor(color,color) + def writeBothColor(color: Color): Unit = { + writeBothColor(color, color) } } diff --git a/Ev3LangScala/src/ev3dev4s/actuators/Motor.scala b/Ev3LangScala/src/ev3dev4s/actuators/Motor.scala index 74d5bcb..c331b5f 100644 --- a/Ev3LangScala/src/ev3dev4s/actuators/Motor.scala +++ b/Ev3LangScala/src/ev3dev4s/actuators/Motor.scala @@ -16,20 +16,21 @@ import ev3dev4s.scala2measure.MilliSeconds * @author David Walend * @since v0.0.0 */ -sealed abstract class Motor(port: MotorPort,motorFS:Option[MotorFS]) extends Gadget(port,motorFS){ +//noinspection ScalaUnusedSymbol +sealed abstract class Motor(port: MotorPort, motorFS: Option[MotorFS]) extends Gadget(port, motorFS) { - def writeCommand(command: MotorCommand):Unit = checkPort(_.writeCommand(command)) + def writeCommand(command: MotorCommand): Unit = checkPort(_.writeCommand(command)) - def writeStopAction(command:MotorStopCommand):Unit = checkPort(_.writeStopAction(command)) + def writeStopAction(command: MotorStopCommand): Unit = checkPort(_.writeStopAction(command)) - def writeDutyCycle(dutyCycle:DutyCycle):Unit = checkPort(_.writeDutyCycle(dutyCycle)) + def writeDutyCycle(dutyCycle: DutyCycle): Unit = checkPort(_.writeDutyCycle(dutyCycle)) - def maxSpeed:DegreesPerSecond + def maxSpeed: DegreesPerSecond - def observedMaxSpeed:DegreesPerSecond + def observedMaxSpeed: DegreesPerSecond - def writeSpeed(speed:DegreesPerSecond):Unit = { - val safeSpeed = if(speed.abs < maxSpeed ) speed + def writeSpeed(speed: DegreesPerSecond): Unit = { + val safeSpeed = if (speed.abs < maxSpeed) { speed } else { Log.log(s"requested speed $speed is greater than $maxSpeed - using $maxSpeed") (speed.sign * maxSpeed).degreesPerSecond @@ -45,25 +46,25 @@ sealed abstract class Motor(port: MotorPort,motorFS:Option[MotorFS]) extends Gad checkPort(_.writeRampDownSpeed(fromMaxToZero)) } - def writePosition(degrees:Degrees):Unit = checkPort(_.writePosition(degrees)) + def writePosition(degrees: Degrees): Unit = checkPort(_.writePosition(degrees)) - def resetPosition():Unit = writePosition(0.degrees) + def resetPosition(): Unit = writePosition(0.degrees) - def writeGoalPosition(degrees:Degrees):Unit = checkPort(_.writeGoalPosition(degrees)) + def writeGoalPosition(degrees: Degrees): Unit = checkPort(_.writeGoalPosition(degrees)) - def writeDuration(milliseconds:MilliSeconds):Unit = checkPort(_.writeDuration(milliseconds)) + def writeDuration(milliseconds: MilliSeconds): Unit = checkPort(_.writeDuration(milliseconds)) /** * @return position in degrees */ - def readPosition():Degrees = checkPort(_.readPosition()) + def readPosition(): Degrees = checkPort(_.readPosition()) def readState(): Array[MotorState] = checkPort(_.readState()) - def readIsStalled():Boolean = + def readIsStalled(): Boolean = readState().contains(MotorState.STALLED) - def readIsRunning():Boolean = + def readIsRunning(): Boolean = readState().contains(MotorState.RUNNING) def coast(): Unit = { @@ -75,40 +76,42 @@ sealed abstract class Motor(port: MotorPort,motorFS:Option[MotorFS]) extends Gad writeStopAction(MotorStopCommand.BRAKE) writeCommand(MotorCommand.STOP) } + def hold(): Unit = { writeStopAction(MotorStopCommand.HOLD) writeCommand(MotorCommand.STOP) } - def runDutyCycle(dutyCycle:DutyCycle):Unit = { + + def runDutyCycle(dutyCycle: DutyCycle): Unit = { writeDutyCycle(dutyCycle) writeCommand(MotorCommand.RUN_DIRECT) } - def run(speed:DegreesPerSecond):Unit = { + def run(speed: DegreesPerSecond): Unit = { writeSpeed(speed) writeCommand(MotorCommand.RUN) } - def runToAbsolutePosition(speed:DegreesPerSecond,degrees:Degrees):Unit = { + def runToAbsolutePosition(speed: DegreesPerSecond, degrees: Degrees): Unit = { writeSpeed(speed) writeGoalPosition(degrees) writeCommand(MotorCommand.RUN_TO_ABSOLUTE_POSITION) } - def runToRelativePosition(speed:DegreesPerSecond,degrees:Degrees):Unit = { + def runToRelativePosition(speed: DegreesPerSecond, degrees: Degrees): Unit = { writeSpeed(speed) writeGoalPosition(degrees) writeCommand(MotorCommand.RUN_TO_RELATIVE_POSITION) } - def runForDuration(speed:DegreesPerSecond,milliseconds:MilliSeconds):Unit = { + def runForDuration(speed: DegreesPerSecond, milliseconds: MilliSeconds): Unit = { writeSpeed(speed) writeDuration(milliseconds) writeCommand(MotorCommand.RUN_TIME) } } -sealed case class Ev3LargeMotor(override val port:MotorPort, md: Option[MotorFS]) extends Motor(port,md) { +sealed case class Ev3LargeMotor(override val port: MotorPort, md: Option[MotorFS]) extends Motor(port, md) { override def findGadgetFS(): Option[MotorFS] = MotorPortScanner.findGadgetDir(port, Ev3LargeMotor.driverName) .map(MotorFS) @@ -121,7 +124,7 @@ object Ev3LargeMotor { val driverName = "lego-ev3-l-motor" } -sealed case class Ev3MediumMotor(override val port:MotorPort, md: Option[MotorFS]) extends Motor(port,md) { +sealed case class Ev3MediumMotor(override val port: MotorPort, md: Option[MotorFS]) extends Motor(port, md) { override def findGadgetFS(): Option[MotorFS] = MotorPortScanner.findGadgetDir(port, Ev3MediumMotor.driverName) .map(MotorFS) @@ -134,7 +137,7 @@ object Ev3MediumMotor { val driverName = "lego-ev3-m-motor" } -sealed case class MotorCommand(command:String) +sealed case class MotorCommand(command: String) object MotorCommand { /** @@ -148,11 +151,11 @@ object MotorCommand { val RUN_TO_ABSOLUTE_POSITION: MotorCommand = MotorCommand("run-to-abs-pos") /** - run-to-rel-pos: Runs the motor to a position relative to the current position v. The new position will be current position + position_sp. When the new position is reached, the motor will stop using the command specified by stop_action. */ + * run-to-rel-pos: Runs the motor to a position relative to the current position v. The new position will be current position + position_sp. When the new position is reached, the motor will stop using the command specified by stop_action. */ val RUN_TO_RELATIVE_POSITION: MotorCommand = MotorCommand("run-to-rel-pos") /** - run-timed: Run the motor for the amount of time specified in time_sp and then stops the motor using the command specified by stop_action. + * run-timed: Run the motor for the amount of time specified in time_sp and then stops the motor using the command specified by stop_action. */ val RUN_TIME: MotorCommand = MotorCommand("run-timed") @@ -166,15 +169,16 @@ object MotorCommand { val STOP: MotorCommand = MotorCommand("stop") /** - reset: Resets all of the motor parameter attributes to their default values. This will also have the effect of stopping the motor. + * reset: Resets all of the motor parameter attributes to their default values. This will also have the effect of stopping the motor. */ } + /** * Determines the motors behavior when command is set to stop. Possible values are: */ -sealed case class MotorStopCommand(command:String) +sealed case class MotorStopCommand(command: String) -object MotorStopCommand{ +object MotorStopCommand { /** * Removes power from the motor. The motor will freely coast to a stop. */ @@ -191,29 +195,29 @@ object MotorStopCommand{ val HOLD: MotorStopCommand = MotorStopCommand("hold") } -sealed case class MotorState(name:String) +sealed case class MotorState(name: String) -object MotorState{ +object MotorState { /** - running: Power is being sent to the motor. + * running: Power is being sent to the motor. */ val RUNNING: MotorState = MotorState("running") /** - ramping: The motor is ramping up or down and has not yet reached a constant output level. + * ramping: The motor is ramping up or down and has not yet reached a constant output level. */ val RAMPING: MotorState = MotorState("ramping") /** - holding: The motor is not turning, but rather attempting to hold a fixed position. + * holding: The motor is not turning, but rather attempting to hold a fixed position. */ val HOLDING: MotorState = MotorState("holding") /** - overloaded: The motor is turning as fast as possible, but cannot reach its speed_sp. + * overloaded: The motor is turning as fast as possible, but cannot reach its speed_sp. */ val OVERLOADED: MotorState = MotorState("overloaded") /** - stalled: The motor is trying to run but is not turning at all. + * stalled: The motor is trying to run but is not turning at all. */ val STALLED: MotorState = MotorState("stalled") - val values: Array[MotorState] = Array(RUNNING,RAMPING,HOLDING,OVERLOADED,STALLED) -} \ No newline at end of file + val values: Array[MotorState] = Array(RUNNING, RAMPING, HOLDING, OVERLOADED, STALLED) +} diff --git a/Ev3LangScala/src/ev3dev4s/actuators/MotorFS.scala b/Ev3LangScala/src/ev3dev4s/actuators/MotorFS.scala index f18585d..76a89fb 100644 --- a/Ev3LangScala/src/ev3dev4s/actuators/MotorFS.scala +++ b/Ev3LangScala/src/ev3dev4s/actuators/MotorFS.scala @@ -13,12 +13,11 @@ import ev3dev4s.scala2measure.DutyCycle import ev3dev4s.Log /** - * * * @author David Walend * @since v0.0.0 */ -private[actuators] case class MotorFS(motorDir:Path) extends GadgetFS{ +private[actuators] case class MotorFS(motorDir: Path) extends GadgetFS { private val commandWriter = ChannelRewriter(motorDir.resolve("command")) private val stopActionWriter = ChannelRewriter(motorDir.resolve("stop_action")) @@ -34,36 +33,38 @@ private[actuators] case class MotorFS(motorDir:Path) extends GadgetFS{ private val rampDownWriter = ChannelRewriter(motorDir.resolve("ramp_down_sp")) private val positionReader = ChannelRereader(motorDir.resolve("position")) - private val stateReader = ChannelRereader(motorDir.resolve("state"),bufferLength = 52) + private val stateReader = ChannelRereader(motorDir.resolve("state"), bufferLength = 52) //todo maybe writeCommand should be on the write side of a ReadWriteLock - and all others can be on the Read side? - def writeCommand(command: MotorCommand):Unit = + def writeCommand(command: MotorCommand): Unit = commandWriter.writeString(command.command) - def writeStopAction(command:MotorStopCommand):Unit = + def writeStopAction(command: MotorStopCommand): Unit = stopActionWriter.writeString(command.command) - def writeDutyCycle(dutyCycle:DutyCycle):Unit = { - if(dutyCycle.abs > 100.dutyCyclePercent) Log.log(s"abs duty cycle $dutyCycle is greater than ${100.dutyCyclePercent}") + def writeDutyCycle(dutyCycle: DutyCycle): Unit = { + if (dutyCycle.abs > 100.dutyCyclePercent) { + Log.log(s"abs duty cycle $dutyCycle is greater than ${ 100.dutyCyclePercent }") + } dutyCycleSpWriter.writeAsciiInt(dutyCycle.round) } - def writeSpeed(speed:DegreesPerSecond):Unit = + def writeSpeed(speed: DegreesPerSecond): Unit = speedSpWriter.writeAsciiInt(speed.round) - def writePosition(degrees:Degrees):Unit = + def writePosition(degrees: Degrees): Unit = positionWriter.writeAsciiInt(degrees.round) - def resetPosition():Unit = + def resetPosition(): Unit = writePosition(0.degrees) - def writeGoalPosition(degrees:Degrees):Unit = + def writeGoalPosition(degrees: Degrees): Unit = goalPositionWriter.writeAsciiInt(degrees.round) - def writeDuration(milliseconds:MilliSeconds):Unit = + def writeDuration(milliseconds: MilliSeconds): Unit = timeWriter.writeAsciiInt(milliseconds.round) - def writeRampUpSpeed(fromZeroToMax:MilliSeconds):Unit = { + def writeRampUpSpeed(fromZeroToMax: MilliSeconds): Unit = { rampUpWriter.writeAsciiInt(fromZeroToMax.v.round) } @@ -73,14 +74,17 @@ private[actuators] case class MotorFS(motorDir:Path) extends GadgetFS{ /** - * @return position in degrees + * @return position in degrees */ - def readPosition():Degrees = + def readPosition(): Degrees = positionReader.readAsciiInt().degrees - val stateNamesToStates: Map[String, MotorState] = MotorState.values.map{ s => s.name -> s}.toMap + val stateNamesToStates: Map[String, MotorState] = MotorState.values.map { s => s.name -> s }.toMap + def readState(): Array[MotorState] = - stateReader.readString().split(' ').filterNot(_ == "").map{stateNamesToStates(_)} + stateReader.readString().split(' ').filterNot(_ == "").map { + stateNamesToStates(_) + } override def close(): Unit = { stateReader.close() @@ -93,4 +97,4 @@ private[actuators] case class MotorFS(motorDir:Path) extends GadgetFS{ commandWriter.close() timeWriter.close() } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/actuators/MotorPortScanner.scala b/Ev3LangScala/src/ev3dev4s/actuators/MotorPortScanner.scala index 853f91d..33a007e 100644 --- a/Ev3LangScala/src/ev3dev4s/actuators/MotorPortScanner.scala +++ b/Ev3LangScala/src/ev3dev4s/actuators/MotorPortScanner.scala @@ -10,21 +10,21 @@ import java.io.File * @author David Walend * @since v0.0.0 */ -object MotorPortScanner extends GadgetPortScanner(new File("/sys/class/tacho-motor"),MotorPort.values){ - - def scanMotors:Map[MotorPort,Motor] = { - scanGadgetDirs.map{ portAndDir => +object MotorPortScanner extends GadgetPortScanner(new File("/sys/class/tacho-motor"), MotorPort.values) { + + def scanMotors: Map[MotorPort, Motor] = { + scanGadgetDirs.map { portAndDir => val driverName = ChannelRereader.readString(portAndDir._2.resolve("driver_name")) val motor = driverName match { case Ev3LargeMotor.driverName => Ev3LargeMotor(portAndDir._1, Option(MotorFS(portAndDir._2))) case Ev3MediumMotor.driverName => Ev3MediumMotor(portAndDir._1, Option(MotorFS(portAndDir._2))) - case unknown => throw new IllegalArgumentException(s"Unknown driver $driverName") + case unknown => throw new IllegalArgumentException(s"Unknown motor driver $driverName") } portAndDir._1 -> motor } } - def stopAllMotors():Unit = { + def stopAllMotors(): Unit = { scanMotors.values.foreach(_.brake()) } @@ -33,10 +33,10 @@ object MotorPortScanner extends GadgetPortScanner(new File("/sys/class/tacho-mot */ Runtime.getRuntime.addShutdownHook(new Thread({ () => stopAllMotors() - },"stopMotorsAtShutdown")) + }, "stopMotorsAtShutdown")) } -sealed case class MotorPort(name:Char) extends Port +sealed case class MotorPort(name: Char) extends Port object MotorPort { val A: MotorPort = MotorPort('A') @@ -44,6 +44,5 @@ object MotorPort { val C: MotorPort = MotorPort('C') val D: MotorPort = MotorPort('D') - val values: Array[MotorPort] = Array(A,B,C,D) + val values: Array[MotorPort] = Array(A, B, C, D) } - diff --git a/Ev3LangScala/src/ev3dev4s/actuators/Sound.scala b/Ev3LangScala/src/ev3dev4s/actuators/Sound.scala index fe08f5d..5f9af5b 100644 --- a/Ev3LangScala/src/ev3dev4s/actuators/Sound.scala +++ b/Ev3LangScala/src/ev3dev4s/actuators/Sound.scala @@ -21,31 +21,33 @@ import ev3dev4s.scala2measure.Conversions._ object Sound { private var volume = 50.percent - def beep():Unit = + def beep(): Unit = Shell.execute("beep") - def playTone(frequency: Hertz, duration: MilliSeconds, volume: Percent):Unit = { + def playTone(frequency: Hertz, duration: MilliSeconds, volume: Percent): Unit = { this.setVolume(volume) this.playTone(frequency, duration) } + /** * Plays a tone, given its frequency and duration. * * @param frequency The frequency of the tone in Hertz (Hz). * @param duration The duration of the tone4, in milliseconds. */ - def playTone(frequency: Hertz, duration: MilliSeconds):Unit = { + def playTone(frequency: Hertz, duration: MilliSeconds): Unit = { val cmdTone = s"/usr/bin/beep -f ${frequency.round} -l ${duration.round}" Shell.execute(cmdTone) } + /** * Play a wav file. Must be mono, from 8kHz to 48kHz, and 8-bit or 16-bit. * * @param file the 8-bit or 16-bit PWM (WAV) sample file * @param volume the volume percentage 0 - 100 */ - //todo draw from .jar resources - def playSample(file: File, volume: Percent = this.volume):Unit = { + //todo draw from .jar resources + def playSample(file: File, volume: Percent = this.volume): Unit = { this.setVolume(volume) this.playSampleUntilDone(file) } @@ -56,7 +58,7 @@ object Sound { * @param file the 8-bit or 16-bit PWM (WAV) sample file */ //todo draw from .jar resources - def playSampleUntilDone(file: File):Unit = { + def playSampleUntilDone(file: File): Unit = { val audioIn: AudioInputStream = AudioSystem.getAudioInputStream(file.toURI.toURL) val clip = AudioSystem.getClip clip.open(audioIn) @@ -65,12 +67,13 @@ object Sound { clip.close() audioIn.close() } + /** * Set the master volume level * * @param volume 0-100 */ - def setVolume(volume: Percent):Unit = { + def setVolume(volume: Percent): Unit = { this.volume = volume val cmdVolume = s"/usr/bin/amixer set PCM,0 $volume%" Shell.execute(cmdVolume) @@ -78,8 +81,8 @@ object Sound { /** * Get the current master volume level - */ - def getVolume:Percent = volume + */ + def getVolume: Percent = volume /** diff --git a/Ev3LangScala/src/ev3dev4s/lcd/tty/Lcd.scala b/Ev3LangScala/src/ev3dev4s/lcd/tty/Lcd.scala index 0a8a93c..6cdc1e2 100644 --- a/Ev3LangScala/src/ev3dev4s/lcd/tty/Lcd.scala +++ b/Ev3LangScala/src/ev3dev4s/lcd/tty/Lcd.scala @@ -17,7 +17,7 @@ object Lcd extends AutoCloseable { val sttySane = new Runnable { override def run(): Unit = Shell.execute("stty -F /dev/tty sane") } - Runtime.getRuntime.addShutdownHook(new Thread(sttySane,"reset stty at shutdown")) + Runtime.getRuntime.addShutdownHook(new Thread(sttySane, "reset stty at shutdown")) Shell.execute("setfont Uni3-TerminusBold32x16") Shell.execute("stty -F /dev/tty -echoctl -echo") @@ -25,27 +25,27 @@ object Lcd extends AutoCloseable { //using a ChannelRewriter gives an "IOException: Illegal seek" in JDK11 new PrintStream( new BufferedOutputStream( - new FileOutputStream("/dev/tty"),64 + new FileOutputStream("/dev/tty"), 64 ) ) } // 4 Rows of 11 Characters for Uni3-TerminusBold32x16 val maxRow = 3 - val maxColumn=10 - private lazy val characters: Array[Array[Char]] = Array.fill(maxRow+1,maxColumn+1)(' ') + val maxColumn = 10 + private lazy val characters: Array[Array[Char]] = Array.fill(maxRow + 1, maxColumn + 1)(' ') val rows: Seq[Int] = 0.to(maxRow) - private lazy val clearRow:Array[Char] = Array.fill(maxColumn+1)(' ') + private lazy val clearRow: Array[Char] = Array.fill(maxColumn + 1)(' ') - def flush():Unit = { + def flush(): Unit = { printStream.print("\u001b[1;1H\u001b[0J") // tty black magic! See https://en.wikipedia.org/wiki/ANSI_escape_code //noinspection MakeArrayToString rows.foreach(i => printStream.print(characters(i))) printStream.flush() } - def clear():Unit = rows.foreach(i => clearRow.copyToArray(characters(i))) + def clear(): Unit = rows.foreach(i => clearRow.copyToArray(characters(i))) override def close(): Unit = { printStream.close() @@ -60,27 +60,27 @@ object Lcd extends AutoCloseable { } val RIGHT: Justify = new Justify { - override def start(length: Int): Int = Math.max(maxColumn + 1 - length,0) + override def start(length: Int): Int = Math.max(maxColumn + 1 - length, 0) } val CENTER: Justify = new Justify { - override def start(length: Int): Int = Math.max((maxColumn/2) + 1 - ((length+1)/2),0) + override def start(length: Int): Int = Math.max((maxColumn / 2) + 1 - ((length + 1) / 2), 0) // 11:0 10:1 9:1 8:2 7:2 6:3 5:3 4:4 3:4 2:5 1:5 } - def set(row:Int,column:Int,char: Char):Unit = { + def set(row: Int, column: Int, char: Char): Unit = { characters(row)(column) = char } - def set(row: Int, column:Int, string: String): Unit = { + def set(row: Int, column: Int, string: String): Unit = { val chars: Array[Char] = string.toCharArray chars.copyToArray(characters(row), column) } - def set(row:Int,string:String,justification: Justify = LEFT):Unit = { + def set(row: Int, string: String, justification: Justify = LEFT): Unit = { val chars: Array[Char] = string.toCharArray val start = justification.start(chars.length) chars.copyToArray(characters(row), start) } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/lego/ColorSensor.scala b/Ev3LangScala/src/ev3dev4s/lego/ColorSensor.scala index 5859a10..8b331a8 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/ColorSensor.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/ColorSensor.scala @@ -12,11 +12,13 @@ import ev3dev4s.sensors.{Ev3ColorSensor, SensorPort, SensorPortScanner} object ColorSensor { private var sensors: Map[SensorPort, Ev3ColorSensor] = _ + private def scanSensors(): Unit = { sensors = SensorPortScanner.scanSensors.collect { case (port: SensorPort, sensor: Ev3ColorSensor) => port -> sensor } } + scanSensors() def readReflected(port: SensorPort): Percent = handleUnplugged( @@ -24,7 +26,7 @@ object ColorSensor { scanSensors ) - def readColor(port: SensorPort): Ev3ColorSensor.Color = handleUnplugged(sensors(port).colorMode().readColor(),scanSensors) + def readColor(port: SensorPort): Ev3ColorSensor.Color = handleUnplugged(sensors(port).colorMode().readColor(), scanSensors) - def readAmbient(port: SensorPort): Percent = handleUnplugged(sensors(port).ambientMode().readAmbient(),scanSensors) -} \ No newline at end of file + def readAmbient(port: SensorPort): Percent = handleUnplugged(sensors(port).ambientMode().readAmbient(), scanSensors) +} diff --git a/Ev3LangScala/src/ev3dev4s/lego/Display.scala b/Ev3LangScala/src/ev3dev4s/lego/Display.scala index 9b0575a..b622148 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/Display.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/Display.scala @@ -10,21 +10,22 @@ import ev3dev4s.scala2measure.LedIntensity * @author David Walend * @since v0.0.0 */ -object Display{ +object Display { sealed case class LedColor(redIntensity: LedIntensity, greenIntensity: LedIntensity) object LedColor { - val Red: LedColor = LedColor(Ev3Led.brightest,Ev3Led.darkest) - val Green: LedColor = LedColor(Ev3Led.darkest,Ev3Led.brightest) - val Orange: LedColor = LedColor(Ev3Led.brightest,Ev3Led.brightest) - val Off:LedColor = LedColor(Ev3Led.darkest,Ev3Led.darkest) + val Red: LedColor = LedColor(Ev3Led.brightest, Ev3Led.darkest) + val Green: LedColor = LedColor(Ev3Led.darkest, Ev3Led.brightest) + val Orange: LedColor = LedColor(Ev3Led.brightest, Ev3Led.brightest) + val Off: LedColor = LedColor(Ev3Led.darkest, Ev3Led.darkest) } - def setLedsTo(color:LedColor): Unit = setLedsTo(color,color) - def setLedsTo(left:LedColor,right:LedColor): Unit = { - Ev3Led.Left.writeBrightness(left.redIntensity,left.greenIntensity) - Ev3Led.Right.writeBrightness(right.redIntensity,right.greenIntensity) + def setLedsTo(color: LedColor): Unit = setLedsTo(color, color) + + def setLedsTo(left: LedColor, right: LedColor): Unit = { + Ev3Led.Left.writeBrightness(left.redIntensity, left.greenIntensity) + Ev3Led.Right.writeBrightness(right.redIntensity, right.greenIntensity) } def clearLcd(): Unit = { @@ -37,7 +38,7 @@ object Display{ Lcd.flush() } - def write(string: String, row: Int, column:Int): Unit = { + def write(string: String, row: Int, column: Int): Unit = { Lcd.set(row, column, string) Lcd.flush() } diff --git a/Ev3LangScala/src/ev3dev4s/lego/Gyroscope.scala b/Ev3LangScala/src/ev3dev4s/lego/Gyroscope.scala index ef75fee..b1d17aa 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/Gyroscope.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/Gyroscope.scala @@ -2,7 +2,6 @@ package ev3dev4s.lego import ev3dev4s.scala2measure.Degrees import ev3dev4s.sensors.{Ev3Gyroscope, SensorPort, SensorPortScanner} -import ev3dev4s.sysfs.UnpluggedException /** * @@ -13,19 +12,19 @@ import ev3dev4s.sysfs.UnpluggedException object Gyroscope { private var sensors: Map[SensorPort, Ev3Gyroscope] = _ - private def scanSensors():Unit = { + + private def scanSensors(): Unit = { sensors = SensorPortScanner.scanSensors.collect { case (port: SensorPort, sensor: Ev3Gyroscope) => port -> sensor } } + scanSensors() - def readHeading(port: SensorPort): Degrees = handleUnplugged[Degrees](sensors(port).headingMode().readHeading(),scanSensors) + def readHeading(port: SensorPort): Degrees = handleUnplugged[Degrees](sensors(port).headingMode().readHeading(), scanSensors) - def reset(port: SensorPort): Unit = handleUnplugged[Unit](sensors(port).headingMode().zero(),scanSensors) + def reset(port: SensorPort): Unit = handleUnplugged[Unit](sensors(port).headingMode().zero(), scanSensors) - def setHeading(port: SensorPort,heading:Degrees): Unit = handleUnplugged[Unit](sensors(port).headingMode().setHeading(heading),scanSensors) + def setHeading(port: SensorPort, heading: Degrees): Unit = handleUnplugged[Unit](sensors(port).headingMode().setHeading(heading), scanSensors) } - - \ No newline at end of file diff --git a/Ev3LangScala/src/ev3dev4s/lego/Motors.scala b/Ev3LangScala/src/ev3dev4s/lego/Motors.scala index 6a10a63..6a364c6 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/Motors.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/Motors.scala @@ -1,6 +1,6 @@ package ev3dev4s.lego -import ev3dev4s.actuators.{Motor, MotorCommand, MotorPort, MotorPortScanner, MotorState, MotorStopCommand} +import ev3dev4s.actuators.{Motor, MotorCommand, MotorPort, MotorPortScanner, MotorStopCommand} import ev3dev4s.scala2measure.{Degrees, DegreesPerSecond, MilliSeconds} import ev3dev4s.scala2measure.Conversions._ import ev3dev4s.os.Time @@ -13,49 +13,51 @@ import ev3dev4s.os.Time */ object Motors { - private[lego] var motors:Map[MotorPort,Motor] = _ + private[lego] var motors: Map[MotorPort, Motor] = _ + private def scanMotors(): Unit = { motors = MotorPortScanner.scanMotors //induce lego default halt behavior motors.values.foreach(_.writeStopAction(MotorStopCommand.HOLD)) } + scanMotors() - private[lego] def handleUnpluggedMotor[A](block: => A):A = { - handleUnplugged(block,scanMotors) + private[lego] def handleUnpluggedMotor[A](block: => A): A = { + handleUnplugged(block, scanMotors) } - private[lego] def watchForStop(motor:Motor):Unit = - while({ + private[lego] def watchForStop(motor: Motor): Unit = + while ( { motor.readIsRunning() }) { //Hand over control to the OS to let it update motor state Time.pause(1.milliseconds) } - def runForDegrees(port:MotorPort,degrees: Degrees): Unit = handleUnpluggedMotor{ + def runForDegrees(port: MotorPort, degrees: Degrees): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writeGoalPosition(degrees) motor.writeCommand(MotorCommand.RUN_TO_RELATIVE_POSITION) watchForStop(motor) } - def start(port: MotorPort): Unit = handleUnpluggedMotor{ + def start(port: MotorPort): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writeCommand(MotorCommand.RUN) } - def setSpeed(port: MotorPort,speed:DegreesPerSecond): Unit = handleUnpluggedMotor{ + def setSpeed(port: MotorPort, speed: DegreesPerSecond): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writeSpeed(speed) } - def stop(port: MotorPort): Unit = handleUnpluggedMotor{ + def stop(port: MotorPort): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writeCommand(MotorCommand.STOP) } - def runForDegrees(port:MotorPort,degrees: Degrees,speed:DegreesPerSecond): Unit = handleUnpluggedMotor{ + def runForDegrees(port: MotorPort, degrees: Degrees, speed: DegreesPerSecond): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writeSpeed(speed) motor.writeGoalPosition(degrees) @@ -63,31 +65,31 @@ object Motors { watchForStop(motor) } - def runForDuration(port:MotorPort,duration: MilliSeconds,speed:DegreesPerSecond): Unit = handleUnpluggedMotor{ - val motor:Motor = motors(port) + def runForDuration(port: MotorPort, duration: MilliSeconds, speed: DegreesPerSecond): Unit = handleUnpluggedMotor { + val motor: Motor = motors(port) motor.writeSpeed(speed) motor.writeDuration(duration) motor.writeCommand(MotorCommand.RUN_TIME) watchForStop(motor) } - def start(port: MotorPort,speed: DegreesPerSecond): Unit = handleUnpluggedMotor{ + def start(port: MotorPort, speed: DegreesPerSecond): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writeSpeed(speed) motor.writeCommand(MotorCommand.RUN) } - def resetDegreesCounted(port: MotorPort): Unit = handleUnpluggedMotor{ + def resetDegreesCounted(port: MotorPort): Unit = handleUnpluggedMotor { val motor: Motor = motors(port) motor.writePosition(0.degrees) } - def degreesCounted(port: MotorPort): Degrees = handleUnpluggedMotor{ + def degreesCounted(port: MotorPort): Degrees = handleUnpluggedMotor { val motor: Motor = motors(port) motor.readPosition() } - def setStopCommand(port:MotorPort,stopCommand: MotorStopCommand): Unit = handleUnpluggedMotor{ + def setStopCommand(port: MotorPort, stopCommand: MotorStopCommand): Unit = handleUnpluggedMotor { val motor = motors(port) motor.writeStopAction(stopCommand) } diff --git a/Ev3LangScala/src/ev3dev4s/lego/Movement.scala b/Ev3LangScala/src/ev3dev4s/lego/Movement.scala index 4ee1f4b..a8affa3 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/Movement.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/Movement.scala @@ -21,16 +21,17 @@ object Movement { rightMotorPort = Option(right) } - def leftMotor:Option[Motor] = leftMotorPort.flatMap(Motors.motors.get(_)) - def rightMotor:Option[Motor] = rightMotorPort.flatMap(Motors.motors.get(_)) + def leftMotor: Option[Motor] = leftMotorPort.flatMap(Motors.motors.get(_)) + + def rightMotor: Option[Motor] = rightMotorPort.flatMap(Motors.motors.get(_)) /** * Turn the pair of motors the number of degrees at the same speed. * * @param motorDegrees The absolute distance to turn the motor - * @param speed Left motor speed. Negative is backwards. + * @param speed Left motor speed. Negative is backwards. */ - def move(motorDegrees: Degrees, speed: DegreesPerSecond): Unit = handleUnpluggedMotor{ + def move(motorDegrees: Degrees, speed: DegreesPerSecond): Unit = handleUnpluggedMotor { leftMotor.foreach(_.writeGoalPosition(relativeGoalPosition(motorDegrees, speed))) rightMotor.foreach(_.writeGoalPosition(relativeGoalPosition(motorDegrees, speed))) leftMotor.foreach(_.writeSpeed(speed)) @@ -46,7 +47,7 @@ object Movement { (motorDegrees.abs * speed.sign).degrees } - def startMoving(leftSpeed: DegreesPerSecond, rightSpeed: DegreesPerSecond): Unit = handleUnpluggedMotor{ + def startMoving(leftSpeed: DegreesPerSecond, rightSpeed: DegreesPerSecond): Unit = handleUnpluggedMotor { leftMotor.foreach(_.writeSpeed(leftSpeed)) rightMotor.foreach(_.writeSpeed(rightSpeed)) leftMotor.foreach(_.writeCommand(MotorCommand.RUN)) @@ -57,14 +58,17 @@ object Movement { * Turn the pair of motors the number of degrees at two different speeds. * * @param motorDegrees The absolute distance to turn the motor - * @param leftSpeed Left motor speed. Negative is backwards. - * @param rightSpeed Right motor speed. Negative is backwards. + * @param leftSpeed Left motor speed. Negative is backwards. + * @param rightSpeed Right motor speed. Negative is backwards. */ - def move(motorDegrees: Degrees, leftSpeed: DegreesPerSecond, rightSpeed: DegreesPerSecond): Unit = handleUnpluggedMotor{ - val (watched, notWatched) = if (leftSpeed.abs > rightSpeed.abs) (leftMotor, rightMotor) - else (rightMotor, leftMotor) - leftMotor.foreach(_.writeGoalPosition(relativeGoalPosition(motorDegrees,leftSpeed))) - rightMotor.foreach(_.writeGoalPosition(relativeGoalPosition(motorDegrees,rightSpeed))) + def move(motorDegrees: Degrees, leftSpeed: DegreesPerSecond, rightSpeed: DegreesPerSecond): Unit = handleUnpluggedMotor { + val (watched, notWatched) = if (leftSpeed.abs > rightSpeed.abs) { + (leftMotor, rightMotor) + } else { + (rightMotor, leftMotor) + } + leftMotor.foreach(_.writeGoalPosition(relativeGoalPosition(motorDegrees, leftSpeed))) + rightMotor.foreach(_.writeGoalPosition(relativeGoalPosition(motorDegrees, rightSpeed))) leftMotor.foreach(_.writeSpeed(leftSpeed)) rightMotor.foreach(_.writeSpeed(rightSpeed)) leftMotor.foreach(_.writeCommand(MotorCommand.RUN_TO_RELATIVE_POSITION)) @@ -77,13 +81,16 @@ object Movement { /** * Turn the pair of motors the number of degrees at two different speeds. * - * @param duration The time to turn the motor before stopping it. - * @param leftSpeed Left motor speed. Negative is backwards. - * @param rightSpeed Right motor speed. Negative is backwards. + * @param duration The time to turn the motor before stopping it. + * @param leftSpeed Left motor speed. Negative is backwards. + * @param rightSpeed Right motor speed. Negative is backwards. */ - def moveDuration(duration: MilliSeconds, leftSpeed: DegreesPerSecond, rightSpeed: DegreesPerSecond): Unit = handleUnpluggedMotor{ - val (watched, notWatched) = if (leftSpeed.abs > rightSpeed.abs) (leftMotor, rightMotor) - else (rightMotor, leftMotor) + def moveDuration(duration: MilliSeconds, leftSpeed: DegreesPerSecond, rightSpeed: DegreesPerSecond): Unit = handleUnpluggedMotor { + val (watched, notWatched) = if (leftSpeed.abs > rightSpeed.abs) { + (leftMotor, rightMotor) + } else { + (rightMotor, leftMotor) + } leftMotor.foreach(_.writeDuration(duration)) rightMotor.foreach(_.writeDuration(duration)) leftMotor.foreach(_.writeSpeed(leftSpeed)) @@ -95,14 +102,17 @@ object Movement { notWatched.foreach(_.writeCommand(MotorCommand.STOP)) } - private def steerMotors(steer: Percent): (Option[Motor], Option[Motor]) = if (steer < 0.percent) (leftMotor, rightMotor) - else (rightMotor, leftMotor) + private def steerMotors(steer: Percent): (Option[Motor], Option[Motor]) = if (steer < 0.percent) { + (leftMotor, rightMotor) + } else { + (rightMotor, leftMotor) + } private def innerMotorProportion(steer: Percent): Unitless = ((100f - 2f * steer.abs.v) / 100f).unitless - def moveSteer(steer: Percent, speed: DegreesPerSecond, degrees: Degrees): Unit = handleUnpluggedMotor{ + def moveSteer(steer: Percent, speed: DegreesPerSecond, degrees: Degrees): Unit = handleUnpluggedMotor { val (innerMotor, outerMotor) = steerMotors(steer) val innerSpeed: DegreesPerSecond = (speed.v * innerMotorProportion(steer).v).degreesPerSecond val innerDegrees = (degrees.v * innerMotorProportion(steer).v).degrees @@ -118,7 +128,7 @@ object Movement { rightMotor.foreach(Motors.watchForStop) } - def startMovingSteer(steer: Percent, speed: DegreesPerSecond): Unit = handleUnpluggedMotor{ + def startMovingSteer(steer: Percent, speed: DegreesPerSecond): Unit = handleUnpluggedMotor { val (innerMotor, outerMotor) = steerMotors(steer) val innerSpeed: DegreesPerSecond = (speed.v * innerMotorProportion(steer).v).degreesPerSecond outerMotor.foreach(_.writeSpeed(speed)) @@ -128,15 +138,14 @@ object Movement { } - def stop(): Unit = handleUnpluggedMotor{ + def stop(): Unit = handleUnpluggedMotor { leftMotor.foreach(_.writeCommand(MotorCommand.STOP)) rightMotor.foreach(_.writeCommand(MotorCommand.STOP)) } - def atStop(stopCommand: MotorStopCommand): Unit = handleUnpluggedMotor{ + def atStop(stopCommand: MotorStopCommand): Unit = handleUnpluggedMotor { leftMotor.foreach(_.writeStopAction(stopCommand)) rightMotor.foreach(_.writeStopAction(stopCommand)) } } - \ No newline at end of file diff --git a/Ev3LangScala/src/ev3dev4s/lego/Sound.scala b/Ev3LangScala/src/ev3dev4s/lego/Sound.scala index 603e403..360f40b 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/Sound.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/Sound.scala @@ -16,11 +16,11 @@ object Sound { /** * @param file .wav file to play */ - def startSound(file:File): Unit = { + def startSound(file: File): Unit = { Ev3Sound.playSample(file) } - def playSound(file:File): Unit = { + def playSound(file: File): Unit = { Ev3Sound.playSampleUntilDone(file) } @@ -28,7 +28,7 @@ object Sound { Ev3Sound.playTone(frequency, duration) } - def speak(say:String):Unit = { + def speak(say: String): Unit = { Ev3Sound.speak(say) } } diff --git a/Ev3LangScala/src/ev3dev4s/lego/TouchSensor.scala b/Ev3LangScala/src/ev3dev4s/lego/TouchSensor.scala index 201356d..91fd9f7 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/TouchSensor.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/TouchSensor.scala @@ -11,12 +11,14 @@ import ev3dev4s.sensors.{Ev3TouchSensor, SensorPort, SensorPortScanner} object TouchSensor { private var sensors: Map[SensorPort, Ev3TouchSensor] = _ + private def scanSensors(): Unit = { sensors = SensorPortScanner.scanSensors.collect { case (port: SensorPort, sensor: Ev3TouchSensor) => port -> sensor } } + scanSensors() - def readTouch(port:SensorPort):Boolean = handleUnplugged(sensors(port).readTouch(),scanSensors) -} \ No newline at end of file + def readTouch(port: SensorPort): Boolean = handleUnplugged(sensors(port).readTouch(), scanSensors) +} diff --git a/Ev3LangScala/src/ev3dev4s/lego/package.scala b/Ev3LangScala/src/ev3dev4s/lego/package.scala index c7cb01b..f3e9c76 100644 --- a/Ev3LangScala/src/ev3dev4s/lego/package.scala +++ b/Ev3LangScala/src/ev3dev4s/lego/package.scala @@ -12,8 +12,8 @@ import scala.util.control.NonFatal */ package object lego { - private[lego] def handleUnplugged[A](block: => A, scan:() => Unit): A = { - def scanAndTryAgain(t:Throwable):A = { + private[lego] def handleUnplugged[A](block: => A, scan: () => Unit): A = { + def scanAndTryAgain(t: Throwable): A = { scan() try { block diff --git a/Ev3LangScala/src/ev3dev4s/os/Time.scala b/Ev3LangScala/src/ev3dev4s/os/Time.scala index 0f8699a..7c422a7 100644 --- a/Ev3LangScala/src/ev3dev4s/os/Time.scala +++ b/Ev3LangScala/src/ev3dev4s/os/Time.scala @@ -16,9 +16,11 @@ object Time { val deadline: Float = now() + milliseconds.v System.gc() val sleepTime: Float = deadline - now() - if (sleepTime > 0) Thread.sleep(sleepTime.round) + if (sleepTime > 0) { + Thread.sleep(sleepTime.round) + } } def pause(): Unit = Thread.`yield`() -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/scala2measure/Conversions.scala b/Ev3LangScala/src/ev3dev4s/scala2measure/Conversions.scala index f992584..7dffb6d 100644 --- a/Ev3LangScala/src/ev3dev4s/scala2measure/Conversions.scala +++ b/Ev3LangScala/src/ev3dev4s/scala2measure/Conversions.scala @@ -57,4 +57,4 @@ object Conversions { def Hz = new Hertz(f) } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/scala2measure/Measured.scala b/Ev3LangScala/src/ev3dev4s/scala2measure/Measured.scala index a1ed800..d89dc2c 100644 --- a/Ev3LangScala/src/ev3dev4s/scala2measure/Measured.scala +++ b/Ev3LangScala/src/ev3dev4s/scala2measure/Measured.scala @@ -1,20 +1,22 @@ package ev3dev4s.scala2measure -//todo when either something like coulomb is available for scala3 or you have to shift back to Scala 2, use someone else's library for unit operations +// todo when either something like coulomb is available for scala3 or you have +// to shift back to Scala 2, use someone else's library for unit operations + /** * A universal trait of things that are measured with units. * * This provides general-purpose operations for those things. */ trait Measured[M <: Measured[M]] extends Any { - def v: Float //todo fine to change to Ratio if Float doesn't work out + def v: Float // todo fine to change to Ratio if Float doesn't work out def create(i: Float): M - def toString(): String + //noinspection + def toString(): String // todo figure out def toString(): String - //todo figure out def toString():String - def unary_- = create(-this.v) //todo add type annotation when allowed + def unary_- : M = create(-this.v) def +(m: M): M = create(this.v + m.v) @@ -32,7 +34,7 @@ trait Measured[M <: Measured[M]] extends Any { def *(m: Measured[_]): Float = this.v * m.v - def *(f:Float):M = create(this.v * f) + def *(f: Float): M = create(this.v * f) def /(m: Measured[_]): Float = this.v / m.v @@ -47,79 +49,79 @@ trait Measured[M <: Measured[M]] extends Any { //todo figure out how to do a Range } -object Measured{ - def min[M <: Measured[M]](m1:M,m2:M):M = if(m1.v < m2.v) m1 - else m2 - def max[M <: Measured[M]](m1:M,m2:M):M = if(m1.v > m2.v) m1 - else m2 +object Measured { + def min[M <: Measured[M]](m1: M, m2: M): M = if (m1.v < m2.v) { m1 } else { m2 } + + def max[M <: Measured[M]](m1: M, m2: M): M = if (m1.v > m2.v) { m1 } else { m2 } } -class Degrees(val v:Float) extends AnyVal with Measured[Degrees] { +class Degrees(val v: Float) extends AnyVal with Measured[Degrees] { def create(i: Float) = new Degrees(i) - override def toString(): String = s"${v.round}d" + override def toString(): String = s"${ v.round }d" /** * @return a v between -180 and +179 */ def unwind: Degrees = { val remainder = v % 360 - if (remainder < -180) create(remainder + 360) - else if (remainder >= 180) create(remainder - 360) - else create(remainder) + if (remainder < -180) { create(remainder + 360) } + else if (remainder >= 180) { create(remainder - 360) } + else { create(remainder) } } } -class Percent(val v:Float) extends AnyVal with Measured[Percent] { +class Percent(val v: Float) extends AnyVal with Measured[Percent] { def create(i: Float) = new Percent(i) override def toString(): String = s"$v%" } -class MilliSeconds(val v:Float) extends AnyVal with Measured[MilliSeconds] { +class MilliSeconds(val v: Float) extends AnyVal with Measured[MilliSeconds] { def create(i: Float) = new MilliSeconds(i) - override def toString(): String = s"${v}ms" + override def toString(): String = s"${ v }ms" } -class DegreesPerSecond(val v:Float) extends AnyVal with Measured[DegreesPerSecond] { +class DegreesPerSecond(val v: Float) extends AnyVal with Measured[DegreesPerSecond] { def create(i: Float) = new DegreesPerSecond(i) - override def toString(): String = s"${v}dps" + override def toString(): String = s"${ v }dps" } -class Unitless(val v:Float) extends AnyVal with Measured[Unitless] { +class Unitless(val v: Float) extends AnyVal with Measured[Unitless] { def create(i: Float) = new Unitless(i) - override def toString(): String = s"${v}" + override def toString(): String = s"$v" } -class Microvolts(val v:Float) extends AnyVal with Measured[Microvolts]{ - def create(i:Float) = new Microvolts(i) - override def toString():String = s"${v}uV" +class Microvolts(val v: Float) extends AnyVal with Measured[Microvolts] { + def create(i: Float) = new Microvolts(i) + + override def toString(): String = s"${ v }uV" } -class DutyCycle(val v:Float) extends AnyVal with Measured[DutyCycle] { +class DutyCycle(val v: Float) extends AnyVal with Measured[DutyCycle] { def create(i: Float) = new DutyCycle(i) - override def toString(): String = s"${v}%" + override def toString(): String = s"$v%" } -class LedIntensity(val v:Float) extends AnyVal with Measured[LedIntensity] { +class LedIntensity(val v: Float) extends AnyVal with Measured[LedIntensity] { def create(i: Float) = new LedIntensity(i) - override def toString(): String = s"${v}i" + override def toString(): String = s"${ v }i" } -class MilliMeters(val v:Float) extends AnyVal with Measured[MilliMeters] { +class MilliMeters(val v: Float) extends AnyVal with Measured[MilliMeters] { def create(i: Float) = new MilliMeters(i) - override def toString(): String = s"${v}mm" + override def toString(): String = s"${ v }mm" } -class Hertz(val v:Float) extends AnyVal with Measured[Hertz] { +class Hertz(val v: Float) extends AnyVal with Measured[Hertz] { override def create(i: Float): Hertz = new Hertz(i) - override def toString(): String = s"${v}Hz" -} \ No newline at end of file + override def toString(): String = s"${ v }Hz" +} diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Ev3Battery.scala b/Ev3LangScala/src/ev3dev4s/sensors/Ev3Battery.scala index 5985453..7b7b4e8 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Ev3Battery.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Ev3Battery.scala @@ -26,5 +26,3 @@ object Ev3Battery extends AutoCloseable { voltageRereader.close() } } - - diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Ev3ColorSensor.scala b/Ev3LangScala/src/ev3dev4s/sensors/Ev3ColorSensor.scala index 99cc5a3..82bbe0b 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Ev3ColorSensor.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Ev3ColorSensor.scala @@ -9,14 +9,13 @@ import java.nio.file.Path * @author David Walend * @since v0.0.0 */ -case class Ev3ColorSensor(override val port:SensorPort,initialSensorDir:Option[Path]) - extends MultiModeSensor(port,initialSensorDir.map(MultiModeSensorFS.Value012SensorFS)) { +case class Ev3ColorSensor(override val port: SensorPort, initialSensorDir: Option[Path]) + extends MultiModeSensor(port, initialSensorDir.map(MultiModeSensorFS.Value012SensorFS)) { override def findGadgetFS(): Option[MultiModeSensorFS.Value012SensorFS] = SensorPortScanner.findGadgetDir(port, Ev3ColorSensor.driverName) .map(MultiModeSensorFS.Value012SensorFS) - private lazy val onlyReflectMode: ReflectMode = ReflectMode() def reflectMode(): ReflectMode = @@ -71,23 +70,23 @@ case class Ev3ColorSensor(override val port:SensorPort,initialSensorDir:Option[P } } } - /* todo -COL-REFLECT Reflected light - sets LED color to red pct (percent) 0 1 value0: Reflected light intensity (0 to 100) -COL-AMBIENT Ambient light - sets LED color to blue (dimly lit) pct (percent) 0 1 value0: Ambient light intensity (0 to 100) -COL-COLOR Color - sets LED color to white (all LEDs rapidly cycling) col (color) 0 1 value0: Detected color (0 to 7) [26] -REF-RAW Raw Reflected - sets LED color to red none 0 2 +/* todo +COL-REFLECT || Reflected light - sets LED color to red || pct (percent) || 0 || 1 || value0: Reflected light intensity (0 to 100) +COL-AMBIENT || Ambient light - sets LED color to blue (dimly lit) || pct (percent) || 0 || 1 || value0: Ambient light intensity (0 to 100) +COL-COLOR || Color - sets LED color to white (all LEDs rapidly cycling) || col (color) || 0 || 1 || value0: Detected color (0 to 7) [26] +REF-RAW || Raw Reflected - sets LED color to red || none || 0 || 2 value0: ??? (0 to 1020???) value1: ??? (0 to 1020???) -RGB-RAW Raw Color Components - sets LED color to white (all LEDs rapidly cycling) none 0 3 +RGB-RAW || Raw Color Components - sets LED color to white (all LEDs rapidly cycling) || none || 0 || 3 value0: Red (0 to 1020???) value1: Green (0 to 1020???) value2: Blue (0 to 1020???) -COL-CAL [27] Calibration ??? - sets LED color to red, flashing every 4 seconds, then goes continuous none 0 4 +COL-CAL [27] || Calibration ??? - sets LED color to red, flashing every 4 seconds, then goes continuous || none || 0 || 4 value0: ??? value1: ??? @@ -95,15 +94,15 @@ value1: ??? value2: ??? value3: ??? - */ + */ -object Ev3ColorSensor{ +object Ev3ColorSensor { val driverName = "lego-ev3-color" /** * @see https://docs.ev3dev.org/projects/lego-linux-drivers/en/ev3dev-stretch/sensor_data.html#lego-ev3-color-mode2-value0 */ - sealed case class Color(name:String) + sealed case class Color(name: String) object Color { val NoColor: Color = Color("No") @@ -115,8 +114,6 @@ object Ev3ColorSensor{ val White: Color = Color("White") val Brown: Color = Color("Brown") - val values: Array[Color] = Array(NoColor,Black,Blue,Green,Yellow,Red,White,Brown) + val values: Array[Color] = Array(NoColor, Black, Blue, Green, Yellow, Red, White, Brown) } } - - diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Ev3Gyroscope.scala b/Ev3LangScala/src/ev3dev4s/sensors/Ev3Gyroscope.scala index cd102b2..1f71904 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Ev3Gyroscope.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Ev3Gyroscope.scala @@ -1,14 +1,15 @@ package ev3dev4s.sensors +import java.io.File +import java.nio.file.Path +import scala.collection.immutable.ArraySeq + import ev3dev4s.os.Time import ev3dev4s.Log import ev3dev4s.sysfs.{ChannelRereader, ChannelRewriter, GadgetUnplugged, UnpluggedException} import ev3dev4s.scala2measure.Degrees import ev3dev4s.scala2measure.Conversions._ - -import java.io.File -import java.nio.file.Path -import scala.collection.immutable.ArraySeq +import ev3dev4s.Ev3System /** * @@ -16,18 +17,21 @@ import scala.collection.immutable.ArraySeq * @author David Walend * @since v0.0.0 */ -case class Ev3Gyroscope(override val port:SensorPort,initialSensorDir:Option[Path]) - extends MultiModeSensor(port,initialSensorDir.map(MultiModeSensorFS.Value0SensorFS)){ //todo change to Value01SensorFS to support GYRO-G&A +//noinspection ScalaUnnecessaryParentheses +case class Ev3Gyroscope(override val port: SensorPort, initialSensorDir: Option[Path]) + extends MultiModeSensor(port, initialSensorDir.map(MultiModeSensorFS.Value0SensorFS)) { //todo change to Value01SensorFS to support GYRO-G&A override def findGadgetFS(): Option[MultiModeSensorFS.Value0SensorFS] = - SensorPortScanner.findGadgetDir(port,Ev3Gyroscope.driverName) + SensorPortScanner.findGadgetDir(port, Ev3Gyroscope.driverName) .map(MultiModeSensorFS.Value0SensorFS) private lazy val onlyHeadingMode: HeadingMode = HeadingMode() - def headingMode():HeadingMode = setMaybeWriteMode(onlyHeadingMode) + + def headingMode(): HeadingMode = setMaybeWriteMode(onlyHeadingMode) private lazy val onlyRateMode: RateMode = RateMode() - def rateMode():RateMode = setMaybeWriteMode(onlyRateMode) + + def rateMode(): RateMode = setMaybeWriteMode(onlyRateMode) /** * Simulate unplugging then plugging in the gyroscope - in software @@ -36,7 +40,7 @@ case class Ev3Gyroscope(override val port:SensorPort,initialSensorDir:Option[Pat * @see https://www.aposteriori.com.sg/ev3dev-research-notes/ * @see https://github.com/ev3dev/ev3dev/issues/1387 */ - def calibrate():Unit = despin() + def calibrate(): Unit = despin() /** * Angle in degrees @@ -44,7 +48,7 @@ case class Ev3Gyroscope(override val port:SensorPort,initialSensorDir:Option[Pat sealed case class HeadingMode() extends Mode { val name = "GYRO-ANG" - @volatile var offset: Degrees = 0.degrees + @volatile private var offset: Degrees = 0.degrees zero() /** @@ -69,9 +73,11 @@ case class Ev3Gyroscope(override val port:SensorPort,initialSensorDir:Option[Pat offset = offset.unwind } } + /** * Angle change rate in degrees per second */ + //noinspection ScalaUnusedSymbol sealed case class RateMode() extends Mode { val name = "GYRO-RATE" @@ -80,22 +86,21 @@ case class Ev3Gyroscope(override val port:SensorPort,initialSensorDir:Option[Pat } } - /* todo + /* todo GYRO-CAL - does not work. Not sure what it does do, but it doesn't recalibrate the gyro -GYRO-RATE Rotational Speed d/s (degrees per second) 0 1 value0: Rotational Speed (-440 to 440) [22] -GYRO-FAS Rotational Speed none 0 1 value0: Rotational Speed (-1464 to 1535) [22] -GYRO-G&A [23] Angle and Rotational Speed none 0 2 +GYRO-RATE || Rotational Speed || d/s (degrees per second) || 0 || 1 || value0: Rotational Speed (-440 to 440) [22] +GYRO-FAS || Rotational Speed || none || 0 || 1 || value0: Rotational Speed (-1464 to 1535) [22] +GYRO-G&A [23] || Angle and Rotational Speed || none || 0 || 2 value0: Angle (-32768 to 32767) [21] [22] value1: Rotational Speed (-440 to 440) [22] -TILT-RATE [24] Rotational Speed (2nd axis) d/s (degrees per second) 0 1 value0: Rotational Speed (-440 to 440) [25] -TILT-ANG [24] Angle (2nd axis) deg (degrees) 0 1 value0: Angle (-32768 to 32767) [25] - */ +TILT-RATE [24] || Rotational Speed (2nd axis) || d/s (degrees per second) || 0 || 1 || value0: Rotational Speed (-440 to 440) [25] +TILT-ANG [24] || Angle (2nd axis) || deg (degrees) || 0 || 1 || value0: Angle (-32768 to 32767) [25] + */ - import ev3dev4s.Ev3System val ledProgress: Seq[() => Any] = Seq( () => { Ev3System.leftLed.writeRed() @@ -115,8 +120,8 @@ TILT-ANG [24] Angle (2nd axis) deg (degrees) 0 1 value0: Angle (-32768 to 32767) } ) - def despin(reportProgress: Seq[() => Any] = ledProgress):Unit = { - def scanForPortDir():Path = { + def despin(reportProgress: Seq[() => Any] = ledProgress): Unit = { + def scanForPortDir(): Path = { val legoPortsDir: File = new File("/sys/class/lego-port") Log.log(s"Scan $legoPortsDir for the right address") ArraySeq.unsafeWrapArray(legoPortsDir.listFiles()).map { (dir: File) => @@ -124,23 +129,23 @@ TILT-ANG [24] Angle (2nd axis) deg (degrees) 0 1 value0: Angle (-32768 to 32767) val addressPath = dir.toPath.resolve("address") val portChar: Char = ChannelRereader.readString(addressPath).last (portChar -> dir.toPath) - }.toMap.get(port.name).getOrElse(throw UnpluggedException(port)) + }.toMap.getOrElse(port.name, throw UnpluggedException(port)) } - def restartSensorSoftBoot(legoPortDir:Path):Unit = { + def restartSensorSoftBoot(legoPortDir: Path): Unit = { //write "auto" to the right port in /sys/class/lego-port/port1/mode Log.log(s"Restart sensor in $legoPortDir by writing auto to mode") ChannelRewriter.writeString(legoPortDir.resolve("mode"), "auto") Time.pause(2000.milliseconds) } - def scanForSensor(port:SensorPort):Boolean = { + def scanForSensor(port: SensorPort): Boolean = { Log.log(s"Look for the sensor in $port for 20 seconds") val deadline = System.currentTimeMillis() + 20000L //some restarts don't come back give up and try again //todo this might be cleaner with @tailrec ! var found = false - while ({ + while ( { try { val maybeSensorPath: Option[Path] = SensorPortScanner.findGadgetDir(port, Ev3Gyroscope.driverName) Log.log(s"maybeSensorPath is $maybeSensorPath") @@ -162,7 +167,9 @@ TILT-ANG [24] Angle (2nd axis) deg (degrees) 0 1 value0: Angle (-32768 to 32767) Log.log(s"Failed with $x") System.currentTimeMillis() < deadline // try again if there's time } - }){Time.pause(500.milliseconds) } + }) { + Time.pause(500.milliseconds) + } found } @@ -171,19 +178,20 @@ TILT-ANG [24] Angle (2nd axis) deg (degrees) 0 1 value0: Angle (-32768 to 32767) Log.log(s"despin $this at $port") unsetGadgetFS() - while ({ + while ( { try { + //noinspection ZeroIndexToHead reportProgress(0)() val legoPortDir: Path = scanForPortDir() Log.log(s"legoPortDir is $legoPortDir") reportProgress(1)() restartSensorSoftBoot(legoPortDir) reportProgress(2)() - !scanForSensor(port) //keep looking if no sensor found + !scanForSensor(port) // keep looking if no sensor found } catch { case GadgetUnplugged(_) => true } - }){ + }) { Time.pause() } @@ -191,7 +199,7 @@ TILT-ANG [24] Angle (2nd axis) deg (degrees) 0 1 value0: Angle (-32768 to 32767) reportProgress(3)() - Log.log(s"Successfully despun") + Log.log(s"Successfully de-spun") } } @@ -199,20 +207,20 @@ object Ev3Gyroscope { val driverName = "lego-ev3-gyro" } - /* todo another way for despin to fail - a new kind of unplugged thing +/* todo another way for despin to fail - a new kind of unplugged thing 1643172523163 Read 0 from /sys/class/lego-sensor/sensor4 java.io.IOException: Invalid argument - at java.base/sun.nio.ch.FileDispatcherImpl.pwrite0(Native Method) - at java.base/sun.nio.ch.FileDispatcherImpl.pwrite(FileDispatcherImpl.java:68) - at java.base/sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:109) - at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:79) - at java.base/sun.nio.ch.FileChannelImpl.writeInternal(FileChannelImpl.java:850) - at java.base/sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:836) - at ev3dev4s.sysfs.ChannelRewriter.writeString(ChannelRewriter.scala:25) - at ev3dev4s.sysfs.ChannelRewriter$.writeString(ChannelRewriter.scala:40) - at ev3dev4s.sensors.Ev3Gyroscope.scanForSensor$2$$anonfun$1(Ev3Gyroscope.scala:149) - at scala.Option.map(Option.scala:242) - at ev3dev4s.sensors.Ev3Gyroscope.scanForSensor$1(Ev3Gyroscope.scala:152) - at ev3dev4s.sensors.Ev3Gyroscope.despin(Ev3Gyroscope.scala:179) - - */ +at java.base/sun.nio.ch.FileDispatcherImpl.pwrite0(Native Method) +at java.base/sun.nio.ch.FileDispatcherImpl.pwrite(FileDispatcherImpl.java:68) +at java.base/sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:109) +at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:79) +at java.base/sun.nio.ch.FileChannelImpl.writeInternal(FileChannelImpl.java:850) +at java.base/sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:836) +at ev3dev4s.sysfs.ChannelRewriter.writeString(ChannelRewriter.scala:25) +at ev3dev4s.sysfs.ChannelRewriter$.writeString(ChannelRewriter.scala:40) +at ev3dev4s.sensors.Ev3Gyroscope.scanForSensor$2$$anonfun$1(Ev3Gyroscope.scala:149) +at scala.Option.map(Option.scala:242) +at ev3dev4s.sensors.Ev3Gyroscope.scanForSensor$1(Ev3Gyroscope.scala:152) +at ev3dev4s.sensors.Ev3Gyroscope.despin(Ev3Gyroscope.scala:179) + +*/ diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Ev3InfraredSensor.scala b/Ev3LangScala/src/ev3dev4s/sensors/Ev3InfraredSensor.scala index cd4498a..d423101 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Ev3InfraredSensor.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Ev3InfraredSensor.scala @@ -6,8 +6,9 @@ import java.nio.file.Path * @author David Walend * @since v0.0.0 */ -case class Ev3InfraredSensor(override val port:SensorPort,initialSensorDir:Option[Path]) - extends MultiModeSensor(port,initialSensorDir.map(MultiModeSensorFS.Value012SensorFS)) { //todo all eight channels +//noinspection ScalaUnusedSymbol +case class Ev3InfraredSensor(override val port: SensorPort, initialSensorDir: Option[Path]) + extends MultiModeSensor(port, initialSensorDir.map(MultiModeSensorFS.Value012SensorFS)) { //todo all eight channels override def findGadgetFS(): Option[MultiModeSensorFS.Value012SensorFS] = SensorPortScanner.findGadgetDir(port, Ev3InfraredSensor.driverName) @@ -18,6 +19,7 @@ case class Ev3InfraredSensor(override val port:SensorPort,initialSensorDir:Optio def remoteMode(): RemoteMode = setMaybeWriteMode(onlyRemoteMode) sealed case class RemoteMode() extends Mode { + import ev3dev4s.sensors.Ev3InfraredSensor.RemoteButton val name = "IR-REMOTE" @@ -31,19 +33,20 @@ case class Ev3InfraredSensor(override val port:SensorPort,initialSensorDir:Optio } import RemoteButton._ - lazy val intToButtons:Map[Int,Set[RemoteButton]] = Map( + + lazy val intToButtons: Map[Int, Set[RemoteButton]] = Map( 0 -> Set(), 1 -> Set(LeftUp), 2 -> Set(LeftDown), 3 -> Set(RightUp), 4 -> Set(RightDown), - 5 -> Set(LeftUp,RightUp), - 6 -> Set(LeftUp,RightDown), - 7 -> Set(LeftDown,RightUp), - 8 -> Set(LeftDown,RightDown), + 5 -> Set(LeftUp, RightUp), + 6 -> Set(LeftUp, RightDown), + 7 -> Set(LeftDown, RightUp), + 8 -> Set(LeftDown, RightDown), 9 -> Set(Beacon), - 10 -> Set(LeftUp,LeftDown), - 11 -> Set(RightUp,RightDown), + 10 -> Set(LeftUp, LeftDown), + 11 -> Set(RightUp, RightDown), ) } @@ -52,13 +55,13 @@ case class Ev3InfraredSensor(override val port:SensorPort,initialSensorDir:Optio All the other modes */ -object Ev3InfraredSensor{ +object Ev3InfraredSensor { val driverName = "lego-ev3-ir" /** * @see https://docs.ev3dev.org/projects/lego-linux-drivers/en/ev3dev-stretch/sensor_data.html#lego-ev3-color-mode2-value0 */ - sealed case class RemoteButton(name:String) + sealed case class RemoteButton(name: String) object RemoteButton { val LeftUp: RemoteButton = RemoteButton("LeftUp") @@ -67,4 +70,4 @@ object Ev3InfraredSensor{ val RightDown: RemoteButton = RemoteButton("RightDown") val Beacon: RemoteButton = RemoteButton("Beacon") } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Ev3KeyPad.scala b/Ev3LangScala/src/ev3dev4s/sensors/Ev3KeyPad.scala index 34ad1bc..b45e75f 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Ev3KeyPad.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Ev3KeyPad.scala @@ -13,29 +13,29 @@ import scala.annotation.tailrec */ object Ev3KeyPad extends AutoCloseable { - sealed case class Key(byte: Byte, name:String) + sealed case class Key(byte: Byte, name: String) - object Key{ - val Up: Key = Key(0x67,"Up") - val Down: Key = Key(0x6c,"Down") - val Left: Key = Key(0x69,"Left") - val Right: Key = Key(0x6a,"Right") - val Enter: Key = Key(0x1c,"Enter") - val Escape: Key = Key(0x0e,"Escape") + object Key { + val Up: Key = Key(0x67, "Up") + val Down: Key = Key(0x6c, "Down") + val Left: Key = Key(0x69, "Left") + val Right: Key = Key(0x6a, "Right") + val Enter: Key = Key(0x1c, "Enter") + val Escape: Key = Key(0x0e, "Escape") - val values: Array[Key] = Array(Up,Down,Left,Right,Enter,Escape) + val values: Array[Key] = Array(Up, Down, Left, Right, Enter, Escape) } - sealed case class State(byte: Byte, name:String) + sealed case class State(byte: Byte, name: String) object State { - val Pressed: State = State(0x01,"Pressed") - val Released: State = State(0x00,"Released") + val Pressed: State = State(0x01, "Pressed") + val Released: State = State(0x00, "Released") - val values: Array[State] = Array(Pressed,Released) + val values: Array[State] = Array(Pressed, Released) } - val bytesToKeyStates: Map[(Byte, Byte), (Key,State)] = { + val bytesToKeyStates: Map[(Byte, Byte), (Key, State)] = { val keyStates: Array[(Key, State)] = for {key <- Key.values state <- State.values} yield (key, state) keyStates.map(keyState => (keyState._1.byte, keyState._2.byte) -> keyState).toMap @@ -45,18 +45,18 @@ object Ev3KeyPad extends AutoCloseable { private val keyPadInputStream = new DataInputStream(new FileInputStream(keyPadEventPath)) private val bytes32: Array[Byte] = Array.fill[Byte](32)(0x0) - def blockUntilAnyKey(startTime:Long = Time.now()): (Key, State) = this.synchronized{ + def blockUntilAnyKey(startTime: Long = Time.now()): (Key, State) = this.synchronized { recursiveBlockUntilAnyKey(startTime) } - + @tailrec - private final def recursiveBlockUntilAnyKey(startTime:Long): (Key, State) = { + private final def recursiveBlockUntilAnyKey(startTime: Long): (Key, State) = { val KEY_INDEX = 10 // should be a key.byte val STATE_INDEX = 12 // should be a state.byte keyPadInputStream.readFully(bytes32) //debounce the keypad - if(Time.now() - startTime > 5) {// long enough to clear the old pushes + if (Time.now() - startTime > 5) { // long enough to clear the old pushes val keyAndState: (Byte, Byte) = (bytes32(KEY_INDEX), bytes32(STATE_INDEX)) bytesToKeyStates.getOrElse(keyAndState, throw new IllegalStateException(s"No key state for $keyAndState")) } else { @@ -68,4 +68,4 @@ object Ev3KeyPad extends AutoCloseable { override def close(): Unit = this.synchronized { keyPadInputStream.close() } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Ev3TouchSensor.scala b/Ev3LangScala/src/ev3dev4s/sensors/Ev3TouchSensor.scala index 46502bc..d8b03f5 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Ev3TouchSensor.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Ev3TouchSensor.scala @@ -8,11 +8,11 @@ import java.nio.file.Path * @author David Walend * @since v0.0.0 */ -case class Ev3TouchSensor(override val port:SensorPort,initialSensorDir:Option[Path]) - extends Sensor(port,initialSensorDir.map(Ev3TouchSensor.Ev3TouchSensorFS)){ +case class Ev3TouchSensor(override val port: SensorPort, initialSensorDir: Option[Path]) + extends Sensor(port, initialSensorDir.map(Ev3TouchSensor.Ev3TouchSensorFS)) { override def findGadgetFS(): Option[Ev3TouchSensor.Ev3TouchSensorFS] = - SensorPortScanner.findGadgetDir(port,Ev3TouchSensor.driverName) + SensorPortScanner.findGadgetDir(port, Ev3TouchSensor.driverName) .map(Ev3TouchSensor.Ev3TouchSensorFS) def readTouch(): Boolean = checkPort(_.readValue0Int() == 1) @@ -30,4 +30,4 @@ object Ev3TouchSensor { override def close(): Unit = value0Reader.close() } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/sensors/Sensor.scala b/Ev3LangScala/src/ev3dev4s/sensors/Sensor.scala index 40fcfb0..642ca47 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/Sensor.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/Sensor.scala @@ -9,12 +9,12 @@ import scala.reflect.ClassTag * @author David Walend * @since v0.0.0 */ -abstract class Sensor[SFS <: SensorFS](port:SensorPort,initialSensorFS: Option[SFS]) extends Gadget(port,initialSensorFS) +abstract class Sensor[SFS <: SensorFS](port: SensorPort, initialSensorFS: Option[SFS]) extends Gadget(port, initialSensorFS) trait SensorFS extends GadgetFS -abstract class MultiModeSensor[SFS <: MultiModeSensorFS](port:SensorPort,initialSensorFS: Option[SFS]) - extends Sensor(port,initialSensorFS) { +abstract class MultiModeSensor[SFS <: MultiModeSensorFS](port: SensorPort, initialSensorFS: Option[SFS]) + extends Sensor(port, initialSensorFS) { private var mode: Option[Mode] = None @@ -62,7 +62,6 @@ object MultiModeSensorFS { } } - case class Value012SensorFS(sensorDir: Path) extends MultiModeSensorFS { private val modeWriter = ChannelRewriter(sensorDir.resolve("mode")) private val value0Reader = ChannelRereader(sensorDir.resolve("value0")) @@ -80,4 +79,4 @@ object MultiModeSensorFS { modeWriter.close() } } -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/sensors/SensorPortScanner.scala b/Ev3LangScala/src/ev3dev4s/sensors/SensorPortScanner.scala index e531b5b..af298db 100644 --- a/Ev3LangScala/src/ev3dev4s/sensors/SensorPortScanner.scala +++ b/Ev3LangScala/src/ev3dev4s/sensors/SensorPortScanner.scala @@ -11,9 +11,9 @@ import java.io.File * @author David Walend * @since v0.0.0 */ -object SensorPortScanner extends GadgetPortScanner(new File("/sys/class/lego-sensor"),SensorPort.values){ - def scanSensors:Map[SensorPort,Sensor[_]] = { - scanGadgetDirs.map{portAndDir => +object SensorPortScanner extends GadgetPortScanner(new File("/sys/class/lego-sensor"), SensorPort.values) { + def scanSensors: Map[SensorPort, Sensor[_]] = { + scanGadgetDirs.map { portAndDir => val driverName = ChannelRereader.readString(portAndDir._2.resolve("driver_name")) Log.log(s"$portAndDir $driverName") val sensor = driverName match { @@ -28,13 +28,13 @@ object SensorPortScanner extends GadgetPortScanner(new File("/sys/class/lego-sen } } -sealed case class SensorPort(name:Char) extends Port +sealed case class SensorPort(name: Char) extends Port object SensorPort { - val One: SensorPort = SensorPort ('1') - val Two: SensorPort = SensorPort ('2') - val Three: SensorPort = SensorPort ('3') - val Four: SensorPort = SensorPort ('4') + val One: SensorPort = SensorPort('1') + val Two: SensorPort = SensorPort('2') + val Three: SensorPort = SensorPort('3') + val Four: SensorPort = SensorPort('4') - val values: Array[SensorPort] = Array(One,Two,Three,Four) -} \ No newline at end of file + val values: Array[SensorPort] = Array(One, Two, Three, Four) +} diff --git a/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRereader.scala b/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRereader.scala index 9b6ddae..9360fbe 100644 --- a/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRereader.scala +++ b/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRereader.scala @@ -17,9 +17,9 @@ case class ChannelRereader(path: Path, bufferLength: Int = 32) extends AutoClose private def readBytes(): Int = this.synchronized { byteBuffer.clear - try + try { channel.read(byteBuffer, 0) - catch { + } catch { case _: ClosedChannelException => channel = FileChannel.open(path) channel.read(byteBuffer, 0) @@ -28,12 +28,12 @@ case class ChannelRereader(path: Path, bufferLength: Int = 32) extends AutoClose def readString(): String = this.synchronized { val n = readBytes() - if ((n == -1) || (n == 0)) "" - else if (n < -1) throw new IOException("Unexpected read byte count of " + n + " while reading " + path) + if ((n == -1) || (n == 0)) { "" } + else if (n < -1) { throw new IOException("Unexpected read byte count of " + n + " while reading " + path) } else { val bytes: Array[Byte] = byteBuffer.array - if (bytes(n - 1) == '\n') new String(bytes, 0, n - 1, StandardCharsets.UTF_8) - else new String(bytes, 0, n, StandardCharsets.UTF_8) + if (bytes(n - 1) == '\n') { new String(bytes, 0, n - 1, StandardCharsets.UTF_8) } + else { new String(bytes, 0, n, StandardCharsets.UTF_8) } } } @@ -46,35 +46,36 @@ case class ChannelRereader(path: Path, bufferLength: Int = 32) extends AutoClose object ChannelRereader { def readString(path: Path, bufferLength: Int = 32): String = { val reader = ChannelRereader(path, bufferLength) - try + try { reader.readString() - finally + } finally { reader.close() + } } def readAsciiInt(path: Path, bufferLength: Int = 32): Int = { val reader = ChannelRereader(path, bufferLength) - try + try { reader.readAsciiInt() - finally + } finally { reader.close() + } } } - /* ev3.replay.CalibrateGyro$@1353651 finished in 266 milliseconds java.nio.channels.ClosedChannelException - at java.base/sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:150) - at java.base/sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:790) - at ev3dev4s.sysfs.ChannelRereader.readString(ChannelRereader.scala:21) - at ev3dev4s.sysfs.ChannelRereader.readAsciiInt(ChannelRereader.scala:31) - at ev3dev4s.sensors.Ev3Gyroscope$HeadingMode.readRawHeading(Ev3Gyroscope.scala:41) - at ev3dev4s.sensors.Ev3Gyroscope$HeadingMode.readHeading(Ev3Gyroscope.scala:45) - at ev3.replay.Robot$.readHeading(Robot.scala:94) - at ev3.replay.WileyMenu.drawScreen(WileyMenu.scala:78) - at ev3.replay.WileyMenu.run(WileyMenu.scala:31) - at ev3.replay.Sorties$.run(Sorties.scala:43) - at ev3dev4s.JarRunner$.main(JarRunner.scala:27) - at ev3dev4s.JarRunner.main(JarRunner.scala) -*/ \ No newline at end of file +at java.base/sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:150) +at java.base/sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:790) +at ev3dev4s.sysfs.ChannelRereader.readString(ChannelRereader.scala:21) +at ev3dev4s.sysfs.ChannelRereader.readAsciiInt(ChannelRereader.scala:31) +at ev3dev4s.sensors.Ev3Gyroscope$HeadingMode.readRawHeading(Ev3Gyroscope.scala:41) +at ev3dev4s.sensors.Ev3Gyroscope$HeadingMode.readHeading(Ev3Gyroscope.scala:45) +at ev3.replay.Robot$.readHeading(Robot.scala:94) +at ev3.replay.WileyMenu.drawScreen(WileyMenu.scala:78) +at ev3.replay.WileyMenu.run(WileyMenu.scala:31) +at ev3.replay.Sorties$.run(Sorties.scala:43) +at ev3dev4s.JarRunner$.main(JarRunner.scala:27) +at ev3dev4s.JarRunner.main(JarRunner.scala) +*/ diff --git a/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRewriter.scala b/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRewriter.scala index e4390d2..0ca1ffb 100644 --- a/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRewriter.scala +++ b/Ev3LangScala/src/ev3dev4s/sysfs/ChannelRewriter.scala @@ -3,8 +3,7 @@ package ev3dev4s.sysfs import java.nio.ByteBuffer import java.nio.channels.FileChannel import java.nio.charset.StandardCharsets -import java.nio.file.{AccessDeniedException,Path,StandardOpenOption} -import scala.annotation.tailrec +import java.nio.file.{Path, StandardOpenOption} /** * @@ -12,31 +11,31 @@ import scala.annotation.tailrec * * @author David Walend */ -case class ChannelRewriter(path: Path,bufferLength:Int = 32) extends AutoCloseable { - - private val channel = FileChannel.open(path,StandardOpenOption.WRITE) +case class ChannelRewriter(path: Path, bufferLength: Int = 32) extends AutoCloseable { + + private val channel = FileChannel.open(path, StandardOpenOption.WRITE) private val byteBuffer = ByteBuffer.allocate(bufferLength) - def writeString(string: String):Unit = this.synchronized{ - byteBuffer.clear () - byteBuffer.put (string.getBytes (StandardCharsets.UTF_8) ) - byteBuffer.flip () - channel.truncate (0) - channel.write (byteBuffer, 0) - channel.force (false) + def writeString(string: String): Unit = this.synchronized { + byteBuffer.clear() + byteBuffer.put(string.getBytes(StandardCharsets.UTF_8)) + byteBuffer.flip() + channel.truncate(0) + channel.write(byteBuffer, 0) + channel.force(false) } - def writeAsciiInt(i: Int):Unit = writeString(Integer.toString(i)) + def writeAsciiInt(i: Int): Unit = writeString(Integer.toString(i)) - def close():Unit = this.synchronized{ + def close(): Unit = this.synchronized { channel.close() } } -object ChannelRewriter{ +object ChannelRewriter { - def writeString(path:Path,string: String,bufferLength:Int = 32):Unit = { - val rewriter = ChannelRewriter(path,bufferLength) + def writeString(path: Path, string: String, bufferLength: Int = 32): Unit = { + val rewriter = ChannelRewriter(path, bufferLength) rewriter.writeString(string) rewriter.close() } diff --git a/Ev3LangScala/src/ev3dev4s/sysfs/Gadget.scala b/Ev3LangScala/src/ev3dev4s/sysfs/Gadget.scala index d84a6a4..1048e51 100644 --- a/Ev3LangScala/src/ev3dev4s/sysfs/Gadget.scala +++ b/Ev3LangScala/src/ev3dev4s/sysfs/Gadget.scala @@ -1,7 +1,7 @@ package ev3dev4s.sysfs import java.io.IOException -import java.nio.file.{AccessDeniedException,NoSuchFileException} +import java.nio.file.{AccessDeniedException, NoSuchFileException} import ev3dev4s.Log @@ -11,17 +11,17 @@ import ev3dev4s.Log * @author David Walend * @since v0.0.0 */ -abstract class Gadget[GFS <: GadgetFS,GPort <: Port](val port:GPort,initialGadgetFS: Option[GFS]) extends AutoCloseable{ +abstract class Gadget[GFS <: GadgetFS, GPort <: Port](val port: GPort, initialGadgetFS: Option[GFS]) extends AutoCloseable { - private var gadgetFS:Option[GFS] = initialGadgetFS + private var gadgetFS: Option[GFS] = initialGadgetFS - def findGadgetFS():Option[GFS] + def findGadgetFS(): Option[GFS] - protected def unsetGadgetFS():Unit = synchronized{ + protected def unsetGadgetFS(): Unit = synchronized { gadgetFS = None } - def checkPort[A](action:GFS => A):A = synchronized { + def checkPort[A](action: GFS => A): A = synchronized { def handleUnpluggedGadget(t: Throwable): Nothing = { try { gadgetFS.foreach(_.close) @@ -46,7 +46,7 @@ abstract class Gadget[GFS <: GadgetFS,GPort <: Port](val port:GPort,initialGadge catch { case GadgetUnplugged(x) => handleUnpluggedGadget(x) case x: Throwable => - Log.log(s"caught $x with '${x.getMessage}'",x) + Log.log(s"caught $x with '${x.getMessage}'", x) throw x } } @@ -60,10 +60,10 @@ abstract class Gadget[GFS <: GadgetFS,GPort <: Port](val port:GPort,initialGadge trait GadgetFS extends AutoCloseable trait Port { - def name:Char + def name: Char } -case class UnpluggedException(port: Port,cause:Throwable) extends Exception(s"$port gadget unplugged",cause) +case class UnpluggedException(port: Port, cause: Throwable) extends Exception(s"$port gadget unplugged", cause) object UnpluggedException { def apply(port: Port): UnpluggedException = UnpluggedException(port, null) @@ -77,13 +77,13 @@ object UnpluggedException { } } -object GadgetUnplugged{ +object GadgetUnplugged { /** * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal */ def apply(t: Throwable): Boolean = t match { // VirtualMachineError includes OutOfMemoryError and other fatal errors - case _: NoSuchFileException | _: AccessDeniedException => true + case _: NoSuchFileException | _: AccessDeniedException => true case iox: IOException if iox.getMessage == "No such device" => true case iox: IOException if iox.getMessage == "No such device or address" => true case iox: IOException if iox.getMessage == "Device or resource busy" => true @@ -94,4 +94,4 @@ object GadgetUnplugged{ * Returns Some(t) if NonFatal(t) == true, otherwise None */ def unapply(t: Throwable): Option[Throwable] = Some(t).filter(apply) -} \ No newline at end of file +} diff --git a/Ev3LangScala/src/ev3dev4s/sysfs/GadgetPortScanner.scala b/Ev3LangScala/src/ev3dev4s/sysfs/GadgetPortScanner.scala index 9869dc3..38b7e93 100644 --- a/Ev3LangScala/src/ev3dev4s/sysfs/GadgetPortScanner.scala +++ b/Ev3LangScala/src/ev3dev4s/sysfs/GadgetPortScanner.scala @@ -1,7 +1,7 @@ package ev3dev4s.sysfs import java.io.File -import java.nio.file.{Path,NoSuchFileException} +import java.nio.file.{Path, NoSuchFileException} import scala.collection.immutable.ArraySeq /** @@ -10,7 +10,8 @@ import scala.collection.immutable.ArraySeq * @author David Walend * @since v0.0.0 */ -abstract class GadgetPortScanner[P <: Port](gadgetDir:File,ports:Array[P]) { +//noinspection ScalaUnnecessaryParentheses +abstract class GadgetPortScanner[P <: Port](gadgetDir: File, ports: Array[P]) { val namesToPorts: Map[Char, P] = ports.map { p => p.name -> p }.toMap @@ -28,8 +29,8 @@ abstract class GadgetPortScanner[P <: Port](gadgetDir:File,ports:Array[P]) { scanGadgetDirs.get(port) .map { dir => val foundDriverName = ChannelRereader.readString(dir.resolve("driver_name")) - if (foundDriverName == expectedDriverName) dir - else throw WrongGadgetInPortException(port, expectedDriverName, foundDriverName) + if (foundDriverName == expectedDriverName) { dir } + else { throw WrongGadgetInPortException(port, expectedDriverName, foundDriverName) } } } catch { @@ -37,5 +38,5 @@ abstract class GadgetPortScanner[P <: Port](gadgetDir:File,ports:Array[P]) { } } -case class WrongGadgetInPortException(port:Port,expectedDriverName:String,foundDriverName:String) - extends Exception(s"Expected $expectedDriverName in $port but found $foundDriverName") \ No newline at end of file +case class WrongGadgetInPortException(port: Port, expectedDriverName: String, foundDriverName: String) + extends Exception(s"Expected $expectedDriverName in $port but found $foundDriverName") diff --git a/Ev3LangScala/src/ev3dev4s/sysfs/Shell.scala b/Ev3LangScala/src/ev3dev4s/sysfs/Shell.scala index c523008..90cf998 100644 --- a/Ev3LangScala/src/ev3dev4s/sysfs/Shell.scala +++ b/Ev3LangScala/src/ev3dev4s/sysfs/Shell.scala @@ -1,5 +1,6 @@ package ev3dev4s.sysfs +import java.io.ByteArrayOutputStream import ev3dev4s.Log object Shell { @@ -15,14 +16,15 @@ object Shell { val p: Process = Runtime.getRuntime.exec(command) p.waitFor - import java.io.ByteArrayOutputStream val output = new ByteArrayOutputStream val buffer = new Array[Byte](1024) var length = 0 - while ({ + while ( { length = p.getInputStream.read(buffer) - length != -1 }) - { output.write(buffer, 0, length) } + length != -1 + }) { + output.write(buffer, 0, length) + } p.getInputStream.close() output.toString("UTF-8") @@ -33,19 +35,21 @@ object Shell { val p: Process = Runtime.getRuntime.exec(command) p.waitFor - Log.log("Completed "+command.mkString(" ")) + Log.log("Completed " + command.mkString(" ")) import java.io.ByteArrayOutputStream val output = new ByteArrayOutputStream val buffer = new Array[Byte](1024) var length = 0 - while ({ + while ( { length = p.getInputStream.read(buffer) - length != -1 }) - { output.write(buffer, 0, length) } + length != -1 + }) { + output.write(buffer, 0, length) + } p.getInputStream.close() output.toString("UTF-8") } -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/Ev3LedExample.scala b/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/Ev3LedExample.scala index 0a69be9..6946af3 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/Ev3LedExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/Ev3LedExample.scala @@ -35,6 +35,7 @@ object Ev3LedExample { Thread.sleep(10) } } + Ev3System.leftLed.writeYellow() Ev3System.rightLed.writeYellow() } diff --git a/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/MotorUnplugExample.scala b/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/MotorUnplugExample.scala index cf30364..8befbd9 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/MotorUnplugExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/actuators/examples/MotorUnplugExample.scala @@ -30,4 +30,4 @@ object MotorUnplugExample { } } } -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/examples/AllGadgetsExample.scala b/Ev3LangScalaExample/src/ev3dev4s/examples/AllGadgetsExample.scala index 44a0040..bd3ba7f 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/examples/AllGadgetsExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/examples/AllGadgetsExample.scala @@ -1,16 +1,17 @@ package ev3dev4s.examples -import ev3dev4s.{Ev3System, sensors} -import ev3dev4s.actuators.{Ev3Led, Motor} -import ev3dev4s.sensors.{Ev3ColorSensor, Ev3Gyroscope, Ev3TouchSensor, Mode, Sensor} +import ev3dev4s.Ev3System +import ev3dev4s.actuators.Motor +import ev3dev4s.sensors.{Ev3ColorSensor, Ev3Gyroscope, Ev3TouchSensor, Sensor} import ev3dev4s.sysfs.UnpluggedException /** - * Excercise all the gadgets on the robot - in a loop + * Exercise all the gadgets on the robot - in a loop * * @author David Walend * @since v0.0.0 */ +//noinspection RedundantBlock object AllGadgetsExample extends Runnable { override def run(): Unit = { Ev3System.leftLed.writeOff() @@ -29,37 +30,35 @@ object AllGadgetsExample extends Runnable { while (true) { motors.foreach { (motor: Motor) => + //noinspection ScalaUnusedSymbol try { - println(s"motor $motor ${ - motor.readPosition() - }") - } - catch { - case ux: UnpluggedException => println(s"motor $motor unplugged") + println(s"motor $motor ${ motor.readPosition() }") } + catch { case _ux: UnpluggedException => println(s"motor $motor unplugged") } } sensors.foreach { (sensor: Sensor[_]) => + //noinspection ScalaUnusedSymbol try { sensor match { - case gyroscope: Ev3Gyroscope => + case gyroscope: Ev3Gyroscope => { val number = gyroscope.currentMode.collect { case m: gyroscope.HeadingMode => m.readHeading() } println(s"sensor $sensor $number") - case colorSensor: Ev3ColorSensor => + } + case colorSensor: Ev3ColorSensor => { val number = colorSensor.currentMode.collect { case m: colorSensor.ReflectMode => m.readReflect() } println(s"sensor $sensor $number") - case touchSensor: Ev3TouchSensor => println(s"sensor $sensor ${ - touchSensor.readTouch() - }") + } + case touchSensor: Ev3TouchSensor => { + println(s"sensor $sensor ${ touchSensor.readTouch() }") + } } } - catch { - case ux: UnpluggedException => println(s"sensor $sensor unplugged") - } + catch { case ux: UnpluggedException => println(s"sensor $sensor unplugged") } } System.gc() @@ -67,4 +66,4 @@ object AllGadgetsExample extends Runnable { println() } } -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/examples/FiveXHelloWorld.scala b/Ev3LangScalaExample/src/ev3dev4s/examples/FiveXHelloWorld.scala index 46ff764..903ea72 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/examples/FiveXHelloWorld.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/examples/FiveXHelloWorld.scala @@ -10,11 +10,11 @@ object FiveXHelloWorld extends Runnable { Display.clearLcd() Display.setLedsTo(Display.LedColor.Orange) Log.log("Hello World") - Display.write("Hello World",0) + Display.write("Hello World", 0) Sound.speak("Hello World") - Sound.playBeep(200.Hz,100.ms) + Sound.playBeep(200.Hz, 100.ms) Display.setLedsTo(Display.LedColor.Green) - Display.write("Push Button",3) + Display.write("Push Button", 3) Ev3System.keyPad.blockUntilAnyKey() } } diff --git a/Ev3LangScalaExample/src/ev3dev4s/examples/JarRunnerExample.scala b/Ev3LangScalaExample/src/ev3dev4s/examples/JarRunnerExample.scala index df201af..ae7ecd5 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/examples/JarRunnerExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/examples/JarRunnerExample.scala @@ -27,4 +27,4 @@ object JarRunnerExample extends Runnable { } } } -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtyMenu.scala b/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtyMenu.scala index faacbee..ba9e65e 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtyMenu.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtyMenu.scala @@ -10,7 +10,7 @@ import ev3dev4s.sensors.Ev3KeyPad * @author David Walend * @since v0.0.0 */ -case class TtyMenu(actions:Array[_ <: TtyMenuAction],setLcd:TtyMenu => Unit) extends Runnable { +case class TtyMenu(actions: Array[_ <: TtyMenuAction], setLcd: TtyMenu => Unit) extends Runnable { @volatile var index = 0 @volatile var keepGoing = true @@ -51,14 +51,20 @@ case class TtyMenu(actions:Array[_ <: TtyMenuAction],setLcd:TtyMenu => Unit) ext keepGoing = false def decrementMenu(): Unit = { - index = if (index == 0) actions.length - 1 - else index - 1 + index = if (index == 0) { + actions.length - 1 + } else { + index - 1 + } drawScreen() } def incrementMenu(): Unit = { - index = if (index == actions.length - 1) 0 - else index + 1 + index = if (index == actions.length - 1) { + 0 + } else { + index + 1 + } drawScreen() } @@ -120,9 +126,9 @@ object TtyMenu extends Runnable { } } -case class LedAction(aLabel:String,action:() => Unit) extends TtyMenuAction { +case class LedAction(aLabel: String, action: () => Unit) extends TtyMenuAction { override def label: String = aLabel override def run(menu: TtyMenu): Unit = action() -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtySensorsAndMenu.scala b/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtySensorsAndMenu.scala index 01acfba..b28ad12 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtySensorsAndMenu.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/lcd/tty/examples/TtySensorsAndMenu.scala @@ -62,8 +62,8 @@ object TtySensorsAndMenu extends Runnable { val gyroscope: Ev3Gyroscope = Ev3System.portsToSensors.values.collectFirst { case g: Ev3Gyroscope => g }.get def setSensorRows(): Unit = { - Lcd.set(0, s"${elapsedTime}s", Lcd.RIGHT) - val heading: String = UnpluggedException.safeString(() => s"${gyroscope.headingMode().readHeading().round}d") + Lcd.set(0, s"${ elapsedTime }s", Lcd.RIGHT) + val heading: String = UnpluggedException.safeString(() => s"${ gyroscope.headingMode().readHeading().round }d") Lcd.set(0, heading, Lcd.LEFT) } @@ -118,4 +118,4 @@ object DespinGyro extends TtyMenuAction { override def run(menu: TtyMenu): Unit = gyroscope.despin() -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3BatteryExample.scala b/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3BatteryExample.scala index e9f19e7..b00929f 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3BatteryExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3BatteryExample.scala @@ -10,9 +10,10 @@ import ev3dev4s.sensors.Ev3Battery */ object Ev3BatteryExample { - def main(args: Array[String]): Unit = + def main(args: Array[String]): Unit = { for (_ <- 1 to 20) { - println(s"${Ev3Battery.readMicrovolts()} ${Ev3Battery.readMicoramps()}") + println(s"${ Ev3Battery.readMicrovolts() } ${ Ev3Battery.readMicoramps() }") Thread.sleep(100) } + } } diff --git a/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3ColorReflectExample.scala b/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3ColorReflectExample.scala index fd18c24..ac0531f 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3ColorReflectExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3ColorReflectExample.scala @@ -22,4 +22,4 @@ object Ev3ColorSensorExample { Thread.sleep(100) } } -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3GyroscopeExample.scala b/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3GyroscopeExample.scala index a86caa6..0124440 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3GyroscopeExample.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/sensors/examples/Ev3GyroscopeExample.scala @@ -30,4 +30,4 @@ object Ev3GyroscopeExample { Thread.sleep(100) } } -} \ No newline at end of file +} diff --git a/Ev3LangScalaExample/src/ev3dev4s/sensors/gyroscope/examples/GyroDriveStraight.scala b/Ev3LangScalaExample/src/ev3dev4s/sensors/gyroscope/examples/GyroDriveStraight.scala index b8f1ec0..6b98d4a 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/sensors/gyroscope/examples/GyroDriveStraight.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/sensors/gyroscope/examples/GyroDriveStraight.scala @@ -1,12 +1,10 @@ package ev3dev4s.sensors.gyroscope.examples -import ev3dev4s.actuators.{Motor, MotorCommand, MotorPort, MotorStopCommand, MotorState} +import ev3dev4s.actuators.{Motor, MotorCommand, MotorPort, MotorStopCommand} import ev3dev4s.sensors.{Ev3Gyroscope, Ev3KeyPad} import ev3dev4s.{Ev3System, Log} -import ev3dev4s.scala2measure.Degrees +import ev3dev4s.scala2measure.{Degrees, DegreesPerSecond, DutyCycle, MilliMeters} import ev3dev4s.scala2measure.Conversions._ -import ev3dev4s.scala2measure.DegreesPerSecond -import ev3dev4s.scala2measure.DutyCycle /** * @@ -14,6 +12,7 @@ import ev3dev4s.scala2measure.DutyCycle * @author David Walend * @since v0.0.0 */ +//noinspection ScalaUnusedSymbol object GyroDriveStraight extends Runnable { @@ -84,29 +83,30 @@ object GyroDriveStraight extends Runnable { while (keepGoing()) { val heading: Degrees = Robot.headingMode.readHeading() val steerAdjust: DutyCycle = - if (heading == goalHeading) 0.dutyCyclePercent - else { + if (heading == goalHeading) { + 0.dutyCyclePercent + } else { //about 1% per degree off seems good - but it should really care about wheel base width val proportionalSteerAdjust = ((goalHeading - heading) * dutyCycle / 100).dutyCyclePercent - if (proportionalSteerAdjust.abs > 1.dutyCyclePercent) proportionalSteerAdjust - else if (proportionalSteerAdjust == 0.dutyCyclePercent) 0.dutyCyclePercent - else if (proportionalSteerAdjust > 0.dutyCyclePercent) 1.dutyCyclePercent - else -1.dutyCyclePercent + if (proportionalSteerAdjust.abs > 1.dutyCyclePercent) { proportionalSteerAdjust } + else if (proportionalSteerAdjust == 0.dutyCyclePercent) { 0.dutyCyclePercent } + else if (proportionalSteerAdjust > 0.dutyCyclePercent) { 1.dutyCyclePercent } + else { -1.dutyCyclePercent } } def dutyCyclesFromAdjust(): (DutyCycle, DutyCycle) = { val leftIdeal = ((dutyCycle + steerAdjust) / 10.unitless).dutyCyclePercent val rightIdeal = ((dutyCycle - steerAdjust) / 10.unitless).dutyCyclePercent (leftIdeal, rightIdeal) - //todo for fractions - //val (leftSteering, rightSteering) = (leftIdeal,rightIdeal) - //todo for fractions - //if(leftIdeal != rightIdeal) (leftIdeal,rightIdeal) - //else if(steerAdjust.v > 0) (leftIdeal+1,rightIdeal) - //else if(steerAdjust.v < 0) (leftIdeal,rightIdeal+1) - //else (leftIdeal,rightIdeal) - //todo speed up very slow movement by 10. Not sure this is usefulif(leftSteering >= 10 && rightSteering >= 10) (leftSteering,rightSteering) - //todo speed up very slow movement by 10. Not sure this is useful else (leftSteering+10,rightSteering+10) + // todo for fractions + // val (leftSteering, rightSteering) = (leftIdeal,rightIdeal) + // todo for fractions + // if(leftIdeal != rightIdeal) (leftIdeal,rightIdeal) + // else if(steerAdjust.v > 0) (leftIdeal+1,rightIdeal) + // else if(steerAdjust.v < 0) (leftIdeal,rightIdeal+1) + // else (leftIdeal,rightIdeal) + // todo speed up very slow movement by 10. Not sure this is useful: if(leftSteering >= 10 && rightSteering >= 10) (leftSteering,rightSteering) + // todo speed up very slow movement by 10. Not sure this is useful else (leftSteering+10,rightSteering+10) } val (leftDutyCycle, rightDutyCycle) = dutyCyclesFromAdjust() @@ -209,7 +209,7 @@ object GyroDriveStraight extends Runnable { /** * Adjust the speed based on the current gyro heading to drive in an arc. - * This method assumes the goal absolute postions have already been written + * This method assumes the goal absolute positions have already been written * * @param goalHeading that the gyroscope should read during this traverse * @param averageSpeed degrees/second for moving the robot quickly @@ -268,14 +268,15 @@ object GyroDriveStraight extends Runnable { */ } +//noinspection ScalaUnusedSymbol object Robot { - val driveWheelDiameter = 11.studs - val driveWheelCircumference = (driveWheelDiameter.v * Math.PI.toFloat).mm + val driveWheelDiameter: MilliMeters = 11.studs + val driveWheelCircumference: MilliMeters = (driveWheelDiameter.v * Math.PI.toFloat).mm - val robotWheelbase = 18.studs + val robotWheelbase: MilliMeters = 18.studs - val keypad = Ev3System.keyPad + val keypad: Ev3KeyPad.type = Ev3System.keyPad val gyroscope: Ev3Gyroscope = Ev3System.portsToSensors.values.collectFirst { case gyro: Ev3Gyroscope => gyro }.get val headingMode: gyroscope.HeadingMode = gyroscope.headingMode() @@ -307,7 +308,3 @@ object Robot { rightMotor.writeCommand(MotorCommand.STOP) } } - - - - diff --git a/Ev3LangScalaExample/src/ev3dev4s/timing/GyroFeedbackLoop.scala b/Ev3LangScalaExample/src/ev3dev4s/timing/GyroFeedbackLoop.scala index 3c41456..3f0ea08 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/timing/GyroFeedbackLoop.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/timing/GyroFeedbackLoop.scala @@ -1,6 +1,6 @@ package ev3dev4s.timing -import ev3dev4s.sensors.gyroscope.examples.{Robot,GyroDriveStraight} +import ev3dev4s.sensors.gyroscope.examples.{Robot, GyroDriveStraight} import ev3dev4s.os.Time import ev3dev4s.Log @@ -10,24 +10,24 @@ import ev3dev4s.scala2measure.Conversions._ import ev3dev4s.sensors.Ev3KeyPad import ev3dev4s.scala2measure.DutyCycle + /** * A test of time to run a reasonable control loop for various comparisons - * + * * Baseline - before messing with unit-based numbers in controls * 1638416904531 13929 loop closures in 60000 for 4.30756 milliseconds per loop closure - * - * With my own units for Degrees and Percent (duty cyle) + * + * With my own units for Degrees and Percent (duty cycle) * 1639715964387 14436 loop closures in 60000 for 4.1562757 milliseconds per loop closure - * + * * With my own universal trait for the arithmetic operations * 1640018240566 19308 loop closures in 60000 for 3.10752 milliseconds per loop closure * * With Floats instead of Ints underlying the units * 1645127290993 18331 loop closures in 60000 for 3.2731438 milliseconds per loop closure - */ + */ object GyroFeedbackLoop extends Runnable { - def main(args: Array[String]): Unit = - run() + def main(args: Array[String]): Unit = run() override def run(): Unit = { // Robot.gyroscope.despin() @@ -49,9 +49,9 @@ object GyroFeedbackLoop extends Runnable { /** * Gyro straight with the duty cycle * - * @param goalHeading that the gyroscope should read during this traverse - * @param dutyCycle degrees per second to turn the motors - * @param milliseconds time to travel + * @param goalHeading that the gyroscope should read during this traverse + * @param dutyCycle degrees per second to turn the motors + * @param milliseconds time to travel */ def driveGyroFeedbackTime( goalHeading: Degrees, diff --git a/Ev3LangScalaExample/src/ev3dev4s/timing/Simplest.scala b/Ev3LangScalaExample/src/ev3dev4s/timing/Simplest.scala index aa8140f..2bd5ac3 100644 --- a/Ev3LangScalaExample/src/ev3dev4s/timing/Simplest.scala +++ b/Ev3LangScalaExample/src/ev3dev4s/timing/Simplest.scala @@ -1,8 +1,5 @@ package ev3dev4s.timing -import ev3dev4s.Ev3System -import ev3dev4s.actuators.Ev3Led - /** * Run via * diff --git a/Ev3LangScalaLessons/0-Clear-Vs-Cryptic.md b/Ev3LangScalaLessons/0-Clear-Vs-Cryptic.md index 567fed0..430cb0e 100644 --- a/Ev3LangScalaLessons/0-Clear-Vs-Cryptic.md +++ b/Ev3LangScalaLessons/0-Clear-Vs-Cryptic.md @@ -91,4 +91,4 @@ ssh into the ev3 and run > brickrun -r -- java -jar Ev3LangScala.jar Ev3LangScalaLesson.jar Lesson0 -todo do away with brickrun \ No newline at end of file +todo do away with brickrun diff --git a/Ev3LangScalaLessons/Outline.md b/Ev3LangScalaLessons/Outline.md index 68d1378..d721e1d 100644 --- a/Ev3LangScalaLessons/Outline.md +++ b/Ev3LangScalaLessons/Outline.md @@ -90,4 +90,3 @@ ev3dev4s Lessons Gyro arc drive with predictive control 11 Moves, Waypoints, Sorties, and Everything 12 Telling the Story - diff --git a/README.md b/README.md index de44b6d..a245811 100644 --- a/README.md +++ b/README.md @@ -85,4 +85,3 @@ In the ev3dev OS menu on the Ev3 File Browser -> MasterPiece.bash* (It will blink green for about 45 seconds before honking and starting) -