Bootloader

Форк
0
/
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

14
using namespace Mcucpp::Modbus;
15
using namespace Bootloader;
16

17
BootloaderProtocol::BootloaderProtocol(BootloaderApp &bootloader)
18
    : _bootloader{bootloader}
19
{
20
}
21

22

23
bool BootloaderProtocol::Init()
24
{
25
    Clock::HsiClock::Enable();
26
    BootDeviceClock::SelectClockSource(Clock::UsartClockSrc::Hsi);
27

28
    rtuTransport.SetStaticBuffers(&rxChunk, &txChunk);
29
    BootDevice::Init(115200, BootDevice::Default | BootDevice::TwoStopBits);
30
    BootDevice::SelectTxRxPins<TxPin, RxPin>();
31
    BootDevice::SetRxTimeout(20);
32
    RxPin::SetPullUp(RxPin::PullMode::PullUp);
33

34
    BootDevice::SelectDePin<DePin>();
35

36
    modbus.SetAddress(BootModbusAddr);
37
    modbus.OnWriteHoldingRegs = [this](uint16_t s, uint16_t c, DataBuffer &b) { return WriteHoldingRegisters(s, c, b); };
38
    modbus.OnReadHoldingRegs = [this](uint16_t s, uint16_t c, DataBuffer &b) { return ReadHoldingRegisters(s, c, b); };
39
    modbus.OnReadInputRegisters = [this](uint16_t s, uint16_t c, DataBuffer &b) { return ReadInputRegisters(s, c, b); };
40

41
    if (!rtuTransport.StartListen())
42
    {
43
        return false;
44
    }
45
    return true;
46
}
47

48
uint16_t BootloaderProtocol::GetPageMapItem(uint16_t index)
49
{
50
    PageProps prop = (PageProps)(index % PageMapEntrySize);
51
    uint16_t page = index / PageMapEntrySize;
52

53
    if (page >= Flash::PageCount())
54
    {
55
        return 0;
56
    }
57
    if (prop == PageProps::AddressLo)
58
    {
59
        return (uint16_t)(Flash::PageAddress(page) & 0xffff);
60
    }
61
    if (prop == PageProps::AddressHi)
62
    {
63
        return (uint16_t)((Flash::PageAddress(page) >> 16) & 0xffff);
64
    }
65
    if (prop == PageProps::SizeLo)
66
    {
67
        return (uint16_t)(Flash::PageSize(page) & 0xffff);
68
    }
69
    if (prop == PageProps::SizeHi)
70
    {
71
        return (uint16_t)((Flash::PageSize(page) >> 16) & 0xffff);
72
    }
73

74
    return 0xffff;
75
}
76

77
ModbusError BootloaderProtocol::ReadInputRegisters(uint16_t start, uint16_t count, DataBuffer &buffer)
78
{
79
    uint16_t end = std::min<uint16_t>(start + count, Flash::PageCount() * PageMapEntrySize);
80
    for (uint16_t reg = start; reg < end; reg++)
81
    {
82
        buffer.WriteU16Be(GetPageMapItem(reg));
83
    }
84
    return ModbusError::NoError;
85
}
86

87
ModbusError BootloaderProtocol::ReadHoldingRegisters(uint16_t start, uint16_t count, DataBuffer &buffer)
88
{
89
    #if defined(_DEBUG) && _DEBUG
90
    cout << "RD: " << setw(5) << start << setw(5) << count << "\r\n";
91
    #endif
92
    uint16_t bootDataEnd = std::min<uint16_t>(start + count, sizeof(BootData) / 2);
93
    uint16_t *bootDataPtr = reinterpret_cast<uint16_t *>(&_bootloader.GetBootData());
94
    for (uint16_t reg = start; reg < bootDataEnd; reg++)
95
    {
96
        buffer.WriteU16Be(bootDataPtr[reg]);
97
    }
98

99
    return ModbusError::NoError;
100
}
101

