diff --git a/car_fmw/Makefile b/car_fmw/Makefile index 9362eb65e0a..ae2849a4f3d 100644 --- a/car_fmw/Makefile +++ b/car_fmw/Makefile @@ -22,6 +22,7 @@ KT=$(TRANSLATOR_DIR)/build/libs/translator-1.0.jar LD=arm-none-eabi-ld OBJ_COPY=arm-none-eabi-objcopy GDB=arm-none-eabi-gdb +PROTOC=$(PWD)/../proto/build/protoc LL=llc-3.6 LLINK=llvm-link-3.6 @@ -73,6 +74,9 @@ $(LIB_DIR)/app.ll: $(SRC_DIR)/**/*.kt $(SRC_DIR)/*.kt $(KT): cd $(TRANSLATOR_DIR) && ./gradlew jar +proto: + $(PROTOC) -I$(SRC_DIR)/proto --kotlin_out=$(SRC_DIR)/proto_src $(SRC_DIR)/proto/*.proto + flash: $(CAR_FMW_BIN) $(ST_DIR)/st-flash write $(CAR_FMW_BIN) 0x8000000 diff --git a/car_fmw/src/include/communication.kt b/car_fmw/src/include/communication.kt new file mode 100644 index 00000000000..d36b4a4e1f0 --- /dev/null +++ b/car_fmw/src/include/communication.kt @@ -0,0 +1,8 @@ + +external fun VCP_init() +external fun send_int(i: Int) +external fun send_buffer(size: Int, pointer: Int) + +fun sendByteArray(arr: ByteArray) { + send_buffer(arr.size, arr.data) +} \ No newline at end of file diff --git a/car_fmw/src/include/general.kt b/car_fmw/src/include/general.kt index 271789adce8..b6f7da271a4 100644 --- a/car_fmw/src/include/general.kt +++ b/car_fmw/src/include/general.kt @@ -3,4 +3,5 @@ fun init() { time_init() engine_init() leds_init() + VCP_init() } diff --git a/car_fmw/src/main.kt b/car_fmw/src/main.kt index b029c546d70..9354e965945 100644 --- a/car_fmw/src/main.kt +++ b/car_fmw/src/main.kt @@ -1,5 +1,16 @@ +fun writeProto() { + val msg = DirectionResponse.BuilderDirectionResponse(4242).build() +// val size = msg.getSizeNoTag() +// val buffer = ByteArray(size) +// val outputStream = CodedOutputStream(buffer) +// +// msg.writeTo(outputStream) +// sendByteArray(buffer) +} + fun main() { init() + writeProto() simpleRoute() } diff --git a/car_fmw/src/proto/direction.proto b/car_fmw/src/proto/direction.proto new file mode 100644 index 00000000000..196fcebbc27 --- /dev/null +++ b/car_fmw/src/proto/direction.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package carkot; + +option java_package = "proto.car"; +option java_outer_classname = "Direction"; + +message DirectionRequest { + enum Command { + stop = 0; + forward = 1; + backward = 2; + left = 3; + right = 4; + } + Command command = 1; + int32 sid = 2; +} + +message DirectionResponse { + int32 code = 1; +} diff --git a/car_fmw/src/proto_runtime/CodedInputStream.kt b/car_fmw/src/proto_runtime/CodedInputStream.kt new file mode 100644 index 00000000000..5474b90fcc4 --- /dev/null +++ b/car_fmw/src/proto_runtime/CodedInputStream.kt @@ -0,0 +1,208 @@ +/** + * Created by Dmitry Savvinov on 7/6/16. + * + * Hides details of work with Protobuf encoding + * + * Note that CodedInputStream reads protobuf-defined types from stream (such as int32, sint32, etc), + * while CodedOutputStream has methods for writing Kotlin-types (such as Boolean, Int, Long, Short, etc) + * + */ + +// TODO: refactor correctness checks into readTag +class CodedInputStream(val buffer: ByteArray) { + val inputStream: KotlinInputStream + init { + inputStream = KotlinInputStream(buffer) // TODO: Java's realization uses hand-written buffers. Why? + } + + fun readInt32(expectedFieldNumber: Int): Int { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + val actualFieldNumber = WireFormat.getTagFieldNumber(tag) + val actualWireType = WireFormat.getTagWireType(tag) + checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType) + return readInt32NoTag() + } + + // Note that unsigned integer types are stored as their signed counterparts with top bit + // simply stored in the sign bit - similar to Java's protobuf implementation. Hence, all + // methods reading unsigned ints simply redirect call to corresponding signed-reading method + fun readUInt32(expectedFieldNumber: Int): Int { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readUInt32NoTag() + } + + fun readUInt32NoTag(): Int { + return readInt32NoTag() + } + + fun readInt64(expectedFieldNumber: Int): Long { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readInt64NoTag() + } + + // See note on unsigned integers implementations above + fun readUInt64(expectedFieldNumber: Int): Long { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readUInt64NoTag() + } + + fun readUInt64NoTag(): Long { + return readInt64NoTag() + } + + fun readBool(expectedFieldNumber: Int): Boolean { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readBoolNoTag() + } + + fun readBoolNoTag(): Boolean { + val readValue = readInt32NoTag() + val boolValue = when (readValue) { + 0 -> false + 1 -> true + else -> false + } + return boolValue + } + + // Reading enums is like reading one int32 number. Caller is responsible for converting this ordinal to enum-object + fun readEnum(expectedFieldNumber: Int): Int { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readEnumNoTag() + } + + fun readEnumNoTag(): Int { + return readUInt32NoTag() + } + + fun readSInt32(expectedFieldNumber: Int): Int { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readSInt32NoTag() + } + + fun readSInt32NoTag(): Int { + return readZigZag32NoTag() + } + + fun readSInt64(expectedFieldNumber: Int): Long { + val tag = readTag(expectedFieldNumber, WireType.VARINT) + return readSInt64NoTag() + } + + fun readSInt64NoTag(): Long { + return readZigZag64NoTag() + } + fun readBytes(expectedFieldNumber: Int): ByteArray { + val tag = readTag(expectedFieldNumber, WireType.LENGTH_DELIMITED) + return readBytesNoTag() + } + + fun readBytesNoTag(): ByteArray { + val length = readInt32NoTag() + return readRawBytes(length) + } + + /** ============ Utility methods ================== + * They are left non-private for cases when one wants to implement her/his own protocol format. + * Then she/he can re-use low-level methods for operating with raw values, that are not annotated with Protobuf tags. + */ + + fun checkFieldCorrectness( + expectedFieldNumber: Int, + actualFieldNumber: Int, + expectedWireType: WireType, + actualWireType: WireType) { + if (expectedFieldNumber != actualFieldNumber) { + return + } + + if (expectedWireType.id != actualWireType.id) { + return + } + } + + fun readRawBytes(count: Int): ByteArray { + val ba = ByteArray(count) + var i = 0 + while (i < count) { + ba[i] = inputStream.read().toByte() + i++ + } + return ba + } + + // reads tag. Note that it returns 0 for the end of message! + fun readTag(expectedFieldNumber: Int, expectedWireType: WireType): Int { + if (isAtEnd()) { + return 0 // we can safely return 0 as sign of end of message, because 0-tags are illegal + } + val tag = readInt32NoTag() + if (tag == 0) { // if we somehow had read 0-tag, then message is corrupted + return 0 + } + + val actualFieldNumber = WireFormat.getTagFieldNumber(tag) + val actualWireType = WireFormat.getTagWireType(tag) + checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, expectedWireType, actualWireType) + return tag + } + + // reads varint not larger than 32-bit integer according to protobuf varint-encoding + fun readInt32NoTag(): Int { + var done: Boolean = false + var result: Int = 0 + var step: Int = 0 + while (!done) { + val byte: Int = inputStream.read().toInt() + result = result or + ( + (byte and WireFormat.VARINT_INFO_BITS_MASK) + shl + (WireFormat.VARINT_INFO_BITS_COUNT * step) + ) + step++ + if ((byte and WireFormat.VARINT_UTIL_BIT_MASK) == 0) { + done = true + } + } + return result + } + + // reads varint not larger than 64-bit integer according to protobuf varint-encoding + fun readInt64NoTag(): Long { + var done: Boolean = false + var result: Long = 0 + var step: Int = 0 + while (!done) { + val byte: Int = inputStream.read().toInt() + result = result or + ( + (byte and WireFormat.VARINT_INFO_BITS_MASK).toLong() + shl + (WireFormat.VARINT_INFO_BITS_COUNT * step) + ) + step++ + if ((byte and WireFormat.VARINT_UTIL_BIT_MASK) == 0 /* || byte == -1 ???? */) { + done = true + } + } + return result + } + + // reads zig-zag encoded integer not larger than 32-bit long + fun readZigZag32NoTag(): Int { + val value = readInt32NoTag() + return (value shr 1) xor (-(value and 1)) // bit magic for decoding zig-zag number + } + + // reads zig-zag encoded integer not larger than 64-bit long + fun readZigZag64NoTag(): Long { + val value = readInt64NoTag() + return (value shr 1) xor (-(value and 1L)) // bit magic for decoding zig-zag number + } + + // checks if at least one more byte can be read from underlying input stream + fun isAtEnd(): Boolean { + return inputStream.isAtEnd() + } +} diff --git a/car_fmw/src/proto_runtime/CodedOutputStream.kt b/car_fmw/src/proto_runtime/CodedOutputStream.kt new file mode 100644 index 00000000000..a55d5a9f2c7 --- /dev/null +++ b/car_fmw/src/proto_runtime/CodedOutputStream.kt @@ -0,0 +1,153 @@ +/** + * Created by user on 7/6/16. + */ + +class CodedOutputStream(val buffer: ByteArray) { + val output = KotlinOutputStream(buffer) + + fun toByteArray(): ByteArray { + return buffer + } + + fun writeTag(fieldNumber: Int, type: WireType) { + val tag = (fieldNumber shl 3) or type.id + writeInt32NoTag(tag) + } + + fun writeInt32(fieldNumber: Int, value: Int) { + writeTag(fieldNumber, WireType.VARINT) + writeInt32NoTag(value) + } + + // Note that unsigned integer types are stored as their signed counterparts with top bit + // simply stored in the sign bit - similar to Java's protobuf implementation. Hence, all + // methods, writing unsigned ints simply redirect call to corresponding signed-writing method + fun writeUInt32(fieldNumber: Int, value: Int) { + writeInt32(fieldNumber, value) + } + + fun writeUInt32NoTag(value: Int) { + writeInt32NoTag(value) + } + + fun writeInt64(fieldNumber: Int, value: Long) { + writeTag(fieldNumber, WireType.VARINT) + writeInt64NoTag(value) + } + + // See notes on unsigned integers implementation above + fun writeUInt64(fieldNumber: Int, value: Long) { + writeInt64(fieldNumber, value) + } + + fun writeUInt64NoTag(value: Long) { + writeInt64NoTag(value) + } + + fun writeBool(fieldNumber: Int, value: Boolean) { + writeTag(fieldNumber, WireType.VARINT) + writeBoolNoTag(value) + } + + fun writeBoolNoTag(value: Boolean) { + writeInt32NoTag(if (value) 1 else 0) + } + + // Writing enums is like writing one int32 number. Caller is responsible for converting enum-object to ordinal + fun writeEnum(fieldNumber: Int, value: Int) { + writeTag(fieldNumber, WireType.VARINT) + writeEnumNoTag(value) + } + + fun writeEnumNoTag(value: Int) { + writeInt32NoTag(value) + } + + fun writeSInt32(fieldNumber: Int, value: Int) { + writeTag(fieldNumber, WireType.VARINT) + writeSInt32NoTag(value) + } + + fun writeSInt32NoTag(value: Int) { + writeInt32NoTag((value shl 1) xor (value shr 31)) + } + + fun writeSInt64(fieldNumber: Int, value: Long) { + writeTag(fieldNumber, WireType.VARINT) + writeSInt64NoTag(value) + } + + fun writeSInt64NoTag(value: Long) { + writeInt64NoTag((value shl 1) xor (value shr 63)) + } + + fun writeBytes(fieldNumber: Int, value: ByteArray) { + if (value.size == 0) { + return + } + writeTag(fieldNumber, WireType.LENGTH_DELIMITED) + writeBytesNoTag(value) + } + + fun writeBytesNoTag(value: ByteArray) { + writeInt32NoTag(value.size) + output.write(value) + } + + /** ============ Utility methods ================== + * They are left non-private for cases when one wants to implement her/his own protocol format. + * Then she/he can re-use low-level methods for operating with raw values, that are not annotated with Protobuf tags. + */ + + fun writeInt32NoTag(value: Int) { + var curValue: Int = value + + // we have at most 32 information bits. With overhead of 1 bit per 7 bits we need at most 5 bytes for encoding + val res = ByteArray(5) + + var resSize = 0 + do { + // encode current 7 bits + var curByte = (curValue and WireFormat.VARINT_INFO_BITS_MASK) + + // discard encoded bits. Note that unsigned shift is needed for cases with negative numbers + curValue = curValue ushr WireFormat.VARINT_INFO_BITS_COUNT + + // check if there will be next byte in encoding and set util bit if needed + if (curValue != 0) { + curByte = curByte or WireFormat.VARINT_UTIL_BIT_MASK + } + + res[resSize] = curByte.toByte() + resSize++ + } while (curValue != 0) + output.write(res, 0, resSize) + } + + fun writeInt64NoTag(value: Long) { + var curValue: Long = value + + // we have at most 64 information bits. With overhead of 1 bit per 7 bits we need at most 10 bytes for encoding + val res = ByteArray(10) + + var resSize = 0 + while(curValue != 0L) { + // encode current 7 bits + var curByte = (curValue and WireFormat.VARINT_INFO_BITS_MASK.toLong()) + + // discard encoded bits. Note that unsigned shift is needed for cases with negative numbers + curValue = curValue ushr WireFormat.VARINT_INFO_BITS_COUNT + + // check if there will be next byte and set util bit if needed + if (curValue != 0L) { + curByte = curByte or WireFormat.VARINT_UTIL_BIT_MASK.toLong() + } + + res[resSize] = curByte.toByte() + resSize++ + } + output.write(res, 0, resSize) + } + + +} diff --git a/car_fmw/src/proto_runtime/KotlinInputStream.kt b/car_fmw/src/proto_runtime/KotlinInputStream.kt new file mode 100644 index 00000000000..2919b1af0ce --- /dev/null +++ b/car_fmw/src/proto_runtime/KotlinInputStream.kt @@ -0,0 +1,16 @@ +/** + * Created by user on 8/8/16. + */ + +class KotlinInputStream(val buffer: ByteArray) { + var pos = 0 + + fun read(): Byte { + pos += 1 + return buffer[pos - 1] + } + + fun isAtEnd(): Boolean { + return pos >= buffer.size + } +} diff --git a/car_fmw/src/proto_runtime/KotlinOutputStream.kt b/car_fmw/src/proto_runtime/KotlinOutputStream.kt new file mode 100644 index 00000000000..51f80aaf766 --- /dev/null +++ b/car_fmw/src/proto_runtime/KotlinOutputStream.kt @@ -0,0 +1,20 @@ +/** + * Created by user on 8/8/16. + */ + +class KotlinOutputStream(val buffer: ByteArray) { + var pos = 0 + + fun write (data: ByteArray) { + write(data, 0, data.size) + } + + fun write (data: ByteArray, begin: Int, size: Int) { + var i = begin + while (i < begin + size) { + buffer[pos] = data[i] + pos += 1 + i++ + } + } +} diff --git a/car_fmw/src/proto_runtime/WireFormat.kt b/car_fmw/src/proto_runtime/WireFormat.kt new file mode 100644 index 00000000000..881ae1bd30b --- /dev/null +++ b/car_fmw/src/proto_runtime/WireFormat.kt @@ -0,0 +1,161 @@ + +object WireFormat { + // couple of constants for magic numbers + val TAG_TYPE_BITS: Int = 3 + val TAG_TYPE_MASK: Int = (1 shl TAG_TYPE_BITS) - 1 + val VARINT_INFO_BITS_COUNT: Int = 7 + val VARINT_INFO_BITS_MASK: Int = 0b01111111 // mask for separating lowest 7 bits, where actual information stored + val VARINT_UTIL_BIT_MASK: Int = 0b10000000 // mask for separating highest bit, that indicates next byte presence + val FIXED_32_BYTE_SIZE: Int = 4 + val FIXED_64_BYTE_SIZE: Int = 8 + + fun getTagWireType(tag: Int): WireType { + return WireType.from((tag and TAG_TYPE_MASK).toByte()) + } + + fun getTagFieldNumber(tag: Int): Int { + return tag ushr TAG_TYPE_BITS + } + + // TODO: refactor casts into function overloading as soon as translator will support it + fun getTagSize(fieldNumber: Int, wireType: WireType): Int { + return getVarint32Size((fieldNumber shl 3) or wireType.id) + } + + fun getVarint32Size(value: Int): Int { + var curValue = value + var size = 0 + while (curValue != 0) { + size += 1 + curValue = curValue ushr VARINT_INFO_BITS_COUNT + } + return size + } + + fun getVarint64Size(value: Long): Int { + var curValue = value + var size = 0 + while (curValue != 0L) { + size += 1 + curValue = curValue ushr VARINT_INFO_BITS_COUNT + } + return size + } + + fun getZigZag32Size(value: Int): Int { + return getVarint32Size((value shl 1) xor (value shr 31)) + } + + fun getZigZag64Size(value: Long): Int { + return getVarint64Size((value shl 1) xor (value shr 63)) + } + + fun getInt32Size(fieldNumber: Int, value: Int): Int { + return getTagSize(fieldNumber, WireType.VARINT) + getVarint32Size(value) + } + + fun getInt32SizeNoTag(value: Int): Int { + return getVarint32Size(value) + } + + fun getUInt32Size(fieldNumber: Int, value: Int): Int { + return getInt32Size(fieldNumber, value) + } + + fun getUInt32SizeNoTag(value: Int): Int { + return getVarint32Size(value) + } + + fun getInt64Size(fieldNumber: Int, value: Long): Int { + return getTagSize(fieldNumber, WireType.VARINT) + getVarint64Size(value) + } + + fun getInt64SizeNoTag(value: Long): Int { + return getVarint64Size(value) + } + + fun getUInt64Size(fieldNumber: Int, value: Long): Int { + return getInt64Size(fieldNumber, value) + } + + fun getUInt64SizeNoTag(value: Long): Int { + return getVarint64Size(value) + } + + fun getBoolSize(fieldNumber: Int, value: Boolean): Int { + val intValue = if (value) 1 else 0 + return getInt32Size(fieldNumber, intValue) + } + + fun getBoolSizeNoTag(value: Boolean): Int { + val intValue = if (value) 1 else 0 + return getInt32SizeNoTag(intValue) + } + + fun getEnumSize(fieldNumber: Int, value: Int): Int { + return getInt32Size(fieldNumber, value) + } + + fun getEnumSizeNoTag(value: Int): Int { + return getInt32SizeNoTag(value) + } + + fun getSInt32Size(fieldNumber: Int, value: Int): Int { + return getTagSize(fieldNumber, WireType.VARINT) + getZigZag32Size(value) + } + + fun getSInt32SizeNoTag(value: Int): Int { + return getZigZag32Size(value) + } + + fun getSInt64Size(fieldNumber: Int, value: Long): Int { + return getTagSize(fieldNumber, WireType.VARINT) + getZigZag64Size(value) + } + + fun getSInt64SizeNoTag(value: Long): Int { + return getZigZag64Size(value) + } + + fun getFixed32Size(fieldNumber: Int, value: Int): Int { + return getTagSize(fieldNumber, WireType.FIX_32) + FIXED_32_BYTE_SIZE + } + + fun getFixed32SizeNoTag(value: Int): Int { + return FIXED_32_BYTE_SIZE + } + + fun getFixed64Size(fieldNumber: Int, value: Long): Int { + return getTagSize(fieldNumber, WireType.FIX_64) + FIXED_64_BYTE_SIZE + } + + fun getFixed64SizeNoTag(value: Long): Int { + return FIXED_64_BYTE_SIZE + } + + fun getDoubleSize(fieldNumber: Int, value: Double): Int { + return getTagSize(fieldNumber, WireType.FIX_64) + FIXED_64_BYTE_SIZE + } + + fun getDoubleSizeNoTag(value: Double): Int { + return FIXED_64_BYTE_SIZE + } + + fun getFloatSize(fieldNumber: Int, value: Float): Int { + return getTagSize(fieldNumber, WireType.FIX_32) + FIXED_32_BYTE_SIZE + } + + fun getFloatSizeNoTag(value: Float): Int { + return FIXED_32_BYTE_SIZE + } + + fun getBytesSize(fieldNumber: Int, value: ByteArray): Int { + if (value.size == 0) + return 0 + var size = 0 + return value.size + getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + getVarint32Size(value.size) + } + + fun getBytesSizeNoTag(value: ByteArray): Int { + return value.size + getVarint32Size(value.size) + } +} diff --git a/car_fmw/src/proto_runtime/WireType.kt b/car_fmw/src/proto_runtime/WireType.kt new file mode 100644 index 00000000000..4ffc150fa68 --- /dev/null +++ b/car_fmw/src/proto_runtime/WireType.kt @@ -0,0 +1,29 @@ +/** + * Created by Dmitry Savvinov on 7/6/16. + * Enum for possible WireTypes. + * See details at [official Google reference](https://developers.google.com/protocol-buffers/docs/encoding#structure) + */ + +enum class WireType(val id: Int) { + VARINT(0), // int32, int64, uint32, uint64, sint32, sint64, bool, enum + FIX_64(1), // fixed64, sfixed64, double + LENGTH_DELIMITED(2), // string, bytes, embedded messages, packed repeated fields + START_GROUP(3), // groups (deprecated) + END_GROUP(4), // groups (deprecated) + FIX_32(5), // fixed32, sfixed32, float + UNDEFINED(6); // indicates error when parsing from Int + + companion object { + fun from (value: Byte): WireType { + return when (value) { + 0.toByte() -> VARINT + 1.toByte() -> FIX_64 + 2.toByte() -> LENGTH_DELIMITED + 3.toByte() -> START_GROUP + 4.toByte() -> END_GROUP + 5.toByte() -> FIX_32 + else -> UNDEFINED + } + } + } +} diff --git a/car_fmw/src/proto_src/direction.kt b/car_fmw/src/proto_src/direction.kt new file mode 100644 index 00000000000..304d525b799 --- /dev/null +++ b/car_fmw/src/proto_src/direction.kt @@ -0,0 +1,301 @@ +class DirectionRequest private constructor (var command: DirectionRequest.Command, var sid: Int) { + //========== Properties =========== + //enum command = 1 + + //int32 sid = 2 + + var errorCode: Int = 0 + + //========== Nested enums declarations =========== + enum class Command(val ord: Int) { + stop (0), + forward (1), + backward (2), + left (3), + right (4), + Unexpected(5); + + companion object { + fun fromIntToCommand (ord: Int): Command { + return when (ord) { + 0 -> Command.stop + 1 -> Command.forward + 2 -> Command.backward + 3 -> Command.left + 4 -> Command.right + else -> Unexpected + } + } + } + } + //========== Serialization methods =========== + fun writeTo (output: CodedOutputStream) { + //enum command = 1 + if (command != DirectionRequest.Command.fromIntToCommand(0)) { + output.writeEnum (1, command.ord) + } + + //int32 sid = 2 + if (sid != 0) { + output.writeInt32 (2, sid) + } + + } + + fun mergeWith (other: DirectionRequest) { + command = other.command + sid = other.sid + } + + fun mergeFromWithSize (input: CodedInputStream, expectedSize: Int) { + val builder = DirectionRequest.BuilderDirectionRequest(DirectionRequest.Command.fromIntToCommand(0), 0) + mergeWith(builder.parseFromWithSize(input, expectedSize).build()) + } + + fun mergeFrom (input: CodedInputStream) { + val builder = DirectionRequest.BuilderDirectionRequest(DirectionRequest.Command.fromIntToCommand(0), 0) + mergeWith(builder.parseFrom(input).build()) + } + + //========== Size-related methods =========== + fun getSize(fieldNumber: Int): Int { + var size = 0 + if (command != DirectionRequest.Command.fromIntToCommand(0)) { + size += WireFormat.getEnumSize(1, command.ord) + } + if (sid != 0) { + size += WireFormat.getInt32Size(2, sid) + } + size += WireFormat.getVarint32Size(size) + WireFormat.getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + return size + } + + fun getSizeNoTag(): Int { + var size = 0 + if (command != DirectionRequest.Command.fromIntToCommand(0)) { + size += WireFormat.getEnumSize(1, command.ord) + } + if (sid != 0) { + size += WireFormat.getInt32Size(2, sid) + } + return size + } + + //========== Builder =========== + class BuilderDirectionRequest constructor (var command: DirectionRequest.Command, var sid: Int) { + //========== Properties =========== + //enum command = 1 + fun setCommand(value: DirectionRequest.Command): DirectionRequest.BuilderDirectionRequest { + command = value + return this + } + + //int32 sid = 2 + fun setSid(value: Int): DirectionRequest.BuilderDirectionRequest { + sid = value + return this + } + + var errorCode: Int = 0 + + //========== Serialization methods =========== + fun writeTo (output: CodedOutputStream) { + //enum command = 1 + if (command != DirectionRequest.Command.fromIntToCommand(0)) { + output.writeEnum (1, command.ord) + } + + //int32 sid = 2 + if (sid != 0) { + output.writeInt32 (2, sid) + } + + } + + //========== Mutating methods =========== + fun build(): DirectionRequest { + return DirectionRequest(command, sid) + } + + fun parseFieldFrom(input: CodedInputStream): Boolean { + if (input.isAtEnd()) { return false } + val tag = input.readInt32NoTag() + if (tag == 0) { return false } + val fieldNumber = WireFormat.getTagFieldNumber(tag) + val wireType = WireFormat.getTagWireType(tag) + when(fieldNumber) { + 1 -> { + if (wireType != WireType.VARINT) { errorCode = 1; return false } + command = DirectionRequest.Command.fromIntToCommand(input.readEnumNoTag()) + } + 2 -> { + if (wireType != WireType.VARINT) { errorCode = 1; return false } + sid = input.readInt32NoTag() + } + } + return true} + + fun parseFromWithSize(input: CodedInputStream, expectedSize: Int): DirectionRequest.BuilderDirectionRequest { + while(getSizeNoTag() < expectedSize) { + parseFieldFrom(input) + } + if (getSizeNoTag() > expectedSize) { errorCode = 2 } + return this + } + + fun parseFrom(input: CodedInputStream): DirectionRequest.BuilderDirectionRequest { + while(parseFieldFrom(input)) {} + return this + } + + //========== Size-related methods =========== + fun getSize(fieldNumber: Int): Int { + var size = 0 + if (command != DirectionRequest.Command.fromIntToCommand(0)) { + size += WireFormat.getEnumSize(1, command.ord) + } + if (sid != 0) { + size += WireFormat.getInt32Size(2, sid) + } + size += WireFormat.getVarint32Size(size) + WireFormat.getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + return size + } + + fun getSizeNoTag(): Int { + var size = 0 + if (command != DirectionRequest.Command.fromIntToCommand(0)) { + size += WireFormat.getEnumSize(1, command.ord) + } + if (sid != 0) { + size += WireFormat.getInt32Size(2, sid) + } + return size + } + + } + +} + + +class DirectionResponse private constructor (var code: Int) { + //========== Properties =========== + //int32 code = 1 + + var errorCode: Int = 0 + + //========== Serialization methods =========== + fun writeTo (output: CodedOutputStream) { + //int32 code = 1 + if (code != 0) { + output.writeInt32 (1, code) + } + + } + + fun mergeWith (other: DirectionResponse) { + code = other.code + } + + fun mergeFromWithSize (input: CodedInputStream, expectedSize: Int) { + val builder = DirectionResponse.BuilderDirectionResponse(0) + mergeWith(builder.parseFromWithSize(input, expectedSize).build()) + } + + fun mergeFrom (input: CodedInputStream) { + val builder = DirectionResponse.BuilderDirectionResponse(0) + mergeWith(builder.parseFrom(input).build()) + } + + //========== Size-related methods =========== + fun getSize(fieldNumber: Int): Int { + var size = 0 + if (code != 0) { + size += WireFormat.getInt32Size(1, code) + } + size += WireFormat.getVarint32Size(size) + WireFormat.getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + return size + } + + fun getSizeNoTag(): Int { + var size = 0 + if (code != 0) { + size += WireFormat.getInt32Size(1, code) + } + return size + } + + //========== Builder =========== + class BuilderDirectionResponse constructor (var code: Int) { + //========== Properties =========== + //int32 code = 1 + fun setCode(value: Int): DirectionResponse.BuilderDirectionResponse { + code = value + return this + } + + var errorCode: Int = 0 + + //========== Serialization methods =========== + fun writeTo (output: CodedOutputStream) { + //int32 code = 1 + if (code != 0) { + output.writeInt32 (1, code) + } + + } + + //========== Mutating methods =========== + fun build(): DirectionResponse { + return DirectionResponse(code) + } + + fun parseFieldFrom(input: CodedInputStream): Boolean { + if (input.isAtEnd()) { return false } + val tag = input.readInt32NoTag() + if (tag == 0) { return false } + val fieldNumber = WireFormat.getTagFieldNumber(tag) + val wireType = WireFormat.getTagWireType(tag) + when(fieldNumber) { + 1 -> { + if (wireType != WireType.VARINT) { errorCode = 1; return false } + code = input.readInt32NoTag() + } + } + return true} + + fun parseFromWithSize(input: CodedInputStream, expectedSize: Int): DirectionResponse.BuilderDirectionResponse { + while(getSizeNoTag() < expectedSize) { + parseFieldFrom(input) + } + if (getSizeNoTag() > expectedSize) { errorCode = 2 } + return this + } + + fun parseFrom(input: CodedInputStream): DirectionResponse.BuilderDirectionResponse { + while(parseFieldFrom(input)) {} + return this + } + + //========== Size-related methods =========== + fun getSize(fieldNumber: Int): Int { + var size = 0 + if (code != 0) { + size += WireFormat.getInt32Size(1, code) + } + size += WireFormat.getVarint32Size(size) + WireFormat.getTagSize(fieldNumber, WireType.LENGTH_DELIMITED) + return size + } + + fun getSizeNoTag(): Int { + var size = 0 + if (code != 0) { + size += WireFormat.getInt32Size(1, code) + } + return size + } + + } + +} + + diff --git a/car_hw/src/communication.c b/car_hw/src/communication.c new file mode 100644 index 00000000000..b7b44c4de3d --- /dev/null +++ b/car_hw/src/communication.c @@ -0,0 +1,36 @@ +#include "communication.h" + +#include +#include +#include + +void send_int(int n) +{ + int i = 0; + char* buffer = (char*) &n; + + for (; i < sizeof(int); ++i) { + VCP_put_char(buffer[i]); + } +} + +void send_buffer(int size, int pointer) +{ + int i = 0; + + send_int(size); + char* buffer = (char*) pointer; + for (; i < size; ++i) { + VCP_put_char(buffer[i]); + } +} + +int receive_int() +{ + return 0; +} + +int receive_buffer() +{ + return 0; +} diff --git a/car_hw/src/include/communication.h b/car_hw/src/include/communication.h new file mode 100644 index 00000000000..a3a13ab27ee --- /dev/null +++ b/car_hw/src/include/communication.h @@ -0,0 +1,7 @@ +#pragma once + +void send_int(int i); +void send_buffer(int size, int pointer); + +int receive_int(); +int receive_buffer(); diff --git a/car_hw/src/main.c b/car_hw/src/main.c index 7bb5e871c5d..25c84af094b 100644 --- a/car_hw/src/main.c +++ b/car_hw/src/main.c @@ -5,46 +5,9 @@ #include "car_leds.h" #include "car_rc.h" #include "car_user_btn.h" +#include "communication.h" #include "time.h" #include "stm32f4xx_conf.h" #include "stm32f4xx_it.h" -/* typedef enum { */ -/* CAR_MODE_PROGRAMMED, */ -/* CAR_MODE_REMOTE_CONTROL, */ -/* CAR_MODE_LAST */ -/* } CAR_MODE; */ -/* static CAR_MODE cur_mode = CAR_MODE_PROGRAMMED; */ -/* static __IO bool cur_mode_stop = false; */ - -/* void stop_cur_mode(void) */ -/* { */ -/* cur_mode_stop = true; */ -/* } */ - -//int main(void) -//{ -// /*!< At this stage the microcontroller clock setting is already configured, -// this is done through SystemInit() function which is called from startup -// file (startup_stm32f4xx.s) before to branch to application main. -// To reconfigure the default setting of SystemInit() function, refer to -// system_stm32f4xx.c file -// */ -// -// /* time_init(); */ -// /* leds_init(); */ -// /* engine_init(); */ -// /* user_btn_init(stop_cur_mode); */ -// /* VCP_init(); */ -// -// /* while(1) { */ -// /* if (cur_mode == CAR_MODE_PROGRAMMED) */ -// /* run_programmed_car(&cur_mode_stop); */ -// /* else if(cur_mode == CAR_MODE_REMOTE_CONTROL) */ -// /* run_rc_car(&cur_mode_stop); */ -// -// /* cur_mode = (cur_mode + 1) % CAR_MODE_LAST; */ -// /* cur_mode_stop = false; */ -// /* } */ -//} diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt index 6955e4b2c6f..f489e692dd0 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt @@ -32,7 +32,10 @@ class ObjectCodegen(state: TranslationState, super.prepareForGenerate() val classInstance = LLVMVariable("object.instance.$fullName", type, objectDeclaration.name, LLVMVariableScope(), pointer = 1) - codeBuilder.addGlobalInitialize(classInstance, type) + codeBuilder.addGlobalInitialize(classInstance, fields, initializedFields.map { + val type = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, it.value)!!.type!! + Pair(it.key, state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, it.value)!!.getValue(type).toString()) + }.toMap() , type) variableManager.addGlobalVariable(fullName, classInstance) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt index e26edbc7376..8d46c40331f 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt @@ -35,6 +35,8 @@ abstract class StructCodegen(val state: TranslationState, get() = "${if (type.location.size > 0) "${type.location.joinToString(".")}." else ""}$structName" open fun prepareForGenerate() { + generateStruct() + for (declaration in classOrObject.declarations) { when (declaration) { is KtNamedFunction -> { @@ -46,7 +48,6 @@ abstract class StructCodegen(val state: TranslationState, } open fun generate() { - generateStruct() generateEnumFields() generatePrimaryConstructor() @@ -70,7 +71,7 @@ abstract class StructCodegen(val state: TranslationState, field.offset = offset offset++ - if ((declaration.initializer != null) && this !is ObjectCodegen) { + if (declaration.initializer != null) { initializedFields.put(field, declaration.initializer!!) } fields.add(field) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt index 543959f1670..23aebd8b472 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -4,6 +4,7 @@ import org.kotlinnative.translator.llvm.types.LLVMCharType import org.kotlinnative.translator.llvm.types.LLVMIntType import org.kotlinnative.translator.llvm.types.LLVMStringType import org.kotlinnative.translator.llvm.types.LLVMType +import java.util.* class LLVMBuilder(val arm: Boolean = false) { private val POINTER_SIZE = 4 @@ -81,8 +82,10 @@ class LLVMBuilder(val arm: Boolean = false) { globalCode.appendln("$variable = private unnamed_addr constant ${type.fullType()} c\"$value\\00\", align 1") } - fun addGlobalInitialize(target: LLVMVariable, classType: LLVMType) { - val code = "$target = internal global $classType zeroinitializer, align ${classType.align}" + fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList, initializers: Map, classType: LLVMType) { + val code = "$target = internal global $classType { ${ + fields.map { it.getType() + " " + if (initializers.containsKey(it)) initializers[it] else "0"}.joinToString() + } }, align ${classType.align}" globalCode.appendln(code) } diff --git a/translator/src/test/kotlin/tests/input/object_1.txt b/translator/src/test/kotlin/tests/input/object_1.txt index 0d05a3c1781..b98970c95f2 100644 --- a/translator/src/test/kotlin/tests/input/object_1.txt +++ b/translator/src/test/kotlin/tests/input/object_1.txt @@ -1 +1,2 @@ singleton_test_Int(5) == 40 +singleton_test2() == 123456789 diff --git a/translator/src/test/kotlin/tests/kotlin/object_1.kt b/translator/src/test/kotlin/tests/kotlin/object_1.kt index 0189ebb54b1..4c1cc3eac15 100644 --- a/translator/src/test/kotlin/tests/kotlin/object_1.kt +++ b/translator/src/test/kotlin/tests/kotlin/object_1.kt @@ -1,4 +1,7 @@ object Singleton { + + val i: Int = 123456789 + fun create(x : Int): Int { return x * 8 } @@ -7,3 +10,7 @@ object Singleton { fun singleton_test(i: Int): Int { return Singleton.create(i) } + +fun singleton_test2(): Int { + return Singleton.i +}