From 92439f40599e27c39b9317f4de8ff474a32e511a Mon Sep 17 00:00:00 2001 From: Philipp Date: Fri, 23 Aug 2024 22:19:19 +0200 Subject: [PATCH] Minor updates and fixes. --- app/dmweb.f90 | 80 ++++++++++++++++++++----------------------- man/dmlog.1 | 6 ++-- share/dmweb/dmpack.js | 58 ++++++++++++++++++------------- src/dm_geojson.f90 | 66 ++++++++++++++++++++--------------- src/dm_tty.f90 | 2 ++ 5 files changed, 115 insertions(+), 97 deletions(-) diff --git a/app/dmweb.f90 b/app/dmweb.f90 index 455cfbd..fde4179 100644 --- a/app/dmweb.f90 +++ b/app/dmweb.f90 @@ -602,39 +602,41 @@ subroutine route_logs(env) call dm_cgi_form(env, param) ! Read and validate parameters. - if (dm_is_error(dm_cgi_get(param, 'from', from)) .or. & - dm_is_error(dm_cgi_get(param, 'to', to)) .or. & - dm_is_error(dm_cgi_get(param, 'max_results', nresults))) then - call html_error('Missing or Invalid Parameters', error=E_INVALID) - exit response_block - end if + valid = .false. - valid = .true. + valid_block: block + ! Mandatory parameters. + if (dm_is_error(dm_cgi_get(param, 'from', from))) exit valid_block + if (dm_is_error(dm_cgi_get(param, 'to', to))) exit valid_block + if (dm_is_error(dm_cgi_get(param, 'max_results', nresults))) exit valid_block - ! Timestamps. - if (.not. dm_time_valid(from)) valid = .false. - if (.not. dm_time_valid(to)) valid = .false. + ! Timestamps. + if (.not. dm_time_valid(from)) exit valid_block + if (.not. dm_time_valid(to)) exit valid_block - ! Node id. - if (dm_is_ok(dm_cgi_get(param, 'node_id', node_id))) then - if (.not. dm_id_valid(node_id)) valid = .false. - end if + ! Node id. + if (dm_is_ok(dm_cgi_get(param, 'node_id', node_id))) then + if (.not. dm_id_valid(node_id)) exit valid_block + end if - ! Sensor id. - if (dm_is_ok(dm_cgi_get(param, 'sensor_id', sensor_id))) then - if (.not. dm_id_valid(sensor_id)) valid = .false. - end if + ! Sensor id. + if (dm_is_ok(dm_cgi_get(param, 'sensor_id', sensor_id))) then + if (.not. dm_id_valid(sensor_id)) exit valid_block + end if - ! Target id. - if (dm_is_ok(dm_cgi_get(param, 'target_id', target_id))) then - if (.not. dm_id_valid(target_id)) valid = .false. - end if + ! Target id. + if (dm_is_ok(dm_cgi_get(param, 'target_id', target_id))) then + if (.not. dm_id_valid(target_id)) exit valid_block + end if - ! Number of results. - if (.not. dm_array_has(max_results, nresults)) valid = .false. + ! Number of results. + if (.not. dm_array_has(max_results, nresults)) exit valid_block + + valid = .true. + end block valid_block if (.not. valid) then - call html_error('Invalid Parameters', error=E_INVALID) + call html_error('Missing or Invalid Parameters', error=E_INVALID) exit response_block end if @@ -724,6 +726,7 @@ subroutine route_map(env) integer :: i, rc integer :: nn, ns, nt + logical :: comma real(kind=r8) :: lon, lat type(db_type) :: db @@ -789,38 +792,29 @@ subroutine route_map(env) call dm_cgi_out('const lon = ' // dm_ftoa(lon) // ';') call dm_cgi_out('const lat = ' // dm_ftoa(lat) // ';') call dm_cgi_out('const zoom = 5;') - call dm_cgi_out('const features = [') + call dm_cgi_out('const geoJson = { "type": "FeatureCollection", "features": [') nn = size(nodes) ns = size(sensors) nt = size(targets) do i = 1, nn - if (i < nn .or. ns > 0 .or. nt > 0) then - call dm_cgi_out(dm_geojson_from(nodes(i)) // ',') - else - call dm_cgi_out(dm_geojson_from(nodes(i))) - end if + comma = (i < nn .or. ns > 0 .or. nt > 0) + call dm_cgi_out(dm_geojson_from(nodes(i), comma)) end do do i = 1, ns - if (i < ns .or. nt > 0) then - call dm_cgi_out(dm_geojson_from(sensors(i)) // ',') - else - call dm_cgi_out(dm_geojson_from(sensors(i))) - end if + comma = (i < ns .or. nt > 0) + call dm_cgi_out(dm_geojson_from(sensors(i), comma)) end do do i = 1, nt - if (i < nt) then - call dm_cgi_out(dm_geojson_from(targets(i)) // ',') - else - call dm_cgi_out(dm_geojson_from(targets(i))) - end if + comma = (i < nt) + call dm_cgi_out(dm_geojson_from(targets(i), comma)) end do - call dm_cgi_out('];') - call dm_cgi_out('createMap(id, url, lon, lat, zoom, features);') + call dm_cgi_out(']};') + call dm_cgi_out('createMap(id, url, lon, lat, zoom, geoJson);') call dm_cgi_out(H_SCRIPT_END) ! Output page footer. diff --git a/man/dmlog.1 b/man/dmlog.1 index 745a68e..8d39ed6 100644 --- a/man/dmlog.1 +++ b/man/dmlog.1 @@ -1,13 +1,13 @@ '\" t .\" Title: dmlog .\" Author: Philipp Engel -.\" Generator: Asciidoctor 2.0.16 -.\" Date: 2024-08-09 +.\" Generator: Asciidoctor 2.0.23 +.\" Date: 2024-08-10 .\" Manual: User Commands .\" Source: DMLOG .\" Language: English .\" -.TH "DMLOG" "1" "2024-08-09" "DMLOG" "User Commands" +.TH "DMLOG" "1" "2024-08-10" "DMLOG" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/share/dmweb/dmpack.js b/share/dmweb/dmpack.js index 37e39bb..6d8f650 100644 --- a/share/dmweb/dmpack.js +++ b/share/dmweb/dmpack.js @@ -8,18 +8,17 @@ * @param {number} lon - The longitude coordinate. * @param {number} lat - The latitude coordinate. * @param {number} zoom - The Leaflet zoom level. - * @param {array} features - Array of GeoJSON features. + * @param {array} geoJson - GeoJSON feature collection. */ -function createMap(id, url, lon, lat, zoom, features) +function createMap(id, url, lon, lat, zoom, geoJson) { const options = { attributionControl: false }; const view = { lat: lat, lng: lon }; - const maxZoom = 22; - const map = L.map(id, options).setView(view, zoom); + const maxZoom = { maxZoom: 24 }; - L.tileLayer(url, { maxZoom: maxZoom }).addTo(map); + const map = L.map(id, options).setView(view, zoom); - const geoJson = { "type": "FeatureCollection", "features": features }; + L.tileLayer(url, maxZoom).addTo(map); L.geoJson(geoJson, { pointToLayer, @@ -27,24 +26,39 @@ function createMap(id, url, lon, lat, zoom, features) }).addTo(map); } +/** + * Returns true if type is valid. + */ +function isValidType(type) +{ + return (type == 'node' || type == 'sensor' || type == 'target'); +} + /** * Leaflet callback function. */ function onEachFeature(feature, layer) { + const base = '/dmpack'; + let content = ''; if (feature.properties && feature.properties.type && feature.properties.data) { - if (feature.properties.data.name) + if (feature.properties.data.id && features.properties.data.name) { - content += `${feature.properties.data.name} (${feature.properties.type})
`; - } + let name; - if (feature.properties.data.meta) - { - content += feature.properties.data.meta; + if (isValidType(features.properties.type)) + name = `${feature.properties.data.name}`; + else + name = `${feature.properties.data.name}`; + + content += `${name} `; } + + content += `${feature.properties.type}
`; + if (feature.properties.data.meta) content += feature.properties.data.meta; } layer.bindPopup(content); @@ -55,6 +69,12 @@ function onEachFeature(feature, layer) */ function pointToLayer(feature, latlng) { + const colors = { + node: "gold", + sensor: "crimson", + target: "chartreuse" + }; + let options = { radius: 4, fillColor: "black", @@ -64,18 +84,8 @@ function pointToLayer(feature, latlng) fillOpacity: 0.8 }; - switch (feature.properties.type) - { - case 'node': - options.fillColor = "gold"; - break; - case 'sensor': - options.fillColor = "crimson"; - break; - case 'target': - options.fillColor = "chartreuse"; - break; - } + if (feature.properties && feature.properties.type && colors.hasOwnProperty(feature.properties.type)) + options.fillColor = colors[feature.properties.type]; return L.circleMarker(latlng, options); } diff --git a/src/dm_geojson.f90 b/src/dm_geojson.f90 index 3351353..cb5c869 100644 --- a/src/dm_geojson.f90 +++ b/src/dm_geojson.f90 @@ -40,7 +40,7 @@ module dm_geojson ! ****************************************************************** ! PUBLIC PROCEDURES. ! ****************************************************************** - subroutine dm_geojson_feature_point(geojson, type, lon, lat, alt, data) + subroutine dm_geojson_feature_point(geojson, type, lon, lat, alt, data, comma) !! Returns GeoJSON feature point of given DMPACK type, longitude, !! latitude, altitude, and type data in JSON. The output string !! `geojson` is of the following form: @@ -74,104 +74,116 @@ subroutine dm_geojson_feature_point(geojson, type, lon, lat, alt, data) !! ``` !! !! The property _data_ is set to the passed JSON string `data`. - character(len=:), allocatable, intent(out) :: geojson !! Output GeoJSON string. - integer, intent(in) :: type !! Point type (`TYPE_NODE`, `TYPE_SENSOR`, `TYPE_TARGET`). - real(kind=r8), intent(in) :: lon !! Point longitude (decimal). - real(kind=r8), intent(in) :: lat !! Point latitude (decimal). - real(kind=r8), intent(in) :: alt !! Point altitude. - character(len=*), intent(in) :: data !! Point JSON data. + character(len=:), allocatable, intent(out) :: geojson !! Output GeoJSON string. + integer, intent(in) :: type !! Point type (`TYPE_NODE`, `TYPE_SENSOR`, `TYPE_TARGET`). + real(kind=r8), intent(in) :: lon !! Point longitude (decimal). + real(kind=r8), intent(in) :: lat !! Point latitude (decimal). + real(kind=r8), intent(in) :: alt !! Point altitude. + character(len=*), intent(in) :: data !! Point JSON data. + logical, intent(in), optional :: comma !! Append comma separator. integer :: type_ + logical :: comma_ type_ = TYPE_NONE if (dm_type_valid(type)) type_ = type + comma_ = .false. + if (present(comma)) comma_ = comma + geojson = '{"type":"Feature","geometry":{"type":"Point","coordinates":[' // & dm_ftoa(lon) // ',' // dm_ftoa(lat) // ',' // dm_ftoa(alt) // & ']},"properties":{"type":"' // trim(TYPE_NAMES(type_)) // '","data":' // & trim(data) // '}}' + if (comma_) geojson = geojson // ',' end subroutine dm_geojson_feature_point ! ****************************************************************** ! PRIVATE PROCEDURES. ! ****************************************************************** - function geojson_from_node(node) result(geojson) + function geojson_from_node(node, comma) result(geojson) !! Returns node as allocatable string in GeoJSON format. use :: dm_node, only: node_type - type(node_type), intent(inout) :: node !! Node type. - character(len=:), allocatable :: geojson !! GeoJSON string. + type(node_type), intent(inout) :: node !! Node type. + logical, intent(in), optional :: comma !! Append comma separator. + character(len=:), allocatable :: geojson !! GeoJSON string. - call dm_geojson_feature_point(geojson, TYPE_NODE, node%lon, node%lat, node%alt, dm_json_from(node)) + call dm_geojson_feature_point(geojson, TYPE_NODE, node%lon, node%lat, node%alt, dm_json_from(node), comma) end function geojson_from_node - function geojson_from_sensor(sensor) result(geojson) + function geojson_from_sensor(sensor, comma) result(geojson) !! Returns sensor as allocatable string in GeoJSON format. use :: dm_sensor, only: sensor_type - type(sensor_type), intent(inout) :: sensor !! Sensor type. - character(len=:), allocatable :: geojson !! GeoJSON string. + type(sensor_type), intent(inout) :: sensor !! Sensor type. + logical, intent(in), optional :: comma !! Append comma separator. + character(len=:), allocatable :: geojson !! GeoJSON string. - call dm_geojson_feature_point(geojson, TYPE_SENSOR, sensor%lon, sensor%lat, sensor%alt, dm_json_from(sensor)) + call dm_geojson_feature_point(geojson, TYPE_SENSOR, sensor%lon, sensor%lat, sensor%alt, dm_json_from(sensor), comma) end function geojson_from_sensor - function geojson_from_target(target) result(geojson) + function geojson_from_target(target, comma) result(geojson) !! Returns target as allocatable string in GeoJSON format. use :: dm_target, only: target_type - type(target_type), intent(inout) :: target !! Target type. - character(len=:), allocatable :: geojson !! GeoJSON string. + type(target_type), intent(inout) :: target !! Target type. + logical, intent(in), optional :: comma !! Append comma separator. + character(len=:), allocatable :: geojson !! GeoJSON string. - call dm_geojson_feature_point(geojson, TYPE_TARGET, target%lon, target%lat, target%alt, dm_json_from(target)) + call dm_geojson_feature_point(geojson, TYPE_TARGET, target%lon, target%lat, target%alt, dm_json_from(target), comma) end function geojson_from_target - integer function geojson_write_node(node, unit) result(rc) + integer function geojson_write_node(node, unit, comma) result(rc) !! Writes node to file or standard output. use :: dm_node, only: node_type - type(node_type), intent(inout) :: node !! Node type. - integer, intent(in), optional :: unit !! File unit. + type(node_type), intent(inout) :: node !! Node type. + integer, intent(in), optional :: unit !! File unit. + logical, intent(in), optional :: comma !! Append comma separator. integer :: stat, unit_ rc = E_WRITE unit_ = stdout if (present(unit)) unit_ = unit - write (unit_, '(a)', iostat=stat) dm_geojson_from(node) + write (unit_, '(a)', iostat=stat) dm_geojson_from(node, comma) if (stat /= 0) return rc = E_NONE end function geojson_write_node - integer function geojson_write_sensor(sensor, unit) result(rc) + integer function geojson_write_sensor(sensor, unit, comma) result(rc) !! Writes sensor to file or standard output. use :: dm_sensor, only: sensor_type type(sensor_type), intent(inout) :: sensor !! Sensor type. integer, intent(in), optional :: unit !! File unit. + logical, intent(in), optional :: comma !! Append comma separator. integer :: stat, unit_ rc = E_WRITE unit_ = stdout if (present(unit)) unit_ = unit - write (unit_, '(a)', iostat=stat) dm_geojson_from(sensor) + write (unit_, '(a)', iostat=stat) dm_geojson_from(sensor, comma) if (stat /= 0) return rc = E_NONE end function geojson_write_sensor - integer function geojson_write_target(target, unit) result(rc) + integer function geojson_write_target(target, unit, comma) result(rc) !! Writes target to file or standard output. use :: dm_target, only: target_type type(target_type), intent(inout) :: target !! Target type. integer, intent(in), optional :: unit !! File unit. + logical, intent(in), optional :: comma !! Append comma separator. integer :: stat, unit_ rc = E_WRITE unit_ = stdout if (present(unit)) unit_ = unit - write (unit_, '(a)', iostat=stat) dm_geojson_from(target) + write (unit_, '(a)', iostat=stat) dm_geojson_from(target, comma) if (stat /= 0) return rc = E_NONE end function geojson_write_target diff --git a/src/dm_tty.f90 b/src/dm_tty.f90 index 6ffa14e..0311943 100644 --- a/src/dm_tty.f90 +++ b/src/dm_tty.f90 @@ -279,9 +279,11 @@ integer function dm_tty_open(tty, path, baud_rate, byte_size, parity, stop_bits) tty%fd = c_open(trim(tty%path) // c_null_char, flags, 0_c_mode_t) if (tty%fd < 0) return + ! Set TTY attributes. rc = dm_tty_set_attributes(tty) if (dm_is_error(rc)) return + ! Flush input and output buffer. rc = dm_tty_flush(tty) end function dm_tty_open