diff --git a/application/.cproject b/application/.cproject index ec67505..6312112 100644 --- a/application/.cproject +++ b/application/.cproject @@ -193,44 +193,44 @@ - @@ -368,4 +369,5 @@ + diff --git a/application/Release/makefile b/application/Release/makefile index 9261951..385b984 100644 --- a/application/Release/makefile +++ b/application/Release/makefile @@ -61,7 +61,7 @@ all: ais_transponder.elf secondary-outputs ais_transponder.elf: $(OBJS) $(USER_OBJS) @echo 'Building target: $@' @echo 'Invoking: Cross ARM C++ Linker' - arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -flto -Wall -Wextra -g -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"ais_transponder.map" --specs=nano.specs -u _printf_float -o "ais_transponder.elf" $(OBJS) $(USER_OBJS) $(LIBS) + arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -flto -Wall -Wextra -g -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -s -L"../ldscripts" -Wl,-Map,"ais_transponder.map" --specs=nano.specs -o "ais_transponder.elf" $(OBJS) $(USER_OBJS) $(LIBS) @echo 'Finished building target: $@' @echo ' ' diff --git a/application/src/CommandProcessor.cpp b/application/src/CommandProcessor.cpp index d1120ec..51840b5 100644 --- a/application/src/CommandProcessor.cpp +++ b/application/src/CommandProcessor.cpp @@ -12,11 +12,11 @@ #include "globals.h" #include "stm32f30x.h" - -CommandProcessor &CommandProcessor::instance() +CommandProcessor & +CommandProcessor::instance() { - static CommandProcessor __instance; - return __instance; + static CommandProcessor __instance; + return __instance; } CommandProcessor::CommandProcessor() @@ -24,267 +24,291 @@ CommandProcessor::CommandProcessor() } -void CommandProcessor::init() +void +CommandProcessor::init() { - EventQueue::instance().addObserver(this, REQUEST_EVENT|RESET_EVENT); + EventQueue::instance ().addObserver (this, REQUEST_EVENT | RESET_EVENT); } -void CommandProcessor::processEvent(const Event &e) +void +CommandProcessor::processEvent(const Event &e) { - if ( e.type == RESET_EVENT ) { - NVIC_SystemReset (); - return; - } - - switch(e.request.operation) { - case OP_GET: - if ( strcmp(e.request.field, "mmsi") == 0 ) - returnMMSI(); - else if ( strcmp(e.request.field, "name") == 0 ) - returnName(); - else if ( strcmp(e.request.field, "callsign") == 0 ) - returnCallSign(); - else if ( strcmp(e.request.field, "beam") == 0 ) - returnBeam(); - else if ( strcmp(e.request.field, "length") == 0 ) - returnLength(); - else if ( strcmp(e.request.field, "mode") == 0 ) - returnMode(); - else if ( strcmp(e.request.field, "vesseldata") == 0 ) - returnVesselData(); - else if ( strcmp(e.request.field, "version") == 0 ) - returnVersion(); - else if ( strcmp(e.request.field, "status") == 0 ) - returnStatus(); - else - sendError("Unknown field"); - break; - case OP_SET: - if ( strcmp(e.request.field, "mmsi") == 0 ) - setMMSI(atoi(e.request.value)); - else if ( strcmp(e.request.field, "name") == 0 ) - setName(e.request.value); - else if ( strcmp(e.request.field, "callsign") == 0 ) - setCallSign(e.request.value); - else if ( strcmp(e.request.field, "beam") == 0 ) - setBeam(atoi(e.request.value)); - else if ( strcmp(e.request.field, "length") == 0 ) - setLength(atoi(e.request.value)); - else if ( strcmp(e.request.field, "mode") == 0 ) - setMode(e.request.value); - else if ( strcmp(e.request.field, "vesseldata") == 0 ) - setVesselData(e.request.value); - else - sendError("Unknown field"); - break; - - } -} - -void CommandProcessor::sendError(const char *err) -{ - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = false; - strcpy(reply->response.data, err); - EventQueue::instance().push(reply); -} - -void CommandProcessor::sendEmptyReply(bool success) -{ - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = success; - reply->response.data[0] = 0; - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnVersion() -{ - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - strcpy(reply->response.data, REVISION); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnMMSI() -{ - StationData data; - EEPROM::instance().readStationData(data); - - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - sprintf(reply->response.data, "%lu", data.mmsi); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnCallSign() -{ - StationData data; - EEPROM::instance().readStationData(data); - - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - sprintf(reply->response.data, "%s", data.callsign); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnName() -{ - StationData data; - EEPROM::instance().readStationData(data); - - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - sprintf(reply->response.data, "%s", data.name); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnBeam() -{ - StationData data; - EEPROM::instance().readStationData(data); - - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - sprintf(reply->response.data, "%d", data.beam); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnLength() -{ - StationData data; - EEPROM::instance().readStationData(data); - - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - sprintf(reply->response.data, "%d", data.len); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnMode() -{ -} - -void CommandProcessor::returnVesselData() -{ - StationData data; - EEPROM::instance().readStationData(data); - - Event *reply = EventPool::instance().newEvent(RESPONSE_EVENT); - reply->response.success = true; - - sprintf(reply->response.data, "%lu,%s,%s,%d,%d", data.mmsi, data.name, data.callsign, data.beam, data.len); - EventQueue::instance().push(reply); -} - -void CommandProcessor::returnStatus() -{ -} - -void CommandProcessor::setMMSI(uint32_t mmsi) -{ - StationData data; - EEPROM::instance().readStationData(data); - data.mmsi = mmsi; - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); -} - -void CommandProcessor::setName(const char* name) -{ - StationData data; - EEPROM::instance().readStationData(data); - strcpy(data.name, name); - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); -} - -void CommandProcessor::setCallSign(const char *callsign) -{ - StationData data; - EEPROM::instance().readStationData(data); - strcpy(data.callsign, callsign); - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); -} - -void CommandProcessor::setBeam(uint8_t beam) -{ - StationData data; - EEPROM::instance().readStationData(data); - data.beam = beam; - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); -} - -void CommandProcessor::setLength(uint8_t len) -{ - StationData data; - EEPROM::instance().readStationData(data); - data.len = len; - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); -} - -void CommandProcessor::setVesselData(const char *s) -{ - StationData data; - EEPROM::instance().readStationData(data); - int items = sscanf(s, "%lu,%s,%s,%cu,%cu", &data.mmsi, data.name, data.callsign, &data.beam, &data.len); - if ( items < 5 ) - sendEmptyReply(false); - else { - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); - } -} - -void CommandProcessor::setMode(const char *mode) -{ - if (strcmp (mode, "dfu") == 0) - { - FLASH_Unlock (); - FLASH_Status status = FLASH_WaitForLastOperation (FLASH_ER_PRG_TIMEOUT); - if ( status != FLASH_COMPLETE ) { - sendError("Unable to unlock flash"); - return; - } - - FLASH_ErasePage (METADATA_ADDRESS); - status = FLASH_WaitForLastOperation (FLASH_ER_PRG_TIMEOUT); - if ( status != FLASH_COMPLETE ) { - sendError("Unable to erase metadata page"); - return; - } - - FLASH_Lock (); - FLASH_WaitForLastOperation (FLASH_ER_PRG_TIMEOUT); - if ( status != FLASH_COMPLETE ) { - sendError("Unable to lock flash"); - return; - } - - //sendEmptyReply (true); - Event *e = EventPool::instance().newEvent(RESET_EVENT); - EventQueue::instance().push(e); + if (e.type == RESET_EVENT) { + NVIC_SystemReset (); + return; + } + + switch (e.request.operation) { + case OP_GET: + if (strcmp (e.request.field, "mmsi") == 0) + returnMMSI (); + else if (strcmp (e.request.field, "name") == 0) + returnName (); + else if (strcmp (e.request.field, "callsign") == 0) + returnCallSign (); + else if (strcmp (e.request.field, "beam") == 0) + returnBeam (); + else if (strcmp (e.request.field, "length") == 0) + returnLength (); + else if (strcmp (e.request.field, "mode") == 0) + returnMode (); + else if (strcmp (e.request.field, "vesseldata") == 0) + returnVesselData (); + else if (strcmp (e.request.field, "version") == 0) + returnVersion (); + else if (strcmp (e.request.field, "status") == 0) + returnStatus (); + else + sendError ("Unknown field"); + break; + case OP_SET: + if (strcmp (e.request.field, "mmsi") == 0) + setMMSI (atoi (e.request.value)); + else if (strcmp (e.request.field, "name") == 0) + setName (e.request.value); + else if (strcmp (e.request.field, "callsign") == 0) + setCallSign (e.request.value); + else if (strcmp (e.request.field, "beam") == 0) + setBeam (atoi (e.request.value)); + else if (strcmp (e.request.field, "length") == 0) + setLength (atoi (e.request.value)); + else if (strcmp (e.request.field, "mode") == 0) + setMode (e.request.value); + else if (strcmp (e.request.field, "vesseldata") == 0) + setVesselData (e.request.value); + else + sendError ("Unknown field"); + break; + } - else if ( strcmp(mode, "rx") == 0 ) { - StationData data; - EEPROM::instance().readStationData(data); - data.flags |= STATION_RX_ONLY; - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); - } - else if ( strcmp(mode, "trx") == 0 ) { - StationData data; - EEPROM::instance().readStationData(data); - data.flags &= ~(STATION_RX_ONLY); - EEPROM::instance().writeStationData(data); - sendEmptyReply(true); - } - else - sendError("Unrecognized mode"); } +void +CommandProcessor::sendError(const char *err) +{ + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = false; + strcpy (reply->response.data, err); + EventQueue::instance ().push (reply); +} +void +CommandProcessor::sendEmptyReply(bool success) +{ + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = success; + reply->response.data[0] = 0; + EventQueue::instance ().push (reply); +} +void +CommandProcessor::returnVersion() +{ + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + strcpy (reply->response.data, REVISION); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnMMSI() +{ + StationData data; + EEPROM::instance ().readStationData (data); + + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + sprintf (reply->response.data, "%lu", data.mmsi); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnCallSign() +{ + StationData data; + EEPROM::instance ().readStationData (data); + + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + sprintf (reply->response.data, "%s", data.callsign); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnName() +{ + StationData data; + EEPROM::instance ().readStationData (data); + + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + sprintf (reply->response.data, "%s", data.name); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnBeam() +{ + StationData data; + EEPROM::instance ().readStationData (data); + + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + sprintf (reply->response.data, "%d", data.beam); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnLength() +{ + StationData data; + EEPROM::instance ().readStationData (data); + + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + sprintf (reply->response.data, "%d", data.len); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnMode() +{ +} + +void +CommandProcessor::returnVesselData() +{ + StationData data; + EEPROM::instance ().readStationData (data); + + Event *reply = EventPool::instance ().newEvent (RESPONSE_EVENT); + reply->response.success = true; + + sprintf (reply->response.data, "%lu,%s,%s,%d,%d", data.mmsi, data.name, + data.callsign, data.beam, data.len); + EventQueue::instance ().push (reply); +} + +void +CommandProcessor::returnStatus() +{ +} + +void +CommandProcessor::setMMSI(uint32_t mmsi) +{ + StationData data; + EEPROM::instance ().readStationData (data); + data.mmsi = mmsi; + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); +} + +void +CommandProcessor::setName(const char* name) +{ + StationData data; + EEPROM::instance ().readStationData (data); + strncpy (data.name, name, sizeof data.name); + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); +} + +void +CommandProcessor::setCallSign(const char *callsign) +{ + StationData data; + EEPROM::instance ().readStationData (data); + strncpy (data.callsign, callsign, sizeof data.callsign); + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); +} + +void +CommandProcessor::setBeam(uint8_t beam) +{ + StationData data; + EEPROM::instance ().readStationData (data); + data.beam = beam; + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); +} + +void +CommandProcessor::setLength(uint8_t len) +{ + StationData data; + EEPROM::instance ().readStationData (data); + data.len = len; + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); +} + +void +CommandProcessor::setVesselData(const char *s) +{ + StationData data; + EEPROM::instance ().readStationData (data); + + /* + * TODO: Add to/from CSV methods in StationData and use tokenization instead of sscanf() + */ + int items = sscanf (s, "%lu,%s,%s,%cu,%cu", &data.mmsi, data.name, data.callsign, &data.beam, &data.len); + if (items < 5) + sendEmptyReply (false); + else { + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); + } +} + +void +CommandProcessor::setMode(const char *mode) +{ + if (strcmp (mode, "dfu") == 0) { + FLASH_Unlock (); + FLASH_Status status = FLASH_WaitForLastOperation (FLASH_ER_PRG_TIMEOUT); + if (status != FLASH_COMPLETE) { + sendError ("Unable to unlock flash"); + return; + } + + FLASH_ErasePage (METADATA_ADDRESS); + status = FLASH_WaitForLastOperation (FLASH_ER_PRG_TIMEOUT); + if (status != FLASH_COMPLETE) { + sendError ("Unable to erase metadata page"); + return; + } + + FLASH_Lock (); + FLASH_WaitForLastOperation (FLASH_ER_PRG_TIMEOUT); + if (status != FLASH_COMPLETE) { + sendError ("Unable to lock flash"); + return; + } + + /* + * UART takes a while to send reply, so unless we add considerable delay here, it won't make it before MCU reset + */ + //sendEmptyReply (true); + Event *e = EventPool::instance ().newEvent (RESET_EVENT); + EventQueue::instance ().push (e); + } + else if (strcmp (mode, "rx") == 0) { + StationData data; + EEPROM::instance ().readStationData (data); + data.flags |= STATION_RX_ONLY; + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); + } + else if (strcmp (mode, "trx") == 0) { + StationData data; + EEPROM::instance ().readStationData (data); + data.flags &= ~(STATION_RX_ONLY); + EEPROM::instance ().writeStationData (data); + sendEmptyReply (true); + } + else + sendError ("Unrecognized mode"); +} diff --git a/application/src/EventQueue.cpp b/application/src/EventQueue.cpp index 00eab24..d6337dd 100644 --- a/application/src/EventQueue.cpp +++ b/application/src/EventQueue.cpp @@ -57,11 +57,13 @@ void EventQueue::dispatch() if (mQueue->pop(e)) { for ( map::iterator c = mConsumers.begin(); c != mConsumers.end(); ++c ) { - // Utils::delay(1000); if ( c->second & e->type ) c->first->processEvent(*e); } + EventPool::instance().deleteEvent(e); + + // TODO: Make LEDManager an EventConsumer instead if ( e->type == AIS_PACKET_EVENT ) LEDManager::instance().blink(LEDManager::GREEN_LED); } diff --git a/application/src/TXScheduler.cpp b/application/src/TXScheduler.cpp index 7678380..6da005a 100644 --- a/application/src/TXScheduler.cpp +++ b/application/src/TXScheduler.cpp @@ -65,7 +65,7 @@ void TXScheduler::processEvent(const Event &e) if ( stationData.flags & STATION_RX_ONLY ) return; - // Using a moving average to determine transmission rate + // Using a moving average of SOG to determine transmission rate double alpha = 0.2; mAvgSpeed = mAvgSpeed * (1.0 - alpha) + e.gpsFix.speed * alpha; @@ -75,14 +75,13 @@ void TXScheduler::processEvent(const Event &e) printf2("Unable to allocate TX packet for message 18, will try again later\r\n"); break; } - AISMessage18 msg; + AISMessage18 msg; msg.latitude = e.gpsFix.lat; msg.longitude = e.gpsFix.lng; msg.sog = e.gpsFix.speed; msg.cog = e.gpsFix.cog; msg.utc = e.gpsFix.utc; - msg.encode (stationData, *p1); RadioManager::instance ().scheduleTransmission (p1); @@ -98,6 +97,7 @@ void TXScheduler::processEvent(const Event &e) printf2("Unable to allocate TX packet for 24A\r\n"); break; } + AISMessage24A msg2; msg2.encode(stationData, *p2); RadioManager::instance().scheduleTransmission(p2);