diff --git a/car_srv/kotlinSrv/src/Car.kt b/car_srv/kotlinSrv/src/Car.kt index bbd9dd08808..cda4733075f 100644 --- a/car_srv/kotlinSrv/src/Car.kt +++ b/car_srv/kotlinSrv/src/Car.kt @@ -17,8 +17,6 @@ class Car constructor(routeExecutor: RouteExecutor, controller: Control) { var angle: Double var moveDirection: MoveDirection = MoveDirection.STOP - var startMoveOn: Int = 0 - val routeExecutor: RouteExecutor val controller: Control @@ -31,6 +29,10 @@ class Car constructor(routeExecutor: RouteExecutor, controller: Control) { this.angle = 0.0 } + fun stopCar() { + move(MoveDirection.STOP, 0.0, {}) + } + fun refreshLocation(delta: Int) { val deltaSeconds = delta.toDouble() / 1000 when (moveDirection) { diff --git a/car_srv/kotlinSrv/src/Main.kt b/car_srv/kotlinSrv/src/Main.kt index 75bfd9611ae..654d851e0fb 100644 --- a/car_srv/kotlinSrv/src/Main.kt +++ b/car_srv/kotlinSrv/src/Main.kt @@ -1,30 +1,56 @@ -import carControl.ControlImpl -import carControl.RouteExecutorImpl -import server.Server -import server.handlers.AbstractHandler -import server.handlers.flash.LoadBin -import server.handlers.rc.Control +import exceptions.RcControlException +import net.server.handlers.AbstractHandler +import net.server.handlers.flash.LoadBin +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. */ -var transportFilePath: String = "./test"//todo init on start after start udev -val thisCar = Car(RouteExecutorImpl(), ControlImpl()) val deltaTimeLocationRefresh: Int = 100//ms +val serverPort: Int = 8888 +val serverIp: String = "127.0.0.1" + +val protoBuf = require("protobufjs") fun main(args: Array) { - val protoBuf = require("protobufjs") - val controlConstructor = protoBuf.loadProtoFile("./proto/" + "direction.proto").build("carkot") + val controlConstructor = protoBuf.loadProtoFile(getRelativePathToProto("direction.proto")).build("carkot") + val rcSessionConstructor = protoBuf.loadProtoFile(getRelativePathToProto("rc_session.proto")).build("carkot") + val carkotConstructor = protoBuf.loadProtoFile(getRelativePathToProto("carkot.proto")).build("carkot") + + val handlers: MutableMap = mutableMapOf() - handlers.put("/control", Control(controlConstructor.DirectionRequest, controlConstructor.DirectionResponse)) + handlers.put("/rc/control", Control(controlConstructor.DirectionRequest, controlConstructor.DirectionResponse)) + handlers.put("/rc/connect", Connect(null, rcSessionConstructor.SessionUpResponse)) + handlers.put("/rc/disconnect", Disconnect(rcSessionConstructor.SessionDownRequest, rcSessionConstructor.SessionDownResponse)) + handlers.put("/rc/heartbeat", Heartbeat(rcSessionConstructor.HeartBeatRequest, rcSessionConstructor.HeartBeatResponse)) - val srv = Server(handlers) - srv.start() + handlers.put("/loadBin", LoadBin(carkotConstructor.Upload, carkotConstructor.UploadResult)) + //todo work with main server - setInterval({ thisCar.refreshLocation(deltaTimeLocationRefresh) }, deltaTimeLocationRefresh); + net.server.start(handlers, serverPort) + val udev = Udev() + udev.start() + + MicroController.instance.start() + +} + +fun getRelativePathToProto(fileName: String): String { + return "./proto/" + fileName +} + +fun trimBuffer(buffer: dynamic, length: Int): dynamic { + val byteArray = ByteArray(length); + for (i in 0..length - 1) { + byteArray[i] = buffer[i] + } + return js("new Buffer(byteArray)") } @native diff --git a/car_srv/kotlinSrv/src/MicroController.kt b/car_srv/kotlinSrv/src/MicroController.kt new file mode 100644 index 00000000000..70c7eb81c67 --- /dev/null +++ b/car_srv/kotlinSrv/src/MicroController.kt @@ -0,0 +1,118 @@ +import carControl.ControlImpl +import carControl.RouteExecutorImpl +import exceptions.RcControlException + +/** + * Created by user on 7/28/16. + */ +class MicroController private constructor() { + + var uid: Int + + var rcSid: Int + var rcLastRequest: Int//heartbeat + + val vendorID: String + val modelID: String + var transportFilePath: String + + val car: Car + + init { + this.rcSid = 0 + this.rcLastRequest = 0 + this.uid = 0 + this.vendorID = "0483" + this.modelID = "5740" + this.transportFilePath = "" + + this.car = Car(RouteExecutorImpl(), ControlImpl()) + } + + fun start() { + + if (!isConnected()) { + connectToServer(serverIp, serverPort) + } + + this.transportFilePath = "./temp"//todo need init + + 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.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 uid != 0 + } + + fun rcHeartBeat(sid: Int) { + if (sid != this.rcSid) { + throw RcControlException() + } + rcLastRequest = Date().getTime() + } + + fun connectToServer(thisIp: String, thisPort: Int) { + val connectProtobuf = protoBuf.loadProtoFile(getRelativePathToProto("connect.proto")).build("carkot") + val requestObject = js("new connectProtobuf.ConnectionRequest({ip:thisIp, port:thisPort})").encode() + net.sendRequest(trimBuffer(requestObject.buffer, requestObject.limit), "/connect", { resultData -> + val responseObject = connectProtobuf.ConnectionResponse.decode(resultData) + if (responseObject.code == 0) { + this.uid = responseObject.uid + } else { + println("server login error\n" + + "code: ${responseObject.code}\n" + + "error message: ${responseObject.errorMsg}") + } + }, { error -> + println("connection error (to main server). error message:\n" + error) + }) + } + + companion object { + val instance = MicroController() + } + +} diff --git a/car_srv/kotlinSrv/src/Udev.kt b/car_srv/kotlinSrv/src/Udev.kt index 72c176987a7..a6b9516d746 100644 --- a/car_srv/kotlinSrv/src/Udev.kt +++ b/car_srv/kotlinSrv/src/Udev.kt @@ -2,4 +2,31 @@ * Created by user on 7/27/16. */ class Udev { + + val udev: dynamic + + init { + udev = require("udev") + } + + fun start() { + val monitor = udev.monitor() + val microController = MicroController.instance + monitor.on("add", { device -> + if (device.ID_VENDOR_ID == microController.vendorID && device.ID_MODEL_ID == microController.modelID && device.SUBSYSTEM == "tty") { + //mc connected + println("mc connected. transport file is " + device.DEVNAME) + microController.transportFilePath = device.DEVNAME; + } + }) + + monitor.on("remove", { device -> + if (device.ID_VENDOR_ID == microController.vendorID && device.ID_MODEL_ID == microController.modelID && device.SUBSYSTEM == "tty") { + //mc disconnected + println("mc disconnected") + microController.transportFilePath = "" + } + }) + } + } \ No newline at end of file diff --git a/car_srv/kotlinSrv/src/carControl/ControlImpl.kt b/car_srv/kotlinSrv/src/carControl/ControlImpl.kt index c896ea06069..9dd1faebcb9 100644 --- a/car_srv/kotlinSrv/src/carControl/ControlImpl.kt +++ b/car_srv/kotlinSrv/src/carControl/ControlImpl.kt @@ -1,7 +1,7 @@ package carControl +import MicroController import require -import transportFilePath /** @@ -51,7 +51,7 @@ class ControlImpl : Control { fun writeToFile(byte: Byte) { - fs.appendFile(transportFilePath, byte.toString(), "binary", { err -> + fs.appendFile(MicroController.instance.transportFilePath, byte.toString(), "binary", { err -> if (err) { println("error") } else { diff --git a/car_srv/kotlinSrv/src/carControl/RouteExecutorImpl.kt b/car_srv/kotlinSrv/src/carControl/RouteExecutorImpl.kt index 1fe457d707f..30ffae9a781 100644 --- a/car_srv/kotlinSrv/src/carControl/RouteExecutorImpl.kt +++ b/car_srv/kotlinSrv/src/carControl/RouteExecutorImpl.kt @@ -1,6 +1,5 @@ package carControl -import thisCar /** * Created by user on 7/27/16. @@ -44,10 +43,10 @@ class RouteExecutorImpl : RouteExecutor { fun executeCommand(commands: List>, currentCommandIdx: Int) { if (currentCommandIdx == commands.size) { - thisCar.routeDone() + MicroController.instance.car.routeDone() } val currentCommand = commands.get(currentCommandIdx) - thisCar.move(currentCommand.first, currentCommand.second, { + MicroController.instance.car.move(currentCommand.first, currentCommand.second, { executeCommand(commands, currentCommandIdx + 1) }) } diff --git a/car_srv/kotlinSrv/src/exceptions/RcControlException.kt b/car_srv/kotlinSrv/src/exceptions/RcControlException.kt new file mode 100644 index 00000000000..4c368fc918a --- /dev/null +++ b/car_srv/kotlinSrv/src/exceptions/RcControlException.kt @@ -0,0 +1,8 @@ +package exceptions + +/** + * Created by user on 7/28/16. + */ +class RcControlException : Exception() { + +} \ No newline at end of file diff --git a/car_srv/kotlinSrv/src/net/Client.kt b/car_srv/kotlinSrv/src/net/Client.kt new file mode 100644 index 00000000000..dc498fa69f5 --- /dev/null +++ b/car_srv/kotlinSrv/src/net/Client.kt @@ -0,0 +1,32 @@ +package net + +import require + +/** + * Created by user on 7/28/16. + */ +val http = require("http") + +fun sendRequest(dataBuffer: dynamic, url: String, successCallback: (responseData: ByteArray) -> Unit, errorCallback: (err: dynamic) -> Unit) { + val options: dynamic = {} + val serverAddress = "127.0.0.1" + val port = 7925 + js("options = {hostname:serverAddress, port:port, path:url, method:'POST'}") + + val request = http.request(options, { response -> + val resData = mutableListOf() + response.on("data", { datas -> + for (i in 0..datas.length - 1) { + resData.add(datas[i]) + } + }) + response.on("end", { + successCallback.invoke(resData.toByteArray()) + }) + }) + request.on("error", { err -> + errorCallback.invoke(err) + }) + request.write(dataBuffer) + request.end() +} \ No newline at end of file diff --git a/car_srv/kotlinSrv/src/server/Server.kt b/car_srv/kotlinSrv/src/net/server/Server.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/Server.kt rename to car_srv/kotlinSrv/src/net/server/Server.kt diff --git a/car_srv/kotlinSrv/src/server/handlers/AbstractHandler.kt b/car_srv/kotlinSrv/src/net/server/handlers/AbstractHandler.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/handlers/AbstractHandler.kt rename to car_srv/kotlinSrv/src/net/server/handlers/AbstractHandler.kt diff --git a/car_srv/kotlinSrv/src/server/handlers/flash/LoadBin.kt b/car_srv/kotlinSrv/src/net/server/handlers/flash/LoadBin.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/handlers/flash/LoadBin.kt rename to car_srv/kotlinSrv/src/net/server/handlers/flash/LoadBin.kt diff --git a/car_srv/kotlinSrv/src/server/handlers/rc/Connect.kt b/car_srv/kotlinSrv/src/net/server/handlers/rc/Connect.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/handlers/rc/Connect.kt rename to car_srv/kotlinSrv/src/net/server/handlers/rc/Connect.kt diff --git a/car_srv/kotlinSrv/src/server/handlers/rc/Control.kt b/car_srv/kotlinSrv/src/net/server/handlers/rc/Control.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/handlers/rc/Control.kt rename to car_srv/kotlinSrv/src/net/server/handlers/rc/Control.kt diff --git a/car_srv/kotlinSrv/src/server/handlers/rc/Disconnect.kt b/car_srv/kotlinSrv/src/net/server/handlers/rc/Disconnect.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/handlers/rc/Disconnect.kt rename to car_srv/kotlinSrv/src/net/server/handlers/rc/Disconnect.kt diff --git a/car_srv/kotlinSrv/src/server/handlers/rc/Heartbeat.kt b/car_srv/kotlinSrv/src/net/server/handlers/rc/Heartbeat.kt similarity index 100% rename from car_srv/kotlinSrv/src/server/handlers/rc/Heartbeat.kt rename to car_srv/kotlinSrv/src/net/server/handlers/rc/Heartbeat.kt