Bootloader
/
boot_protocol.cpp
211 строк · 6.7 Кб
1#include <flash.h>2#include <usart.h>3#include <iopins.h>4#include <Timers.h>5#include <binary_stream.h>6#include <dispatcher.h>7#include <sys_tick.h>8#include <watchdog.h>9
10#include <array>11#include "bootloader.h"12#include "boot_protocol.h"13
14using namespace Mcucpp::Modbus;15using namespace Bootloader;16
17BootloaderProtocol::BootloaderProtocol(BootloaderApp &bootloader)18: _bootloader{bootloader}19{
20}
21
22
23bool BootloaderProtocol::Init()24{
25Clock::HsiClock::Enable();26BootDeviceClock::SelectClockSource(Clock::UsartClockSrc::Hsi);27
28rtuTransport.SetStaticBuffers(&rxChunk, &txChunk);29BootDevice::Init(115200, BootDevice::Default | BootDevice::TwoStopBits);30BootDevice::SelectTxRxPins<TxPin, RxPin>();31BootDevice::SetRxTimeout(20);32RxPin::SetPullUp(RxPin::PullMode::PullUp);33
34BootDevice::SelectDePin<DePin>();35
36modbus.SetAddress(BootModbusAddr);37modbus.OnWriteHoldingRegs = [this](uint16_t s, uint16_t c, DataBuffer &b) { return WriteHoldingRegisters(s, c, b); };38modbus.OnReadHoldingRegs = [this](uint16_t s, uint16_t c, DataBuffer &b) { return ReadHoldingRegisters(s, c, b); };39modbus.OnReadInputRegisters = [this](uint16_t s, uint16_t c, DataBuffer &b) { return ReadInputRegisters(s, c, b); };40
41if (!rtuTransport.StartListen())42{43return false;44}45return true;46}
47
48uint16_t BootloaderProtocol::GetPageMapItem(uint16_t index)49{
50PageProps prop = (PageProps)(index % PageMapEntrySize);51uint16_t page = index / PageMapEntrySize;52
53if (page >= Flash::PageCount())54{55return 0;56}57if (prop == PageProps::AddressLo)58{59return (uint16_t)(Flash::PageAddress(page) & 0xffff);60}61if (prop == PageProps::AddressHi)62{63return (uint16_t)((Flash::PageAddress(page) >> 16) & 0xffff);64}65if (prop == PageProps::SizeLo)66{67return (uint16_t)(Flash::PageSize(page) & 0xffff);68}69if (prop == PageProps::SizeHi)70{71return (uint16_t)((Flash::PageSize(page) >> 16) & 0xffff);72}73
74return 0xffff;75}
76
77ModbusError BootloaderProtocol::ReadInputRegisters(uint16_t start, uint16_t count, DataBuffer &buffer)78{
79uint16_t end = std::min<uint16_t>(start + count, Flash::PageCount() * PageMapEntrySize);80for (uint16_t reg = start; reg < end; reg++)81{82buffer.WriteU16Be(GetPageMapItem(reg));83}84return ModbusError::NoError;85}
86
87ModbusError BootloaderProtocol::ReadHoldingRegisters(uint16_t start, uint16_t count, DataBuffer &buffer)88{
89#if defined(_DEBUG) && _DEBUG90cout << "RD: " << setw(5) << start << setw(5) << count << "\r\n";91#endif92uint16_t bootDataEnd = std::min<uint16_t>(start + count, sizeof(BootData) / 2);93uint16_t *bootDataPtr = reinterpret_cast<uint16_t *>(&_bootloader.GetBootData());94for (uint16_t reg = start; reg < bootDataEnd; reg++)95{96buffer.WriteU16Be(bootDataPtr[reg]);97}98
99return ModbusError::NoError;100}
101
102ModbusError BootloaderProtocol::WriteHoldingRegisters(uint16_t start, uint16_t count, DataBuffer &buffer)103{
104uint16_t endReg = start + count;105#if defined(_DEBUG) && _DEBUG106cout << setw(5) << start << setw(5) << count;107if (count < 20)108{109cout << "{";110for (auto d : buffer)111cout << setw(5) << d;112cout << "}";113}114cout << "\r\n";115#endif116if ((start >= CommandAddress && start < CommandAddress + CommandParamsSize) || (endReg >= CommandAddress && endReg < CommandAddress + CommandParamsSize))117{118uint16_t startInRange = (uint16_t)std::max<int>(start - CommandAddress, 0);119uint16_t countInRange = std::min<uint16_t>(count, CommandParamsSize - startInRange);120return WriteCommand(startInRange, countInRange, buffer);121}122
123if ((start >= PageBufferAddr && start < PageBufferAddr + PageBuffer.size()) || (endReg >= PageBufferAddr && endReg < PageBufferAddr + PageBuffer.size()))124{125uint16_t startInRange = (uint16_t)std::max<int>(start - PageBufferAddr, 0);126uint16_t countInRange = std::min<uint16_t>(count, PageBuffer.size() - startInRange);127return WriteBuffer(startInRange, countInRange, buffer);128}129
130return ModbusError::IllegalAddress;131}
132
133ModbusError BootloaderProtocol::WriteBuffer(uint16_t start, uint16_t count, DataBuffer &buffer)134{
135uint16_t endReg = std::min<uint16_t>(start + count, PageBuffer.size());136for (uint16_t reg = start; reg < endReg; reg++)137{138PageBuffer[reg] = buffer.ReadU16Be();139}140return ModbusError::NoError;141}
142
143ModbusError BootloaderProtocol::WriteCommand(uint16_t start, uint16_t count, DataBuffer &buffer)144{
145uint16_t endReg = std::min<uint16_t>(start + count, CommandParamsSize);146for (uint16_t reg = start; reg < endReg; reg++)147{148uint16_t value = buffer.ReadU16Be();149CommandLayout field = (CommandLayout)reg;150if (field == CommandLayout::Page)151{152if (value >= _bootloader.BootStartBootPage())153{154return ModbusError::IllegalValue;155}156_commandData.page = value;157}158if (field == CommandLayout::Offset)159{160if (value >= Flash::PageSize(_commandData.page))161{162return ModbusError::IllegalValue;163}164_commandData.offset = value;165}166if (field == CommandLayout::Length)167{168if (value > Flash::PageSize(_commandData.page) - _commandData.offset)169{170return ModbusError::IllegalValue;171}172_commandData.length = value;173}174if (field == CommandLayout::Command)175{176if (!ExecuteCommand(static_cast<BootCommand>(value)))177{178return ModbusError::NotAcknowledge;179}180}181}182
183return ModbusError::NoError;184}
185
186bool BootloaderProtocol::ExecuteCommand(BootCommand command)187{
188_bootloader.GetBootData().error = BootError::Success;189switch (command)190{191case BootCommand::PageErase:192return _bootloader.EraseFlash(_commandData.page);193case BootCommand::PageWrite:194return _bootloader.WriteFlash(PageBuffer.data(), _commandData.page, _commandData.length, _commandData.offset);195case BootCommand::RunApplication:196return _bootloader.RunApplication();197case BootCommand::Reset:198_bootloader.Reset();199break;200case BootCommand::Activate:201_bootloader.Connected();202break;203case BootCommand::PageRead:204case BootCommand::None:205break;206default:207_bootloader.GetBootData().error = BootError::WrongCommand;208return false;209}210return true;211}