無線機能も思いっきりハマッてしまった。これだけでどれくらい時間を使ったのかも分からないくらいだ。(-_-;)
IEEE802.15.4のAssociateシーケンスのindicateまでは正常に動作するがその後のdata-requestがタイムアウトになってしまう...
data-requestが送信されていないのか受信できていないのかはわからないがアプリ側でdata-requestを送信してみても通常のデータ送信と認識されてしまう。とにかく何をしても解決できないしIEEE802.15.4のプロトコルは起動時のネットワークスキャンに時間がかかるため省電力型のモデルには適さないということもわかった。
なのでTWELITEのように独自プロトコルにすべきという判断に落ち着いてしまった。先駆者であるモノワイヤレス社の判断が正しかったということが自分でやってみてようやくわかった気がする。
こういう通信デバイスでは重複パケットを除去するのもアプリ側の仕事だったりする。NXP社が公開しているサンプルプログラム(AN-1174)のように送信毎にインクリメントするカウンターをペイロードに含ませて受信側で重複パケットを除去するのも注意が必要だ、
例えば8bitのインクリメントカウンター値を送信するとして256個の通信相手に順番に送信するとカウンターが一回りしてしまうため二回目以降の通信が全て重複パケットと見なされ通信できなくなってしまう事態が発生してしまう。また順不同で送信した場合にたまたまカウンター値が重なってしまうことも起こりえるだろう。滅多に起きないエラーは本当に苦労するので確率が低いからといっても妥協するべきではない。そういうことが起こらないようにするには通信相手毎にカウンターを管理すればいいだけだ。
デバイスにゼロから(WPAN_MAX_DEVICES-1)までのアドレスを割り振るだけで同じPanIDとChannelをもつデバイス同士で通信可能となる。親とか子とかの概念もないのでいつでも自由に通信可能だ。
送信時にu8Handle引数にゼロ以外を指定するとACK要求モードとなり規定回数のリトライが行われ送信処理には4-20ms以上かかる。u8Handle引数にゼロ指定するとACKは確認せず2ms以上で処理が完了する。
受信するとWPanReceiveCallbackが呼び出され、送信完了時にWPanTransmitCallbackが呼び出され送信結果が確認できる。
ちなみにWPan::handle()はバックグラウンド処理(yield)から呼び出されることに注意しよう。
【エコーバックのサンプル】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include "device.h" void WPanRecieveCallback(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len) { Debug::printf("receive(%s), %d byte (%d)\n", pu8Data, u8Len, u16Addr); /* Node 0 --> Node 1 */ if (u16Addr) WPan::transmit(u16Addr, pu8Data, u8Len); } void setup(void) { Debug::begin(); /* Node 0 */ WPan::begin(0); /* Node 1 */ // WPan::begin(1); } void loop(void) { static uint32 t = 0; uint32 now = System::micros(); if (now - t >= 1000000) { t += 1000000; /* Node 1 --> Node 0 */ if (WPan::address()) { static const char msg[] = "1234567890"; WPan::transmit(0, (uint8 *)msg, sizeof(msg)); } } } |
【修正履歴】
2022-11-07
下記関数を追加。
void setPanId(uint16 u16PanId);
uint16 getPanId(void);
bool setShortAddress(uint16 u16Addr);
uint16 getShortAddress(void);
void getMacAddress(MAC_ExtAddr_s &addr);
2022-06-02
AESライブラリを作ったのでWPanクラスのセキュリティ対応を行った。規定で有効になっているのでwpan_security.hの設定を事前に変更しておく必要がある。特にWPAN_SECURITY_KEY_DATAの設定は重要なので漏洩がないよう注意して管理してほしい。
2022-05-17
OTA対応により無線でファームウェア更新が可能に。OTA更新処理中にリセットがかかるがその直前でWPanOTAStartCallbackが定義されていれば呼び出される。アプリは新設したreTransmit()を利用するだけで再送処理が行えるようになった。
2022-05-04
divu64u64()がまだバグッてたので再修正。
2022-05-03
TickTimerクラスとdivu64u64()の致命的なバグ修正。その他いろいろ修正したり改良してみた。
2022-04-27
インクルードの循環参照による不具合を避けるためコードを.cppに移動。プロジェクト・プロパティの設定ミスの修正。muldivとtaskライブラリの追加。バックグランド処理のマルチタスク対応など大幅改修。
それとJN5164では_stack,endシンボルが未定義というリンクエラーが出ることがある。JN5164用のSDKのリンカーファイルに不備があるためで開発用プロジェクトに含まれているAppBuildEnd_JN5164.ldを使用することで解決できる。readm.txtを見てSDKのファイルを更新してほしい。
2022-04-21
数字だけだとなんだかよくわからないので通信周波数のチャネル定義を追加。日本は11-26の範囲でのみ利用可能。
【BeyondStudioプロジェクト(ソース一式)】
JN5164-SW4165-bstudio.zip
ちなみにSDK(JN-SW-4165)はJN5169(TWELITE-RED)に対応していないようだ...JN5169な人はMONOSTAGEを利用すること。
NXP JN516X (TWELITE) をプログラミングする(Eclipse-CDT+MWSTAGE)
IEEE802.15.4の世界を自由に楽しもう!!
【ライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* wpan_security.h - Wireless Personal Area Network Library for NXP-JN516x (IEEE802.15.4) Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "aes.h" #ifndef WPAN_SECURITY_ENABLE #define WPAN_SECURITY_ENABLE 1 /* 0=disable, 1=enable */ #endif #define WPAN_SECURITY_AES_MODE AES::AESMODE_CCM_16 /* 16, 32, 64, 128 */ #define WPAN_SECURITY_KEY_DATA "Please rewrite to any data." |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
/* wpan.h - Wireless Personal Area Network Library for NXP-JN516x (IEEE802.15.4) Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include <AppQueueApi.h> #include "wpan_security.h" #ifndef WPAN_DEFAULT_PANID #define WPAN_DEFAULT_PANID 0x5160 #endif #ifndef WPAN_DEFAULT_CHANNEL #define WPAN_DEFAULT_CHANNEL CHANNEL_23 #endif #ifndef WPAN_MAX_DEVICES #define WPAN_MAX_DEVICES 128U #endif #ifndef WPAN_RSV_DEVICES #define WPAN_RSV_ADDRESS 8U #endif #define WPAN_ADDR_BROADCAST 0xFFFFU #if WPAN_SECURITY_ENABLE #define WPAN_MAX_PAYLOAD_SIZE (114 - 1 - WPAN_SECURITY_AES_MODE) #else #define WPAN_MAX_PAYLOAD_SIZE (114 - 1) #endif extern void WPanRecieveCallback(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len) __attribute__((weak)); extern void WPanTransmitCallback(uint8 u8hHandle, uint8 u8Status) __attribute__((weak)); extern void WPanHWEventCallback(uint32 u32Device, uint32 u32ItemBitmap) __attribute__((weak)); extern void WPanOTAStartCallback(void) __attribute__((weak)); class WPan { public: typedef enum { /* 868 MHz (Europe) */ CHANNEL_0, // 868.3 /* 915 MHz (America, Australia) */ CHANNEL_1, // 906 CHANNEL_2, // 908 CHANNEL_3, // 910 CHANNEL_4, // 912 CHANNEL_5, // 914 CHANNEL_6, // 916 CHANNEL_7, // 918 CHANNEL_8, // 920 CHANNEL_9, // 922 CHANNEL_10, // 924 /* 2400 MHz (Worldwide) */ CHANNEL_11, // 2405 CHANNEL_12, // 2410 CHANNEL_13, // 2415 CHANNEL_14, // 2420 CHANNEL_15, // 2425 CHANNEL_16, // 2430 CHANNEL_17, // 2435 CHANNEL_18, // 2440 CHANNEL_19, // 2445 CHANNEL_20, // 2450 CHANNEL_21, // 2455 CHANNEL_22, // 2460 CHANNEL_23, // 2465 CHANNEL_24, // 2470 CHANNEL_25, // 2475 CHANNEL_26, // 2480 } CHANNEL; static void begin(uint16 u16Addr, uint16 u16PanId = WPAN_DEFAULT_PANID, CHANNEL u8Channel = WPAN_DEFAULT_CHANNEL); static void transmit(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len, uint8 u8Handle = 0); static void reTransmit(uint16 u16Addr); static void handle(void); static uint16 address(void); typedef enum { TXPOWER_0 = -32, // -32 dBm TXPOWER_1 = -20, // -20 dBm TXPOWER_2 = -9, // -9 dBm TXPOWER_3 = 0, // 0 dBm #if E_AHI_ADC_SRC_ADC_5 TXPOWER_4 = 10, // 10 dBm (JN5169) #endif } TXPOWER; static void transmissionPower(TXPOWER txpower); protected: typedef struct __attribute__ ((__packed__)) { uint8 u8Tx; uint8 u8Rx; } tsSeqNb; typedef struct transmit { struct transmit *next; MAC_McpsReqRsp_s data; } tsTransmit; /* Data related to associated end devices */ typedef struct { uint16 u16Addr; uint16 u16PanId; tsSeqNb sSeqNb[WPAN_MAX_DEVICES + WPAN_RSV_ADDRESS]; uint32 u32OtaStart; uint32 u32OtaAddr; uint8 u8OtaErase; uint8 u8OtaHandle; uint8 u8OtaHeader[32]; bool bOtaValid; tsTransmit *psTransmit; tsTransmit sTransmitData[4]; } tsNetwork; static void vProcessIncomingMlme(MAC_MlmeDcfmInd_s *psMlmeInd); static void vProcessIncomingMcps(MAC_McpsDcfmInd_s *psMcpsInd); static void vHandleMcpsDataInd(MAC_RxFrameData_s& sFrame); static void vHandleMcpsDataDcfm(MAC_McpsCfmData_s& sDcfmData); static void vProcessIncomingHwEvent(AppQApiHwInd_s *psAHI_Ind); static tsTransmit *getTransmitData(uint16 u16Addr, bool alloc = true); static void removeTransmitData(tsTransmit *psTransmit); static tsSeqNb *getSequenceNumber(uint16 u16Addr); static void vSetMacAddr(MAC_Addr_s& sAddr, uint16 u16Addr); static void write32(uint8 *buf, uint32 data); static uint32 read32(const uint8 *buf); static void OTARecieveCallback(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len); static void OTATransmitCallback(uint8 u8Handle, uint8 u8Status); static void disabeApp(void); static bool FlashInit(void); /* Handles from the MAC */ static tsNetwork sNetwork; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
/* wpan.cpp - Wireless Personal Area Network Library for NXP-JN516x (IEEE802.15.4) Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> #include <PeripheralRegs.h> #include "jn516x.h" #include "crc32.h" #include "wpan.h" WPan::tsNetwork WPan::sNetwork; #if WPAN_SECURITY_ENABLE static const uint8 SECURITY_KEY_DATA[] = WPAN_SECURITY_KEY_DATA; #endif void WPan::begin(uint16 u16Addr, uint16 u16PanId, CHANNEL u8Channel) { if (!WPan::getSequenceNumber(u16Addr)) return; sNetwork.u16Addr = u16Addr; sNetwork.u16PanId = u16PanId; /* set current channel */ eAppApiPlmeSet((PHY_PibAttr_e)PHY_PIB_ATTR_CURRENT_CHANNEL, u8Channel); /* Set up the MAC handles. Must be called AFTER u32AppQApiInit() */ void *s_pvMac = pvAppApiGetMacHandle(); /* Set Pan ID in PIB (also sets match register in hardware) */ MAC_vPibSetPanId(s_pvMac, u16PanId); /* Set short address in PIB (also sets match registers in hardware) */ MAC_vPibSetShortAddr(s_pvMac, u16Addr); /* Enable receiver to be on when idle */ MAC_vPibSetRxOnWhenIdle(s_pvMac, true, false); sNetwork.psTransmit = 0; for (uint32 i = 0; i < sizeof(sNetwork.sTransmitData) / sizeof(sNetwork.sTransmitData[0]); ++i) { sNetwork.sTransmitData[i].next = sNetwork.psTransmit; sNetwork.psTransmit = sNetwork.sTransmitData + i; sNetwork.psTransmit->data.uParam.sReqData.sFrame.sDstAddr.uAddr.u16Short = WPAN_MAX_DEVICES; } } void WPan::transmit(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len, uint8 u8Handle) { MAC_McpsSyncCfm_s sMcpsSyncCfm; tsSeqNb *psSeqNb = getSequenceNumber(u16Addr); if (!psSeqNb || (u8Len > WPAN_MAX_PAYLOAD_SIZE)) return; uint8 u8Tx = ++psSeqNb->u8Tx; u8Tx = (u16Addr == WPAN_ADDR_BROADCAST ? u8Tx | 0x80 : u8Tx & ~0x80); tsTransmit *psTransmit = getTransmitData(u16Addr); /* Create frame transmission request */ psTransmit->data.u8Type = MAC_MCPS_REQ_DATA; psTransmit->data.u8ParamLength = sizeof(MAC_McpsReqData_s); /* Set handle so we can match confirmation to request */ psTransmit->data.uParam.sReqData.u8Handle = u8Handle; /* Use short address for source */ vSetMacAddr(psTransmit->data.uParam.sReqData.sFrame.sSrcAddr, sNetwork.u16Addr); /* Use short address for destination */ vSetMacAddr(psTransmit->data.uParam.sReqData.sFrame.sDstAddr, u16Addr); /* Frame requires ack but not security, indirect Transmit or GTS */ psTransmit->data.uParam.sReqData.sFrame.u8TxOptions = u8Handle && (u16Addr != WPAN_ADDR_BROADCAST) ? MAC_TX_OPTION_ACK : 0; /* Copy Data */ uint8 *pu8Payload = psTransmit->data.uParam.sReqData.sFrame.au8Sdu; *pu8Payload++ = u8Tx; if (pu8Data && u8Len) { #if WPAN_SECURITY_ENABLE uint8 data[128]; memcpy(&data[WPAN_SECURITY_AES_MODE], pu8Data, u8Len); pu8Data = data; AES::begin(WPAN_SECURITY_AES_MODE, (uint8 *)SECURITY_KEY_DATA, sizeof(SECURITY_KEY_DATA)); AES::encryption(&data[WPAN_SECURITY_AES_MODE], u8Len, u8Tx, (uint8 *)&sNetwork.u16Addr, sizeof(sNetwork.u16Addr), data); u8Len += WPAN_SECURITY_AES_MODE; #endif for (uint8 i = 0; i < u8Len; i++) *pu8Payload++ = *pu8Data++; } /* Set frame length */ psTransmit->data.uParam.sReqData.sFrame.u8SduLength = pu8Payload - psTransmit->data.uParam.sReqData.sFrame.au8Sdu; /* Request Transmit */ vAppApiMcpsRequest(&psTransmit->data, &sMcpsSyncCfm); } void WPan::reTransmit(uint16 u16Addr) { MAC_McpsSyncCfm_s sMcpsSyncCfm; tsTransmit *psTransmit = getTransmitData(u16Addr, false); if (psTransmit) vAppApiMcpsRequest(&psTransmit->data, &sMcpsSyncCfm); } void WPan::handle(void) { MAC_MlmeDcfmInd_s *psMlmeInd; MAC_McpsDcfmInd_s *psMcpsInd; AppQApiHwInd_s*psAHI_Ind; /* Check for anything on the MLME upward queue */ if ((psMlmeInd = psAppQApiReadMlmeInd()) != NULL) { vProcessIncomingMlme(psMlmeInd); vAppQApiReturnMlmeIndBuffer(psMlmeInd); }; /* Check for anything on the MCPS upward queue */ if ((psMcpsInd = psAppQApiReadMcpsInd()) != NULL) { vProcessIncomingMcps(psMcpsInd); vAppQApiReturnMcpsIndBuffer(psMcpsInd); }; /* Check for anything on the AHI upward queue */ if ((psAHI_Ind = psAppQApiReadHwInd()) != NULL) { vProcessIncomingHwEvent(psAHI_Ind); vAppQApiReturnHwIndBuffer(psAHI_Ind); }; } uint16 WPan::address(void) { return sNetwork.u16Addr; } void WPan::transmissionPower(TXPOWER txpower) { // n input range of -32 to 31 dBm // For JN5168, JN5164 and JN5161, it is mapped to one of four levels: // -32, -20, -9 and 0 dBm // For JN5169, it is mapped to the nearest of 26 levels in the range: // -32 to 10 dBm eAppApiPlmeSet((PHY_PibAttr_e)PHY_PIB_ATTR_TX_POWER, txpower); #if E_AHI_ADC_SRC_ADC_5 vAHI_RadioSetReducedInputPower(txpower <= 0); #endif } void WPan::vProcessIncomingMlme(MAC_MlmeDcfmInd_s *psMlmeInd) { } void WPan::vProcessIncomingMcps(MAC_McpsDcfmInd_s *psMcpsInd) { /* Only handle incoming data events one device has been started as a coordinator */ switch(psMcpsInd->u8Type) { /* Incoming data frame */ case MAC_MCPS_IND_DATA: vHandleMcpsDataInd(psMcpsInd->uParam.sIndData.sFrame); break; /* Incoming acknowledgement or ack timeout */ case MAC_MCPS_DCFM_DATA: vHandleMcpsDataDcfm(psMcpsInd->uParam.sDcfmData); break; } } void WPan::vHandleMcpsDataInd(MAC_RxFrameData_s& sFrame) { if ((sFrame.sSrcAddr.u8AddrMode == 2) && (sFrame.u8SduLength > 0)) { uint16 u16Addr = sFrame.sSrcAddr.uAddr.u16Short; tsSeqNb *psSeqNb = getSequenceNumber(u16Addr); if (psSeqNb) { uint8 *pu8Sdu = sFrame.au8Sdu + 1; uint8 u8SduLen = sFrame.u8SduLength - 1; #if WPAN_SECURITY_ENABLE if (u8SduLen) { uint8 data[128]; memcpy(data, pu8Sdu, u8SduLen); pu8Sdu = &data[WPAN_SECURITY_AES_MODE]; u8SduLen -= WPAN_SECURITY_AES_MODE; AES::begin(WPAN_SECURITY_AES_MODE, (uint8 *)SECURITY_KEY_DATA, sizeof(SECURITY_KEY_DATA)); if (!AES::decryption(pu8Sdu, u8SduLen, sFrame.au8Sdu[0], (uint8 *)&u16Addr, sizeof(u16Addr), data)) return; // security failed. } #endif tsTransmit *psTransmit = getTransmitData(u16Addr, false); if (psSeqNb->u8Rx != sFrame.au8Sdu[0]) { /* new packet */ psSeqNb->u8Rx = sFrame.au8Sdu[0]; /* remove transmit data */ removeTransmitData(psTransmit); /* process received packet */ if ((u16Addr == JN516x::ADDR_OTA_BRIDGE) || (u16Addr == JN516x::ADDR_OTA_BRIDGE2)) OTARecieveCallback(u16Addr, pu8Sdu, u8SduLen); else if (WPanRecieveCallback) WPanRecieveCallback(u16Addr, pu8Sdu, u8SduLen); } else if (psTransmit && (sFrame.sDstAddr.uAddr.u16Short != WPAN_ADDR_BROADCAST)) { /* If it is not a broadcast packet, the last transmitted data will be retransmitted. */ MAC_McpsSyncCfm_s sMcpsSyncCfm; vAppApiMcpsRequest(&psTransmit->data, &sMcpsSyncCfm); } } } } void WPan::vHandleMcpsDataDcfm(MAC_McpsCfmData_s& sDcfmData) { OTATransmitCallback(sDcfmData.u8Handle, sDcfmData.u8Status); if (WPanTransmitCallback) WPanTransmitCallback(sDcfmData.u8Handle, sDcfmData.u8Status); } void WPan::vProcessIncomingHwEvent(AppQApiHwInd_s *psAHI_Ind) { if (WPanHWEventCallback) WPanHWEventCallback(psAHI_Ind->u32DeviceId, psAHI_Ind->u32ItemBitmap); } WPan::tsTransmit *WPan::getTransmitData(uint16 u16Addr, bool alloc) { tsTransmit **p, *q; for (p = &sNetwork.psTransmit; *p; p = &(*p)->next) { if ((alloc && !(*p)->next) || ((*p)->data.uParam.sReqData.sFrame.sDstAddr.uAddr.u16Short == u16Addr)) { *p = (q = *p)->next; q->next = sNetwork.psTransmit; sNetwork.psTransmit = q; return q; } } return 0; } void WPan::removeTransmitData(tsTransmit *psTransmit) { tsTransmit **p; if (psTransmit) { for (p = &sNetwork.psTransmit;; p = &(*p)->next) { if (*p == psTransmit) { *p = psTransmit->next; psTransmit->next = 0; psTransmit->data.uParam.sReqData.sFrame.sDstAddr.uAddr.u16Short = WPAN_MAX_DEVICES; } if (!(*p)->next) { (*p)->next = psTransmit; break; } } } } WPan::tsSeqNb *WPan::getSequenceNumber(uint16 u16Addr) { return u16Addr < WPAN_MAX_DEVICES ? sNetwork.sSeqNb + u16Addr : (u16Addr >= (uint16)-WPAN_RSV_ADDRESS ? sNetwork.sSeqNb + WPAN_MAX_DEVICES + WPAN_RSV_ADDRESS + (int16)u16Addr : 0); } void WPan::vSetMacAddr(MAC_Addr_s& sAddr, uint16 u16Addr) { sAddr.u8AddrMode = 2; sAddr.u16PanId = sNetwork.u16PanId; sAddr.uAddr.u16Short = u16Addr; } void WPan::write32(uint8 *buf, uint32 data) { buf[3] = (uint8)(data >> 0); buf[2] = (uint8)(data >> 8); buf[1] = (uint8)(data >> 16); buf[0] = (uint8)(data >> 24); } uint32 WPan::read32(const uint8 *buf) { return ((uint32)buf[0] << 24) | ((uint32)buf[1] << 16) | ((uint16)buf[2] << 8) | ((uint8 )buf[3] << 0); } void WPan::OTARecieveCallback(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len) { #if defined(JN5179) JN516x::tsFlashHeader_JN5179 sFlashHeader; #else JN516x::tsFlashHeader sFlashHeader; #endif uint32 u32Remap; uint8 u8Sector; uint8 u8Ack[16] = { *pu8Data++, JN516x::OTA_STATUS_OK }; uint8 u8AckLen = 2; uint8 u8Handle = 0; --u8Len; switch (u8Ack[0]) { case JN516x::OTA_UPDATE_CHIPVER: u32Remap = u32REG_SysRead(REG_SYS_FLASH_REMAP); u8Sector = JN516x::chipFlashSectors(CHIP_VERSION) - 1; if (u8Sector < 8) vREG_SysWrite(REG_SYS_FLASH_REMAP , (u32Remap & ~(0x0F << ((u8Sector & 7) << 2))) | (u8Sector << ((u8Sector & 7) << 2))); #if defined(JN5169) || defined(JN5179) else { u32Remap = u32REG_SysRead(REG_SYS_FLASH_REMAP2); vREG_SysWrite(REG_SYS_FLASH_REMAP2, (u32Remap & ~(0x0F << ((u8Sector & 7) << 2))) | (u8Sector << ((u8Sector & 7) << 2))); } #endif if (!FlashInit()) u8Ack[1] = JN516x::OTA_STATUS_SDK_ERROR; else if (!bAHI_FullFlashRead(FLASH_SECTOR_OFFSET(u8Sector), sizeof(sFlashHeader), (uint8 *)&sFlashHeader)) u8Ack[1] = JN516x::OTA_STATUS_SDK_ERROR; else { // check OTA-BOOT if (u8Sector == (u32Remap & 0x0F)) sNetwork.bOtaValid = true; else if (sFlashHeader.imageSize <= FLASH_SECTOR_OFFSET(u8Sector - (u32Remap & 0x0F))) { sNetwork.bOtaValid = false; sNetwork.bOtaValid = memcmp(sFlashHeader.sBIR.magicNumber, JN516x::MAGICNUMBER, sizeof(JN516x::MAGICNUMBER)) == 0; #if defined(JN5179) sNetwork.bOtaValid |= memcmp(sFlashHeader.sBIR.magicNumber, JN516x::MAGICNUMBER_JN5179, sizeof(JN516x::MAGICNUMBER)) == 0; #endif sNetwork.bOtaValid &= sFlashHeader.sBIR.status == 0x01; sNetwork.bOtaValid &= sFlashHeader.sBIR.applicationID == 0x0000; } write32(u8Ack + 2, CHIP_VERSION); u8Ack[6] = sNetwork.bOtaValid; u8AckLen = 7; } break; case JN516x::OTA_UPDATE_BLDMODE: u8Sector = (u8Len && (pu8Data[0] == 0xBF) ? 0xBF : 0xFF); if (sNetwork.bOtaValid || (u8Sector == 0xBF)) sNetwork.u8OtaHandle = u8Handle = u8Sector; else u8Ack[1] = JN516x::OTA_STATUS_BLD_ERROR; break; case JN516x::OTA_UPDATE_START: u8Sector = u32REG_SysRead(REG_SYS_FLASH_REMAP) & 0x0F; if (u8Sector && (u8Sector != JN516x::chipFlashSectors(CHIP_VERSION) - 1)) u8Ack[1] = JN516x::OTA_STATUS_BLD_ERROR; else if (!FlashInit()) u8Ack[1] = JN516x::OTA_STATUS_SDK_ERROR; else { if (u8Sector) { vREG_SysWrite(REG_SYS_FLASH_REMAP , 0x65432100U | (u32REG_SysRead(REG_SYS_FLASH_REMAP) & 0x0F)); #if defined(JN5169) || defined(JN5179) vREG_SysWrite(REG_SYS_FLASH_REMAP2, 0xEDCBA987U); #endif sNetwork.u32OtaStart = FLASH_SECTOR_OFFSET(1); } else { vREG_SysWrite(REG_SYS_FLASH_REMAP , 0x76543210U); #if defined(JN5169) || defined(JN5179) vREG_SysWrite(REG_SYS_FLASH_REMAP2, 0xFEDCBA98U); #endif sNetwork.u32OtaStart = FLASH_SECTOR_OFFSET(JN516x::chipFlashSectors(CHIP_VERSION) - 1); } sNetwork.u32OtaAddr = sNetwork.u32OtaStart; sNetwork.u8OtaErase = 0xFF; sNetwork.u8OtaHandle = 0; CRC32::init(); } break; case JN516x::OTA_UPDATE_PROGRAM: CRC32::update(pu8Data, u8Len); if (sNetwork.u32OtaAddr == sNetwork.u32OtaStart) { memcpy(sNetwork.u8OtaHeader, pu8Data, sizeof(sNetwork.u8OtaHeader)); sNetwork.u32OtaAddr += sizeof(sNetwork.u8OtaHeader); pu8Data += sizeof(sNetwork.u8OtaHeader); u8Len -= sizeof(sNetwork.u8OtaHeader); } u8Sector = (sNetwork.u32OtaAddr + (u8Len ? u8Len - 1 : 0)) >> 15; if (sNetwork.u8OtaErase != u8Sector) { sNetwork.u8OtaErase = u8Sector; if (!bAHI_FlashEraseSector(u8Sector)) { u8Ack[1] = JN516x::OTA_STATUS_SDK_ERROR; break; } } if (!bAHI_FullFlashProgram(sNetwork.u32OtaAddr, u8Len, (uint8 *)pu8Data)) u8Ack[1] = JN516x::OTA_STATUS_SDK_ERROR; else sNetwork.u32OtaAddr += u8Len; break; case JN516x::OTA_UPDATE_END: if (CRC32::result() == read32(pu8Data)) sNetwork.u8OtaHandle = u8Handle = 0xFE; else { u8Ack[1] = JN516x::OTA_STATUS_CRC_ERROR; write32(u8Ack + 2, CRC32::result()); u8AckLen = 6; } break; default: u8Ack[1] = JN516x::OTA_STATUS_ARG_ERROR; break; } transmit(u16Addr, u8Ack, u8AckLen, u8Handle); } void WPan::OTATransmitCallback(uint8 u8Handle, uint8 u8Status) { if (sNetwork.u8OtaHandle && (sNetwork.u8OtaHandle == u8Handle)) { sNetwork.u8OtaHandle = 0; if (u8Status == 0) { switch (u8Handle) { case 0xFF: if ((u32REG_SysRead(REG_SYS_FLASH_REMAP) & 0x0F) != JN516x::chipFlashSectors(CHIP_VERSION) - 1) { if (WPanOTAStartCallback) WPanOTAStartCallback(); disabeApp(); vAHI_SwReset(); } break; case 0xFE: if (bAHI_FullFlashProgram(sNetwork.u32OtaStart, sizeof(sNetwork.u8OtaHeader), sNetwork.u8OtaHeader)) vAHI_SwReset(); break; } } } } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" void WPan::disabeApp(void) { uint8 u8Buf[32]; if (bAHI_FullFlashRead(0, sizeof(u8Buf), u8Buf)) { #if defined(JN5179) ((JN516x::tsFlashHeader_JN5179 *)u8Buf)->sBIR.status = 0; #else ((JN516x::tsFlashHeader *)u8Buf)->sBIR.status = 0; #endif bAHI_FullFlashProgram(0, sizeof(u8Buf), u8Buf); } } #pragma GCC diagnostic pop bool WPan::FlashInit(void) { return bAHI_FlashInit(E_FL_CHIP_AUTO, 0); } |
【関連投稿】
NXP JN516X (TWELITE) をプログラミングする(開発環境の構築)
NXP JN516X (TWELITE) をプログラミングする(メイン・ルーチン)
NXP JN516X (TWELITE) をプログラミングする(TICKTIMER)
NXP JN516X (TWELITE) をプログラミングする(UART)
NXP JN516X (TWELITE) をプログラミングする(SYSTEM)
NXP JN516X (TWELITE) をプログラミングする(GPIO)
NXP JN516X (TWELITE) をプログラミングする(TIMER)
NXP JN516X (TWELITE) をプログラミングする(ALARM)
NXP JN516X (TWELITE) をプログラミングする(WAKETIMER)
NXP JN516X (TWELITE) をプログラミングする(WATCHDOG)
NXP JN516X (TWELITE) をプログラミングする(I2C)
NXP JN516X (TWELITE) をプログラミングする(SPI)
NXP JN516X (TWELITE) をプログラミングする(ADC)
NXP JN516X (TWELITE) をプログラミングする(COMPARATOR)
NXP JN516X (TWELITE) をプログラミングする(CLOCK)
NXP JN516X (TWELITE) をプログラミングする(BROWNOUT)
NXP JN516X (TWELITE) をプログラミングする(PULSCOUNTER)
NXP JN516X (TWELITE) をプログラミングする(INFRARED)
NXP JN516X (TWELITE) をプログラミングする(RANDOM-GENERATOR)
NXP JN516X (TWELITE) をプログラミングする(FLASH)
NXP JN516X (TWELITE) をプログラミングする(EEPROM)
NXP JN516X (TWELITE) をプログラミングする(WPAN)
NXP JN516X (TWELITE) をプログラミングする(Eclipse-CDT+MWSTAGE)
NXP JN516X (TWELITE) をプログラミングする(乗算と除算)
NXP JN516X (TWELITE) をプログラミングする(マルチタスク)
NXP JN516X (TWELITE) をプログラミングする(フラッシュ・プログラマー)
NXP JN516X (TWELITE) をプログラミングする(OTA UPDATE)
NXP JN516X (TWELITE) をプログラミングする(TWELITE CUE/MC3630)
NXP JN516X (TWELITE) をプログラミングする(LED)
NXP JN516X (TWELITE) をプログラミングする(AES)
NXP JN516X (TWELITE) をプログラミングする(Downloads)