/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.thingml.networkplugins.c.posix;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.sintef.thingml.Configuration;
import org.sintef.thingml.ExternalConnector;
import org.sintef.thingml.Message;
import org.sintef.thingml.Port;
import org.sintef.thingml.Protocol;
import org.sintef.thingml.Thing;
import org.sintef.thingml.helpers.AnnotatedElementHelper;
import org.thingml.compilers.Context;
import org.thingml.compilers.c.CCompilerContext;
import org.thingml.compilers.spi.NetworkPlugin;
import org.thingml.compilers.spi.SerializationPlugin;
/**
*
* @author sintef
*/
public class PosixUDPPlugin extends NetworkPlugin {
CCompilerContext ctx;
public String getPluginID() {
return "PosixUDPPlugin";
}
public List<String> getSupportedProtocols() {
List<String> res = new ArrayList<>();
res.add("UDP");
res.add("udp");
return res;
}
public List<String> getTargetedLanguages() {
List<String> res = new ArrayList<>();
res.add("posix");
res.add("posixmt");
return res;
}
public void generateNetworkLibrary(Configuration cfg, Context ctx, Set<Protocol> protocols) {
this.ctx = (CCompilerContext) ctx;
for (Protocol prot : protocols) {
UDPPort port = new UDPPort();
port.protocol = prot;
try {
port.sp = ctx.getSerializationPlugin(prot);
} catch (UnsupportedEncodingException uee) {
System.err.println("Could not get serialization plugin... Expect some errors in the generated code");
uee.printStackTrace();
return;
}
for (ExternalConnector eco : this.getExternalConnectors(cfg, prot)) {
port.ecos.add(eco);
eco.setName(eco.getProtocol().getName());
}
port.generateNetworkLibrary(this.ctx, cfg);
}
}
private class UDPPort {
Set<ExternalConnector> ecos;
Protocol protocol;
Set<Message> messages;
SerializationPlugin sp;
String paramPort, paramIP;
UDPPort() {
ecos = new HashSet<>();
messages = new HashSet();
}
public void generateMessageForwarders(StringBuilder builder, StringBuilder headerbuilder, Configuration cfg, Protocol prot) {
for (ThingPortMessage tpm : getMessagesSent(cfg, prot)) {
Thing t = tpm.t;
Port p = tpm.p;
Message m = tpm.m;
SerializationPlugin sp = null;
try {
sp = ctx.getSerializationPlugin(prot);
} catch (UnsupportedEncodingException uee) {
System.err.println("Could not get serialization plugin... Expect some errors in the generated code");
uee.printStackTrace();
return;
}
builder.append("// Forwarding of messages " + prot.getName() + "::" + t.getName() + "::" + p.getName() + "::" + m.getName() + "\n");
builder.append("void forward_" + prot.getName() + "_" + ctx.getSenderName(t, p, m));
ctx.appendFormalParameters(t, builder, m);
builder.append("{\n");
String i = sp.generateSerialization(builder, "forward_buf", m);
builder.append("\n//Forwarding with specified function \n");
if(AnnotatedElementHelper.hasAnnotation(protocol, "udp_target_selection")) {
builder.append(prot.getName() + "_forwardMessage(forward_buf, " + i + ", " + paramIP + ", " + paramPort + ");\n");
} else {
builder.append(prot.getName() + "_forwardMessage(forward_buf, " + i + ");\n");
}
builder.append("}\n\n");
}
}
void generateNetworkLibrary(CCompilerContext ctx, Configuration cfg) {
if (!ecos.isEmpty()) {
String ctemplate = ctx.getTemplateByID("templates/PosixUDPPlugin.c");
String htemplate = ctx.getTemplateByID("templates/PosixUDPPlugin.h");
String portName = protocol.getName();
//Threaded listener --- BEGIN
ctx.addToInitCode("\n" + portName + "_instance.listener_id = add_instance(&" + portName + "_instance);\n");
StringBuilder initThread = new StringBuilder();
initThread.append("//" + portName + ":\n");
initThread.append(portName + "_setup();\n");
initThread.append("pthread_t thread_");
initThread.append(portName);
initThread.append(";\n");
initThread.append("pthread_create( &thread_");
initThread.append(portName);
initThread.append(", NULL, ");
initThread.append(portName + "_start_receiver_process");
initThread.append(", NULL);\n");
ctx.addToInitCode(initThread.toString());
//Threaded listener --- END
if(AnnotatedElementHelper.hasAnnotation(protocol, "udp_target_selection")) {
if (AnnotatedElementHelper.hasAnnotation(protocol, "udp_param_ip")) {
paramIP = AnnotatedElementHelper.annotation(protocol, "udp_param_ip").iterator().next();
}
if (AnnotatedElementHelper.hasAnnotation(protocol, "udp_param_port")) {
paramPort = AnnotatedElementHelper.annotation(protocol, "udp_param_port").iterator().next();
}
String remoteCfgForward = " memset((char *) &/*PORT_NAME*/_si_remote, 0, sizeof(/*PORT_NAME*/_si_remote));\n" +
"\n" +
" /*PORT_NAME*/_si_remote.sin_family = AF_INET;\n" +
" /*PORT_NAME*/_si_remote.sin_port = htons(port);\n" +
" /*PORT_NAME*/_si_remote.sin_addr = addr_from_uint32(ip);\n";
ctemplate = ctemplate.replace("/*REMOTE_CFG_SETUP*/", "");
ctemplate = ctemplate.replace("/*REMOTE_PARAM*/", ", uint32_t ip, uint16_t port");
ctemplate = ctemplate.replace("/*REMOTE_CFG_FORWARD*/", remoteCfgForward);
} else {
String remoteCfgSetup = " memset((char *) &/*PORT_NAME*/_si_remote, 0, sizeof(/*PORT_NAME*/_si_remote));\n" +
"\n" +
" /*PORT_NAME*/_si_remote.sin_family = AF_INET;\n" +
" /*PORT_NAME*/_si_remote.sin_port = htons(/*PORT_NAME*/_REMOTE_PORT);\n" +
" if (inet_aton(/*PORT_NAME*/_REMOTE_ADDR, &(/*PORT_NAME*/_si_remote.sin_addr)) == 0) {\n" +
" printf(\"Failed copying src address\\n\");\n" +
" }";
ctemplate = ctemplate.replace("/*REMOTE_CFG_SETUP*/", remoteCfgSetup);
ctemplate = ctemplate.replace("/*REMOTE_PARAM*/", "");
ctemplate = ctemplate.replace("/*REMOTE_CFG_FORWARD*/", "");
}
ctemplate = ctemplate.replace("/*PORT_NAME*/", portName);
htemplate = htemplate.replace("/*PORT_NAME*/", portName);
String address;
if (AnnotatedElementHelper.hasAnnotation(protocol, "udp_address")) {
address = AnnotatedElementHelper.annotation(protocol, "udp_address").iterator().next();
ctemplate = ctemplate.replace("/*REMOTE_ADDR*/", address);
}
Integer localPort;
if (AnnotatedElementHelper.hasAnnotation(protocol, "udp_local_port")) {
localPort = Integer.parseInt(AnnotatedElementHelper.annotation(protocol, "udp_local_port").iterator().next());
} else {
localPort = 10000;
}
ctemplate = ctemplate.replace("/*LOCAL_PORT*/", localPort.toString());
Integer remotePort;
if (AnnotatedElementHelper.hasAnnotation(protocol, "udp_remote_port")) {
remotePort = Integer.parseInt(AnnotatedElementHelper.annotation(protocol, "udp_remote_port").iterator().next());
} else {
remotePort = 10000;
}
ctemplate = ctemplate.replace("/*REMOTE_PORT*/", remotePort.toString());
//Parser
for (ThingPortMessage tpm : getMessagesReceived(cfg, protocol)) {
Message m = tpm.m;
messages.add(m);
}
StringBuilder ParserImplementation = new StringBuilder();
ParserImplementation.append("void " + portName + "_parser(byte * msg, uint16_t size");
if(AnnotatedElementHelper.hasAnnotation(protocol, "udp_target_selection")) {
ParserImplementation.append(", uint32_t provided_" + paramIP + ", uint16_t provided_" + paramPort);
}
ParserImplementation.append(") {\n");
sp.generateParserBody(ParserImplementation, "msg", "size", messages, portName + "_instance.listener_id");
ParserImplementation.append("}\n");
ctemplate = ctemplate.replace("/*PARSER_IMPLEMENTATION*/", sp.generateSubFunctions() + ParserImplementation);
String ParserCall = portName + "_parser(buf, recv_len";
if(AnnotatedElementHelper.hasAnnotation(protocol, "udp_target_selection")) {
ParserCall += ", " + portName + "_si_rcv.sin_addr.s_addr, ntohs(" + portName + "_si_rcv.sin_port)";
}
ParserCall += ");";
ctemplate = ctemplate.replace("/*PARSER_CALL*/", ParserCall);
ctemplate = ctemplate.replace("/*PARSER_IMPLEMENTATION*/", ParserImplementation);
//End parser
htemplate = htemplate.replace("/*PATH_TO_C*/", protocol.getName() + ".c");
StringBuilder b = new StringBuilder();
StringBuilder h = new StringBuilder();
generateMessageForwarders(b, h, cfg, protocol);
ctemplate += "\n" + b;
htemplate += "\n" + h;
ctx.getBuilder(protocol.getName() + ".c").append(ctemplate);
ctx.getBuilder(protocol.getName() + ".h").append(htemplate);
ctx.addToIncludes("#include \"" + protocol.getName() + ".h\"");
}
}
}
}