Skip to content

Commit

Permalink
Add MQTTS to HonoMQTT (eclipse#290)
Browse files Browse the repository at this point in the history
* Add MQTTS to HonoMQTT
* properly fix WLAN
  • Loading branch information
wegendt-bosch authored Mar 1, 2019
1 parent 05b400d commit adc9ac0
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 72 deletions.
12 changes: 11 additions & 1 deletion platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ connectivity many MQTT {
/**
* A time server to use to get the current time. This is needed to allow certificate validation for MQTTS.
*/
configuration-item sntpServer: string = "pool.ntp.org:123"
configuration-item sntpServer: string = "sntp://pool.ntp.org:123"

/**
* The path to the server's public certificate to use for authentication. PEM format. Absolute or relative to the project root.
Expand Down Expand Up @@ -837,13 +837,23 @@ connectivity many HonoMqtt {
*/
required configuration-item url : string

/**
* A time server to use to get the current time. This is needed to allow certificate validation for MQTTS.
*/
configuration-item sntpServer: string = "sntp://pool.ntp.org:123"

/**
* The client identifier (here: clientID) is a identifier of each MQTT client
* connecting to a MQTT broker. It needs to be unique for the broker to
* know the state of the client.
*/
required configuration-item clientId : string

/**
* The path to the server's public certificate to use for authentication. PEM format. Absolute or relative to the project root.
*/
configuration-item certificatePath: string

required configuration-item authentication: HonoAuthentication

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class MqttGenerator extends AbstractSystemResourceGenerator {

val auth = StaticValueInferrer.infer(configuration.getExpression("authentication"), []);

codeFragmentProvider.create('''
val result = codeFragmentProvider.create('''
Retcode_T exception = RETCODE_OK;
«IF auth instanceof SumTypeRepr»
«IF auth.isLogin()»
Expand Down Expand Up @@ -185,15 +185,20 @@ class MqttGenerator extends AbstractSystemResourceGenerator {

«IF isSecure»
SNTP_Setup_T sntpSetup = {
.ServerUrl = "«sntpUri.path»",
.ServerUrl = "«sntpUri.host»",
.ServerPort = «sntpPort»
};
«ENDIF»
''')
.addHeader("Serval_Mqtt.h", true, IncludePath.LOW_PRIORITY)
.addHeader("stdint.h", true, IncludePath.HIGH_PRIORITY)
.addHeader("XdkCommonInfo.h", true)
.addHeader("BCDS_NetworkConfig.h", true)
.addHeader("BCDS_WlanNetworkConfig.h", true)
if(isSecure) {
result.addHeader("HTTPRestClientSecurity.h", true)
}
return result;
}
override generateEnable() {
Expand Down Expand Up @@ -230,10 +235,11 @@ class MqttGenerator extends AbstractSystemResourceGenerator {
* Since there is no point in doing a HTTPS communication without a valid time */
do
{
exception = SNTP_GetTimeFromServer(&sntpTimeStampFromServer, 60);
exception = SNTP_GetTimeFromServer(&sntpTimeStampFromServer, 1000);
if ((RETCODE_OK != exception) || (0UL == sntpTimeStampFromServer))
{
«loggingGenerator.generateLogStatement(LogLevel.Warning, "MQTT_Enable : SNTP server time was not synchronized. Retrying..."
BSP_Board_Delay(1000);
}
} while (0UL == sntpTimeStampFromServer);

Expand All @@ -242,6 +248,8 @@ class MqttGenerator extends AbstractSystemResourceGenerator {
TimeStamp_SecsToTm(sntpTimeStampFromServer, &time);
TimeStamp_TmToIso8601(&time, timezoneISO8601format, 40);

«loggingGenerator.generateLogStatement(LogLevel.Info, "MQTT_Enable : Getting time successful. Current time is %s", codeFragmentProvider.create('''timezoneISO8601format'''))»

BCDS_UNUSED(sntpTimeStampFromServer); /* Copy of sntpTimeStampFromServer will be used be HTTPS for TLS handshake */

«generatorUtils.generateExceptionHandler(setup, "exception"
Expand All @@ -266,7 +274,7 @@ class MqttGenerator extends AbstractSystemResourceGenerator {

«generatorUtils.generateExceptionHandler(setup, "exception"

exception = NetworkConfig_GetIpAddress((uint8_t *) MQTT_BROKER_HOST, &brokerIpAddress);
exception = WlanNetworkConfig_GetIpAddress((uint8_t *) MQTT_BROKER_HOST, &brokerIpAddress);
if(RETCODE_OK != exception) {
«loggingGenerator.generateLogStatement(LogLevel.Error, "MQTT_Enable : Failed to resolve host: %s", codeFragmentProvider.create('''MQTT_BROKER_HOST'''))»
return exception;
Expand Down Expand Up @@ -332,10 +340,12 @@ class MqttGenerator extends AbstractSystemResourceGenerator {

return exception;
''')
.addHeader("BCDS_BSP_Board.h", true)
.addHeader("XDK_SNTP.h", true)
.addHeader("MbedTLSAdapter.h", true)
.addHeader("HTTPRestClientSecurity.h", true)
.addHeader("time.h", true);
.addHeader("time.h", true)
.addHeader("XDK_TimeStamp.h", true)
result.setPreamble('''
«IF auth instanceof SumTypeRepr»
«IF auth.isLogin()»
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class MqttValidator implements IResourceValidator {

val urlContentString = urlContent as String;

val sntpConfigValue = setup.getConfigurationItemValue("sntpSever");
val sntpConfigValue = setup.getConfigurationItemValue("sntpServer");
val sntpString = StaticValueInferrer.infer(sntpConfigValue, []);

try {
Expand Down Expand Up @@ -92,12 +92,15 @@ class MqttValidator implements IResourceValidator {
try {
if(sntpString instanceof String) {
val sntpUrl = new URI(sntpString);
if(!sntpUrl.scheme.nullOrEmpty) {
acceptor.acceptError("SNTP must not have a scheme", sntpConfigValue, null, 0, "");
if(sntpUrl.scheme != "sntp") {
acceptor.acceptError("SNTP must have scheme 'sntp://'", sntpConfigValue, null, 0, "");
}
if(sntpUrl.path.nullOrEmpty) {
if(sntpUrl.host.nullOrEmpty) {
acceptor.acceptError("SNTP must have a host", sntpConfigValue, null, 0, "");
}
if(!sntpUrl.path.nullOrEmpty) {
acceptor.acceptError("SNTP must not have a path (" + sntpUrl.path + ")", sntpConfigValue, null, 0, "");
}
}
} catch(MalformedURLException e) {
acceptor.acceptError("URL is malformed: " + e.message, sntpConfigValue, ProgramPackage.Literals.CONFIGURATION_ITEM_VALUE__VALUE, 0, "url_is_malformed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,36 @@ class WlanGenerator extends AbstractSystemResourceGenerator {
protected IPlatformLoggingGenerator loggingGenerator

override generateSetup() {
CodeFragment.EMPTY;
codeFragmentProvider.create('''
Retcode_T exception = RETCODE_OK;
«IF configuration.getBoolean("isHostPgmEnabled")»
exception = WLANHostPgm_Setup();
«generateLoggingExceptionHandler("WLAN host programming", "setting up")»
«ENDIF»
NetworkConfigSemaphore = xSemaphoreCreateBinary();
if (NULL == NetworkConfigSemaphore)
{
printf("Failed to create Semaphore \r\n");
return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_SEMAPHORE_ERROR);
}
WlanEventSemaphore = xSemaphoreCreateBinary();
if (NULL == WlanEventSemaphore)
{
vSemaphoreDelete(NetworkConfigSemaphore);
printf("Failed to create Semaphore \r\n");
return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_SEMAPHORE_ERROR);
}
return (exception);
''')
.setPreamble('''
static SemaphoreHandle_t WlanEventSemaphore = NULL;
static SemaphoreHandle_t NetworkConfigSemaphore = NULL;
''')
.addHeader("semphr.h", true);
}

@Inject
Expand All @@ -52,73 +81,55 @@ class WlanGenerator extends AbstractSystemResourceGenerator {
val auth = StaticValueInferrer.infer(configuration.getExpression("authentication"), []);
val result = codeFragmentProvider.create('''
Retcode_T retcode = RETCODE_OK;
Retcode_T exception = RETCODE_OK;
/* The order of calls is important here. WlanConnect_init initializes the CC3100 and prepares
* its future use. Calls to NetworkConfig_ fail if WlanConnect_Init was not called beforehand.
*/
retcode = WlanConnect_Init(«baseName»_StatusCallback);
if(RETCODE_OK != retcode)
{
return retcode;
}
/* Initialize the Wireless Network Driver */
exception = WlanNetworkConnect_Init(«baseName»_WlanConnectStatusCallback);
«generateLoggingExceptionHandler("WlanNetworkConnect", "init")»
/* Semaphore take to flush the existing queue events without timeout. Hence no need to consider the return value */
(void) xSemaphoreTake(WlanEventSemaphore, 0U);
«IF ipConfigExpr instanceof SumTypeRepr»
«IF ipConfigExpr.name.contains("Dhcp")»
retcode = NetworkConfig_SetIpDhcp(NULL);
if (RETCODE_OK != retcode)
{
return retcode;
}
/* Semaphore take to flush the existing queue events without timeout. Hence no need to consider the return value */
(void) xSemaphoreTake(NetworkConfigSemaphore, 0U);
exception = WlanNetworkConfig_SetIpDhcp(«baseName»_NetworkIpConfigStatusCallback);
«generateLoggingExceptionHandler("DHCP", "setting")»
«ELSEIF ipConfigExpr.name == "Static"»
NetworkConfig_IpSettings_T staticIpSettings;
WlanNetworkConfig_IpSettings_T staticIpSettings;
staticIpSettings.isDHCP = false;
staticIpSettings.ipV4 = sl_Htonl(XDK_NETWORK_IPV4(«(StaticValueInferrer.infer(ipConfigExpr.properties.get("ip"), []) as String)?.split("\\.")?.join(", ")»));
staticIpSettings.ipV4Mask = sl_Htonl(XDK_NETWORK_IPV4(«(StaticValueInferrer.infer(ipConfigExpr.properties.get("subnetMask"), []) as String)?.split("\\.")?.join(", ")»));
staticIpSettings.ipV4Gateway = sl_Htonl(XDK_NETWORK_IPV4(«(StaticValueInferrer.infer(ipConfigExpr.properties.get("gateway"), []) as String)?.split("\\.")?.join(", ")»));
staticIpSettings.ipV4DnsServer = sl_Htonl(XDK_NETWORK_IPV4(«(StaticValueInferrer.infer(ipConfigExpr.properties.get("dns"), []) as String)?.split("\\.")?.join(", ")»));
retcode = NetworkConfig_SetIpStatic(staticIpSettings);
if (RETCODE_OK != retcode)
{
return retcode;
}
exception = WlanNetworkConfig_SetIpStatic(staticIpSettings);
«generateLoggingExceptionHandler("static IP", "setting")»
«ENDIF»
«ELSE»
ERROR: INVALID CONFIGURATION: ipConfiguration
«ENDIF»
«IF auth instanceof SumTypeRepr»
«IF auth.name == "None"»
/* Passing NULL as onConnection callback (last parameter) makes this a blocking call, i.e. the
* WlanConnect_Open function will return only once a connection to the WLAN has been established,
* or if something went wrong while trying to do so. If you wanted non-blocking behavior, pass
* a callback instead of NULL. */
«loggingGenerator.generateLogStatement(LogLevel.Info, "Connecting to open network: %s", codeFragmentProvider.create('''NETWORK_SSID'''))»
retcode = WlanConnect_Open((WlanConnect_SSID_T) NETWORK_SSID, true);
if(RETCODE_OK != retcode)
exception = WlanNetworkConnect_Open((WlanNetworkConnect_SSID_T) NETWORK_SSID);
if(RETCODE_OK != exception)
{
return retcode;
return exception;
}
«ELSEIF auth.name == "Personal"»
/* Passing NULL as onConnection callback (last parameter) makes this a blocking call, i.e. the
* WlanConnect_WPA function will return only once a connection to the WLAN has been established,
* or if something went wrong while trying to do so. If you wanted non-blocking behavior, pass
* a callback instead of NULL. */
«loggingGenerator.generateLogStatement(LogLevel.Info, "Connecting to personal network: %s", codeFragmentProvider.create('''NETWORK_SSID'''))»
retcode = WlanConnect_WPA((WlanConnect_SSID_T) NETWORK_SSID, (WlanConnect_PassPhrase_T) NETWORK_PSK, true);
if(RETCODE_OK != retcode)
exception = WlanNetworkConnect_PersonalWPA((WlanNetworkConnect_SSID_T) NETWORK_SSID, (WlanNetworkConnect_PassPhrase_T) NETWORK_PSK);
if(RETCODE_OK != exception)
{
return retcode;
return exception;
}
«ELSEIF auth.name == "Enterprise"»
«IF configuration.getBoolean("isHostPgmEnabled")»
«loggingGenerator.generateLogStatement(LogLevel.Info, "Connecting to enterprise network with host programming: %s", codeFragmentProvider.create('''NETWORK_SSID'''))»
retcode = WLANHostPgm_Enable();
if(RETCODE_OK != retcode)
{
return retcode;
}
exception = WLANHostPgm_Enable();
«generateLoggingExceptionHandler("WLAN host programming", "enable")»
«ELSE»
«loggingGenerator.generateLogStatement(LogLevel.Info, "Connecting to enterprise network without host programming: %s", codeFragmentProvider.create('''NETWORK_SSID'''))»
«ENDIF»
Expand All @@ -130,14 +141,10 @@ class WlanGenerator extends AbstractSystemResourceGenerator {
return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_WLAN_SL_SET_FAILED);
}
/* Passing NULL as onConnection callback (last parameter) makes this a blocking call, i.e. the
* WlanConnect_EnterpriseWPA function will return only once a connection to the WLAN has been established,
* or if something went wrong while trying to do so. If you wanted non-blocking behavior, pass
* a callback instead of NULL. */
retcode = WlanConnect_EnterpriseWPA((WlanConnect_SSID_T) NETWORK_SSID, (WlanConnect_Username_T) NETWORK_USERNAME, (WlanConnect_PassPhrase_T) NETWORK_PASSWORD, true);
if(RETCODE_OK != retcode)
exception = WlanNetworkConnect_EnterpriseWPA((WlanNetworkConnect_SSID_T) NETWORK_SSID, (WlanNetworkConnect_Username_T) NETWORK_USERNAME, (WlanNetworkConnect_PassPhrase_T) NETWORK_PASSWORD);
if(RETCODE_OK != exception)
{
return retcode;
return exception;
}
else
{
Expand All @@ -148,13 +155,26 @@ class WlanGenerator extends AbstractSystemResourceGenerator {
ERROR: INVALID CONFIGURATION: authentication
«ENDIF»
«IF ipConfigExpr instanceof SumTypeRepr»
«IF ipConfigExpr.name.contains("Dhcp")»
if (pdTRUE == xSemaphoreTake(NetworkConfigSemaphore, 200000))
{
exception = WlanEventSemaphoreHandle();
}
else
{
exception = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_SEMAPHORE_ERROR);
}
«ELSEIF ipConfigExpr.name == "Static"»
exception = WlanEventSemaphoreHandle();
«ENDIF»
«ENDIF»
NetworkConfig_IpSettings_T currentIpSettings;
retcode = NetworkConfig_GetIpSettings(&currentIpSettings);
if(RETCODE_OK != retcode)
WlanNetworkConfig_IpSettings_T currentIpSettings;
exception = WlanNetworkConfig_GetIpSettings(&currentIpSettings);
if(RETCODE_OK != exception)
{
return retcode;
return exception;
}
else
{
Expand Down Expand Up @@ -186,13 +206,41 @@ class WlanGenerator extends AbstractSystemResourceGenerator {
«ELSE»
ERROR: INVALID CONFIGURATION: authentication
«ENDIF»
«setup.buildStatusCallback(eventHandler)»
«setup.buildStatusCallbacks()»
static Retcode_T WlanEventSemaphoreHandle(void)
{
Retcode_T exception = RETCODE_OK;
uint8_t count = 0;
if (pdTRUE == xSemaphoreTake(WlanEventSemaphore, 200000))
{
do
{
if ((WLANNETWORKCONFIG_IPV4_ACQUIRED == WlanNetworkConfig_GetIpStatus()) && (WLANNETWORK_CONNECTED == WlanNetworkConnect_GetStatus()))
{
exception = RETCODE_OK;
}
else
{
vTaskDelay(500);
count++;
exception = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_WLAN_CONNECT_FAILED);
}
} while ((RETCODE_OK != exception)
&& (UINT8_C(5) >= count));
}
else
{
exception = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_SEMAPHORE_ERROR);
}
return exception;
}
''')
.addHeader('XdkCommonInfo.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('BCDS_Basics.h', true, IncludePath.VERY_HIGH_PRIORITY)
.addHeader('BCDS_WlanConnect.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('BCDS_NetworkConfig.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('BCDS_Wlan.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('BCDS_WlanNetworkConfig.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('Serval_Network.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('Serval_Ip.h', true, IncludePath.HIGH_PRIORITY)
.addHeader('wlan.h', true, IncludePath.HIGH_PRIORITY)
Expand All @@ -208,15 +256,20 @@ class WlanGenerator extends AbstractSystemResourceGenerator {
}
return result
}
private def CodeFragment buildStatusCallback(SystemResourceSetup component, Iterable<EventHandlerDeclaration> declarations) {
private def CodeFragment buildStatusCallbacks(SystemResourceSetup component) {
val baseName = component.baseName
codeFragmentProvider.create('''
static void «baseName»_StatusCallback(WlanConnect_Status_T connectStatus)
static void «baseName»_WlanConnectStatusCallback(WlanNetworkConnect_Status_T connectStatus)
{
BCDS_UNUSED(connectStatus);
(void) xSemaphoreGive(WlanEventSemaphore);
}
static void «baseName»_NetworkIpConfigStatusCallback(WlanNetworkConfig_IpStatus_T ipStatus)
{
BCDS_UNUSED(ipStatus);
(void) xSemaphoreGive(NetworkConfigSemaphore);
}
''')
}
}
Loading

0 comments on commit adc9ac0

Please sign in to comment.