amiro-os / components / serial_reset / serial_can_mux.cpp @ ec052975
History | View | Annotate | Download (5.857 KB)
1 | 58fe0e0b | Thomas Schöpping | #include <ch.h> |
---|---|---|---|
2 | #include <hal.h> |
||
3 | #include <string.h> // memcpy |
||
4 | #include <chprintf.h> |
||
5 | #include <amiro/Constants.h> |
||
6 | |||
7 | #include <amiro/serial_reset/serial_can_mux.hpp> |
||
8 | |||
9 | using namespace amiro; |
||
10 | using namespace chibios_rt; |
||
11 | |||
12 | SerialCanMux::SerialCanMux(SerialDriver *_sd_, CANDriver *can, const uint8_t boardId)
|
||
13 | : BaseSequentialStreamInterface(), |
||
14 | sd_(_sd_), |
||
15 | canDriver(can) |
||
16 | { |
||
17 | // oqueue(ob, 500, NULL, NULL);
|
||
18 | myID = boardId; |
||
19 | queryShellID = boardId; |
||
20 | replyShellID = boardId; |
||
21 | |||
22 | resetStatus = 0;
|
||
23 | resetAddBytes = 0;
|
||
24 | |||
25 | txmsg.IDE = CAN_IDE_STD; |
||
26 | txmsg.RTR = CAN_RTR_DATA; |
||
27 | txmsg.DLC = 0;
|
||
28 | } |
||
29 | |||
30 | SerialCanMux::~SerialCanMux() { |
||
31 | |||
32 | }; |
||
33 | |||
34 | /*
|
||
35 | * resets system for entering in bootloader.
|
||
36 | */
|
||
37 | void SerialCanMux::restartSystem(void) { |
||
38 | //TODO Set reset SYS_PD_N
|
||
39 | NVIC_SystemReset(); |
||
40 | } |
||
41 | |||
42 | /*
|
||
43 | * checks bytes for reset command sequence.
|
||
44 | * if the last byte and the following identification number of the device have been sent,
|
||
45 | * the microcontroller will be reset
|
||
46 | */
|
||
47 | bool SerialCanMux::checkByteForBLReset(uint8_t *inputs, size_t size) {
|
||
48 | /* Run throug all given bytes */
|
||
49 | for (size_t idx=0; idx < size; idx++) { |
||
50 | uint8_t input = *(inputs+idx); |
||
51 | |||
52 | /*
|
||
53 | * if the last byte of reset command sequence has not been sent yet,
|
||
54 | * check new byte and handle reset status
|
||
55 | */
|
||
56 | if (resetStatus < INPUT_BL_RESET_LENGTH) {
|
||
57 | if (input == inputBLReset[resetStatus]) {
|
||
58 | resetStatus++; |
||
59 | if (resetStatus == INPUT_BL_RESET_LENGTH) {
|
||
60 | chprintf((BaseSequentialStream*)sd_, "\n\nDo reset ...\n\n");
|
||
61 | uint8_t ledCount; |
||
62 | for (ledCount=0; ledCount<20; ledCount++) { |
||
63 | // boardWriteLed(1);
|
||
64 | chThdSleepMilliseconds(100);
|
||
65 | // boardWriteLed(0);
|
||
66 | chThdSleepMilliseconds(100);
|
||
67 | } |
||
68 | restartSystem(); |
||
69 | } |
||
70 | } else {
|
||
71 | resetStatus = 0;
|
||
72 | resetAddBytes = 0;
|
||
73 | } |
||
74 | |||
75 | /*
|
||
76 | * if the last byte of reset command sequence has been sent,
|
||
77 | * save new byte as identification number of the device which shall be flashed and
|
||
78 | * reset microcontroller
|
||
79 | */
|
||
80 | } else {
|
||
81 | inputAddBytes[resetAddBytes] = input; |
||
82 | resetAddBytes++; |
||
83 | if (resetAddBytes >= INPUT_BL_RESET_ADDITIONAL_BYTES) {
|
||
84 | chprintf((BaseSequentialStream*)sd_, "\n\nAt device %x: Do reset ...\n\n", input);
|
||
85 | chThdSleepMilliseconds(OFFSET_TIME_RESET_MS); |
||
86 | restartSystem(); |
||
87 | } |
||
88 | } |
||
89 | } |
||
90 | |||
91 | return (resetStatus > 0); |
||
92 | } |
||
93 | |||
94 | |||
95 | msg_t SerialCanMux::sendViaCan(uint32_t id, uint8_t *inputs, size_t size) { |
||
96 | msg_t status; |
||
97 | txmsg.SID = (id << CAN::DEVICE_ID_SHIFT) | myID; |
||
98 | for (size_t i=0; i<size; i+=8) { |
||
99 | txmsg.DLC = (size < (i + 8)) ? size-i : 8; |
||
100 | memcpy(txmsg.data8, &inputs[i], txmsg.DLC); |
||
101 | status = canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, TIME_INFINITE); |
||
102 | if (status!= RDY_OK)
|
||
103 | return status;
|
||
104 | } |
||
105 | |||
106 | return RDY_OK;
|
||
107 | } |
||
108 | |||
109 | //----------------------------------------------------------------
|
||
110 | |||
111 | /*
|
||
112 | * Interface implementation.
|
||
113 | */
|
||
114 | |||
115 | size_t SerialCanMux::write(const uint8_t *bp, size_t n) {
|
||
116 | size_t size; |
||
117 | |||
118 | if (myID != replyShellID) {
|
||
119 | msg_t status = sendViaCan(CAN::SHELL_REPLY_ID(replyShellID), (uint8_t *)bp, n); |
||
120 | BaseThread::sleep(US2ST(500));
|
||
121 | size = (status == RDY_OK) ? n : 0;
|
||
122 | } else {
|
||
123 | size = sdWrite(sd_, bp, n); |
||
124 | } |
||
125 | |||
126 | return size;
|
||
127 | } |
||
128 | |||
129 | size_t SerialCanMux::read(uint8_t *bp, size_t n) { |
||
130 | size_t size = sdRead(sd_, inputChar, n); |
||
131 | |||
132 | checkByteForBLReset(inputChar, size); |
||
133 | |||
134 | if (myID != queryShellID)
|
||
135 | sendViaCan(CAN::SHELL_QUERY_ID(queryShellID),inputChar, size); |
||
136 | else
|
||
137 | memcpy(bp, inputChar, size); |
||
138 | |||
139 | return size;
|
||
140 | } |
||
141 | |||
142 | msg_t SerialCanMux::put(uint8_t b) { |
||
143 | msg_t byte; |
||
144 | |||
145 | if (myID != replyShellID) {
|
||
146 | byte = sendViaCan(CAN::SHELL_REPLY_ID(replyShellID), &b, 1);
|
||
147 | BaseThread::sleep(US2ST(200));
|
||
148 | } else {
|
||
149 | byte = sdPut(sd_, b); |
||
150 | } |
||
151 | |||
152 | return byte;
|
||
153 | } |
||
154 | |||
155 | msg_t SerialCanMux::get(void) {
|
||
156 | msg_t byte = sdGet(sd_); |
||
157 | uint8_t b = (uint8_t) byte; |
||
158 | |||
159 | checkByteForBLReset(&b, 1);
|
||
160 | |||
161 | if (myID != queryShellID)
|
||
162 | sendViaCan(CAN::SHELL_QUERY_ID(queryShellID), &b, 1);
|
||
163 | |||
164 | return byte;
|
||
165 | } |
||
166 | |||
167 | //----------------------------------------------------------------
|
||
168 | |||
169 | /*
|
||
170 | * Converse data from CAN bus into input queue of serial driver.
|
||
171 | */
|
||
172 | |||
173 | void SerialCanMux::convCan2Serial(uint8_t *data_can, size_t n) {
|
||
174 | chSysLock(); |
||
175 | for (size_t i=0; i < n; i++) |
||
176 | sdIncomingDataI(sd_, data_can[i]); |
||
177 | chSysUnlock(); |
||
178 | } |
||
179 | |||
180 | void SerialCanMux::sendSwitchCmd(uint8_t setid) {
|
||
181 | |||
182 | if (myID == setid)
|
||
183 | chprintf((BaseSequentialStream*)sd_, "Stay at the same shell\n");
|
||
184 | else if (replyShellID == setid) |
||
185 | chprintf((BaseSequentialStream*)sd_, "Switch to the own shell\n");
|
||
186 | else
|
||
187 | chprintf((BaseSequentialStream*)sd_, "Switch to the shell on board %d\n", setid);
|
||
188 | |||
189 | if (myID != setid) {
|
||
190 | |||
191 | if (replyShellID != setid) {
|
||
192 | // To set the new remote shell via CAN bus.
|
||
193 | txmsg.SID = ((CAN::SHELL_QUERY_ID(setid)) << CAN::DEVICE_ID_SHIFT) | replyShellID; |
||
194 | txmsg.DLC = 0;
|
||
195 | canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, US2ST(545));
|
||
196 | } |
||
197 | |||
198 | if (replyShellID == myID) {
|
||
199 | queryShellID = setid; |
||
200 | } else {
|
||
201 | if (replyShellID == setid)
|
||
202 | // To return the own shell via CAN bus.
|
||
203 | txmsg.SID = ((CAN::SHELL_QUERY_ID(replyShellID)) << CAN::DEVICE_ID_SHIFT) | replyShellID; |
||
204 | else
|
||
205 | // To set the serial board to the new remote shell.
|
||
206 | txmsg.SID = ((CAN::SHELL_QUERY_ID(replyShellID)) << CAN::DEVICE_ID_SHIFT) | setid; |
||
207 | |||
208 | txmsg.DLC = 0;
|
||
209 | canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, US2ST(545));
|
||
210 | |||
211 | replyShellID = myID; |
||
212 | } |
||
213 | } |
||
214 | } |
||
215 | |||
216 | void SerialCanMux::rcvSwitchCmd(uint8_t setid) {
|
||
217 | |||
218 | if (myID == setid) {
|
||
219 | chprintf((BaseSequentialStream*)sd_, "\nReturn own shell\n\n");
|
||
220 | queryShellID = setid; |
||
221 | } else if (myID != queryShellID) { |
||
222 | chprintf((BaseSequentialStream*)sd_, "\nSwitch to the shell on board %d\n", setid);
|
||
223 | queryShellID = setid; |
||
224 | } else {
|
||
225 | chprintf((BaseSequentialStream*)sd_, "\nShell shown in board %d\n\n", setid);
|
||
226 | replyShellID = setid; |
||
227 | } |
||
228 | } |