e2 studio を使用して Renesas Synergy SK-S7G2 ボードで動作するように、arduino 用の Lmic ライブラリ ビルド ( https://github.com/matthijskooijman/arduino-lmic ) を実行しようとしています。hal.cpp ファイルを変更したところ、コードが完全に実行され、TTN ネットワークでアップリンク メッセージが表示されるようになりました。私が直面している問題は、私のフレームが aes 暗号化の間で何らかの形で変化していることです (私の推測)。暗号化の前に確認したところ、LMIC.frame[6]
と
のLMIC.frame[7]
値が示されています0x00
が、何らかの理由で、TTN ネットワークで受信しているのは です0xFF
。このため、TTN の cnt65535
が最初のカウントとして表示されます。
ライブラリには使用できる 2 つの aes メソッドがあり、両方を試しましたが、同じ結果が得られました。
これまでに思いついた理由は次のとおりです。
- ライブラリは8ビットarduinoを対象としているため、32ビットarm m4プロセッサが原因である可能性があります(ただし、ライブラリにはaes用の32ビットプロセッサバージョンもあり、それも試しましたが同じ結果が得られました)
- 私の
hal_ticks()
機能は、本来すべきことをまだ行っていません。
どなたかからの情報提供をお待ちしております。以下に、e2 studio のコンソール出力と、TTN ネットワークで受信した物理ペイロードを示します。作成した hal.c ファイルも添付します。
前もって感謝します
TTN で受信した物理ペイロード
406511012680 FFFF 0171F9EF1810C3B61F4D4EDE940844A945CE
e2 studio で実行中のコンソール メッセージ
Starting..
Time: 0
RXMODE_RSSI
5824: engineUpdate, opmode=0x808
7349: TXMODE, freq=868100000, len=26, SF=7, BW=125, CR=4/5, IH=0
Packet queued
42111: RXMODE_SINGLE, freq=868100000, SF=7, BW=125, CR=4/5, IH=0
73505: RXMODE_SINGLE, freq=869525000, SF=9, BW=125, CR=4/5, IH=0
75435Event
EV_TXCOMPLETE (includes waiting for RX windows)
79028: engineUpdate, opmode=0x900
hal.c ファイル
/*
* hal.c
*
* Created on: Jul 4, 2019
* Author: areeb
*/
/*******************************************************************************
* Copyright (c) 2015 Matthijs Kooijman
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This the HAL to run LMIC on top of the Arduino environment.
*******************************************************************************/
#include <hal/hal.h>
#include "hal_data.h"
#include <stdio.h>
#include "../lmic/lmic.h"
ssp_err_t err;
u4_t t ;
unsigned int ticks=0, fg=0;
u2_t cnt=0 ;
uint32_t scaled = 0, ch=0;
static volatile bool spi_done = false;
static bool dio_states[3] = {0};
void spi_callback(spi_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
spi_done= true;
}
void timer0_callback(timer_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
ticks++;
}
void irq_callback(external_irq_callback_args_t *p_args)
{
if(p_args->channel == 1)
{
dio_states[0]=1;
radio_irq_handler(0);
dio_states[0]=0;
}
else if(p_args->channel == 2)
{
dio_states[1]=1;
radio_irq_handler(1);
dio_states[0]=0;
}
else if(p_args->channel == 14)
{
dio_states[2]=1;
radio_irq_handler(2);
}
else
{
;
}
// if(p_args->channel == 14)
// {
// radio_irq_handler(2);
// }
}
// -----------------------------------------------------------------------------
// I/O
//#define nss (IOPORT_PORT_04_PIN_13)
//
//#define rst (IOPORT_PORT_05_PIN_11)
u1_t transmit[1]={0},ccc=0;
u1_t recv[1]={0};
static void hal_io_init () {
// g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT);
}
// val == 1 => tx 1
void hal_pin_rxtx (u1_t val) {
}
// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
g_ioport.p_api->init(g_ioport.p_cfg);
if(val == 0 || val == 1)
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_LOW);
else if (val == 1)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_HIGH);
}
else
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
}
}
ioport_level_t readpin;
u1_t rd=0;
//static void hal_io_check() {
//
// uint8_t i;
// for (i = 0; i < NUM_DIO; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
// g_ioport.p_api->pinRead(lmic_pins.dio[i], &readpin);
// if(readpin == IOPORT_LEVEL_HIGH)
// rd = 1;
// else
// rd = 0;
//
// if (dio_states[i] != readpin) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
//
//
//}
void hal_io_check() {
uint8_t i;
// for (i = 0; i < 3; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
//
// if (dio_states[i] != 0) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
// radio_irq_handler(0);
}
// -----------------------------------------------------------------------------
// SPI
//static const SPISettings settings(10E6, MSBFIRST, SPI_MODE0);
static void hal_spi_init () {
err = g_spi0.p_api->open(g_spi0.p_ctrl,g_spi0.p_cfg);
err = g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
err = g_timer0.p_api->start(g_timer0.p_ctrl);
g_external_irq0.p_api->open(g_external_irq0.p_ctrl,g_external_irq0.p_cfg);
g_external_irq0.p_api->enable(g_external_irq0.p_ctrl);
g_external_irq0.p_api->triggerSet(g_external_irq0.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq1.p_api->open(g_external_irq1.p_ctrl,g_external_irq1.p_cfg);
g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
g_external_irq1.p_api->triggerSet(g_external_irq1.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq2.p_api->open(g_external_irq2.p_ctrl,g_external_irq2.p_cfg);
g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
g_external_irq2.p_api->triggerSet(g_external_irq2.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
}
void hal_pin_nss (u1_t val) {
g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_LOW);
else if(val == 1)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_HIGH);
}
// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
if((out & 0x80) == 0x80)
{
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return 0;
}
else if((out > 0x00) && (out & 0x80) != 0x80)
{
ccc = out;
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
}
else if(out == 0x00)
{
g_spi0.p_api->read(g_spi0.p_ctrl, recv, sizeof(recv), SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return recv[0];
}
return recv[0];
}
// -----------------------------------------------------------------------------
// TIME
static void hal_time_init () {
// Nothing to do
}
u4_t hal_ticks () {
// Because micros() is scaled down in this function, micros() will
// overflow before the tick timer should, causing the tick timer to
// miss a significant part of its values if not corrected. To fix
// this, the "overflow" serves as an overflow area for the micros()
// counter. It consists of three parts:
// - The US_PER_OSTICK upper bits are effectively an extension for
// the micros() counter and are added to the result of this
// function.
// - The next bit overlaps with the most significant bit of
// micros(). This is used to detect micros() overflows.
// - The remaining bits are always zero.
//
// By comparing the overlapping bit with the corresponding bit in
// the micros() return value, overflows can be detected and the
// upper bits are incremented. This is done using some clever
// bitwise operations, to remove the need for comparisons and a
// jumps, which should result in efficient code. By avoiding shifts
// other than by multiples of 8 as much as possible, this is also
// efficient on AVR (which only has 1-bit shifts).
// g_timer0.p_api->stop(g_timer0.p_ctrl);
// static uint8_t overflow = 0;
// Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
// the others will be the lower bits of our return value.
// u4_t t = ticks;
// g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
// cnt = 65535-cnt;
// if( (cnt > 65000) && (cnt < 65535 ) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// scaled = ticks >> US_PER_OSTICK_EXPONENT; // 625
// Most significant byte of scaled
// uint8_t msb = scaled >> 24;
// Mask pointing to the overlapping bit in msb and overflow.
// const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
// Update overflow. If the overlapping bit is different
// between overflow and msb, it is added to the stored value,
// so the overlapping bit becomes equal again and, if it changed
// from 1 to 0, the upper bits are incremented.
// overflow += (msb ^ overflow) & mask;
// Return the scaled value with the upper bits of stored added. The
// overlapping bit will be equal and the lower bits will be 0, so
// bitwise or is a no-op for them.
// g_timer0.p_api->start(g_timer0.p_ctrl);
// return scaled | ((uint32_t)overflow << 24);
// 0 leads to correct, but overly complex code (it could just return
// micros() unmodified), 8 leaves no room for the overlapping bit.
// static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
t = ticks;
//
//// hal_disableIRQs();
///
g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
if(cnt != 0 )
cnt = 65535 - cnt;
// if( (cnt < 500) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// hal_enableIRQs();
return ((t<<16)|cnt);
}
// Returns the number of ticks until time. Negative values indicate that
// time has already passed.
static s4_t delta_time(u4_t time) {
u4_t t = hal_ticks();
s4_t d = time - t;
if( d<=0 ) return 0; // in the past
if( (d>>16)!=0 ) return 0xFFFF; // far ahead
return (u2_t)d;
}
void hal_waitUntil (u4_t time) {
while( delta_time(time) != 0 );
}
// s4_t delta = delta_time(time);
// // From delayMicroseconds docs: Currently, the largest value that
// // will produce an accurate delay is 16383.
// while (delta > (16000 / US_PER_OSTICK)) {
// R_BSP_SoftwareDelay(16, BSP_DELAY_UNITS_MILLISECONDS);
// delta -= (16000 / US_PER_OSTICK);
// }
// if (delta > 0)
// R_BSP_SoftwareDelay((delta * US_PER_OSTICK), BSP_DELAY_UNITS_MICROSECONDS);
//// delayMicroseconds(delta * US_PER_OSTICK);
//}
// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
// No need to schedule wakeup, since we're not sleeping
return delta_time(time) <= 0;
}
static uint8_t irqlevel = 0;
void hal_disableIRQs () {
// __disable_irq();
// g_timer0.p_api->close(g_timer0.p_ctrl);
// g_external_irq1.p_api->disable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->disable(g_external_irq2.p_ctrl);
irqlevel++;
}
void hal_enableIRQs () {
if(--irqlevel == 0) {
// __enable_irq();
// g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
// g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
// Instead of using proper interrupts (which are a bit tricky
// and/or not available on all pins on AVR), just poll the pin
// values. Since os_runloop disables and re-enables interrupts,
// putting this here makes sure we check at least once every
// loop.
//
// As an additional bonus, this prevents the can of worms that
// we would otherwise get for running SPI transfers inside ISRs
hal_io_check();
}
hal_io_check();
}
void hal_sleep () {
// Not implemented
}
// -----------------------------------------------------------------------------
#if defined(LMIC_PRINTF_TO)
static int uart_putchar (char c, FILE *)
{
LMIC_PRINTF_TO.write(c) ;
return 0 ;
}
void hal_printf_init() {
// create a FILE structure to reference our UART output function
static FILE uartout;
memset(&uartout, 0, sizeof(uartout));
// fill in the UART file descriptor with pointer to writer.
fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
// The uart is the standard output device STDOUT.
stdout = &uartout ;
}
#endif // defined(LMIC_PRINTF_TO)
void hal_init () {
// configure radio I/O and interrupt handler
hal_io_init();
// configure radio SPI
hal_spi_init();
// configure timer and interrupt handler
hal_time_init();
#if defined(LMIC_PRINTF_TO)
// printf support
hal_printf_init();
#endif
}
void hal_failed (const char *file, u2_t line) {
}