refactoring raspberry server

This commit is contained in:
MaximZaitsev
2016-08-19 13:50:50 +03:00
parent 21c6a1e3ce
commit ad54a070b9
23 changed files with 240 additions and 295 deletions
-11
View File
@@ -1,14 +1,3 @@
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
+1 -4
View File
@@ -1,6 +1,3 @@
/**
* Created by user on 8/16/16.
*/
class Config(val configFileName: String = "config.cfg") {
@@ -10,7 +7,7 @@ class Config(val configFileName: String = "config.cfg") {
fun loadConfig(): Boolean {
try {
fs.accessSync(configFileName, fs.F_OK);
fs.accessSync(configFileName, fs.F_OK)
} catch (e: dynamic) {
// create it
fs.openSync(configFileName, "w")
-18
View File
@@ -1,20 +1,2 @@
/**
* 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
}
@@ -1,9 +0,0 @@
/**
* Created by user on 8/18/16.
*/
interface MCConnectObservable<V> {
fun addObserver(MCConnectObserver: MCConnectObserver<V>)
fun removeObserver(MCConnectObserver: MCConnectObserver<V>)
}
+2 -5
View File
@@ -1,9 +1,6 @@
/**
* Created by user on 8/18/16.
*/
interface MCConnectObserver<V> {
interface MCConnectObserver<in V> {
fun connect(vararg params: V)
fun connect(transportFileName: V)
fun disconnect()
}
+19 -18
View File
@@ -1,34 +1,27 @@
/**
* Created by user on 8/16/16.
*/
class McTransport() {
class McTransport() : MCConnectObserver<String> {
private var writeStream: dynamic = null
private var readStream: dynamic = null
private val resultBytes = arrayListOf<Byte>()
private var callback: (bytes: ByteArray) -> Unit = {}
init {
McConditionMonitor.instance.addObserver(this)
}
fun sendBytes(bytes: ByteArray) {
val bytesHeader = encodeInt(bytes.size)
println("write: " + bytesHeader)
println("write: $bytesHeader")
writeStream.write(js("new Buffer(bytesHeader)"))
println("write: " + bytes)
println("write: $bytes")
writeStream.write(js("new Buffer(bytes)"))
}
fun sendBytes(byte: Byte) {
sendBytes(ByteArray(1, { idx -> byte }))
}
fun initStreams(pathToFile: String) {
writeStream = fs.createWriteStream(pathToFile);
private fun initStreams(pathToFile: String) {
writeStream = fs.createWriteStream(pathToFile)
readStream = fs.createReadStream(pathToFile)
readStream.on("readable", fun() {
val data = readStream.read()
if (data == null) {
return
}
val data = readStream.read() ?: return
var messageLength = getBodyLength(resultBytes)
for (i in 0..data.length - 1) {
@@ -43,11 +36,19 @@ class McTransport() {
})
}
override fun connect(transportFileName: String) {
initStreams(transportFileName)
}
override fun disconnect() {
closeStreams()
}
fun setCallBack(cb: (bytes: ByteArray) -> Unit) {
this.callback = cb
}
fun closeStreams() {
private fun closeStreams() {
writeStream.end()
writeStream = null
readStream = null
+14 -14
View File
@@ -1,22 +1,18 @@
import control.car.RouteExecutorToUsb
import control.car.ControllerToUsb
import net.Client
import net.server.handlers.AbstractHandler
import net.server.handlers.ProtoType
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.Control
/**
* Created by user on 7/26/16.
*/
val deltaTimeLocationRefresh: Int = 100
val carServerPort: Int = 8888
val mainServerPort = 7925
val config = Config()
val fs = require("fs")
val fs: dynamic = require("fs")
fun main(args: Array<String>) {
if (!config.loadConfig()) {
println("incorrect config format!")
@@ -25,17 +21,21 @@ fun main(args: Array<String>) {
val handlers: MutableMap<String, AbstractHandler> = mutableMapOf()
val routeExecutor = RouteExecutorToUsb()
val carController = ControllerToUsb()
handlers.put("/rc/control", Control())
handlers.put("/loadBin", LoadBin())
handlers.put("/route", SetRoute(routeExecutor))
handlers.put("/route", SetRoute(carController))
handlers.put("/getLocation", GetLocation())
handlers.put("/debug/memoty", Memory())
handlers.put("/debug/memory", Memory())
handlers.put("/protoType", ProtoType())
Client.instance.connectToServer(config.getCarIp(), carServerPort)
mcTransport.setCallBack { bytes ->
println("read: " + bytes.toString())
}
net.server.start(handlers, carServerPort)
val mcConditionMonitor = McConditionMonitor.instance
mcConditionMonitor.start()
MicroController.instance.start()
}
+5 -11
View File
@@ -2,7 +2,7 @@
* Created by user on 7/27/16.
* observable class, check mc condition and notify observers about changes
*/
class McConditionMonitor private constructor() : MCConnectObservable<String> {
class McConditionMonitor private constructor() {
private val udev: dynamic = require("udev")
private val exec: dynamic = require("child_process").execSync
@@ -25,14 +25,10 @@ class McConditionMonitor private constructor() : MCConnectObservable<String> {
readFileIfMcConnected()
}
override fun addObserver(MCConnectObserver: MCConnectObserver<String>) {
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)
@@ -46,9 +42,9 @@ class McConditionMonitor private constructor() : MCConnectObservable<String> {
}
private fun isOurMcDevice(device: dynamic): Boolean {
val microController = MicroController.instance
return (device.ID_VENDOR_ID == microController.vendorID)
&& (device.ID_MODEL_ID == microController.modelID)
val mcState = McState.instance
return (device.ID_VENDOR_ID == mcState.VENDORID)
&& (device.ID_MODEL_ID == mcState.MODELID)
&& (device.SUBSYSTEM == "tty")
}
@@ -59,8 +55,6 @@ class McConditionMonitor private constructor() : MCConnectObservable<String> {
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)
+13 -6
View File
@@ -1,20 +1,27 @@
/**
* Created by user on 8/18/16.
*/
class McState {
class McState : MCConnectObserver<String> {
val VENDORID = "0483"
val MODELID = "5740"
private var connected = false
private var transportFileName = ""
init {
McConditionMonitor.instance.addObserver(this)
}
fun isConnected(): Boolean {
return connected
}
fun connect() {
this.connected = true
override fun connect(transportFileName: String) {
this.transportFileName = transportFileName
connected = true
}
override fun disconnect() {
connected = false
}
companion object {
val instance = McState()
-67
View File
@@ -1,67 +0,0 @@
import control.emulator.RouteExecutorImpl
import control.car.RouteExecutorToUsb
import exceptions.RcControlException
import kotlin.js.Date
/**
* 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: CarState
init {
this.rcSid = 0
this.rcLastRequest = 0
this.uid = 0
this.vendorID = "0483"
this.modelID = "5740"
this.transportFilePath = ""
this.car = CarState.instance
}
fun start() {
connectToServer(config.getCarIp(), carServerPort)
mcTransport.setCallBack { bytes ->
println("read: " + bytes.toString())
}
// setInterval({ this.car.refreshLocation(deltaTimeLocationRefresh) }, deltaTimeLocationRefresh);
}
fun connectToServer(thisIp: String, thisPort: Int) {
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 ->
val responseObject = ConnectionResponse.BuilderConnectionResponse(0, 0).build()
responseObject.mergeFrom(CodedInputStream(resultData))
if (responseObject.code == 0) {
this.uid = responseObject.uid
} else {
println("server login error\n" +
"code: ${responseObject.code}")
}
}, { error ->
println("connection error (to main server). error message:\n" + error)
})
}
companion object {
val instance = MicroController()
}
}
@@ -2,11 +2,10 @@ package control
import RouteRequest
/**
* Created by user on 7/27/16.
*/
interface RouteExecutor {
interface Controller {
fun executeRoute(route: RouteRequest)
fun getSensorData(degrees: IntArray): IntArray
}
@@ -1,12 +1,11 @@
package control.car
import RouteRequest
import control.RouteExecutor
import encodeProtoBuf
import mcTransport
import CodedOutputStream
import RouteRequest
import control.Controller
import mcTransport
class RouteExecutorToUsb : RouteExecutor {
class ControllerToUsb : Controller {
override fun executeRoute(route: RouteRequest) {
println("Execute Route:")
@@ -21,4 +20,8 @@ class RouteExecutorToUsb : RouteExecutor {
mcTransport.sendBytes(routeBytes)
}
}
override fun getSensorData(degrees: IntArray): IntArray {
return IntArray(0)//todo make after connect sensor to car
}
}
@@ -1,49 +1,47 @@
package control.emulator
import RouteRequest
import control.RouteExecutor
import control.Controller
/**
* Created by user on 7/27/16.
*/
class RouteExecutorImpl : RouteExecutor {
class ControllerEmulator : Controller {
private val MOVE_VELOCITY = 0.3278
private val ROTATION_VELOCITY = 12.3
enum class MoveDirection {
LEFT,
RIGHT,
FORWARD,
BACKWARD,
STOP
ERROR
}
override fun executeRoute(route: RouteRequest) {
val angles = route.angles
val distances = route.distances
val moveTimes = route.moveTime
val moveDirections = route.moveDirection
//list of move direction and time to this move in ms
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))
}
moveTimes.forEachIndexed { idx, value ->
val moveDirection =
when (moveDirections[idx]) {
0 -> MoveDirection.FORWARD
1 -> MoveDirection.BACKWARD
2 -> MoveDirection.LEFT
3 -> MoveDirection.RIGHT
else -> MoveDirection.ERROR
}
commands.add(Pair(moveDirection, value))
}
commands.add(Pair(MoveDirection.STOP, 0))
executeCommand(commands, 0)
}
override fun getSensorData(degrees: IntArray): IntArray {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
fun executeCommand(commands: List<Pair<MoveDirection, Int>>, currentCommandIdx: Int) {
// if (currentCommandIdx == commands.size) {
// MicroController.instance.car.routeDone()
@@ -1,8 +0,0 @@
package exceptions
/**
* Created by user on 7/28/16.
*/
class RcControlException : Exception() {
}
+53 -25
View File
@@ -1,34 +1,62 @@
package net
import require
import mainServerPort
import CodedInputStream
import CodedOutputStream
import ConnectionRequest
import ConnectionResponse
import config
import mainServerPort
import require
/**
* Created by user on 7/28/16.
*/
val http = require("http")
class Client() {
fun sendRequest(dataBuffer: dynamic, url: String, successCallback: (responseData: ByteArray) -> Unit, errorCallback: (err: dynamic) -> Unit) {
val options: dynamic = {}
val serverAddress = config.getIp()
val port = mainServerPort
js("options = {hostname:serverAddress, port:port, path:url, method:'POST'}")
private val http = require("http")
private var uid: Int = -1
val request = http.request(options, { response ->
val resData = mutableListOf<Byte>()
response.on("data", { datas ->
for (i in 0..datas.length - 1) {
resData.add(datas[i])
fun sendRequest(dataBuffer: dynamic, url: String, successCallback: (responseData: ByteArray) -> Unit, errorCallback: (err: dynamic) -> Unit) {
val options: dynamic = {}
//serverAddress, port and url used on js function. Idea don's see this
val serverAddress = config.getIp()
val port = mainServerPort
js("options = {hostname:serverAddress, port:port, path:url, method:'POST'}")
val request = http.request(options, { response ->
val resData = mutableListOf<Byte>()
response.on("data", { data ->
for (i in 0..data.length - 1) {
resData.add(data[i])
}
})
response.on("end", {
successCallback.invoke(resData.toByteArray())
})
})
request.on("error", { err ->
errorCallback.invoke(err)
})
request.write(dataBuffer)
request.end()
}
fun connectToServer(thisIp: String, thisPort: Int) {
val requestObject = ConnectionRequest.BuilderConnectionRequest(thisIp.split(".").map { str -> parseInt(str, 10) }.toIntArray(), thisPort).build()
val bytes = ByteArray(requestObject.getSizeNoTag())
requestObject.writeTo(CodedOutputStream(bytes))
sendRequest(js("new Buffer(bytes)"), "/connect", { resultData ->
val responseObject = ConnectionResponse.BuilderConnectionResponse(0, 0).build()
responseObject.mergeFrom(CodedInputStream(resultData))
if (responseObject.code == 0) {
this.uid = responseObject.uid
} else {
println("server login error\n" +
"code: ${responseObject.code}")
}
}, { error ->
println("connection error (to main server). error message:\n" + error)
})
response.on("end", {
successCallback.invoke(resData.toByteArray())
})
})
request.on("error", { err ->
errorCallback.invoke(err)
})
request.write(dataBuffer)
request.end()
}
companion object {
val instance = Client()
}
}
+8 -9
View File
@@ -1,20 +1,16 @@
package net.server
import require
import net.server.handlers.AbstractHandler
/**
* Created by user on 7/27/16.
*/
import require
fun start(handlers: MutableMap<String, AbstractHandler>, port: Int) {
val http = require("http")
val url = require("url")
http.createServer({ request, response ->
val content = mutableListOf<Byte>()
val urlName = url.parse(request.url).pathname;
val handler = handlers.get(urlName)
val urlName = url.parse(request.url).pathname
val handler = handlers[urlName]
request.on("data", {
data ->
for (i in 0..data.length - 1) {
@@ -23,9 +19,12 @@ fun start(handlers: MutableMap<String, AbstractHandler>, port: Int) {
})
request.on("end", {
if (handler != null) {
handler.execute(content, response)
try {
handler.execute(content, response)
} catch (e: dynamic) {
response.end()
}
} else {
//todo write error on incorrect url
response.end()
}
})
@@ -1,10 +1,14 @@
package net.server.handlers
import CodedOutputStream
import DebugResponseMemoryStats
import DirectionResponse
import LocationResponse
import RouteDoneRequest
import RouteRequest
import RouteResponse
import UploadResult
/**
* Created by user on 7/27/16.
*/
abstract class AbstractHandler {
fun execute(data: List<Byte>, response: dynamic) {
@@ -18,4 +22,48 @@ abstract class AbstractHandler {
abstract fun getBytesResponse(data: ByteArray, callback: (b: ByteArray) -> Unit)
protected fun <T> encodeProtoBuf(protoMessage: T): ByteArray {
val routeBytes: ByteArray
if (protoMessage is LocationResponse) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else if (protoMessage is UploadResult) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else if (protoMessage is DebugResponseMemoryStats) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else if (protoMessage is DirectionResponse) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else if (protoMessage is RouteResponse) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else if (protoMessage is RouteRequest) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else if (protoMessage is RouteDoneRequest) {
val protoSize = protoMessage.getSizeNoTag()
routeBytes = ByteArray(protoSize)
val codedOutput = CodedOutputStream(routeBytes)
protoMessage.writeTo(codedOutput)
} else {
println("PROTO MESSAGE DON'T ENCODE!")
routeBytes = ByteArray(0)
}
return routeBytes
}
}
@@ -0,0 +1,24 @@
package net.server.handlers
import McState
import TaskRequest
import mcTransport
class ProtoType : AbstractHandler {
val fromServerObjectBuilder: TaskRequest.BuilderTaskRequest
constructor() : super() {
fromServerObjectBuilder = TaskRequest.BuilderTaskRequest(TaskRequest.TYPE.DEBUG)
}
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
if (!McState.instance.isConnected()) {
println("mc is disconnected!")
callback.invoke(ByteArray(0))
return
}
mcTransport.sendBytes(data)
callback.invoke(ByteArray(0))
}
}
@@ -3,13 +3,9 @@ package net.server.handlers.debug
import DebugRequest
import DebugResponseMemoryStats
import McState
import encodeProtoBuf
import mcTransport
import net.server.handlers.AbstractHandler
/**
* Created by user on 8/18/16.
*/
class Memory : AbstractHandler {
val fromServerObjectBuilder: DebugRequest.BuilderDebugRequest
@@ -3,14 +3,10 @@ package net.server.handlers.flash
import CodedInputStream
import Upload
import UploadResult
import encodeProtoBuf
import mcTransport
import net.server.handlers.AbstractHandler
import require
/**
* Created by user on 7/27/16.
*/
class LoadBin : AbstractHandler {
val exec: dynamic
@@ -1,13 +1,9 @@
package net.server.handlers.main
import CarState
import LocationResponse
import MicroController
import encodeProtoBuf
import net.server.handlers.AbstractHandler
/**
* Created by user on 7/28/16.
*/
class GetLocation : AbstractHandler {
val toServerObjectBuilder: LocationResponse.BuilderLocationResponse
@@ -18,8 +14,8 @@ class GetLocation : AbstractHandler {
}
override fun getBytesResponse(data: ByteArray, callback: (ByteArray) -> Unit) {
val car = MicroController.instance.car
val locationData = LocationResponse.LocationData.BuilderLocationData(car.x.toInt(), car.y.toInt(), car.angle.toInt()).build()
val carState = CarState.instance
val locationData = LocationResponse.LocationData.BuilderLocationData(carState.x.toInt(), carState.y.toInt(), carState.angle.toInt()).build()
val responseMessage = toServerObjectBuilder.setLocationResponseData(locationData).build()
callback.invoke(encodeProtoBuf(responseMessage))
}
@@ -1,31 +1,25 @@
package net.server.handlers.main
import CodedInputStream
import MicroController
import McState
import RouteRequest
import RouteResponse
import control.RouteExecutor
import CodedOutputStream
import control.Controller
import net.server.handlers.AbstractHandler
/**
* Created by user on 7/28/16.
*/
class SetRoute : AbstractHandler {
val fromServerObjectBuilder: RouteRequest.BuilderRouteRequest
val toServerObjectBuilder: RouteResponse.BuilderRouteResponse
val routeExecutor: RouteExecutor
val controller: Controller
constructor(routeExecutor: RouteExecutor) : super() {
this.routeExecutor = routeExecutor
constructor(routeExecutor: Controller) : super() {
this.controller = 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 (!McState.instance.isConnected()) {
@@ -34,17 +28,9 @@ class SetRoute : AbstractHandler {
callback.invoke(encodeProtoBuf(responseMessage))
return
}
routeExecutor.executeRoute(message)
controller.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
}
}
@@ -3,15 +3,9 @@ package net.server.handlers.rc
import CodedInputStream
import DirectionRequest
import DirectionResponse
import MicroController
import control.emulator.RouteExecutorImpl.MoveDirection
import encodeProtoBuf
import exceptions.RcControlException
import control.emulator.ControllerEmulator.MoveDirection
import net.server.handlers.AbstractHandler
/**
* Created by user on 7/27/16.
*/
class Control : AbstractHandler {
val fromServerObjectBuilder: DirectionRequest.BuilderDirectionRequest
@@ -23,6 +17,7 @@ class Control : AbstractHandler {
}
override fun getBytesResponse(data: ByteArray, callback: (b: ByteArray) -> Unit) {
//TODO now this handler don't make nothing. need fix:)
val message = fromServerObjectBuilder.build()
message.mergeFrom(CodedInputStream(data))
val commandNumber = message.command
@@ -45,13 +40,7 @@ class Control : AbstractHandler {
}
else -> MoveDirection.STOP
}
val resultCode: Int
try {
// MicroController.instance.RcMove(command, sid)
resultCode = 0
} catch (e: RcControlException) {
resultCode = 12
}
val resultCode: Int = 0
val resultMessage = toServerObjectBuilder.setCode(resultCode).build()
callback.invoke(encodeProtoBuf(resultMessage))
}