Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Augmented support for Arduino #1384

Merged
merged 15 commits into from
Oct 8, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,15 @@ public void recognizeHostNames() throws Exception {
List.of("[foo, {bar: baz}]", "[1]", PrimitiveType.STRING),
List.of("{bar: baz}", "", UnionType.STRING_OR_STRING_ARRAY)
),
UnionType.PLATFORM_STRING_OR_DICTIONARY, List.of(
List.of("[bar, baz]", "", UnionType.PLATFORM_STRING_OR_DICTIONARY),
List.of("{name: [1, 2, 3]}", ".name", PrimitiveType.STRING),
List.of("{name: {bar: baz}}", ".name", PrimitiveType.STRING),
List.of("{board: [1, 2, 3]}", ".board", PrimitiveType.STRING),
List.of("{board: {bar: baz}}", ".board", PrimitiveType.STRING),
List.of("{baud-rate: [1, 2, 3]}", ".baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER),
List.of("{baud-rate: {bar: baz}}", ".baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER)
),
UnionType.FILE_OR_FILE_ARRAY, List.of(
List.of("[1 msec]", "[0]", PrimitiveType.FILE),
List.of("[foo, {bar: baz}]", "[1]", PrimitiveType.FILE),
Expand Down
96 changes: 89 additions & 7 deletions org.lflang/src/org/lflang/TargetConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ public class TargetConfig {
*/
public Set<TargetProperty> setByUser = new HashSet<>();

/**
* Specify Baud Rate for Embedded Devices, including Arduino.
*/
public int baudRate = 9600;

/**
* A list of custom build commands that replace the default build process of
* directly invoking a designated compiler. A common usage of this target
Expand Down Expand Up @@ -195,13 +190,17 @@ public class TargetConfig {
public boolean noRuntimeValidation = false;

/**
* Set the target platform.
* Set the target platform config.
* This tells the build system what platform-specific support
* files it needs to incorporate at compile time.
*
* This is now a wrapped class to account for overloaded definitions
* of defining platform (either a string or dictionary of values)
*
* @author Samuel Berkun (sberkun@berkeley.edu)
* @author Anirudh Rengarajan (arengarajan@berkeley.edu)
*/
public Platform platform = Platform.AUTO;
public PlatformOptions platformOptions = new PlatformOptions();

/**
* List of proto files to be processed by the code generator.
Expand Down Expand Up @@ -346,6 +345,89 @@ public static class DockerOptions {
public String from = "alpine:latest";
}

/**
* Enum representing the different boards supported by Arduino-CMake and future embedded boards.
*/
public enum Board {
NONE(),
YN("Arduino Yn [avr.yun]"),
UNO("Arduino Uno [avr.uno]"),
DUEMILANOVE("Arduino Duemilanove or Diecimila [avr.diecimila]"),
DIECIMILA("Arduino Duemilanove or Diecimila [avr.diecimila]"),
NANO("Arduino Nano [avr.nano]"),
MEGA("Arduino Mega or Mega 2560 [avr.mega]"),
MEGA_2560("Arduino Mega or Mega 2560 [avr.mega]"),
MEGA_ADK("Arduino Mega ADK [avr.megaADK]"),
LEONARDO("Arduino Leonardo [avr.leonardo]"),
LEONARDO_ETH("Arduino Leonardo ETH [avr.leonardoeth]"),
MICRO("Arduino Micro [avr.micro]"),
ESPLORA("Arduino Esplora [avr.esplora]"),
MINI("Arduino Mini [avr.mini]"),
ETHERNET("Arduino Ethernet [avr.ethernet]"),
FIO("Arduino Fio [avr.fio]"),
BT("Arduino BT [avr.bt]"),
LILYPAD_USB("LilyPad Arduino USB [avr.LilyPadUSB]"),
LILYPAD("LilyPad Arduino [avr.lilypad]"),
PRO("Arduino Pro or Pro Mini [avr.pro]"),
PRO_MINI("Arduino Pro or Pro Mini [avr.pro]"),
NG("Arduino NG or older [avr.atmegang]"),
OLDER("Arduino NG or older [avr.atmegang]"),
ROBOT_CONTROL("Arduino Robot Control [avr.robotControl]"),
ROBOT_MOTOR("Arduino Robot Motor [avr.robotMotor]"),
GEMMA("Arduino Gemma [avr.gemma]"),
CIRCUIT_PLAYGROUND("Adafruit Circuit Playground [avr.circuitplay32u4cat]"),
YN_MINI("Arduino Yn Mini [avr.yunmini]"),
INDUSTRIAL_101("Arduino Industrial 101 [avr.chiwawa]"),
LININO_ONE("Linino One [avr.one]"),
UNO_WIFI("Arduino Uno WiFi [avr.unowifi]"),
SAM_DUE_PROG("Arduino Due (Programming Port) [sam.arduino_due_x_dbg]"),
SAM_DUE_NATIVE("Arduino Due (Native USB Port) [sam.arduino_due_x]");

String boardName;
Board() {
this.boardName = this.toString();
}
Board(String boardName) {
this.boardName = boardName;
}

/**
* Return the name in lower case.
*/
@Override
public String toString() {
return this.name().toLowerCase();
}

/**
* Get the CMake name for the platform.
*/
public String getBoardName() {
return this.boardName;
}
}

/**
* Settings related to Platform Options.
*/
public static class PlatformOptions {

/**
* The base platform we build our LF Files on. Should be set to AUTO by default unless developing for specific OS/Embedded Platform
*/
public Platform platform = Platform.AUTO;

/**
* The base board we target when building LF on Arduino/Embedded Boards. For OS development and generic embedded systems, this value is unused.
*/
public Board board = Board.UNO;

/**
* The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate amongst systems like Arduino, so it's the default value.
*/
public int baudRate = 9600;
}

/**
* Settings related to tracing options.
*/
Expand Down
101 changes: 87 additions & 14 deletions org.lflang/src/org/lflang/TargetProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
import java.util.stream.Collectors;

import org.eclipse.xtext.util.RuntimeIOException;
import org.lflang.TargetConfig.Board;
import org.lflang.TargetConfig.DockerOptions;
import org.lflang.TargetConfig.PlatformOptions;
import org.lflang.TargetConfig.TracingOptions;
import org.lflang.generator.InvalidLfSourceException;
import org.lflang.generator.rust.CargoDependencySpec;
Expand All @@ -57,14 +59,6 @@
*/
public enum TargetProperty {

/**
* Directive to specify the baud-rate used by the runtime for embedded systems (Arduino).
*/
BAUD_RATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER,
List.of(Target.C, Target.CCPP),
(config, value, err) -> {
config.baudRate = ASTUtils.toInteger(value);
}),

/**
* Directive to let the generator use the custom build command.
Expand Down Expand Up @@ -308,13 +302,51 @@ public enum TargetProperty {
}),

/**
* Directive to specify the platform for cross code generation.
* Directive to specify the platform for cross code generation. This is either a string of the platform
* or a dictionary of options that includes the string name.
*/
PLATFORM("platform", UnionType.PLATFORM_UNION, Target.ALL,
(config, value, err) -> {
config.platform = (Platform) UnionType.PLATFORM_UNION
.forName(ASTUtils.elementToSingleString(value));
}),
PLATFORM("platform", UnionType.PLATFORM_STRING_OR_DICTIONARY, Target.ALL,
(config, value, err) -> {
if (value.getLiteral() != null) {
config.platformOptions = new PlatformOptions();
config.platformOptions.platform = (Platform) UnionType.PLATFORM_UNION
.forName(ASTUtils.elementToSingleString(value));
} else {
config.platformOptions= new PlatformOptions();
for (KeyValuePair entry : value.getKeyvalue().getPairs()) {
PlatformOption option = (PlatformOption) DictionaryType.PLATFORM_DICT
.forName(entry.getName());
switch (option) {
case NAME:
Platform p = (Platform) UnionType.PLATFORM_UNION
.forName(ASTUtils.elementToSingleString(entry.getValue()));
if(p == null){
String s = "Unidentified Platform Type, LF supports the following platform types: " + Arrays.asList(Platform.values()).toString();
err.reportError(s);
throw new AssertionError(s);
}
config.platformOptions.platform = p;
break;
case BAUDRATE:
config.platformOptions.baudRate = ASTUtils.toInteger(entry.getValue());
break;
case BOARD:
Board b = (Board) UnionType.BOARD_UNION
.forName(ASTUtils.elementToSingleString(entry.getValue()));
if(b == null){
String s = "Unidentified Board Type, LF supports the following board types: " + Arrays.asList(Board.values()).toString();
err.reportError(s);
throw new AssertionError(s);
}

config.platformOptions.board = b;
break;
default:
break;
}
}
}
}),

/**
* Directive for specifying .proto files that need to be compiled and their
Expand Down Expand Up @@ -722,6 +754,7 @@ public interface DictionaryElement {
public enum DictionaryType implements TargetPropertyType {
CLOCK_SYNC_OPTION_DICT(Arrays.asList(ClockSyncOption.values())),
DOCKER_DICT(Arrays.asList(DockerOption.values())),
PLATFORM_DICT(Arrays.asList(PlatformOption.values())),
COORDINATION_OPTION_DICT(Arrays.asList(CoordinationOption.values())),
TRACING_DICT(Arrays.asList(TracingOption.values()));

Expand Down Expand Up @@ -811,6 +844,9 @@ public enum UnionType implements TargetPropertyType {
STRING_OR_STRING_ARRAY(
Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY),
null),
PLATFORM_STRING_OR_DICTIONARY(
Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT),
null),
FILE_OR_FILE_ARRAY(
Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null),
BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null),
Expand All @@ -819,6 +855,7 @@ public enum UnionType implements TargetPropertyType {
SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()),
LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO),
PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO),
BOARD_UNION(Arrays.asList(Board.values()), Board.NONE),
CLOCK_SYNC_UNION(Arrays.asList(ClockSyncMode.values()),
ClockSyncMode.INIT),
DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT),
Expand Down Expand Up @@ -1285,6 +1322,42 @@ public TargetPropertyType getType() {
}
}


/**
* Clock synchronization options.
* @author{Marten Lohstroh <marten@berkeley.edu>}
*/
public enum PlatformOption implements DictionaryElement {
NAME("name", PrimitiveType.STRING),
BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER),
BOARD("board", PrimitiveType.STRING);

public final PrimitiveType type;

private final String description;

private PlatformOption(String alias, PrimitiveType type) {
this.description = alias;
this.type = type;
}


/**
* Return the description of this dictionary element.
*/
@Override
public String toString() {
return this.description;
}

/**
* Return the type associated with this dictionary element.
*/
public TargetPropertyType getType() {
return this.type;
}
}

/**
* Coordination options.
* @author{Edward A. Lee <eal@berkeley.edu>}
Expand Down
10 changes: 5 additions & 5 deletions org.lflang/src/org/lflang/generator/c/CCmakeCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ public LFCommand compileCmakeCommand(
FileUtil.toUnixString(fileConfig.getSrcGenPath())
));

if(targetConfig.platform == Platform.ARDUINO) {
arguments.add(0, "-DCMAKE_TOOLCHAIN_FILE="
+ FileUtil.globFilesEndsWith(fileConfig.srcPkgPath.getParent().getParent(), "Arduino-toolchain.cmake").get(0));
arguments.add(0, "-DARDUINO_BOARD_OPTIONS_FILE="
+ FileUtil.globFilesEndsWith(fileConfig.getSrcGenPath(), "BoardOptions.cmake").get(0));
if(targetConfig.platformOptions.platform == Platform.ARDUINO) {
arguments.add("-DCMAKE_TOOLCHAIN_FILE="
+ fileConfig.getSrcGenPath().resolve("toolchain/Arduino-toolchain.cmake"));
arguments.add("-DARDUINO_BOARD_OPTIONS_FILE="
+ fileConfig.getSrcGenPath().resolve("toolchain/BoardOptions.cmake"));
}

if (GeneratorUtils.isHostWindows()) {
Expand Down
8 changes: 4 additions & 4 deletions org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ CodeBuilder generateCMakeCode(
cMakeCode.newLine();
}

if (targetConfig.platform != Platform.AUTO) {
cMakeCode.pr("set(CMAKE_SYSTEM_NAME "+targetConfig.platform.getcMakeName()+")");
if (targetConfig.platformOptions.platform != Platform.AUTO) {
cMakeCode.pr("set(CMAKE_SYSTEM_NAME "+targetConfig.platformOptions.platform.getcMakeName()+")");
}
cMakeCode.pr("include(${CoreLib}/platform/Platform.cmake)");
cMakeCode.newLine();
Expand Down Expand Up @@ -242,8 +242,8 @@ CodeBuilder generateCMakeCode(
cMakeCode.pr(")");
cMakeCode.newLine();

if (this.targetConfig.platform == Platform.ARDUINO) {
cMakeCode.pr("target_link_arduino_libraries ( ${LF_MAIN_TARGET} PRIVATE core)");
if (this.targetConfig.platformOptions.platform == Platform.ARDUINO) {
cMakeCode.pr("target_link_arduino_libraries ( ${LF_MAIN_TARGET} AUTO_PUBLIC)");
cMakeCode.pr("target_enable_arduino_upload(${LF_MAIN_TARGET})");
}

Expand Down
39 changes: 30 additions & 9 deletions org.lflang/src/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -555,12 +555,6 @@ public void doGenerate(Resource resource, LFGeneratorContext context) {
copyUserFiles(this.targetConfig, this.fileConfig);
}

// If we are running an Arduino Target, need to copy over the BoardOptions file.
if (targetConfig.platform == Platform.ARDUINO) {
FileUtil.copyFile(FileUtil.globFilesEndsWith(fileConfig.srcPath, "BoardOptions.cmake").get(0),
Paths.get(fileConfig.getSrcGenPath().toString(),File.separator, "BoardOptions.cmake"));
}

// Copy the core lib
FileUtil.copyFilesFromClassPath(
"/lib/c/reactor-c/core",
Expand All @@ -573,6 +567,33 @@ public void doGenerate(Resource resource, LFGeneratorContext context) {
);
// Copy the C target files
copyTargetFiles();

// If we are running an Arduino Target, need to copy over the Arduino-CMake files.
if (targetConfig.platformOptions.platform == Platform.ARDUINO) {
FileUtil.copyDirectoryFromClassPath(
"/lib/platform/arduino/Arduino-CMake-Toolchain/Arduino",
fileConfig.getSrcGenPath().resolve("toolchain/Arduino"),
false
);
FileUtil.copyDirectoryFromClassPath(
"/lib/platform/arduino/Arduino-CMake-Toolchain/Platform",
fileConfig.getSrcGenPath().resolve("toolchain/Platform"),
false
);
FileUtil.copyFileFromClassPath(
"/lib/platform/arduino/Arduino-CMake-Toolchain/Arduino-toolchain.cmake",
fileConfig.getSrcGenPath().resolve("toolchain/Arduino-toolchain.cmake"),
true
);

StringBuilder s = new StringBuilder();
s.append("set(ARDUINO_BOARD \"");
s.append(targetConfig.platformOptions.board.getBoardName());
s.append("\")");
FileUtil.writeToFile(s.toString(),
fileConfig.getSrcGenPath().resolve("toolchain/BoardOptions.cmake"));
}

// Write the generated code
code.writeToFile(targetFile);
} catch (IOException e) {
Expand Down Expand Up @@ -1098,8 +1119,8 @@ private void generateReactorChildren(
private void pickCompilePlatform() {
var osName = System.getProperty("os.name").toLowerCase();
// if platform target was set, use given platform instead
if (targetConfig.platform != Platform.AUTO) {
osName = targetConfig.platform.toString();
if (targetConfig.platformOptions.platform != Platform.AUTO) {
osName = targetConfig.platformOptions.platform.toString();
}
if (osName.contains("arduino")) {
return;
Expand Down Expand Up @@ -2262,7 +2283,7 @@ protected void setUpGeneralParameters() {
// So that each separate compile knows about modal reactors, do this:
targetConfig.compileDefinitions.put("MODAL_REACTORS", "");
}
if (targetConfig.threading && targetConfig.platform == Platform.ARDUINO) {
if (targetConfig.threading && targetConfig.platformOptions.platform == Platform.ARDUINO) {

//Add error message when user attempts to set threading=true for Arduino
if (targetConfig.setByUser.contains(TargetProperty.THREADING)) {
Expand Down
Loading