102
ModbusError BootloaderProtocol::WriteHoldingRegisters(uint16_t start, uint16_t count, DataBuffer &buffer)
103
{
104
    uint16_t endReg = start + count;
105
#if defined(_DEBUG) && _DEBUG
106
    cout << setw(5) << start << setw(5) << count;
107
    if (count < 20)
108
    {
109
        cout << "{";
110
        for (auto d : buffer)
111
            cout << setw(5) << d;
112
        cout << "}";
113
    }
114
    cout << "\r\n";
115
#endif
116
    if ((start >= CommandAddress && start < CommandAddress + CommandParamsSize) || (endReg >= CommandAddress && endReg < CommandAddress + CommandParamsSize))
117
    {
118
        uint16_t startInRange = (uint16_t)std::max<int>(start - CommandAddress, 0);
119
        uint16_t countInRange = std::min<uint16_t>(count, CommandParamsSize - startInRange);
120
        return WriteCommand(startInRange, countInRange, buffer);
121
    }
122

123
    if ((start >= PageBufferAddr && start < PageBufferAddr + PageBuffer.size()) || (endReg >= PageBufferAddr && endReg < PageBufferAddr + PageBuffer.size()))
124
    {
125
        uint16_t startInRange = (uint16_t)std::max<int>(start - PageBufferAddr, 0);
126
        uint16_t countInRange = std::min<uint16_t>(count, PageBuffer.size() - startInRange);
127
        return WriteBuffer(startInRange, countInRange, buffer);
128
    }
129

130
    return ModbusError::IllegalAddress;
131
}
132

133
ModbusError BootloaderProtocol::WriteBuffer(uint16_t start, uint16_t count, DataBuffer &buffer)
134
{
135
    uint16_t endReg = std::min<uint16_t>(start + count, PageBuffer.size());
136
    for (uint16_t reg = start; reg < endReg; reg++)
137
    {
138
        PageBuffer[reg] = buffer.ReadU16Be();
139
    }
140
    return ModbusError::NoError;
141
}
142

143
ModbusError BootloaderProtocol::WriteCommand(uint16_t start, uint16_t count, DataBuffer &buffer)
144
{
145
    uint16_t endReg = std::min<uint16_t>(start + count, CommandParamsSize);
146
    for (uint16_t reg = start; reg < endReg; reg++)
147
    {
148
        uint16_t value = buffer.ReadU16Be();
149
        CommandLayout field = (CommandLayout)reg;
150
        if (field == CommandLayout::Page)
151
        {
152
            if (value >= _bootloader.BootStartBootPage())
153
            {
154
                return ModbusError::IllegalValue;
155
            }
156
            _commandData.page = value;
157
        }
158
        if (field == CommandLayout::Offset)
159
        {
160
            if (value >= Flash::PageSize(_commandData.page))
161
            {
162
                return ModbusError::IllegalValue;
163
            }
164
            _commandData.offset = value;
165
        }
166
        if (field == CommandLayout::Length)
167
        {
168
            if (value > Flash::PageSize(_commandData.page) - _commandData.offset)
169
            {
170
                return ModbusError::IllegalValue;
171
            }
172
            _commandData.length = value;
173
        }
174
        if (field == CommandLayout::Command)
175
        {
176
            if (!ExecuteCommand(static_cast<BootCommand>(value)))
177
            {
178
                return ModbusError::NotAcknowledge;
179
            }
180
        }
181
    }
182

183
    return ModbusError::NoError;
184
}
185

186
bool BootloaderProtocol::ExecuteCommand(BootCommand command)
187
{
188
    _bootloader.GetBootData().error = BootError::Success;
189
    switch (command)
190
    {
191
    case BootCommand::PageErase:
192
        return _bootloader.EraseFlash(_commandData.page);
193
    case BootCommand::PageWrite:
194
        return _bootloader.WriteFlash(PageBuffer.data(), _commandData.page, _commandData.length, _commandData.offset);
195
    case BootCommand::RunApplication:
196
        return _bootloader.RunApplication();
197
    case BootCommand::Reset:
198
        _bootloader.Reset();
199
        break;
200
    case BootCommand::Activate:
201
        _bootloader.Connected();
202
        break;
203
    case BootCommand::PageRead:
204
    case BootCommand::None:
205
        break;
206
    default:
207
        _bootloader.GetBootData().error = BootError::WrongCommand;
208
        return false;
209
    }
210
    return true;
211
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.