I have used STM32CubeMX/IDE to generate a USB HID project for the STM32F3DISCOVERY board.
The USB BTABLE register is zero, indicating that the BTABLE is at the start of the Packet Memory Area.
(I zero the whole PMA at program start, to avoid stale values.)
Just before the execution of the __HAL_RCC_USB_CLK_ENABLE macro (in HAL_PCD_MspInit() in usbd_conf.c) the values of the BTABLE (at index zero onwards, in the PMA are:
After that macro is executed, the values are:
The macro expands to:
do { \
volatile uint32_t tmpreg; \
((((RCC_TypeDef *) ((0x40000000UL + 0x00020000UL) + 0x00001000UL))->APB1ENR) |= ((0x1UL << (23U))));\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = ((((RCC_TypeDef *) ((0x40000000UL + 0x00020000UL) + 0x00001000UL))->APB1ENR) & ((0x1UL << (23U))));\
(void)tmpreg; \
} while(0U)
How does this macro cause the BTABLE to be initialised?
(I need pma[12] to be 0x100 instead of 0x0 as I want to use endpoint 3 for the HID interface in a composite device. I am using this simple HID device to test the use of a different endpoint. Changing 0x81 to 0x83 in USBD_LL_Init() and #define HID_EPIN_ADDR are not sufficient to change the value of pma[12]. The incorrect TX pointer at pma[12] is used and corrupt data is observed in wireshark.)
Update:
If I add code to manually set pma[12] to 0x100:
HAL_StatusTypeDef HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd,
uint16_t ep_addr,
uint16_t ep_kind,
uint32_t pmaadress)
...
/* Here we check if the endpoint is single or double Buffer*/
if (ep_kind == PCD_SNG_BUF)
{
/* Single Buffer */
ep->doublebuffer = 0U;
/* Configure the PMA */
ep->pmaadress = (uint16_t)pmaadress;
// correct PMA BTABLE
uint32_t *btable = (uint32_t *) USB_PMAADDR; // Test this.
if (ep->is_in) {
btable[ep->num * 4] = pmaadress;
}
}
The value at pam[12] does get set, but it later gets overwritten:
__HAL_RCC_USB_CLK_ENABLE() enables clocks for the USB block. Before it is enabled, all peripheral locations are read as zeroes. After clock is enabled, the actual PMA content becomes visible, whatever was written there before reset or random garbage left after the power up. So executing __HAL_RCC_USB_CLK_ENABLE() has nothing to do with your problem.
I don't know where the TX buffer address for endpoint 3 gets overwritten, but I guess it is the Cube sets it when it decides to send data on the endpoint. I am not familiar with the Cube, does it have an API to send a USB packet?
Also, double-check that your pma array has the right definition. On F1 and I likely F3, there is a 2-byte value at each of the 32-bit location.
UPD: Sorry, I saw this question first, but your real problem is why TX addr gets overwritten or not set up correctly.
Here is the structure of the packet header in pcap:
struct pcap_pkthdr {
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire)*/
};
I wonder what is the real difference between caplen and len? And where are they used?
len is the actual length of the packet on the wire. caplen is the length which is captured and thus present in the pcap file. caplen can be the same but also smaller than len.
How many bytes of a packet will be captured can be specified for example in tcpdump with -s size. While on many system tcpdump will capture up to 64k by default for example on OpenBSD it will only capture 116 bytes by default.
I have to read and write some values to a Bike Smart trainer with BLE (Bluetooth Low Energy) used with Flutter. When I try to read the values from the GATT characteristic org.bluetooth.characteristic.supported_power_range (found on bluetooth.org site https://www.bluetooth.com/specifications/gatt/characteristics/ ) I get the return value of an Int List [0,0,200,0,1,0].
The GATT characteristic sais that there are 3 sint16 fields for Min., Max. and step size Watts (Power).
The Byte transmission order also sais that the least significant octet is transmitted first.
My guessings are, that the 3 parameters are returned in an Int array with 8bit value each. But I can't interpret the 200 for maybe the maximum Power setting. Because the smart trainer should provide max. 2300W Watts resistance (ELITE Drivo https://www.elite-it.com/de/produkte/home-trainer/rollentrainer-interaktive/drivo)
The Output results from this code snippet:
device.readCharacteristic(savedCharacteristics[Characteristics.SUPPORTED_POWER_RANGE]).then((List<int> result) {
result.forEach((i) {
print(i.toString());
});
});
// result: [0,0,200,0,1,0]
Maybe some one of u knows how to interpret the binary/hex/dec values of the flutter_blue characteristic output.
Or some hints would be great
Edit
For future readers, I got the solution. I'm a bit asheamed because I read the wrong characteristic.
The return value [0,0,200,0,1,0] was for supported resistance level. (which is 20% and the 200 shows the 20% with a resolution of 0.1 like described in the GATT spec)
I also got a return value for the supported power level which was [0,0,160,15,1,0]. Now the solution how to read the 2 Bytes of max powre level: you get the 160,15 the spec sais LSO (least significant octet first, don't confuse it with LSB least significant bit first). In fact of that you have to read it like 15,160. now do the math with the first Byte 15*256 + 160 = 4000 and thats the correct maximum supported power of the trainer like in the datasheet.
I hope I help someone with that. Thanks for the two replys they are also correct and helped me to find my mistake.
I had the same problem connecting to a Polar H10 to recover HR and RR intervals. It might not be 100% the same, but I think my case can guide you to solve yours.
I am receiving the same list as you like these two examples:
[0,60]
[16,61,524,2]
Looking at the specs of the GATT Bluetooth Heart Rate Service I figured that each element of the list retrieved matches 1 byte of the data transmitted by the characteristic you are subscripted to. For this service, the first byte, i.e., the first element of the list, has some flags to point out if there is an RR value after the HR value (16) or not (0). This is just two cases among the many different ones that can ocur depending on the flags values, but I think it shows how important this first byte can be.
After that, the HR value is coded as an unsigned integer with 8 bits (UINT8), that is, the HR values match the second element of the lists shown before. However, the RR interval is coded as an unsigned integer eith 16bits (UINT16), so it complicates the translation of those two last elements of the list #2 [16,61,524,2], because we should use 16 bits to get this value and the bytes are not in the correct order.
This is when we import the library dart:typed_data
import 'dart:typed_data';
...
_parseHr(List<int> value) {
// First sort the values in the list to interpret correctly the bytes
List<int> valueSorted = [];
valueSorted.insert(0, value[0]);
valueSorted.insert(1, value[1]);
for (var i=0; i< (value.length-3); i++) {
valueSorted.insert(i+2, value[i+3]);
valueSorted.insert(i+3, value[i+2]);
}
// Get flags directly from list
var flags = valueSorted[0];
// Get the ByteBuffer view of the data to recode it later
var buffer = new Uint8List.fromList(valueSorted).buffer; // Buffer bytes from list
if (flags == 0) {
// HR
var hrBuffer = new ByteData.view(buffer, 1, 1); // Get second byte
var hr = hrBuffer.getUint8(0); // Recode as UINT8
print(hr);
}
if (flags == 16) {
// HR
var hrBuffer = new ByteData.view(buffer, 1, 1); // Get second byte
var hr = hrBuffer.getUint8(0); // Recode as UINT8
// RR (more than one can be retrieved in the list)
var nRr = (valueSorted.length-2)/2; // Remove flags and hr from byte count; then split in two since RR is coded as UINT16
List<int> rrs = [];
for (var i = 0; i < nRr; i++) {
var rrBuffer = new ByteData.view(buffer, 2+(i*2), 2); // Get pairs of bytes counting since the 3rd byte
var rr = rrBuffer.getUint16(0); // Recode as UINT16
rrs.insert(i,rr);
}
print(rrs);
}
Hope it helps, the key is to get the buffer view of the sorted list, get the bytes that you need, and recode them as the standard points out.
I used print(new String.fromCharCodes(value)); and that worked for me.
value is your return from List<int> value = await characteristic.read();
I thank ukBaz for his answer to this question. Write data to BLE device and read its response flutter?
You can use my package byte_data_wrapper to transform this data to a decimal value which you can understand:
Get the buffer:
import 'dart:typed_data';
final buffer = Uint16List.fromList(result).buffer;
Create the byteDataCreator:
// Don't forget to add it to your pubspec.yaml
//dependencies:
// byte_data_wrapper:
// git: git://github.com/Taym95/byte_data_wrapper.git
import 'byte_data_wrapper/byte_data_wrapper.dart';
final byteDataCreator = ByteDataCreator.view(buffer);
Get your data :
// You can use getUint8() if valeu is Uint8
final min = byteDataCreator.getUint16();
final max = byteDataCreator.getUint16();
final stepSize = byteDataCreator.getUint16();
I know its too late to answer this but if there is anyone still having a trouble, just convert it manually to be an integer. Because I think you are receiving a type of ByteArray (correct me if I'm wrong).
num bytesToInteger(List<int> bytes) {
/// Given
/// 232 3 0 0
/// Endian.little representation:
/// To binary
/// 00000000 00000000 00000011 11101000
/// Combine
/// 00000000000000000000001111101000
/// Equivalent : 1000
num value = 0;
//Forcing to be Endian.little (I think most devices nowadays uses this type)
if (Endian.host == Endian.big) {
bytes = List.from(bytes.reversed);
}
for (var i = 0, length = bytes.length; i < length; i++) {
value += bytes[i] * pow(256, i);
}
return value;
}
and vice versa when you try to write over 255
Uint8List integerToBytes(int value) {
const arrayLength = 4;
return Uint8List(arrayLength)..buffer.asByteData().setInt32(0, value, Endian.little);
}
Hope this helps.
P.S. I also posted the similar problem here.
I know this should be easy but...
I'm trying to get the MIDI channel number from a midiStatus message.
I have MIDI information coming in:
MIDIPacket *packet = (MIDIPacket*)pktList->packet;
for(int i = 0; i<pktList->numPackets; i++){
Byte midiStatus = packet->data[0];
Byte midiCommand = midiStatus>>4;
if(midiCommand == 0x80){} ///note off
if(midiCommand == 0x90){} ///note on
}
I tried
Byte midiChannel = midiStatus - midiCommand
but that did not seem to give me the correct values.
First of all, not all MIDI messages have channels in them. (For instance, clock messages and sysex messages don't.) Messages with channels are called "voice" messages.
In order to determine whether an arbitrary MIDI message is a voice message, you need to check the top 4 bits of the first byte. Then, once you know you have a voice message, the channel is in the low 4 bits of the first byte.
Voice messages are between 0x8n and 0xEn, where n is the channel.
Byte midiStatus = packet->data[0];
Byte midiCommand = midiStatus & 0xF0; // mask off all but top 4 bits
if (midiCommand >= 0x80 && midiCommand <= 0xE0) {
// it's a voice message
// find the channel by masking off all but the low 4 bits
Byte midiChannel = midiStatus & 0x0F;
// now you can look at the particular midiCommand and decide what to do
}
Also note that MIDI channels are between 0-15 in the message, but are normally presented to users as being between 1-16. You'll have to add 1 before you show the channel to the user, or subtract 1 if you take values from the user.
I can't write data at index above 128 in byte array.
code is given below.
private void Write1(APDU apdu) throws ISOException
{
apdu.setIncomingAndReceive();
byte[] apduBuffer = apdu.getBuffer();
byte j = (byte)apduBuffer[4]; // Return incoming bytes lets take 160
Buffer1 = new byte[j]; // initialize a array with size 160
for (byte i=0; i<j; i++)
Buffer1[(byte)i] = (byte)apduBuffer[5+i];
}
It gives me error 6F 00 (It means reach End Of file).
I am using:
smart card type = contact card
using java card 2.2.2 with jcop using apdu
Your code contains several problems:
As already pointed out by 'pst' you are using a signed byte value which works only up to 128 - use a short instead
Your are creating a new buffer Buffer1 on every call of your Write1 method. On JavaCard there is usually no automatic garbage collection - therefore memory allocation should only be done once when the app is installed. If you only want to process the data in the adpu buffer just use it from there. And if you want to copy data from one byte array into another better use javacard.framework.Util.arrayCopy(..).
You are calling apdu.setIncomingAndReceive(); but ignore the return value. The return value gives you the number of bytes of data you can read.
The following code is from the API docs and shows the common way:
short bytesLeft = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
if (bytesLeft < (short)55) ISOException.throwIt( ISO7816.SW_WRONG_LENGTH );
short readCount = apdu.setIncomingAndReceive();
while ( bytesLeft > 0){
// process bytes in buffer[5] to buffer[readCount+4];
bytesLeft -= readCount;
readCount = apdu.receiveBytes ( ISO7816.OFFSET_CDATA );
}
short j = (short) apdu_buffer[ISO7816.OFFSET_LC] & 0xFF
Elaborating on pst's answer. A byte has 2^8 bits numbers, or rather 256. But if you are working with signed numbers, they will work in a cycle instead. So, 128 will be actually -128, 129 will be -127 and so on.
Update: While the following answer is "valid" for normal Java, please refer to Roberts answer for Java Card-specific information, as well additional concerns/approaches.
In Java a byte has values in the range [-128, 127] so, when you say "160", that's not what the code is really giving you :)
Perhaps you'd like to use:
int j = apduBuffer[4] & 0xFF;
That "upcasts" the value apduBuffer[4] to an int while treating the original byte data as an unsigned value.
Likewise, i should also be an int (to avoid a nasty overflow-and-loop-forever bug), and the System.arraycopy method could be handy as well...
(I have no idea if that is the only/real problem -- or if the above is a viable solution on a Java Card -- but it sure is a problem and aligns with the "128 limit" mentioned.)
Happy coding.