65535 cnt value on TTN network - eclipse
I'm trying to run Lmic library build for arduino (https://github.com/matthijskooijman/arduino-lmic) to work with my Renesas Synergy SK-S7G2 board using e2 studio.
I have altered the hal.cpp file and now the code runs perfectly and I can see the up-link message on the TTN network, The problem that I am facing is that my frame is somehow changing between aes encryption (my guess) because I have checked it before encryption and it shows the LMIC.frame[6] and
LMIC.frame[7] values to be 0x00 but for some reason what I am receiving on the TTN network is 0xFF. and because of this the cnt on TTN shows 65535 as the first count.
The library has 2 aes methods which can be used and I have tried both but they give me the same result.
The reasons I have come up with so far is:
32 bit arm m4 processor may be the cause, as the library was intended for 8 bit arduino (but library also has a 32bit processor version for aes and I have tried that as well but got same result)
My hal_ticks() function is still not doing what it is supposed to do.
I would love an input from anyone, below you can see the console output on e2 studio and the physical payload received on the TTN network. I am also attaching the hal.c file that I have made.
Thank you in advance
physical payload received on TTN
406511012680 FFFF 0171F9EF1810C3B61F4D4EDE940844A945CE
console messages while running on 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 file
/*
* 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) {
}
Related
change an if / else if statement to a switch case in Arduino
I am making a web server with an ESP32D, I am programming it from the Arduino IDE and I have a function with spaghetti code which I want to refactor with switch case, this is my function, which i am calling in the void loop() void control(){ if (header.indexOf("GET /2/on") >= 0) { Serial.println("GPIO 2 on"); output2State = "on"; digitalWrite(output2, HIGH); } else if (header.indexOf("GET /2/off") >= 0) { Serial.println("GPIO 2 off"); output2State = "off"; digitalWrite(output2, LOW); } else if (header.indexOf("GET /15/on") >= 0) { Serial.println("GPIO 15 on"); output15State = "on"; digitalWrite(output15, HIGH); } else if (header.indexOf("GET /15/off") >= 0) { Serial.println("GPIO 15 off"); output15State = "off"; digitalWrite(output15, LOW); } } void function_loop(){ WiFiClient client = server.available(); // Listen for incoming client // Serial.println(typeOf(client)); if (client) { // If a new client connects, currentTime = millis(); previousTime = currentTime; Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor header += c; if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println("Connection: close"); client.println(); control(); } How could I do to be able to pass it to switch case? I have no idea how to pass the variable to modify (in this case the header.indexOf)
It isn't clear from your example what type your header is, but I'm guessing it is a String. Send header to control() like this control(header); and declare control() like this void control(String& header) {
How to implement ThreadPool::RunAsync in Winrt/C++
I am trying to understand how I could implement a concurrent thread for processing data in a Winrt/Cpp application. As background I have implemented a winRT BLE component that wraps the windows bluetooth function I am using this component in my winrt application and successfully get a notification when the app connects to me bluetooth device Now within the app I would like to "spawn" a process that continually sends a request to the BLE device and process the response. To achieve #3 I thought one approach could be - within the connection notification I would invoke a function called StartDataAcq that uses the threadpool to schedule work, to test out this approach I decided to just use the example shown here https://learn.microsoft.com/en-us/windows/uwp/threading-async/submit-a-work-item-to-the-thread-pool to see if it could work So the implementation looks like this within my code void Datamanager::BleFound( winrt::Windows::Foundation::IInspectable const& /* sender */, uint32_t foundFlags) { OutputDebugStringW((L"Member function Called from DataManager->" + hstring(std::to_wstring(foundFlags)) + L"\r\n").c_str()); if (!acqStarted) { StartDataAcq(); acqStarted = true; } } void DataManager::StartDataAcq() { // The nth prime number to find. const unsigned int n{ 99999999 }; unsigned long nthPrime{ 0 }; //submit work to thread poool m_workItem = Windows::System::Threading::ThreadPool::RunAsync([&](Windows::Foundation::IAsyncAction const& workItem) { unsigned int progress = 0; // For progress reporting. unsigned int primes = 0; // Number of primes found so far. unsigned long int i = 2; // Number iterator. if ((n >= 0) && (n <= 2)) { nthPrime = n; return; } while (primes < (n - 1)) { if (workItem.Status() == Windows::Foundation::AsyncStatus::Canceled) { break; } // Go to the next number. i++; // Check for prime. bool prime = true; for (unsigned int j = 2; j < i; ++j) { if ((i % j) == 0) { prime = false; break; } }; if (prime) { // Found another prime number. primes++; // Report progress at every 10 percent. unsigned int temp = progress; progress = static_cast<unsigned int>(10.f * primes / n); if (progress != temp) { std::wstringstream updateString; updateString << L"Progress to " << n << L"th prime: " << (10 * progress) << std::endl; OutputDebugStringW((L"" + updateString.str() + L"\r\n").c_str()); // Update the UI thread with the CoreDispatcher. /* Windows::ApplicationModel::Core::CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync( Windows::UI::Core::CoreDispatcherPriority::High, Windows::UI::Core::DispatchedHandler([&]() { UpdateUI(updateString.str()); })); */ } } } // Return the nth prime number. nthPrime = i; } , Windows::System::Threading::WorkItemPriority::Normal, Windows::System::Threading::WorkItemOptions::TimeSliced); } I see the message for the connect notification, This debug string - OutputDebugStringW((L"Member function Called from DataManager->" + hstring(std::to_wstring(foundFlags)) + L"\r\n").c_str()); however I never see any output from the async workitem. Can someone please help me spot the issue? Also are there any better ways to do this? I was reading about co-routines but seeing how the work is data processing locally I do not think a co routine would work I also was trying to find out how I could spawn a separate thread and manage it within my code - but am not sure how to do it within the winrt/c++ framework based on Raymond Chen's comment I converted the variables on the stack to std::shared_ptr and the sample works now... Also stumbled upon this link that explains this better than I can... https://learn.microsoft.com/en-us/cpp/parallel/concrt/task-parallelism-concurrency-runtime?view=msvc-170#lambdas void DataManager::StartDataAcq() { auto n = make_shared<UINT32>(9999); auto nthPrime = make_shared<UINT32>(0); m_workItem = Windows::System::Threading::ThreadPool::RunAsync([n,nthPrime](Windows::Foundation::IAsyncAction const& workItem) { unsigned int progress = 0; // For progress reporting. unsigned int primes = 0; // Number of primes found so far. int i = 2; // Number iterator. if ((*n >= 0) && (*n <= 2)) { *nthPrime = *n; //return; } while (primes < (*n - 1)) { if (workItem.Status() == Windows::Foundation::AsyncStatus::Canceled) { break; } // Go to the next number. i++; // Check for prime. bool prime = true; for (unsigned int j = 2; j < i; ++j) { if ((i % j) == 0) { prime = false; break; } }; if (prime) { // Found another prime number. primes++; // Report progress at every 10 percent. unsigned int temp = progress; progress = static_cast<unsigned int>(10.f * primes / *n); if (progress != temp) { std::wstringstream updateString; updateString << L"Progress to " << *n << L" " << i << L" th prime: " << (10 * progress) << std::endl; OutputDebugStringW((L"" + updateString.str() + L"\r\n").c_str()); // Update the UI thread with the CoreDispatcher. /* Windows::ApplicationModel::Core::CoreApplication::MainView().CoreWindow().Dispatcher().RunAsync( Windows::UI::Core::CoreDispatcherPriority::High, Windows::UI::Core::DispatchedHandler([&]() { UpdateUI(updateString.str()); })); */ } } } // Return the nth prime number. *nthPrime = i; std::wstringstream updateString; updateString << L"Found the nth prime " << i << std::endl; OutputDebugStringW((L"" + updateString.str() ).c_str()); } , Windows::System::Threading::WorkItemPriority::Normal, Windows::System::Threading::WorkItemOptions::TimeSliced); }
Processing heterogenous information as it arrives from a Socket
A server sends heterogeneous information as stream of bytes. Strings, for instance, are sent with 4 bytes indicating the length and then the characters. This means that my client app must read 4 bytes as an int (which implies that the 4 bytes are available) and then read as many bytes as indicated (the strings are latin1-encoded). So far I tried two methods: read synchronously with a RawSocket and read the full data dump asynchronously with Socket.listen and process it later. The first method blocks the application, the second is wasteful as it requires to store all the data before processing it. What I could do for asynchronously read N bytes from a Socket, process them, then read M bytes, process them, etc?
This sounds like you need a ring buffer/byte queue where you can append more data when it arrives, then consume as much as needed from the head when it's available. There are different ways to implement one, depending on how much you want to avoid copying the bytes. The simplest would be a growing backing buffer with copying. The second approach would be keeping the original lists and combining them when you read only. Here's a sample implementation: // Copyright 2021 Google LLC. // SPDX-License-Identifier: BSD-3-Clause import "dart:typed_data" show Uint8List; import "dart:collection" show Queue; /// A cyclic buffer of bytes. /// /// Bytes can be appended to the end of the buffer using [append] /// and consumed from the start of the buffer by [read]. class ByteQueue { Uint8List _buffer; int _start = 0; int _length = 0; /// Creates a buffer with zero bytes. /// /// If [initialCapacity] is provided, the buffer will start out /// with that many bytes of initial capacity. It will not need to /// grow until that capacity is exhausted. ByteQueue({int initialCapacity = 256}) : _buffer = Uint8List(initialCapacity); int get _end { var end = _start + _length; if (end > _buffer.length) end -= _buffer.length; return end; } /// Number of bytes currently in the buffer. /// /// This is the maximal number that can be read by [read] and [peek]. int get length => _length; int operator [](int index) { RangeError.checkValidIndex(index, _length); var i = _start + index; if (i > _buffer.length) i -= _buffer.length; return _buffer[i]; } /// Writes circular buffers into other circular buffers. /// /// If [end] \< [start], the range of source wraps around at the end of the list. /// If [offset] + ([end] - [start]) is greater than `target.length`, then /// the write wraps around past the end of the list. static void _write( Uint8List source, int start, int end, Uint8List target, int offset) { int length = end - start; if (length >= 0) { if (offset + length <= target.length) { target.setRange(offset, offset + length, source, start); } else { var firstPart = target.length - offset; target.setRange(offset, target.length, source, start); target.setRange(0, length - firstPart, source, start + firstPart); } } else { var firstPart = source.length - start; _write(source, start, source.length, target, offset); _write(source, 0, end, target, offset + firstPart); } } static int _limit(int value, int limit) => value < limit ? value : value - limit; /// Copies the next [count] bytes of the buffer into [target]. /// /// The bytes are *not* removed from the buffer, and can be read again. /// The bytes are written starting at [offset] in [target]. void peek(int count, Uint8List target, [int offset = 0]) { RangeError.checkValueInInterval(count, 0, _length, "count"); RangeError.checkValueInInterval(offset, 0, target.length, "offset"); if (target.length < count + offset) { throw ArgumentError.value( target, "target", "Must have room for $count elements"); } var end = _limit(_start + count, _buffer.length); _write(_buffer, _start, end, target, 0); } /// Returns the first byte of the buffer. /// /// The buffer is not modified. int peekByte() { if (_length == 0) throw StateError("No element"); return _buffer[_start]; } /// Consumes a single byte from the head of the buffer. int readByte() { if (_length == 0) throw StateError("No element"); var byte = _buffer[_start]; _start = _limit(_start + 1, _buffer.length); _length -= 1; return byte; } /// Consumes the next [count] bytes of the buffer and moves them into [target]. /// /// The bytes are removed from the head of the buffer. /// The bytes are written starting at [offset] in [target]. void read(int count, Uint8List target, [int offset = 0]) { RangeError.checkValueInInterval(count, 0, _length, "count"); RangeError.checkValueInInterval(offset, 0, target.length, "offset"); if (target.length < count + offset) { throw ArgumentError.value( target, "target", "Must have room for $count elements"); } var end = _limit(_start + count, _buffer.length); _write(_buffer, _start, end, target, 0); _start = _limit(_start + count, _buffer.length); _length -= count; } /// Removes the first [count] bytes from the buffer. /// /// Can be useful after a [peek] has turned out to be the bytes /// that you need, or if you know that the following bytes are /// not useful. void remove(int count) { RangeError.checkValueInInterval(count, 0, _length, "count"); _start = _limit(_start + count, _buffer.length); ; } /// Appends [bytes] to the end of the buffer. void append(Uint8List bytes) { var newLength = _length + bytes.length; if (newLength > _buffer.length) { _grow(newLength); } _write(bytes, 0, bytes.length, _buffer, _end); _length = newLength; } void _grow(int newLength) { var capacity = _buffer.length; do { capacity *= 2; } while (capacity < newLength); var newBuffer = Uint8List(capacity); _write(_buffer, _start, _end, newBuffer, 0); _buffer = newBuffer; _start = 0; } } // Or another one with the same interface, // but which doesn't copy bytes into the buffer, only out of it. class ByteQueue2 { final Queue<Uint8List> _source = Queue(); int _length = 0; // The offset into the first element of _source that we haven't consumed. int _start = 0; int get length => _length; void append(Uint8List bytes) { _source.add(bytes); _length += bytes.length; } int peekByte() { if (_length == 0) throw StateError("No element"); return _source.first[_start]; } int readByte() { if (_length == 0) throw StateError("No element"); var first = _source.first; var byte = first[_start]; _start += 1; if (_start >= first.length) { _source.removeFirst(); _start = 0; } _length -= 1; return byte; } void peek(int count, Uint8List target, [int offset = 0]) { RangeError.checkValueInInterval(count, 0, _length, "count"); RangeError.checkValueInInterval(offset, 0, target.length, "offset"); if (offset + count > target.length) { throw ArgumentError.value(target, "target", "Must have length >= ${offset + count}, was: ${target.length}"); } var start = _start; for (var source in _source) { if (count == 0) return; var length = source.length - start; if (count <= length) { target.setRange(offset, offset + count, source, start); return; } target.setRange(offset, offset + length, source, start); start = 0; offset += length; } } void read(int count, Uint8List target, [int offset = 0]) { RangeError.checkValueInInterval(count, 0, _length, "count"); RangeError.checkValueInInterval(offset, 0, target.length, "offset"); if (offset + count > target.length) { throw ArgumentError.value(target, "target", "Must have length >= ${offset + count}, was: ${target.length}"); } var start = _start; while (count > 0) { var source = _source.first; var length = source.length - start; if (count < length) { target.setRange(offset, offset + count, source, start); _start = start + count; _length -= count; return; } target.setRange(offset, offset + length, source, start); offset += length; count -= length; _length -= length; start = _start = 0; _source.removeFirst(); } } } (No priomises).
STM32 UART DMA can receive first time correct then it receive nothing
I'm trying to use dma with uart in stm32f746 nucleo. In receiving mode I can receive correct data in first use. When i try to receive again, receiving buffer doesn't change its initial values before receiving although I can get receive complete signal callback every time. /* Main Loop */ while(1) { HAL_GPIO_TogglePin(LED_PORT,LED_GREEN); // Led Example HAL_Delay(200); pRxData[0]=5; pRxData[1]=0; // HAL_UART_Receive_IT(&UartHandle,pRxData,2); if( HAL_UART_Receive_DMA(&UartHandle,pRxData,2)==HAL_OK); // UART-DMA-IT Example { while (UartReady != SET) // wait for msg len { HAL_GPIO_WritePin(LED_PORT,LED_GREEN,1); HAL_Delay(20); HAL_GPIO_WritePin(LED_PORT,LED_GREEN,0); HAL_Delay(400); } UartReady = RESET; // reset transmition flag LEN = pRxData[0]+pRxData[1]*256; // calc msg length if ( LEN > 0 ) { pTxData[0]= 25;//LEN; // ACK //HAL_UART_Transmit_IT(&UartHandle,pTxData,1); if(HAL_UART_Transmit_DMA(&UartHandle,pTxData,1)==HAL_OK); { while (UartReady != SET) { HAL_Delay(1); } UartReady = RESET; if(HAL_UART_Receive_IT(&UartHandle,pRxData,LEN)==HAL_OK) { //HAL_UART_Receive_DMA(&UartHandle,pRxData,LEN); while (UartReady != SET) // waiting loop for msg { HAL_GPIO_WritePin(LED_PORT,LED_GREEN,1); HAL_Delay(300); HAL_GPIO_WritePin(LED_PORT,LED_GREEN,0); HAL_Delay(50); } UartReady = RESET; if (MBU_StrCompareNC(pRxData,"LED_ON_BLUE",LEN)==0) { HAL_GPIO_WritePin(LED_PORT,LED_BLUE,1); } if (MBU_StrCompareNC(pRxData,"LED_OFF_BLUE",LEN)==0) { HAL_GPIO_WritePin(LED_PORT,LED_BLUE,0); } if (MBU_StrCompareNC(pRxData,"LED_ON_RED",LEN)==0) { HAL_GPIO_WritePin(LED_PORT,LED_RED,1); } if (MBU_StrCompareNC(pRxData,"LED_OFF_RED",LEN)==0) { HAL_GPIO_WritePin(LED_PORT,LED_RED,0); } } HAL_UART_Abort(&UartHandle); } } } } }
select socket call send and recv synchronization
I am using the select call and accepting the connection from "X" no of clients. I made duplex connection i.e. server to client and client to server. When connection is established between 2 entities ,I am going to send data in chunks from one entity to other. During send I read one file in chunks and send the data in chunks. while(file_size !=0) { read_bytes = read(fd, buff, sizeof(buff)); cnt_ = send(_sock_fd,buff,actually_read,0); file_size = file_size - cnt_; printf("total sent remaining %d : %d\n",size,actually_read); } while at receiver side //First I send the header which contain size it got accepted fine but during the following send call I used "get_readable_bytes" (Using ioctl) which returns me the no of bytes arrived at socket `while(size != 0) { int test_ = 0; while(((cnt_= get_readable_bytes(_sock_fd))== 0) )//&& test_ == 0 { cnt_= get_n_readable_bytes(_sock_fd); printf("Total bytes recved %d\n",cnt_); //test_ = test_ + 1; } while(cnt_ != 0) { actually_read = recv(_sock_fd, buff, sizeof(buff),0); int _cnt = get_n_readable_bytes(_sock_fd); printf("Total bytes recved %d\n",cnt_-_cnt); write(_fd,buff,actually_read); cnt_ = cnt_ - actually_read; test_ = 0; } `Now the problem is 1.During this execution of receive function control automatically go to the select function and it tries to execute whole receive function again so is there any way to synchronize the sender and receivers such that when the sender complete then start receiver or as soon as sender start receiver ? 2.And how do I maintain the count of bytes sent and received. and this is my select call `is_read_availble = select(maxfd + 1,&read_set,NULL,NULL,&timeout)` with timeout 10sec.
Sketch of the kind of buffer code you need. (To allow partial reads/writes, the buffers need to be persistent between calls) BTW: you really need to handle the -1 return from read() and write() because they would seriously disturb your buffer-bookkeeping. EINTR + EAGAIN/EWOULDBLOCK is very common. struct buff { unsigned size; unsigned bot; unsigned top; char *buff; }; struct buff bf = {0,0,0,NULL}; initialisation: bf.buff = malloc(SOME_SIZE); /* ... error checking omitted */ bp.size = SOME_SIZE; bp.bot = bp.top =0; reading: unsigned todo; int rc; /* (maybe) shift the buffer down to make place */ todo = bf.top - bf.bot; if (todo) { memmove (bf.buff, bf.buff + bf.bot, todo); bf.top = todo; bf.bot = 0; } todo = bf.size - bf.top; if (!todo) { /* maybe throttle? ... */ return; } rc = read (fd, bf.buff+bp.top, todo); /* ... error checking omitted */ if (rc == -1) switch (errno) {...} else if (rc == 0) {...} else { total_read += rc; bp.top += rc; } writing: unsigned todo; int rc; todo = bf.top - bf.bot; if (!todo) { /* maybe juggle fd_set ... */ return; } rc = write (fd, bf.buff+bp.bot, todo); /* ... error checking omitted */ if (rc == -1) switch (errno) {...} else if (rc ==0) { ...} else { bp.bot += rc; total_written += rc; if (bp.bot == bp.top) bp.bot = bp.top =0; } /* ... this is the place to juggle the fd_set for writing */