refactoring raspberry server
This commit is contained in:
+25
-17
@@ -1,24 +1,8 @@
|
||||
# Car server
|
||||
|
||||
## Building
|
||||
|
||||
move to this directory
|
||||
|
||||
$ ./build.sh
|
||||
|
||||
This command run gradle build and execute *npm install* for downloading used js modules.
|
||||
|
||||
## Run car server
|
||||
|
||||
for run server you can use script
|
||||
|
||||
$ ./run.sh
|
||||
|
||||
## Deploying car server
|
||||
|
||||
*note:* This feature is under development
|
||||
|
||||
*note:* this script use expect script languane. You have to install it
|
||||
*note:* this script use expect script language. You have to install it
|
||||
|
||||
for install expect on ubuntu
|
||||
|
||||
@@ -31,3 +15,27 @@ for deploy server on car use
|
||||
where:
|
||||
{ip_addr} - ip address of raspberry.
|
||||
{user_name} and {password} - user name and password for login on raspberry
|
||||
|
||||
|
||||
## Config file
|
||||
|
||||
on root of compile files (~/server/ after deploy or ./build/js/) you can create
|
||||
config file config.cfg. options write as key:value.
|
||||
all available options. here value - its default value
|
||||
mainServerIp:127.0.0.1
|
||||
thisServerIp:127.0.0.1
|
||||
|
||||
|
||||
## Building and run (for start on local computer)
|
||||
|
||||
move to this directory
|
||||
|
||||
$ ./build.sh
|
||||
|
||||
This command run gradle build and execute *npm install* for downloading used js modules.
|
||||
|
||||
for run server you can use script
|
||||
|
||||
$ ./run.sh
|
||||
|
||||
|
||||
|
||||
@@ -25,26 +25,16 @@ sourceSets {
|
||||
}
|
||||
|
||||
task copyKotlinLib(type: Copy) {
|
||||
from "${projectDir}/helpers/kotlin.js"
|
||||
from "${projectDir}/helpers/package.json"
|
||||
from "${projectDir}/kotlinJsRequiredFiles/kotlin.js"
|
||||
from "${projectDir}/kotlinJsRequiredFiles/package.json"
|
||||
|
||||
into "${projectDir}/build/js"
|
||||
}
|
||||
|
||||
task copyProtoFiles(type: Copy) {
|
||||
|
||||
from "${projectDir}/../../proto/carkot.proto"
|
||||
from "${projectDir}/../../proto/server_car/"
|
||||
|
||||
into "${projectDir}/build/js/proto"
|
||||
}
|
||||
|
||||
|
||||
build.dependsOn copyKotlinLib
|
||||
build.dependsOn copyProtoFiles
|
||||
|
||||
compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/build/js/main.js"
|
||||
compileKotlin2Js.kotlinOptions.outputPrefix = "${projectDir}/helpers/prefix.js"
|
||||
compileKotlin2Js.kotlinOptions.outputPrefix = "${projectDir}/kotlinJsRequiredFiles/connectKotlinLib.js"
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-js-library:$kotlin_version"
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/expect
|
||||
|
||||
# XXX this script works super slow on eugene's machine
|
||||
|
||||
set host ""
|
||||
set userName "pi"
|
||||
set password "111"
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "CarServer",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node main.js"
|
||||
},
|
||||
"author": "maxim",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"udev": "^0.3.0",
|
||||
"commander": "^2.9.0",
|
||||
"protobufjs": "^5.0.1"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/bin/bash
|
||||
# TODO main server ip address should be read from configuration file that is
|
||||
# not overwritten during deploy.
|
||||
cd build/js
|
||||
node main.js
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import carControl.Control
|
||||
import carControl.RouteExecutor
|
||||
import carControl.RouteExecutorImpl.MoveDirection
|
||||
|
||||
private val MOVE_VELOCITY = 0.3278
|
||||
private val ROTATION_VELOCITY = 12.3
|
||||
|
||||
// TODO make Car class mutable state saving entity
|
||||
// that almost doesn't have behavior
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class Car constructor(val routeExecutor: RouteExecutor, val controller: Control) {
|
||||
//position
|
||||
var x: Double
|
||||
var y: Double
|
||||
var angle: Double
|
||||
|
||||
var moveDirection: MoveDirection = MoveDirection.STOP
|
||||
|
||||
|
||||
init {
|
||||
this.x = 0.0
|
||||
this.y = 0.0
|
||||
this.angle = 0.0
|
||||
}
|
||||
|
||||
fun stopCar() {
|
||||
move(MoveDirection.STOP, 0, {})
|
||||
}
|
||||
|
||||
fun refreshLocation(delta: Int) {
|
||||
val deltaSeconds = delta.toDouble() / 1000
|
||||
when (moveDirection) {
|
||||
MoveDirection.FORWARD -> {
|
||||
this.x += MOVE_VELOCITY * deltaSeconds * Math.cos(this.angle * Math.PI / 180);
|
||||
this.y += MOVE_VELOCITY * deltaSeconds * Math.sin(this.angle * Math.PI / 180);
|
||||
}
|
||||
MoveDirection.BACKWARD -> {
|
||||
this.x -= MOVE_VELOCITY * deltaSeconds * Math.cos(this.angle * Math.PI / 180);
|
||||
this.y -= MOVE_VELOCITY * deltaSeconds * Math.sin(this.angle * Math.PI / 180);
|
||||
}
|
||||
MoveDirection.LEFT -> this.angle += ROTATION_VELOCITY * deltaSeconds
|
||||
MoveDirection.RIGHT -> this.angle -= ROTATION_VELOCITY * deltaSeconds
|
||||
else -> {
|
||||
|
||||
}
|
||||
}
|
||||
// println("x=$x; y=$y; angle=$angle")
|
||||
}
|
||||
|
||||
fun routeDone() {
|
||||
controller.stopCar()
|
||||
}
|
||||
|
||||
fun move(moveDirection: MoveDirection, value: Int, callBack: () -> Unit) {
|
||||
//value - angle for rotation command and distance for forward/backward command
|
||||
this.moveDirection = moveDirection
|
||||
when (moveDirection) {
|
||||
MoveDirection.STOP -> controller.stopCar()
|
||||
MoveDirection.FORWARD -> controller.moveCarForward()
|
||||
MoveDirection.BACKWARD -> controller.moveCarBackward()
|
||||
MoveDirection.LEFT -> controller.moveCarLeft()
|
||||
MoveDirection.RIGHT -> controller.moveCarRight()
|
||||
}
|
||||
if (moveDirection != MoveDirection.STOP) {
|
||||
if (moveDirection == MoveDirection.FORWARD || moveDirection == MoveDirection.BACKWARD) {
|
||||
controller.delay(getTimeForMoving(value, MOVE_VELOCITY), callBack)
|
||||
} else {
|
||||
controller.delay(getTimeForMoving(value, ROTATION_VELOCITY), callBack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTimeForMoving(value: Int, velocity: Double): Int {
|
||||
return (1000 * Math.abs(value.toDouble()) / velocity).toInt()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import control.RouteExecutor
|
||||
import control.emulator.RouteExecutorImpl.MoveDirection
|
||||
|
||||
private val MOVE_VELOCITY = 0.3278
|
||||
private val ROTATION_VELOCITY = 12.3
|
||||
|
||||
// TODO make Car class mutable state saving entity
|
||||
// that almost doesn't have behavior
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class CarState private constructor() {
|
||||
//position
|
||||
var x: Double
|
||||
var y: Double
|
||||
var angle: Double
|
||||
|
||||
init {
|
||||
this.x = 0.0
|
||||
this.y = 0.0
|
||||
this.angle = 0.0
|
||||
}
|
||||
|
||||
companion object {
|
||||
val instance = CarState()
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,23 @@
|
||||
/**
|
||||
* Created by user on 8/16/16.
|
||||
*/
|
||||
class Config(val configFileName: String) {
|
||||
class Config(val configFileName: String = "config.cfg") {
|
||||
|
||||
|
||||
private var serverIp = "127.0.0.1"
|
||||
private var thisCarIp = "127.0.0.1"
|
||||
|
||||
fun loadConfig(): Boolean {
|
||||
|
||||
try {
|
||||
fs.accessSync(configFileName, fs.F_OK);
|
||||
} catch (e: dynamic) {
|
||||
// create it
|
||||
fs.openSync(configFileName, "w")
|
||||
}
|
||||
|
||||
val data: String = fs.readFileSync(configFileName, "utf8")
|
||||
println("reader $data")
|
||||
data.split("\n").forEach { line ->
|
||||
val keyValue = line.split(":")
|
||||
if (!line.equals("")) {
|
||||
@@ -16,9 +25,10 @@ class Config(val configFileName: String) {
|
||||
return false
|
||||
}
|
||||
|
||||
println(keyValue.toString())
|
||||
when (keyValue[0]) {
|
||||
"ip" -> serverIp = keyValue[1]
|
||||
"thisIp" -> thisCarIp = keyValue[1]
|
||||
"mainServerIp" -> serverIp = keyValue[1]
|
||||
"thisServerIp" -> thisCarIp = keyValue[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Created by user on 8/18/16.
|
||||
*/
|
||||
|
||||
@native
|
||||
fun require(name: String): dynamic = noImpl
|
||||
|
||||
@native
|
||||
fun setInterval(callBack: () -> Unit, ms: Int): dynamic = noImpl
|
||||
|
||||
@native
|
||||
fun setTimeout(callBack: () -> Unit, ms: Int): dynamic = noImpl
|
||||
|
||||
fun encodeProtoBuf(protoMessage: dynamic): ByteArray {
|
||||
val protoSize = protoMessage.getSizeNoTag()
|
||||
val routeBytes = ByteArray(protoSize)
|
||||
|
||||
protoMessage.writeTo(CodedOutputStream(routeBytes))
|
||||
return routeBytes
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Created by user on 8/18/16.
|
||||
*/
|
||||
interface MCConnectObservable<V> {
|
||||
|
||||
fun addObserver(MCConnectObserver: MCConnectObserver<V>)
|
||||
fun removeObserver(MCConnectObserver: MCConnectObserver<V>)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Created by user on 8/18/16.
|
||||
*/
|
||||
interface MCConnectObserver<V> {
|
||||
|
||||
fun connect(vararg params: V)
|
||||
fun disconnect()
|
||||
|
||||
}
|
||||
@@ -79,7 +79,6 @@ class McTransport() {
|
||||
result += bytes[0].toInt().shl(24)
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val protoHeaderLength: Int = 4
|
||||
@@ -1,23 +1,21 @@
|
||||
import control.car.RouteExecutorToUsb
|
||||
import net.server.handlers.AbstractHandler
|
||||
import net.server.handlers.debug.Memory
|
||||
import net.server.handlers.flash.LoadBin
|
||||
import net.server.handlers.main.GetLocation
|
||||
import net.server.handlers.main.SetRoute
|
||||
import net.server.handlers.rc.Connect
|
||||
import net.server.handlers.rc.Control
|
||||
import net.server.handlers.rc.Disconnect
|
||||
import net.server.handlers.rc.Heartbeat
|
||||
|
||||
/**
|
||||
* Created by user on 7/26/16.
|
||||
*/
|
||||
|
||||
val deltaTimeLocationRefresh: Int = 100//ms
|
||||
val deltaTimeLocationRefresh: Int = 100
|
||||
|
||||
val carServerPort: Int = 8888
|
||||
val mainServerPort = 7925
|
||||
|
||||
val config = Config("config.cfg")
|
||||
val config = Config()
|
||||
val fs = require("fs")
|
||||
fun main(args: Array<String>) {
|
||||
if (!config.loadConfig()) {
|
||||
@@ -26,42 +24,18 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
val handlers: MutableMap<String, AbstractHandler> = mutableMapOf()
|
||||
// TODO remove injection of all internal builders from here
|
||||
handlers.put("/rc/control", Control(DirectionRequest.BuilderDirectionRequest(DirectionRequest.Command.fromIntToCommand(0), 0), DirectionResponse.BuilderDirectionResponse(0)))
|
||||
handlers.put("/rc/connect", Connect(SessionUpResponse.BuilderSessionUpResponse(0, 0)))
|
||||
handlers.put("/rc/disconnect", Disconnect(SessionDownRequest.BuilderSessionDownRequest(0), SessionDownResponse.BuilderSessionDownResponse(0)))
|
||||
handlers.put("/rc/heartbeat", Heartbeat(HeartBeatRequest.BuilderHeartBeatRequest(0), HeartBeatResponse.BuilderHeartBeatResponse(0)))
|
||||
|
||||
handlers.put("/loadBin", LoadBin(Upload.BuilderUpload(ByteArray(0)), UploadResult.BuilderUploadResult(0)))
|
||||
|
||||
handlers.put("/route", SetRoute(RouteRequest.BuilderRouteRequest(IntArray(0), IntArray(0)), RouteResponse.BuilderRouteResponse(0)))
|
||||
handlers.put("/getLocation", GetLocation(LocationResponse.BuilderLocationResponse(LocationResponse.LocationData.BuilderLocationData(0, 0, 0).build(), 0)))
|
||||
|
||||
|
||||
val routeExecutor = RouteExecutorToUsb()
|
||||
handlers.put("/rc/control", Control())
|
||||
handlers.put("/loadBin", LoadBin())
|
||||
handlers.put("/route", SetRoute(routeExecutor))
|
||||
handlers.put("/getLocation", GetLocation())
|
||||
handlers.put("/debug/memoty", Memory())
|
||||
|
||||
net.server.start(handlers, carServerPort)
|
||||
val udev = Udev()
|
||||
udev.start()
|
||||
val mcConditionMonitor = McConditionMonitor.instance
|
||||
mcConditionMonitor.start()
|
||||
|
||||
MicroController.instance.start()
|
||||
|
||||
}
|
||||
|
||||
// TODO move this dump of arbitrary functions that don't have any relation to
|
||||
// to Main.kt from Main.kt
|
||||
|
||||
fun encodeProtoBuf(protoMessage: dynamic): ByteArray {
|
||||
val protoSize = protoMessage.getSizeNoTag()
|
||||
val routeBytes = ByteArray(protoSize)
|
||||
|
||||
protoMessage.writeTo(CodedOutputStream(routeBytes))
|
||||
return routeBytes
|
||||
}
|
||||
|
||||
@native
|
||||
fun require(name: String): dynamic = noImpl
|
||||
@native
|
||||
fun setInterval(callBack: () -> Unit, ms: Int) : dynamic = noImpl
|
||||
@native
|
||||
fun setTimeout(callBack: () -> Unit, ms: Int) : dynamic = noImpl
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
* observable class, check mc condition and notify observers about changes
|
||||
*/
|
||||
class McConditionMonitor private constructor() : MCConnectObservable<String> {
|
||||
|
||||
private val udev: dynamic = require("udev")
|
||||
private val exec: dynamic = require("child_process").execSync
|
||||
private val observersList: MutableList<MCConnectObserver<String>> = arrayListOf()
|
||||
|
||||
fun start() {
|
||||
val monitor = udev.monitor()
|
||||
monitor.on("add", { device ->
|
||||
if (isOurMcDevice(device)) {
|
||||
connectDevice(device)
|
||||
}
|
||||
})
|
||||
|
||||
monitor.on("remove", { device ->
|
||||
if (isOurMcDevice(device)) {
|
||||
disconnectDevice()
|
||||
}
|
||||
})
|
||||
|
||||
readFileIfMcConnected()
|
||||
}
|
||||
|
||||
override fun addObserver(MCConnectObserver: MCConnectObserver<String>) {
|
||||
observersList.add(MCConnectObserver)
|
||||
}
|
||||
|
||||
override fun removeObserver(MCConnectObserver: MCConnectObserver<String>) {
|
||||
observersList.remove(MCConnectObserver)
|
||||
}
|
||||
|
||||
private fun notifyMCConnect(nodeName: String) {
|
||||
for (observer in observersList) {
|
||||
observer.connect(nodeName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyMCDisconnect() {
|
||||
for (observer in observersList) {
|
||||
observer.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isOurMcDevice(device: dynamic): Boolean {
|
||||
val microController = MicroController.instance
|
||||
return (device.ID_VENDOR_ID == microController.vendorID)
|
||||
&& (device.ID_MODEL_ID == microController.modelID)
|
||||
&& (device.SUBSYSTEM == "tty")
|
||||
}
|
||||
|
||||
private fun disconnectDevice() {
|
||||
println("mc disconnected")
|
||||
notifyMCDisconnect()
|
||||
}
|
||||
|
||||
private fun connectDevice(device: dynamic) {
|
||||
val transportFile: String = device.DEVNAME
|
||||
mcTransport.initStreams(transportFile)
|
||||
McState.instance.connect()
|
||||
println("mc connected. transport file is " + transportFile)
|
||||
exec("stty -F $transportFile raw -echo -echoe -echok")
|
||||
notifyMCConnect(transportFile)
|
||||
}
|
||||
|
||||
private fun readFileIfMcConnected() {
|
||||
val allTtyDevices = udev.list("tty")
|
||||
for (device in allTtyDevices) {
|
||||
if (isOurMcDevice(device)) {
|
||||
connectDevice(device)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val instance = McConditionMonitor()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Created by user on 8/18/16.
|
||||
*/
|
||||
class McState {
|
||||
|
||||
|
||||
private var connected = false
|
||||
|
||||
|
||||
fun isConnected(): Boolean {
|
||||
return connected
|
||||
}
|
||||
|
||||
fun connect() {
|
||||
this.connected = true
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
val instance = McState()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import carControl.ControlImpl
|
||||
import carControl.RouteExecutorImpl
|
||||
import carControl.RouteExecutorToUsb
|
||||
import control.emulator.RouteExecutorImpl
|
||||
import control.car.RouteExecutorToUsb
|
||||
import exceptions.RcControlException
|
||||
import kotlin.js.Date
|
||||
|
||||
/**
|
||||
* Created by user on 7/28/16.
|
||||
@@ -17,7 +17,7 @@ class MicroController private constructor() {
|
||||
val modelID: String
|
||||
var transportFilePath: String
|
||||
|
||||
val car: Car
|
||||
val car: CarState
|
||||
|
||||
init {
|
||||
this.rcSid = 0
|
||||
@@ -27,7 +27,8 @@ class MicroController private constructor() {
|
||||
this.modelID = "5740"
|
||||
this.transportFilePath = ""
|
||||
|
||||
this.car = Car(RouteExecutorToUsb(), ControlImpl())
|
||||
|
||||
this.car = CarState.instance
|
||||
}
|
||||
|
||||
fun start() {
|
||||
@@ -38,65 +39,11 @@ class MicroController private constructor() {
|
||||
println("read: " + bytes.toString())
|
||||
}
|
||||
|
||||
setInterval({ this.car.refreshLocation(deltaTimeLocationRefresh) }, deltaTimeLocationRefresh);
|
||||
setInterval({
|
||||
if (needDropRC()) {
|
||||
dropRC()
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
fun dropRC() {
|
||||
this.rcSid = 0
|
||||
car.stopCar()
|
||||
}
|
||||
|
||||
fun disconnectRC(sid: Int) {
|
||||
if (sid != rcSid) {
|
||||
throw RcControlException()
|
||||
}
|
||||
dropRC()
|
||||
}
|
||||
|
||||
fun RcMove(command: RouteExecutorImpl.MoveDirection, sid: Int) {
|
||||
if (sid != this.rcSid) {
|
||||
throw RcControlException()
|
||||
}
|
||||
car.move(command, 0, {})
|
||||
rcHeartBeat(sid)
|
||||
}
|
||||
|
||||
fun needDropRC(): Boolean {
|
||||
return Date().getTime() > (rcLastRequest + 1000) && controlledByRC()
|
||||
}
|
||||
|
||||
fun connectRC(): Int {
|
||||
if (controlledByRC()) {
|
||||
throw RcControlException()
|
||||
}
|
||||
val sid = (Math.random() * 100000).toInt()
|
||||
this.rcSid = sid
|
||||
rcHeartBeat(sid)
|
||||
return sid
|
||||
}
|
||||
|
||||
fun controlledByRC(): Boolean {
|
||||
return (rcSid != 0)
|
||||
}
|
||||
|
||||
fun isConnected(): Boolean {
|
||||
return transportFilePath != ""
|
||||
}
|
||||
|
||||
fun rcHeartBeat(sid: Int) {
|
||||
if (sid != this.rcSid) {
|
||||
throw RcControlException()
|
||||
}
|
||||
rcLastRequest = Date().getTime()
|
||||
// setInterval({ this.car.refreshLocation(deltaTimeLocationRefresh) }, deltaTimeLocationRefresh);
|
||||
}
|
||||
|
||||
fun connectToServer(thisIp: String, thisPort: Int) {
|
||||
val requestObject = ConnectionRequest.BuilderConnectionRequest(config.getCarIp().split(".").map { str -> parseInt(str, 10) }.toIntArray(), carServerPort).build()
|
||||
val requestObject = ConnectionRequest.BuilderConnectionRequest(thisIp.split(".").map { str -> parseInt(str, 10) }.toIntArray(), thisPort).build()
|
||||
val bytes = ByteArray(requestObject.getSizeNoTag())
|
||||
requestObject.writeTo(CodedOutputStream(bytes))
|
||||
net.sendRequest(js("new Buffer(bytes)"), "/connect", { resultData ->
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class Udev {
|
||||
|
||||
val udev: dynamic
|
||||
val exec: dynamic
|
||||
|
||||
init {
|
||||
udev = require("udev")
|
||||
exec = require("child_process").execSync
|
||||
}
|
||||
|
||||
fun start() {
|
||||
val monitor = udev.monitor()
|
||||
monitor.on("add", { device ->
|
||||
if (isOurMcDevice(device)) {
|
||||
connectDevice(device)
|
||||
}
|
||||
})
|
||||
|
||||
monitor.on("remove", { device ->
|
||||
if (isOurMcDevice(device)) {
|
||||
disconnectDevice()
|
||||
}
|
||||
})
|
||||
|
||||
readFileIfMcConnected()
|
||||
}
|
||||
|
||||
fun isOurMcDevice(device: dynamic): Boolean {
|
||||
val microController = MicroController.instance
|
||||
return (device.ID_VENDOR_ID == microController.vendorID)
|
||||
&& (device.ID_MODEL_ID == microController.modelID)
|
||||
&& (device.SUBSYSTEM == "tty")
|
||||
}
|
||||
|
||||
fun disconnectDevice() {
|
||||
println("mc disconnected")
|
||||
MicroController.instance.transportFilePath = ""
|
||||
mcTransport.closeStreams()
|
||||
}
|
||||
|
||||
fun connectDevice(device: dynamic) {
|
||||
println("mc connected. transport file is " + device.DEVNAME)
|
||||
MicroController.instance.transportFilePath = device.DEVNAME;
|
||||
mcTransport.initStreams(device.DEVNAME)
|
||||
exec("stty -F ${MicroController.instance.transportFilePath} raw -echo -echoe -echok")
|
||||
}
|
||||
|
||||
fun readFileIfMcConnected() {
|
||||
val allTtyDevices = udev.list("tty")
|
||||
for (device in allTtyDevices) {
|
||||
if (isOurMcDevice(device)) {
|
||||
connectDevice(device)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package carControl
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
interface Control {
|
||||
|
||||
fun moveCarLeft()
|
||||
fun moveCarRight()
|
||||
fun moveCarForward()
|
||||
fun moveCarBackward()
|
||||
|
||||
fun stopCar()
|
||||
|
||||
fun delay(ms: Int, callBack:()->Unit)
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package carControl
|
||||
|
||||
import MicroController
|
||||
import mcTransport
|
||||
import fs
|
||||
import setTimeout
|
||||
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class ControlImpl : Control {
|
||||
|
||||
|
||||
override fun moveCarLeft() {
|
||||
println("move left")
|
||||
mcTransport.sendBytes(4)
|
||||
}
|
||||
|
||||
override fun moveCarRight() {
|
||||
println("move rigth")
|
||||
mcTransport.sendBytes(3)
|
||||
}
|
||||
|
||||
override fun moveCarForward() {
|
||||
println("move forward")
|
||||
mcTransport.sendBytes(1)
|
||||
}
|
||||
|
||||
override fun moveCarBackward() {
|
||||
println("move backward")
|
||||
mcTransport.sendBytes(2)
|
||||
}
|
||||
|
||||
override fun stopCar() {
|
||||
println("stopped")
|
||||
mcTransport.sendBytes(0)
|
||||
}
|
||||
|
||||
override fun delay(ms: Int, callBack: () -> Unit) {
|
||||
setTimeout(callBack, ms)
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package carControl
|
||||
|
||||
import RouteRequest
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class RouteExecutorImpl : RouteExecutor {
|
||||
|
||||
enum class MoveDirection {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
FORWARD,
|
||||
BACKWARD,
|
||||
STOP
|
||||
}
|
||||
|
||||
override fun executeRoute(route: RouteRequest) {
|
||||
val angles = route.angles
|
||||
val distances = route.distances
|
||||
val commands: MutableList<Pair<MoveDirection, Int>> = mutableListOf()
|
||||
for (i in 0..angles.size - 1) {
|
||||
val angle: Int = angles[i]
|
||||
val distance: Int = distances[i]
|
||||
if (angle != 0) {
|
||||
val command = if (angle > 180) {
|
||||
MoveDirection.RIGHT
|
||||
} else {
|
||||
MoveDirection.LEFT
|
||||
}
|
||||
commands.add(Pair(command, angle))
|
||||
}
|
||||
if (distance != 0) {
|
||||
val command = if (distance > 0) {
|
||||
MoveDirection.FORWARD
|
||||
} else {
|
||||
MoveDirection.BACKWARD
|
||||
}
|
||||
commands.add(Pair(command, distance))
|
||||
}
|
||||
}
|
||||
commands.add(Pair(MoveDirection.STOP, 0))
|
||||
executeCommand(commands, 0)
|
||||
}
|
||||
|
||||
fun executeCommand(commands: List<Pair<MoveDirection, Int>>, currentCommandIdx: Int) {
|
||||
if (currentCommandIdx == commands.size) {
|
||||
MicroController.instance.car.routeDone()
|
||||
}
|
||||
val currentCommand = commands.get(currentCommandIdx)
|
||||
MicroController.instance.car.move(currentCommand.first, currentCommand.second, {
|
||||
executeCommand(commands, currentCommandIdx + 1)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package carControl
|
||||
package control
|
||||
|
||||
import RouteRequest
|
||||
|
||||
+8
-5
@@ -1,16 +1,19 @@
|
||||
package carControl
|
||||
package control.car
|
||||
|
||||
import RouteRequest
|
||||
import mcTransport
|
||||
import encodeInt
|
||||
import decodeInt
|
||||
import control.RouteExecutor
|
||||
import encodeProtoBuf
|
||||
import mcTransport
|
||||
import CodedOutputStream
|
||||
|
||||
class RouteExecutorToUsb : RouteExecutor {
|
||||
|
||||
override fun executeRoute(route: RouteRequest) {
|
||||
println("Execute Route:")
|
||||
val routeBytes = encodeProtoBuf(route)
|
||||
val protoSize = route.getSizeNoTag()
|
||||
val routeBytes = ByteArray(protoSize)
|
||||
|
||||
route.writeTo(CodedOutputStream(routeBytes))
|
||||
|
||||
mcTransport.setCallBack { bytes ->
|
||||
println("Read $bytes;")
|
||||
@@ -0,0 +1,110 @@
|
||||
package control.emulator
|
||||
|
||||
import RouteRequest
|
||||
import control.RouteExecutor
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class RouteExecutorImpl : RouteExecutor {
|
||||
|
||||
enum class MoveDirection {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
FORWARD,
|
||||
BACKWARD,
|
||||
STOP
|
||||
}
|
||||
|
||||
override fun executeRoute(route: RouteRequest) {
|
||||
val angles = route.angles
|
||||
val distances = route.distances
|
||||
val commands: MutableList<Pair<MoveDirection, Int>> = mutableListOf()
|
||||
for (i in 0..angles.size - 1) {
|
||||
val angle: Int = angles[i]
|
||||
val distance: Int = distances[i]
|
||||
if (angle != 0) {
|
||||
val command = if (angle > 180) {
|
||||
MoveDirection.RIGHT
|
||||
} else {
|
||||
MoveDirection.LEFT
|
||||
}
|
||||
commands.add(Pair(command, angle))
|
||||
}
|
||||
if (distance != 0) {
|
||||
val command = if (distance > 0) {
|
||||
MoveDirection.FORWARD
|
||||
} else {
|
||||
MoveDirection.BACKWARD
|
||||
}
|
||||
commands.add(Pair(command, distance))
|
||||
}
|
||||
}
|
||||
commands.add(Pair(MoveDirection.STOP, 0))
|
||||
executeCommand(commands, 0)
|
||||
}
|
||||
|
||||
fun executeCommand(commands: List<Pair<MoveDirection, Int>>, currentCommandIdx: Int) {
|
||||
// if (currentCommandIdx == commands.size) {
|
||||
// MicroController.instance.car.routeDone()
|
||||
// }
|
||||
// val currentCommand = commands.get(currentCommandIdx)
|
||||
// MicroController.instance.car.move(currentCommand.first, currentCommand.second, {
|
||||
// executeCommand(commands, currentCommandIdx + 1)
|
||||
// })
|
||||
}
|
||||
|
||||
// var moveDirection: MoveDirection = MoveDirection.STOP
|
||||
//
|
||||
// fun stopCar() {
|
||||
// move(MoveDirection.STOP, 0, {})
|
||||
// }
|
||||
//
|
||||
// fun refreshLocation(delta: Int) {
|
||||
// val deltaSeconds = delta.toDouble() / 1000
|
||||
// when (moveDirection) {
|
||||
// MoveDirection.FORWARD -> {
|
||||
// this.x += MOVE_VELOCITY * deltaSeconds * Math.cos(this.angle * Math.PI / 180);
|
||||
// this.y += MOVE_VELOCITY * deltaSeconds * Math.sin(this.angle * Math.PI / 180);
|
||||
// }
|
||||
// MoveDirection.BACKWARD -> {
|
||||
// this.x -= MOVE_VELOCITY * deltaSeconds * Math.cos(this.angle * Math.PI / 180);
|
||||
// this.y -= MOVE_VELOCITY * deltaSeconds * Math.sin(this.angle * Math.PI / 180);
|
||||
// }
|
||||
// MoveDirection.LEFT -> this.angle += ROTATION_VELOCITY * deltaSeconds
|
||||
// MoveDirection.RIGHT -> this.angle -= ROTATION_VELOCITY * deltaSeconds
|
||||
// else -> {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//// println("x=$x; y=$y; angle=$angle")
|
||||
// }
|
||||
//
|
||||
// fun routeDone() {
|
||||
// controller.stopCar()
|
||||
// }
|
||||
//
|
||||
// fun move(moveDirection: MoveDirection, value: Int, callBack: () -> Unit) {
|
||||
// //value - angle for rotation command and distance for forward/backward command
|
||||
// this.moveDirection = moveDirection
|
||||
// when (moveDirection) {
|
||||
// MoveDirection.STOP -> controller.stopCar()
|
||||
// MoveDirection.FORWARD -> controller.moveCarForward()
|
||||
// MoveDirection.BACKWARD -> controller.moveCarBackward()
|
||||
// MoveDirection.LEFT -> controller.moveCarLeft()
|
||||
// MoveDirection.RIGHT -> controller.moveCarRight()
|
||||
// }
|
||||
// if (moveDirection != MoveDirection.STOP) {
|
||||
// if (moveDirection == MoveDirection.FORWARD || moveDirection == MoveDirection.BACKWARD) {
|
||||
// controller.delay(getTimeForMoving(value, MOVE_VELOCITY), callBack)
|
||||
// } else {
|
||||
// controller.delay(getTimeForMoving(value, ROTATION_VELOCITY), callBack)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getTimeForMoving(value: Int, velocity: Double): Int {
|
||||
// return (1000 * Math.abs(value.toDouble()) / velocity).toInt()
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.server.handlers
|
||||
|
||||
import CodedOutputStream
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
@@ -13,6 +15,7 @@ abstract class AbstractHandler {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
abstract fun getBytesResponse(data: ByteArray, callback: (b: ByteArray) -> Unit)
|
||||
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
package net.server.handlers.debug
|
||||
|
||||
import CodedInputStream
|
||||
import DebugRequest
|
||||
import DebugResponseMemoryStats
|
||||
import MicroController
|
||||
import McState
|
||||
import encodeProtoBuf
|
||||
import mcTransport
|
||||
import net.server.handlers.AbstractHandler
|
||||
@@ -23,7 +22,7 @@ class Memory : AbstractHandler {
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
|
||||
|
||||
if (!MicroController.instance.isConnected()) {
|
||||
if (!McState.instance.isConnected()) {
|
||||
println("mc is disconnected!")
|
||||
val responseMessage = toServerObjectBuilder.build()
|
||||
callback.invoke(encodeProtoBuf(responseMessage))
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package net.server.handlers.flash
|
||||
|
||||
import net.server.handlers.AbstractHandler
|
||||
import require
|
||||
import CodedInputStream
|
||||
import Upload
|
||||
import UploadResult
|
||||
import encodeProtoBuf
|
||||
import mcTransport
|
||||
import net.server.handlers.AbstractHandler
|
||||
import require
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
@@ -16,9 +18,9 @@ class LoadBin : AbstractHandler {
|
||||
val fromServerObjectBuilder: Upload.BuilderUpload
|
||||
val toServerObjectBuilder: UploadResult.BuilderUploadResult
|
||||
|
||||
constructor(fromSrv: Upload.BuilderUpload, toSrv: UploadResult.BuilderUploadResult) : super() {
|
||||
this.fromServerObjectBuilder = fromSrv
|
||||
this.toServerObjectBuilder = toSrv
|
||||
constructor() : super() {
|
||||
this.fromServerObjectBuilder = Upload.BuilderUpload(ByteArray(0))
|
||||
this.toServerObjectBuilder = UploadResult.BuilderUploadResult(0)
|
||||
this.exec = require("child_process").exec
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package net.server.handlers.main
|
||||
|
||||
import net.server.handlers.AbstractHandler
|
||||
import LocationResponse
|
||||
import MicroController
|
||||
import encodeProtoBuf
|
||||
import net.server.handlers.AbstractHandler
|
||||
|
||||
/**
|
||||
* Created by user on 7/28/16.
|
||||
@@ -10,8 +12,9 @@ class GetLocation : AbstractHandler {
|
||||
|
||||
val toServerObjectBuilder: LocationResponse.BuilderLocationResponse
|
||||
|
||||
constructor(toSrv: LocationResponse.BuilderLocationResponse) : super() {
|
||||
this.toServerObjectBuilder = toSrv
|
||||
constructor() : super() {
|
||||
val defaultLocationData = LocationResponse.LocationData.BuilderLocationData(0, 0, 0).build()
|
||||
this.toServerObjectBuilder = LocationResponse.BuilderLocationResponse(defaultLocationData, 0)
|
||||
}
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
|
||||
|
||||
@@ -4,7 +4,8 @@ import CodedInputStream
|
||||
import MicroController
|
||||
import RouteRequest
|
||||
import RouteResponse
|
||||
import encodeProtoBuf
|
||||
import control.RouteExecutor
|
||||
import CodedOutputStream
|
||||
import net.server.handlers.AbstractHandler
|
||||
|
||||
/**
|
||||
@@ -14,25 +15,36 @@ class SetRoute : AbstractHandler {
|
||||
|
||||
val fromServerObjectBuilder: RouteRequest.BuilderRouteRequest
|
||||
val toServerObjectBuilder: RouteResponse.BuilderRouteResponse
|
||||
val routeExecutor: RouteExecutor
|
||||
|
||||
constructor(fromSrv: RouteRequest.BuilderRouteRequest, toSrv: RouteResponse.BuilderRouteResponse) : super() {
|
||||
this.fromServerObjectBuilder = fromSrv
|
||||
this.toServerObjectBuilder = toSrv
|
||||
constructor(routeExecutor: RouteExecutor) : super() {
|
||||
this.routeExecutor = routeExecutor
|
||||
this.fromServerObjectBuilder = RouteRequest.BuilderRouteRequest(IntArray(0), IntArray(0))
|
||||
this.toServerObjectBuilder = RouteResponse.BuilderRouteResponse(0)
|
||||
}
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
|
||||
println("set route handler")
|
||||
val car = MicroController.instance.car
|
||||
val message = fromServerObjectBuilder.build()
|
||||
message.mergeFrom(CodedInputStream(data))
|
||||
if (!MicroController.instance.isConnected()) {
|
||||
if (!McState.instance.isConnected()) {
|
||||
println("mc is disconnected!")
|
||||
val responseMessage = toServerObjectBuilder.setCode(16).build()
|
||||
callback.invoke(encodeProtoBuf(responseMessage))
|
||||
return
|
||||
}
|
||||
car.routeExecutor.executeRoute(message)
|
||||
routeExecutor.executeRoute(message)
|
||||
val responseMessage = toServerObjectBuilder.setCode(0).build()
|
||||
callback.invoke(encodeProtoBuf(responseMessage))
|
||||
}
|
||||
|
||||
fun encodeProtoBuf(protoMessage: RouteResponse): ByteArray {
|
||||
val protoSize = protoMessage.getSizeNoTag()
|
||||
val routeBytes = ByteArray(protoSize)
|
||||
|
||||
protoMessage.writeTo(CodedOutputStream(routeBytes))
|
||||
return routeBytes
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package net.server.handlers.rc
|
||||
|
||||
import exceptions.RcControlException
|
||||
import net.server.handlers.AbstractHandler
|
||||
import encodeProtoBuf
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class Connect : AbstractHandler {
|
||||
|
||||
val toServerObjectBuilder: SessionUpResponse.BuilderSessionUpResponse
|
||||
|
||||
constructor(toSrv: SessionUpResponse.BuilderSessionUpResponse) : super() {
|
||||
this.toServerObjectBuilder = toSrv
|
||||
}
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
|
||||
val resultCode: Int
|
||||
val sid: Int;
|
||||
try {
|
||||
sid = MicroController.instance.connectRC()
|
||||
resultCode = 0
|
||||
} catch (e: RcControlException) {
|
||||
resultCode = 13
|
||||
sid = 0
|
||||
}
|
||||
val responseMessage = toServerObjectBuilder.setCode(resultCode).setSid(sid).build()
|
||||
callback.invoke(encodeProtoBuf(responseMessage))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
package net.server.handlers.rc
|
||||
|
||||
import CodedInputStream
|
||||
import DirectionRequest
|
||||
import DirectionResponse
|
||||
import MicroController
|
||||
import carControl.RouteExecutorImpl.MoveDirection
|
||||
import control.emulator.RouteExecutorImpl.MoveDirection
|
||||
import encodeProtoBuf
|
||||
import exceptions.RcControlException
|
||||
import net.server.handlers.AbstractHandler
|
||||
import DirectionRequest
|
||||
import CodedInputStream
|
||||
import encodeProtoBuf
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
@@ -16,9 +17,9 @@ class Control : AbstractHandler {
|
||||
val fromServerObjectBuilder: DirectionRequest.BuilderDirectionRequest
|
||||
val toServerObjectBuilder: DirectionResponse.BuilderDirectionResponse
|
||||
|
||||
constructor(fromSrv: DirectionRequest.BuilderDirectionRequest, toSrv: DirectionResponse.BuilderDirectionResponse) : super() {
|
||||
this.fromServerObjectBuilder = fromSrv
|
||||
this.toServerObjectBuilder = toSrv
|
||||
constructor() : super() {
|
||||
this.fromServerObjectBuilder = DirectionRequest.BuilderDirectionRequest(DirectionRequest.Command.fromIntToCommand(0), 0)
|
||||
this.toServerObjectBuilder = DirectionResponse.BuilderDirectionResponse(0)
|
||||
}
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (b: ByteArray) -> Unit) {
|
||||
@@ -46,7 +47,7 @@ class Control : AbstractHandler {
|
||||
}
|
||||
val resultCode: Int
|
||||
try {
|
||||
MicroController.instance.RcMove(command, sid)
|
||||
// MicroController.instance.RcMove(command, sid)
|
||||
resultCode = 0
|
||||
} catch (e: RcControlException) {
|
||||
resultCode = 12
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package net.server.handlers.rc
|
||||
|
||||
import exceptions.RcControlException
|
||||
import net.server.handlers.AbstractHandler
|
||||
import CodedInputStream
|
||||
import encodeProtoBuf
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class Disconnect : AbstractHandler {
|
||||
|
||||
val fromServerObjectBuilder: SessionDownRequest.BuilderSessionDownRequest
|
||||
val toServerObjectBuilder: SessionDownResponse.BuilderSessionDownResponse
|
||||
|
||||
constructor(fromSrv: SessionDownRequest.BuilderSessionDownRequest, toSrv: SessionDownResponse.BuilderSessionDownResponse) : super() {
|
||||
this.fromServerObjectBuilder = fromSrv
|
||||
this.toServerObjectBuilder = toSrv
|
||||
}
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
|
||||
|
||||
val message = fromServerObjectBuilder.build()
|
||||
message.mergeFrom(CodedInputStream(data))
|
||||
val resultCode: Int
|
||||
try {
|
||||
MicroController.instance.disconnectRC(message.sid)
|
||||
resultCode = 0
|
||||
} catch (e: RcControlException) {
|
||||
resultCode = 12
|
||||
}
|
||||
val responseMessage = toServerObjectBuilder.setCode(resultCode).build()
|
||||
callback.invoke(encodeProtoBuf(responseMessage))
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package net.server.handlers.rc
|
||||
|
||||
import exceptions.RcControlException
|
||||
import net.server.handlers.AbstractHandler
|
||||
import CodedInputStream
|
||||
import encodeProtoBuf
|
||||
|
||||
/**
|
||||
* Created by user on 7/27/16.
|
||||
*/
|
||||
class Heartbeat : AbstractHandler {
|
||||
|
||||
val fromServerObjectBuilder: HeartBeatRequest.BuilderHeartBeatRequest
|
||||
val toServerObjectBuilder: HeartBeatResponse.BuilderHeartBeatResponse
|
||||
|
||||
constructor(fromSrv: HeartBeatRequest.BuilderHeartBeatRequest, toSrv: HeartBeatResponse.BuilderHeartBeatResponse) : super() {
|
||||
this.fromServerObjectBuilder = fromSrv
|
||||
this.toServerObjectBuilder = toSrv
|
||||
}
|
||||
|
||||
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
|
||||
val message = fromServerObjectBuilder.build()
|
||||
message.mergeFrom(CodedInputStream(data))
|
||||
val resultCode: Int
|
||||
try {
|
||||
MicroController.instance.rcHeartBeat(message.sid)
|
||||
resultCode = 0
|
||||
} catch (e: RcControlException) {
|
||||
resultCode = 12
|
||||
}
|
||||
val responseMessage = toServerObjectBuilder.setCode(resultCode).build()
|
||||
callback.invoke(encodeProtoBuf(responseMessage))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user