Skip to content

Commit

Permalink
139 java client side needs demo projects (#151)
Browse files Browse the repository at this point in the history
* [#139] Built basic first demo project - morse code transmitter

* [#139] Cleaned up interface for demo

* [#139] Fixed issue in notifications in model

* [#139] Implemented API for notifications

* [#139] Removed logicalSeperator field from notifications in model

* [#139] Finished notification API for client side

* [#139] Made Morse code translator demo work

* [#139] Improved throughput speed with increased serial speed

* [#139] Added nice cli to morse demo

* [#139] Add rx/tx pin choosing, simple version of Morse main

* [#139] Changed Morse CLI to use command line arguments

* [#139] Built first attempt at timeouts

* [#139] Added logging and trimmed generated Zscript

* [#139] Further compacting Zscript produced by morse demo

* [#139] Added first thread barriers around Nodes

* [#139] Implemented bitset approach to command timeouts, completed implementation of timeouts

* [#139] Added callback threadpool

* [#139] Fixed Exception catching across callback threadpools

* [#139] Implemented parse fail handling
  • Loading branch information
More-Wrong authored Dec 29, 2023
1 parent fb9dbf4 commit a65d2e1
Show file tree
Hide file tree
Showing 56 changed files with 2,226 additions and 285 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package net.zscript.javaclient.commandbuilder;

public interface Respondable<T extends ZscriptResponse> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.util.OptionalInt;

import net.zscript.javareceiver.tokenizer.BlockIterator;
import net.zscript.model.components.Zchars;
import net.zscript.model.components.ZscriptStatus;

public interface ZscriptResponse {
/**
Expand All @@ -14,4 +16,18 @@ public interface ZscriptResponse {

OptionalInt getField(char key);

default boolean succeeded() {
OptionalInt status = getField((char) Zchars.Z_STATUS);
return status.isEmpty() || status.getAsInt() == ZscriptStatus.SUCCESS;
}

default boolean failed() {
OptionalInt status = getField((char) Zchars.Z_STATUS);
return status.isPresent() && ZscriptStatus.isFailure(status.getAsInt());
}

default boolean error() {
OptionalInt status = getField((char) Zchars.Z_STATUS);
return status.isPresent() && ZscriptStatus.isError(status.getAsInt());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,24 @@

import java.util.NoSuchElementException;

import net.zscript.javaclient.commandbuilder.Respondable;
import net.zscript.javaclient.commandbuilder.ZscriptResponse;

public class ResponseCaptor<T extends ZscriptResponse> {
public static <T extends ZscriptResponse> ResponseCaptor<T> create() {
return new ResponseCaptor<>();
}

private ZscriptCommandNode<T> command;
private T response = null;
private boolean called = false;

public T get() {
if (called) {
return response;
} else {
throw new NoSuchElementException("Command was not run, so no response exists");
}
}

public boolean wasCalled() {
return called;
private ResponseCaptor() {
}

public void setCommand(ZscriptCommandNode<T> command) {
this.command = command;
}

public ZscriptCommandNode<T> getCommand() {
return command;
}
private Respondable<T> source;

public void resetResponseParsing() {
called = false;
public void setSource(Respondable<T> source) {
this.source = source;
}

public void responseReceived(T response) {
this.response = response;
called = true;
public Respondable<T> getSource() {
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@

import net.zscript.javaclient.commandPaths.ZscriptFieldSet;
import net.zscript.javaclient.ZscriptByteString;
import net.zscript.javaclient.commandbuilder.Respondable;
import net.zscript.javaclient.commandbuilder.ZscriptResponse;
import net.zscript.javaclient.commandbuilder.commandnodes.ZscriptCommandBuilder.BigField;
import net.zscript.javareceiver.tokenizer.ZscriptExpression;

public abstract class ZscriptCommandNode<T extends ZscriptResponse> extends CommandSequenceNode {
public abstract class ZscriptCommandNode<T extends ZscriptResponse> extends CommandSequenceNode implements Respondable<T> {

private final ResponseCaptor<T> captor;

Expand All @@ -32,10 +33,14 @@ protected ZscriptCommandNode(ResponseCaptor<T> captor, List<BigField> bigFields,
this.bigFields = bigFields;
this.fields = fields;
if (captor != null) {
captor.setCommand(this);
captor.setSource(this);
}
}

public ResponseCaptor<T> getCaptor() {
return captor;
}

public abstract T parseResponse(ZscriptExpression response);

public abstract Class<T> getResponseType();
Expand All @@ -44,18 +49,6 @@ public List<CommandSequenceNode> getChildren() {
return Collections.emptyList();
}

public void responseArrived(ZscriptResponse response) {
if (captor != null) {
captor.responseReceived(getResponseType().cast(response));
}
}

public void resetResponseParsing() {
if (captor != null) {
captor.resetResponseParsing();
}
}

public ZscriptFieldSet asFieldSet() {
return ZscriptFieldSet.fromMap(bigFields.stream().map(BigField::getData).collect(Collectors.toList()),
bigFields.stream().map(BigField::isString).collect(Collectors.toList()), fields);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ public boolean isValid() {
public OptionalInt getField(char key) {
return expression.getField(key);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.zscript.javaclient.commandbuilder.notifications;

import java.util.List;

import net.zscript.javaclient.commandbuilder.ZscriptResponse;

public abstract class NotificationHandle {
public abstract <T extends ZscriptResponse> NotificationSection<T> getSection(NotificationSectionId<T> response);

public abstract List<NotificationSection<?>> getSections();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.zscript.javaclient.commandbuilder.notifications;

public abstract class NotificationId<T extends NotificationHandle> {
public abstract int getId();

public abstract Class<T> getHandleType();

public abstract T newHandle();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package net.zscript.javaclient.commandbuilder.notifications;

import net.zscript.javaclient.commandPaths.ZscriptFieldSet;
import net.zscript.javaclient.commandbuilder.Respondable;
import net.zscript.javaclient.commandbuilder.ZscriptResponse;
import net.zscript.javaclient.commandbuilder.commandnodes.ResponseCaptor;
import net.zscript.javareceiver.tokenizer.ZscriptExpression;

public abstract class NotificationSection<T extends ZscriptResponse> implements Respondable<T> {
public abstract Class<T> getResponseType();

public void setCaptor(ResponseCaptor<T> captor) {
captor.setSource(this);
}

public abstract T parseResponse(ZscriptExpression expression);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package net.zscript.javaclient.commandbuilder.notifications;

import net.zscript.javaclient.commandbuilder.ZscriptResponse;

public class NotificationSectionId<T extends ZscriptResponse> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import net.zscript.javaclient.commandbuilder.commandnodes.*;
import net.zscript.javaclient.commandbuilder.defaultCommands.*;
import net.zscript.javaclient.commandbuilder.*;
import net.zscript.javaclient.commandbuilder.commandnodes.*;
import net.zscript.javaclient.commandbuilder.notifications.*;
import net.zscript.javareceiver.tokenizer.*;
import net.zscript.model.components.*;

Expand Down Expand Up @@ -166,28 +167,92 @@ public class {{#upperCamel}}{{moduleName}}{{/upperCamel}}Module {
}
}

{{#notificationSections}}
/** {{description}} */
public static class {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId extends NotificationSectionId<{{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent> {
private static final {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId id = new {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId();

public static {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId {{#lowerCamel}}{{name}}{{/lowerCamel}}NotificationSectionId(){
return id;
}
public static {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId get(){
return id;
}
private {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId(){
}
}
public static class {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSection extends NotificationSection<{{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent> {
@Override
public Class<{{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent> getResponseType(){
return {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent.class;
}

@Override
public {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent parseResponse(ZscriptExpression expression){
return new {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent(expression);
}
}

public static class {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionContent extends ValidatingResponse {
public {{#upperCamel}}{{name}}NotificationSectionContent{{/upperCamel}}(ZscriptExpression response) {
super(response, new byte[] { {{#responseFields}}{{#required}}(byte) '{{key}}', {{/required}}{{/responseFields}} });
}
{{#fields}}
{{>responseField.mustache}}
{{/fields}}
}
{{/notificationSections}}

{{#notifications}}
/** {{description}} */
public static class {{#upperCamel}}{{notificationName}}{{/upperCamel}}Notification {
public static class {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationId extends NotificationId<{{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle>{
public static final {{#upperCamel}}{{moduleName}}{{/upperCamel}}Notifications NTFN = {{#upperCamel}}{{moduleName}}{{/upperCamel}}Notifications.{{#upperCamel}}{{notificationName}}{{/upperCamel}};
private static final {{#upperCamel}}{{name}}{{/upperCamel}}NotificationId id = new {{#upperCamel}}{{name}}{{/upperCamel}}NotificationId();

private {{#upperCamel}}{{name}}{{/upperCamel}}NotificationId(){}

public {{#upperCamel}}{{notificationName}}{{/upperCamel}}Notification(String zscriptResponse) {
public static {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationId {{#lowerCamel}}{{notificationName}}{{/lowerCamel}}NotificationId(){
return id;
}
public static {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationId get(){
return id;
}

{{#sections}}
{{#section}}
/** {{description}} */
public static class {{#upperCamel}}{{sectionName}}{{/upperCamel}}Section extends ValidatingResponse {
public {{#upperCamel}}{{sectionName}}{{/upperCamel}}Section(final ZscriptExpression response) {
super(response, new byte[] { {{#responseFields}}{{#required}}(byte) '{{key}}', {{/required}}{{/responseFields}} });
}
{{#responseFields}}
{{>responseField.mustache}}
{{/responseFields}}
@Override
public int getId(){
return (MODULE_ID << 4) | (int) NTFN.getNotification();
}

@Override
public Class<{{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle> getHandleType(){
return {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle.class;
}

{{/section}}
@Override
public {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle newHandle(){
return new {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle();
}
}
public static class {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle extends NotificationHandle{
private final LinkedHashMap<NotificationSectionId<?>, NotificationSection<?>> sections = new LinkedHashMap<>();
public {{#upperCamel}}{{notificationName}}{{/upperCamel}}NotificationHandle() {
{{#sections}}
{{#section}}
sections.put({{#upperCamel}}{{name}}{{/upperCamel}}NotificationSectionId.get(), new {{#upperCamel}}{{name}}{{/upperCamel}}NotificationSection());
{{/section}}
{{/sections}}
}
@Override
public <T extends ZscriptResponse> NotificationSection<T> getSection(NotificationSectionId<T> response) {
return (NotificationSection<T>) sections.get(response);
}
@Override
public List<NotificationSection<?>> getSections() {
return new ArrayList<>(sections.values());
}
}

{{/notifications}}

}
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,10 @@ private <R extends ZscriptResponse> void checkResponse(final String responseChar
final Consumer<R> listener) {
responseChars.chars().forEach(c -> tokenizer.accept((byte) c));

ResponseCaptor<R> captor = ResponseCaptor.create();
ZscriptCommandNode cmd = commandBuilder.capture(captor)
.build();
ResponseCaptor<R> captor = ResponseCaptor.create();
ZscriptCommandNode<R> cmd = commandBuilder.capture(captor).build();

cmd.responseArrived(cmd.parseResponse(new ZscriptTokenExpression(tokenReader::iterator)));
listener.accept(captor.get());
listener.accept(cmd.parseResponse(new ZscriptTokenExpression(tokenReader::iterator)));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public void toBytes(ZscriptByteString.ZscriptByteStringBuilder builder) {
address.writeTo(builder);
}
content.toBytes(builder);
builder.appendByte('\n');
}

public CommandSequence getContent() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import static net.zscript.javareceiver.tokenizer.TokenBuffer.TokenReader;
import static net.zscript.javareceiver.tokenizer.TokenBuffer.TokenReader.ReadToken;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import net.zscript.javaclient.sequence.ResponseSequence;
import net.zscript.javareceiver.tokenizer.Tokenizer;
import net.zscript.model.components.Zchars;
import net.zscript.util.OptIterator;

Expand All @@ -16,6 +18,14 @@ public class CompleteAddressedResponse {
private final ResponseSequence content;

public static CompleteAddressedResponse parse(TokenReader reader) {
OptIterator<ReadToken> iterEnding = reader.iterator();
for (Optional<ReadToken> opt = iterEnding.next(); opt.isPresent(); opt = iterEnding.next()) {
if (opt.get().isSequenceEndMarker()) {
if (opt.get().getKey() != Tokenizer.NORMAL_SEQUENCE_END) {
throw new RuntimeException("Parse failed with Tokenizer error: " + Integer.toHexString(opt.get().getKey()));
}
}
}
OptIterator<ReadToken> iter = reader.iterator();
List<ZscriptAddress> addresses = new ArrayList<>();
ResponseSequence seq = null;
Expand Down
Loading

0 comments on commit a65d2e1

Please sign in to comment.