diff --git a/etc/manta-12.ini b/etc/manta-12.ini index 926a9b5778..dc732d8257 100644 --- a/etc/manta-12.ini +++ b/etc/manta-12.ini @@ -24,37 +24,166 @@ # https://github.com/LSTS/dune/blob/master/LICENCE.md and # # http://ec.europa.eu/idabc/eupl.html. # ############################################################################ -# Author: Ricardo Martins # +# Author: Pedro Gonçalves # +# Author: Bernardo Gabriel # ############################################################################ [Require hardware/lctr-a9xx.ini] -[Require hardware/radio.ini] [General] Vehicle = manta-12 [Power.MCBv2] -ADC Reference Voltage = 1.1 +Debug Level = None Drive LCD = true -Power Channel 2 - Name = Ethernet Switch -Power Channel 2 - State = 1 -Power Channel 9 - Name = N/C (HUB_4) -Power Channel 9 - State = 0 -Power Channel 10 - Name = Iridium -Power Channel 10 - State = 1 +Use Counter System Off = true +ADC Reference Voltage = 1.077 +ADC Channel 1 - Message = Current +ADC Channel 1 - Entity Label = Charger +ADC Channel 1 - Conversion = 9.4908, 0.0 +ADC Channel 3 - Message = Current +ADC Channel 3 - Entity Label = Main Board +ADC Channel 3 - Conversion = 9.4908, 0.0 +# Private channels. +Power Channel 0 - Name = Private (ATX) +Power Channel 0 - State = 1 +Power Channel 8 - Name = Private (CPU) +Power Channel 8 - State = 1 +# User controllable channels. +Power Channel 1 - Name = LTE (+12V_2) +Power Channel 1 - State = 1 +Power Channel 3 - Name = POE 3 +Power Channel 3 - State = 1 +Power Channel 4 - Name = POE 2 +Power Channel 4 - State = 1 +Power Channel 5 - Name = POE 1 +Power Channel 5 - State = 1 +Power Channel 6 - Name = Modem Power 2 +Power Channel 6 - State = 1 +Power Channel 7 - Name = Modem Power 1 +Power Channel 7 - State = 1 +Power Channel 13 - Name = Switch Ethernet +Power Channel 13 - State = 1 +# Not connected. +Power Channel 2 - Name = N/C (+12V_1) +Power Channel 9 - Name = N/C (+5V_5) +Power Channel 10 - Name = N/C (+5V_4) +Power Channel 11 - Name = N/C (+5V_3) +Power Channel 12 - Name = N/C (+5V_2) +Power Channel 14 - Name = N/C (Bat_Out_3) +[Sensors.GPS] +Enabled = Hardware +Entity Label = GPS +Activation Time = 3.0 +IO Port - Device = uart:///dev/ttyGPS:115200 + +[Supervisors.ClockPPS] +Enabled = Never + +[Monitors.Clock] +Enabled = Hardware +Entity Label = Clock +Minimum GPS Fixes = 30 +Maximum Clock Offset = 2 +Boot Synchronization Timeout = 60 +Hardware Clock Synchronization Command = hwclock -w + +[Transports.MobileInternet] +Enabled = Never [Transports.IridiumSBD] Enabled = Hardware +Debug Level = None Entity Label = Iridium Modem -Serial Port - Device = /dev/ttyUSB0 +Serial Port - Device = /dev/ttyIRIDIUM Serial Port - Baud Rate = 19200 +Use 9523N Module = false +Serial Port 9523 - Baud Rate = 115200 Mailbox Check - Periodicity = 1800 [Transports.Iridium] +Enabled = Hardware + +[UserInterfaces.Buttons] Enabled = Never -Entity Label = Iridium Transport -Device updates - Periodicity = 1200 + +[UserInterfaces.ButtonsRPI] +Enabled = Hardware +Entity Label = Buttons RPI +Debug Level = None +Button 0 = 17 +Button 1 = 27 +Button 2 = 22 +Gpio Work Path = /sys/class/gpio/ + +[UserInterfaces.MantaPanel] +Enabled = Hardware +Entity Label = Panel +Command - On Power Down = service syslog stop +Command - On Power Down Abort = service syslog restart +Power Channel - CPU = System + +[Monitors.MantaFuelLevel] +Enabled = Always +Execution Frequency = 0.2 +Fuel Level 1 = 29.4 +Fuel Level 2 = 28.1 +Fuel Level 3 = 26.8 +Fuel Level 4 = 24.47 +Fuel Level 5 = 22.8 +Entity Label - FuelLevel = FuelLevel +Entity Label for Main Voltage = Main Board +Entity Label for Charger Current = Charger +Current Value Charger Reject = 0.2 +Entity Label = Manta Fuel Level + +[Sensors.ThermalZone] +Enabled = Hardware +Entity Label = Thermal Zone +Execution Frequency = 1 +Path = /sys/class/thermal/thermal_zone0/temp +Entity Label - Temperature = Mainboard (Core) + +[Transports.GSM] +Enabled = Hardware +Entity Label = GSM +Activation Time = 10 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Serial Port - Device = /dev/ttyUSB4 +Serial Port - Baud Rate = 115200 +Reply Timeout = 4.0 +RSSI Periodicity = 60 +Read SMS Periodicity = 10 +SMS Send Timeout = 60 +Request Balance = false +USSD code = 111 + +[Monitors.Emergency] +Enabled = Hardware +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = false +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 60 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +Transmission Interface = GSM +Debug Level = None + +[Autonomy.TextActions] +Enabled = Hardware +Valid Commands = errors, + info, + help, + phone, +Debug Level = None #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] @@ -69,6 +198,5 @@ Device updates - Periodicity = 1200 #[Require hardware/acoustic-modems/evologics_ip_5.ini] #[Require hardware/acoustic-modems/evologics_ip_6.ini] -# For UPORTO / PT-NAVY joint exercises -#[Require testing/joint-umodem.ini] -#[Require testing/joint-evologics.ini] +[Transports.Seatrac] +Serial Port - Device = /dev/ttyEXT diff --git a/src/Power/MCBv2/Task.cpp b/src/Power/MCBv2/Task.cpp index 227a8ed17a..f072886c8f 100644 --- a/src/Power/MCBv2/Task.cpp +++ b/src/Power/MCBv2/Task.cpp @@ -66,6 +66,8 @@ namespace Power static const unsigned c_pwrs_count = 17; //! Id of the backlight power channel. static const unsigned c_pwr_blight = 16; + //! Minimum of readings before power off system + static const unsigned c_minimum_reads_sys_off = 5; //! Commands to the device. enum Commands @@ -129,6 +131,8 @@ namespace Power unsigned pwr_states[c_pwrs_count]; //! True to drived LCD from MCB. bool lcd; + //! True to activate counter for system off readings + bool counter_sys_off; }; struct Task: public Tasks::Task @@ -153,6 +157,8 @@ namespace Power IMC::Message* m_adcs[c_adcs_count]; //! Power channels by name. PowerChannelMap m_pwr_chs; + //! Counter to control Power Off + uint8_t m_counter_sys_off; Task(const std::string& name, Tasks::Context& ctx): Tasks::Task(name, ctx), @@ -208,6 +214,10 @@ namespace Power .defaultValue("false") .description("LCD is controlled by MCB"); + param("Use Counter System Off", m_args.counter_sys_off) + .defaultValue("false") + .description("True to activate counter for system off readings."); + // Register consumers. bind(this); bind(this); @@ -334,6 +344,8 @@ namespace Power else controlPowerChannel(itr->second, IMC::PowerChannelControl::PCC_OP_TURN_OFF); } + + m_counter_sys_off = 0; } //! Write value to position in a given buffer. @@ -522,12 +534,34 @@ namespace Power // Check power off. if ((data[8] & BIT_SW_SYS_ON) == 0) { - m_pwr_down = true; - IMC::PowerOperation pop; - pop.setDestination(getSystemId()); - pop.op = IMC::PowerOperation::POP_PWR_DOWN_IP; - pop.time_remain = (float)(data[8] & 0x1F); - dispatch(pop); + if(m_args.counter_sys_off) + { + if(m_counter_sys_off >= c_minimum_reads_sys_off) + { + m_pwr_down = true; + IMC::PowerOperation pop; + pop.setDestination(getSystemId()); + pop.op = IMC::PowerOperation::POP_PWR_DOWN_IP; + pop.time_remain = (float)(data[8] & 0x1F); + dispatch(pop); + debug("power down sys"); + } + else + { + debug("counter int :%d", m_counter_sys_off); + m_counter_sys_off++; + } + } + else + { + m_pwr_down = true; + IMC::PowerOperation pop; + pop.setDestination(getSystemId()); + pop.op = IMC::PowerOperation::POP_PWR_DOWN_IP; + pop.time_remain = (float)(data[8] & 0x1F); + dispatch(pop); + debug("power down sys"); + } } else if (m_pwr_down) { @@ -536,6 +570,15 @@ namespace Power pop.setDestination(getSystemId()); pop.op = IMC::PowerOperation::POP_PWR_DOWN_ABORTED; dispatch(pop); + m_counter_sys_off = 0; + } + else + { + if(m_counter_sys_off > 0 && m_args.counter_sys_off) + { + debug("counter reset"); + m_counter_sys_off = 0; + } } } (void)data_size; diff --git a/src/Transports/CommManager/Task.cpp b/src/Transports/CommManager/Task.cpp index 5cc54e16a4..ac129e0336 100644 --- a/src/Transports/CommManager/Task.cpp +++ b/src/Transports/CommManager/Task.cpp @@ -298,7 +298,7 @@ namespace Transports if (msg->getDestinationEntity() != getEntityId()) return; - auto tr_list = m_router.getList(); + std::map& tr_list = m_router.getList(); if (tr_list.find(msg->req_id) != tr_list.end()) { @@ -349,7 +349,7 @@ namespace Transports if (msg->getSource() != getSystemId()) return; - auto tr_list = m_router.getList(); + std::map& tr_list = m_router.getList(); if (tr_list.find(msg->req_id) != tr_list.end()) { @@ -399,7 +399,7 @@ namespace Transports return; } - auto tr_list = m_router.getList(); + std::map& tr_list = m_router.getList(); if (tr_list.find(msg->req_id) != tr_list.end()) { @@ -617,7 +617,7 @@ namespace Transports if (msg->getSource() != getSystemId()) return; - auto tr_list = m_router.getList(); + std::map& tr_list = m_router.getList(); if (tr_list.find(msg->req_id) != tr_list.end()) { diff --git a/src/Transports/GSM/Driver.hpp b/src/Transports/GSM/Driver.hpp index 87017e08a8..173ba7d6b0 100644 --- a/src/Transports/GSM/Driver.hpp +++ b/src/Transports/GSM/Driver.hpp @@ -345,8 +345,17 @@ namespace Transports if (header == "OK") return false; + if (String::startsWith(header, "+CMTI:")) + { + getTask()->spew("Ignoring unsolicited message notification (+CMTI)"); + header = readLine(); + } + if (!String::startsWith(header, "+CMGL:")) + { + getTask()->spew("Fail: Data string to parse: %s",header.c_str()); throw Hardware::UnexpectedReply(); + } std::vector parts; String::split(header, ",", parts); diff --git a/src/Transports/GSM/Task.cpp b/src/Transports/GSM/Task.cpp index a45559d024..e2a2a95799 100644 --- a/src/Transports/GSM/Task.cpp +++ b/src/Transports/GSM/Task.cpp @@ -326,13 +326,16 @@ namespace Transports void processQueue(void) { + char entity_state_text[128]; if (m_queue.empty()) { - setEntityState(IMC::EntityState::ESTA_NORMAL, getMessage(Status::CODE_IDLE).c_str()); + std::sprintf(entity_state_text, "active | %s:%d | queue empty", m_args.uart_dev.c_str(), m_args.uart_baud); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(entity_state_text))); return; } - setEntityState(IMC::EntityState::ESTA_NORMAL, getMessage(Status::CODE_ACTIVE).c_str()); + std::sprintf(entity_state_text, "active | %s:%d | queue size %d", m_args.uart_dev.c_str(), m_args.uart_baud, (int)m_queue.size()); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(entity_state_text))); SmsRequest sms_req = m_queue.top(); m_queue.pop(); @@ -371,8 +374,7 @@ namespace Transports m_rssi_timer.reset(); m_rssi = m_driver->getRSSI(); } - - if (m_rsms_timer.overflow()) + else if (m_rsms_timer.overflow()) { m_rsms_timer.reset(); m_driver->checkMessages(); diff --git a/src/UserInterfaces/ButtonsRPI/Task.cmake b/src/UserInterfaces/ButtonsRPI/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/UserInterfaces/ButtonsRPI/Task.cpp b/src/UserInterfaces/ButtonsRPI/Task.cpp new file mode 100644 index 0000000000..785b536ef9 --- /dev/null +++ b/src/UserInterfaces/ButtonsRPI/Task.cpp @@ -0,0 +1,241 @@ +//*************************************************************************** +// Copyright 2007-2024 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Gonçalves * +//*************************************************************************** + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +namespace UserInterfaces +{ + namespace ButtonsRPI + { + using DUNE_NAMESPACES; + + static const int c_number_max_button = 3; + + struct Arguments + { + //! Gpio Number for buttons + int gpio_bt[c_number_max_button]; + //! Work path for gpio manipulation + std::string gpio_work_path; + }; + + struct Task: public Tasks::Task + { + // Button event. + IMC::ButtonEvent m_button_event; + // Task Arguments. + Arguments m_args; + // Buttons State + bool isLastStateHigh[c_number_max_button]; + + Task(const std::string& name, Tasks::Context& ctx): + Tasks::Task(name, ctx) + { + for(uint8_t t = 0; t < c_number_max_button; t++) + { + std::string option = String::str("Button %u", t); + param(option, m_args.gpio_bt[t]) + .description("User Buttons."); + } + + param("Gpio Work Path", m_args.gpio_work_path) + .description("Work path for Gpio manipulation."); + } + + void + onResourceInitialization(void) + { + for(uint8_t t = 0; t < c_number_max_button; t++) + { + if(!exportGpio(m_args.gpio_bt[t])) + { + std::string m_error_text = String::str("Cannot acess to export of pin %d", m_args.gpio_bt[t]); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + throw RestartNeeded(m_error_text, 5); + } + else + { + if(!setGpioDirection(m_args.gpio_bt[t], true)) + { + std::string m_error_text = String::str("Cannot set direction of pin %d", m_args.gpio_bt[t]); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + throw RestartNeeded(m_error_text, 5); + } + } + isLastStateHigh[t] = false; + } + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + void + onResourceRelease(void) + { + for(uint8_t t = 0; t < c_number_max_button; t++) + { + if(!unexportGpio(m_args.gpio_bt[t])) + { + std::string m_error_text = String::str("Cannot acess to unexport of pin %d", m_args.gpio_bt[t]); + debug("%s", m_error_text.c_str()); + } + } + } + + bool + exportGpio(int gpio) + { + std::string path = m_args.gpio_work_path + "/export"; + int result = open (path.c_str(), O_WRONLY); + if (result ==-1) + { + err("Error open export file for pin %d ", gpio); + return false; + } + char buffer[3]; + std::snprintf(buffer, 3, "%d", gpio); + if(write(result, buffer, 3) == -1) + { + close(result); + return false; + } + close(result); + return true; + } + + bool + unexportGpio(int gpio) + { + std::string path = m_args.gpio_work_path + "/unexport"; + int result = open (path.c_str(), O_WRONLY); + if (result==-1) + { + war("Error open unexport file for pin %d ", gpio); + return false; + } + char buffer[3]; + std::snprintf(buffer, 3, "%d", gpio); + if(write(result, buffer, 3) == -1) + { + close(result); + return false; + } + return true; + } + + bool + setGpioDirection(int gpio, bool isInput) + { + char path[64]; + std::snprintf(path, 35, "%s/gpio%d/direction", m_args.gpio_work_path.c_str(), gpio); + int result = open (path, O_WRONLY); + if (result == -1) + { + err("Error open direction file for pin %d ", gpio); + return false; + } + char buffer[3]; + std::snprintf(buffer, 3, "%d", gpio); + if (write(result, ((isInput == true)?"in":"out"),3 ) ==-1) + { + close(result); + return false; + } + close(result); + return true; + } + + bool + isGpioHigh(int gpio) + { + char path[64]; + std::snprintf(path, 35, "%s/gpio%d/value", m_args.gpio_work_path.c_str(), gpio); + int result = open(path, O_RDONLY); + if (result == -1) + { + spew("Error open file value of pin %d", gpio); + return false; + } + char buffer[3]; + if (read(result, buffer, 3) == -1) + { + spew("Error reading value of pin %d", gpio); + close(result); + return false; + } + close(result); + return ((buffer[0] == '1')?true:false); + } + + void + checkButtonsState(void) + { + for (uint8_t t = 0; t < c_number_max_button; t++) + { + if (isGpioHigh(m_args.gpio_bt[t])) + { + if(!isLastStateHigh[t]) + { + isLastStateHigh[t] = true; + spew("button %d set High", m_args.gpio_bt[t]); + m_button_event.button = t; + m_button_event.value = 1; + dispatch(m_button_event); + } + } + else + { + if(isLastStateHigh[t]) + { + isLastStateHigh[t] = false; + spew("button %d set low", m_args.gpio_bt[t]); + m_button_event.button = t; + m_button_event.value = 0; + dispatch(m_button_event); + } + } + } + } + + void + onMain(void) + { + while (!stopping()) + { + Delay::waitMsec(50); + checkButtonsState(); + } + } + }; + } +} + +DUNE_TASK