Updated HIDBridge and NHP
This commit is contained in:
parent
36e125a62d
commit
17045e3a92
4 changed files with 361 additions and 231 deletions
|
|
@ -24,23 +24,33 @@ THE SOFTWARE.
|
|||
#include "HIDBridge.h"
|
||||
|
||||
//================================================================================
|
||||
// HIDBridge
|
||||
// HIDBridge TX
|
||||
//================================================================================
|
||||
|
||||
#ifdef HIDBRIDGE_TX
|
||||
|
||||
HIDBridge_ HIDBridge;
|
||||
|
||||
HIDBridge_::HIDBridge_(void){
|
||||
// empty
|
||||
}
|
||||
|
||||
bool HIDBridge_::begin(Stream &s)
|
||||
void HIDBridge_::begin(void)
|
||||
{
|
||||
begin((Stream*)&s);
|
||||
// start the serial at our own baud rate
|
||||
HIDBRIDGE_TX_SERIAL.begin(HIDBRIDGE_BAUD);
|
||||
|
||||
// wait for the first request to see if usb device is connected
|
||||
available();
|
||||
}
|
||||
|
||||
bool HIDBridge_::begin(Stream* s)
|
||||
void HIDBridge_::end(void)
|
||||
{
|
||||
HIDStream = s;
|
||||
// end the serial transmission and reset our helper values
|
||||
HIDBRIDGE_TX_SERIAL.end();
|
||||
nhp_read.mode = NHP_RESET;
|
||||
isReady = false;
|
||||
isConnected = false;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -48,48 +58,60 @@ void HIDBridge_::err(uint8_t error)
|
|||
{
|
||||
if (!debug)
|
||||
return;
|
||||
debug->println("Softserial");
|
||||
debug->print("Bridge Err TX: ");
|
||||
debug->println(error);
|
||||
}
|
||||
|
||||
void HIDBridge_::readSerial(void)
|
||||
void HIDBridge_::read(void)
|
||||
{
|
||||
// read as long as the Serial is available
|
||||
// but do not block forever
|
||||
for (rx_buffer_index_t i = 0; i < SERIAL_RX_BUFFER_SIZE; i++){
|
||||
|
||||
// read in new Serial byte
|
||||
int b = Serial.read();
|
||||
int b = HIDBRIDGE_TX_SERIAL.read();
|
||||
if (b < 0)
|
||||
break;
|
||||
|
||||
// process with NHP protocol
|
||||
bool newInput = NHPread(b, &nhp_read);
|
||||
bool newInput = readNHP(b, &nhp_read);
|
||||
|
||||
// proceed new valid NHP input
|
||||
if (newInput) {
|
||||
|
||||
// NHP address contains control data or out report data
|
||||
if (nhp_read.mode == NHP_ADDRESS) {
|
||||
switch (nhp_read.address) {
|
||||
// received a control address command
|
||||
case HIDBRIDGE_ADDRESS_CONTROL:
|
||||
|
||||
// received a control address command
|
||||
if (nhp_read.address == HIDBRIDGE_ADDRESS_CONTROL) {
|
||||
// acknowledge/request
|
||||
if (nhp_read.data == HIDBRIDGE_CONTROL_ISREADY)
|
||||
if (nhp_read.data == HIDBRIDGE_CONTROL_ISREADY){
|
||||
isReady = true;
|
||||
isConnected = true;
|
||||
}
|
||||
|
||||
// pause
|
||||
else if (nhp_read.data == HIDBRIDGE_CONTROL_NOTREADY)
|
||||
else if (nhp_read.data == HIDBRIDGE_CONTROL_NOTREADY){
|
||||
isReady = false;
|
||||
isConnected = true;
|
||||
}
|
||||
|
||||
// not
|
||||
// usb device detached
|
||||
else if (nhp_read.data == HIDBRIDGE_CONTROL_NOTCONNECTED){
|
||||
isReady = false;
|
||||
isConnected = false;
|
||||
}
|
||||
|
||||
// not defined control command
|
||||
else
|
||||
err(HIDBRIDGE_ERR_CONTROL);
|
||||
|
||||
break;
|
||||
// received HID out report TODO
|
||||
default:
|
||||
err(HIDBRIDGE_ERR_ADDRESS);
|
||||
break;
|
||||
}
|
||||
|
||||
// received HID out report TODO
|
||||
else
|
||||
err(HIDBRIDGE_ERR_ADDRESS);
|
||||
}
|
||||
|
||||
// received HID out report TODO
|
||||
else if (nhp_read.mode == NHP_COMMAND) {
|
||||
err(HIDBRIDGE_ERR_COMMAND);
|
||||
|
|
@ -106,52 +128,46 @@ void HIDBridge_::readSerial(void)
|
|||
}
|
||||
|
||||
|
||||
bool HIDBridge_::waitForReady(void)
|
||||
bool HIDBridge_::available(void)
|
||||
{
|
||||
// try to wait for a new request/acknowledge
|
||||
uint32_t currentMillis = millis();
|
||||
do{
|
||||
// check for new state information
|
||||
// maybe the host sended a pause signal
|
||||
readSerial();
|
||||
read();
|
||||
|
||||
// check for timeout
|
||||
if ((millis() - currentMillis) > HIDBRIDGE_TX_TIMEOUT) {
|
||||
// check for timeout, do not wait longer if usb device is not connected
|
||||
if (!isConnected || (millis() - currentMillis) > HIDBRIDGE_TX_TIMEOUT) {
|
||||
err(HIDBRIDGE_ERR_TIMEOUT);
|
||||
break;
|
||||
}
|
||||
} while (!isReady); //TODO andn no error in readSerial?
|
||||
} while (!isReady);
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
void HIDBridge_::SendReport(uint8_t reportID, const void* data, int len)
|
||||
{
|
||||
// check if stream pointer is set
|
||||
if (!HIDStream){
|
||||
err(HIDBRIDGE_ERR_NO_SPTR);
|
||||
return;
|
||||
}
|
||||
|
||||
// check the latest request/acknowledge,a pause, error
|
||||
if (!waitForReady()){
|
||||
// check the latest request/acknowledge, pause or error
|
||||
if (!available()){
|
||||
err(HIDBRIDGE_ERR_NOT_RDY);
|
||||
return;
|
||||
}
|
||||
|
||||
// begin transfer with reportID as command
|
||||
HIDStream->write(NHPwriteCommand(reportID));
|
||||
HIDBRIDGE_TX_SERIAL.write(writeNHPCommand(reportID));
|
||||
|
||||
// send data in 4 byte packets with the address of the reportID
|
||||
// the rest (if any, e.g. with 2 byte) is filled with random bytes
|
||||
NHP_Write_Data_t n;
|
||||
for (int i = 0; i < len; i += 4) {
|
||||
NHPwriteAddress(reportID, UINT32_AT_OFFSET(data, i), &n);
|
||||
HIDStream->write(n.writeBuffer, n.writeLength);
|
||||
writeNHPAddress(reportID, UINT32_AT_OFFSET(data, i), &n);
|
||||
HIDBRIDGE_TX_SERIAL.write(n.writeBuffer, n.writeLength);
|
||||
}
|
||||
|
||||
// end transfer with zero command
|
||||
HIDStream->write(NHPwriteCommand(0));
|
||||
HIDBRIDGE_TX_SERIAL.write(writeNHPCommand(0));
|
||||
|
||||
// need a request/acknowledge next time again
|
||||
isReady = false;
|
||||
|
|
@ -163,4 +179,14 @@ void HIDBridge_::SendReport(uint8_t reportID, const void* data, int len)
|
|||
void HID_SendReport(uint8_t reportID, const void* data, int len)
|
||||
{
|
||||
HIDBridge.SendReport(reportID, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef HIDBRIDGE_TX
|
||||
|
||||
//================================================================================
|
||||
// HIDBridge RX
|
||||
//================================================================================
|
||||
|
||||
#ifdef HIDBRIDGE_RX
|
||||
|
||||
#endif // #ifdef HIDBRIDGE_RX
|
||||
|
|
@ -25,18 +25,31 @@ THE SOFTWARE.
|
|||
#define HIDBRIDGE_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#include "NHP.h"
|
||||
|
||||
//================================================================================
|
||||
// Settings
|
||||
//================================================================================
|
||||
|
||||
#define HIDBRIDGE_TX_SERIAL Serial
|
||||
|
||||
#ifdef HOODLOADER2
|
||||
#define HIDBRIDGE_RX
|
||||
#else
|
||||
#define HIDBRIDGE_TX
|
||||
#endif
|
||||
|
||||
//================================================================================
|
||||
// Definitions
|
||||
//================================================================================
|
||||
|
||||
#if defined(HIDBRIDGE_RX) && defined(HIDBRIDGE_TX)
|
||||
#error Cannot send and receive at the same time
|
||||
// also because it will create the instance of the class
|
||||
// even if its not used, so we dont separate the TX and RX class names
|
||||
// function names are kept similar
|
||||
#endif
|
||||
|
||||
#define HIDBRIDGE_TX_TIMEOUT 1000
|
||||
|
||||
#define HIDBRIDGE_BAUD 2000000
|
||||
|
|
@ -45,6 +58,7 @@ THE SOFTWARE.
|
|||
|
||||
#define HIDBRIDGE_CONTROL_ISREADY 0
|
||||
#define HIDBRIDGE_CONTROL_NOTREADY 1
|
||||
#define HIDBRIDGE_CONTROL_NOTCONNECTED 1
|
||||
|
||||
#define HIDBRIDGE_ERR_TIMEOUT 0
|
||||
#define HIDBRIDGE_ERR_NHP_ERR 1
|
||||
|
|
@ -52,41 +66,82 @@ THE SOFTWARE.
|
|||
#define HIDBRIDGE_ERR_ADDRESS 3
|
||||
#define HIDBRIDGE_ERR_CONTROL 4
|
||||
#define HIDBRIDGE_ERR_NOT_RDY 5
|
||||
#define HIDBRIDGE_ERR_NO_SPTR 6
|
||||
|
||||
|
||||
//================================================================================
|
||||
// HIDBridge
|
||||
// HIDBridge TX
|
||||
//================================================================================
|
||||
|
||||
|
||||
#ifdef HIDBRIDGE_TX
|
||||
class HIDBridge_{
|
||||
public:
|
||||
HIDBridge_(void);
|
||||
inline void debugStream(Stream* s){
|
||||
debug = s;
|
||||
}
|
||||
bool begin(Stream &s);
|
||||
bool begin(Stream* s);
|
||||
void readSerial(void);
|
||||
bool waitForReady(void);
|
||||
bool isReady;
|
||||
void task(void);
|
||||
void err(uint8_t error);
|
||||
|
||||
// user functions
|
||||
void begin(void);
|
||||
void end(void);
|
||||
|
||||
// advanced user functions
|
||||
void read(void);
|
||||
bool available(void);
|
||||
|
||||
// public to access via HID_SendReport
|
||||
void SendReport(uint8_t reportID, const void* data, int len);
|
||||
|
||||
private:
|
||||
// debug
|
||||
void err(uint8_t error);
|
||||
inline void debugStream(Stream* s){
|
||||
debug = s;
|
||||
}
|
||||
Stream* debug;
|
||||
Stream* HIDStream; //TODO template?
|
||||
|
||||
private:
|
||||
bool isReady;
|
||||
bool isConnected;
|
||||
|
||||
// temporary NHP protocol read data
|
||||
NHP_Read_Data_t nhp_read;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern HIDBridge_ HIDBridge;
|
||||
#endif
|
||||
|
||||
//================================================================================
|
||||
// HIDBridge RX
|
||||
//================================================================================
|
||||
|
||||
#ifdef HIDBRIDGE_RX
|
||||
class HIDBridge_{
|
||||
public:
|
||||
HIDBridge_(void);
|
||||
|
||||
// user functions
|
||||
void begin(void);
|
||||
void end(void);
|
||||
|
||||
// advanced user functions
|
||||
void read(void);
|
||||
bool available(void);
|
||||
|
||||
// public to access via HID_SendReport
|
||||
void SendReport(uint8_t reportID, const void* data, int len);
|
||||
|
||||
// debug
|
||||
void err(uint8_t error);
|
||||
inline void debugStream(Stream* s){
|
||||
debug = s;
|
||||
}
|
||||
Stream* debug;
|
||||
|
||||
private:
|
||||
bool isReady;
|
||||
|
||||
// temporary NHP protocol read data
|
||||
NHP_Read_Data_t nhp_read;
|
||||
};
|
||||
|
||||
extern HIDBridge_ HIDBridge;
|
||||
#endif
|
||||
|
||||
//================================================================================
|
||||
// Function prototypes
|
||||
|
|
|
|||
195
avr/libraries/HIDBridge/NHP.c
Normal file
195
avr/libraries/HIDBridge/NHP.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
Copyright (c) 2014-2015 NicoHood
|
||||
See the readme for credit to other people.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NHP.h"
|
||||
|
||||
//================================================================================
|
||||
// Read NHP
|
||||
//================================================================================
|
||||
|
||||
bool readNHP(uint8_t input, NHP_Read_Data_t* protocol) {
|
||||
// get old protocol states and save into temporary variables (better compiler optimization)
|
||||
uint8_t readLength = protocol->readLength;
|
||||
uint8_t mode;
|
||||
uint8_t blocks = protocol->blocks;
|
||||
uint8_t errorLevel = protocol->errorLevel;
|
||||
uint32_t data = protocol->data;
|
||||
uint8_t address;
|
||||
bool newInput = false;
|
||||
|
||||
// completely reset the protocol after sucessfull reading/error last time
|
||||
if (protocol->mode) {
|
||||
blocks = 0;
|
||||
readLength = 0;
|
||||
}
|
||||
// check if previous reading had a lead error, copy that lead byte to the beginning
|
||||
else if (errorLevel == NHP_ERR_LEAD) {
|
||||
protocol->readBuffer[0] = protocol->readBuffer[readLength];
|
||||
readLength = 1;
|
||||
}
|
||||
|
||||
// write new byte input to the buffer
|
||||
protocol->readBuffer[readLength++] = input;
|
||||
|
||||
// reset mode and errorLevel to the default (no error, no input)
|
||||
errorLevel = NHP_ERR_NONE;
|
||||
mode = NHP_IN_PROGRESS;
|
||||
|
||||
// check the header(lead/data/end) indicator
|
||||
uint8_t header = input & NHP_HEADER_MASK;
|
||||
|
||||
if (header == NHP_HEADER_LEAD)
|
||||
{
|
||||
if (blocks) {
|
||||
// we were still reading! Log an error but continue reading with this new lead
|
||||
// set indicator to move this lead byte to the beginning next reading
|
||||
errorLevel = NHP_ERR_LEAD;
|
||||
// write the buffer without the new lead, move it next reading
|
||||
readLength--;
|
||||
}
|
||||
|
||||
// read command indicator or block length
|
||||
blocks = (input >> NHP_LENGTH_OFFSET) & (NHP_LENGTH_MASK >> NHP_LENGTH_OFFSET);
|
||||
|
||||
if (blocks == NHP_LENGTH_COMMAND_0 || blocks == NHP_LENGTH_COMMAND_1) {
|
||||
// save command in data variable
|
||||
data = input & NHP_COMMAND_MASK;
|
||||
// return command indicator, reset next reading
|
||||
mode = NHP_COMMAND;
|
||||
newInput = true;
|
||||
}
|
||||
// address data
|
||||
else if (blocks == NHP_LENGTH_HIGH_MSB31) {
|
||||
// save block length + first 4 data bits (special 32 bit case)
|
||||
data = input & NHP_DATA_4BIT_MASK;
|
||||
blocks -= 2;
|
||||
}
|
||||
else {
|
||||
// save block length + first 3 data bits
|
||||
data = input & NHP_DATA_3BIT_MASK;
|
||||
blocks--;
|
||||
}
|
||||
}
|
||||
|
||||
else if (header == NHP_HEADER_END)
|
||||
{
|
||||
// reset next reading on both: valid input or error
|
||||
if (blocks == 1){
|
||||
// valid input, save the address
|
||||
address = input & NHP_ADDRESS_MASK;
|
||||
mode = NHP_ADDRESS;
|
||||
newInput = true;
|
||||
}
|
||||
else{
|
||||
// too early for an end, reset next time
|
||||
errorLevel = NHP_ERR_END;
|
||||
mode = NHP_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
else if (header == NHP_HEADER_DATA_A || header == NHP_HEADER_DATA_B)
|
||||
{
|
||||
if (blocks > 1) {
|
||||
// get next 7 bits of data
|
||||
blocks--;
|
||||
data <<= NHP_DATA_7BIT;
|
||||
// normally dont need & NHP_DATA_7BIT_MASK because the MSB bit is zero
|
||||
data |= (input & NHP_DATA_7BIT_MASK);
|
||||
}
|
||||
else {
|
||||
// log an error, expecting a lead or end byte
|
||||
errorLevel = NHP_ERR_DATA;
|
||||
mode = NHP_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
// save temporary values to the data struct
|
||||
protocol->blocks = blocks;
|
||||
protocol->mode = mode;
|
||||
protocol->readLength = readLength;
|
||||
protocol->address = address;
|
||||
protocol->errorLevel = errorLevel;
|
||||
protocol->data = data;
|
||||
|
||||
// return if we have a new address or command
|
||||
return newInput;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
// Write NHP
|
||||
//================================================================================
|
||||
|
||||
uint8_t writeNHPCommand(uint8_t command) {
|
||||
// write lead mask 11 + length 00|0 or 00|1 including the last bit for the 4 bit command
|
||||
// return the command with protocol around
|
||||
return NHP_HEADER_LEAD | (command & NHP_COMMAND_MASK);
|
||||
}
|
||||
|
||||
void writeNHPAddress(uint8_t address, uint32_t data, NHP_Write_Data_t* protocol) {
|
||||
// start with the maximum size of blocks (6+1 for special MSB case)
|
||||
uint8_t blocks = 7;
|
||||
|
||||
// check for the first 7 bit block that doesnt fit into the first 3 bits
|
||||
while (blocks > 2) {
|
||||
// get the next 7 bit data block, starting from MSB to LSB
|
||||
uint8_t nextvalue = (data >> (7 * (blocks - 3)));
|
||||
if (nextvalue > NHP_DATA_3BIT_MASK) {
|
||||
// data won't fit into the first 3 bits, wee need an extra block for them
|
||||
// don't write them to the lead block, keep the data for the data blocks
|
||||
if (blocks == 7) {
|
||||
// special case for the MSB where we still want to write
|
||||
// the 'too big' value into the lead block
|
||||
protocol->writeBuffer[0] = nextvalue;
|
||||
blocks = 6;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// write the possible first 3 bits and check again if the value is zero
|
||||
// this also ensures that the first byte is always initialized
|
||||
protocol->writeBuffer[0] = nextvalue;
|
||||
blocks--;
|
||||
|
||||
// we have our first bits, stop
|
||||
if (nextvalue)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the rest of the data blocks
|
||||
uint8_t datablocks = blocks - 2;
|
||||
while (datablocks > 0) {
|
||||
protocol->writeBuffer[datablocks] = data & NHP_DATA_7BIT_MASK;
|
||||
data >>= 7;
|
||||
datablocks--;
|
||||
}
|
||||
|
||||
// add lead 11 + length to the first 3 (or 4 for special MSB case) data bits
|
||||
protocol->writeBuffer[0] |= NHP_HEADER_LEAD | (blocks << NHP_LENGTH_OFFSET);
|
||||
|
||||
// write end 10 + address
|
||||
protocol->writeBuffer[blocks - 1] = NHP_HEADER_END | (address & NHP_ADDRESS_MASK);
|
||||
|
||||
// save the number of blocks
|
||||
protocol->writeLength = blocks;
|
||||
}
|
||||
|
|
@ -24,10 +24,14 @@ THE SOFTWARE.
|
|||
#ifndef NHP_H
|
||||
#define NHP_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#include <stdint.h> //uint_t definitions
|
||||
#include <stdbool.h> //bool type
|
||||
|
||||
|
||||
//================================================================================
|
||||
//Settings
|
||||
//================================================================================
|
||||
|
|
@ -48,9 +52,13 @@ THE SOFTWARE.
|
|||
// Lead
|
||||
#define NHP_LENGTH_MASK 0x38 // B00|111|000
|
||||
#define NHP_LENGTH_OFFSET 3
|
||||
#define NHP_LENGTH_COMMAND_0 0 // length 0 indicates a command
|
||||
#define NHP_LENGTH_COMMAND_1 1 // length 1 indicates a command
|
||||
#define NHP_LENGTH_HIGH_MSB31 7 // length 7 indicates MSB 31 is high (1)
|
||||
#define NHP_COMMAND_MASK 0x0F // B0000|1111 // 4bit command(0-15) in lead block
|
||||
|
||||
// Data
|
||||
#define NHP_DATA_7BIT 7 // data blocks contain 7 bit of information
|
||||
#define NHP_DATA_7BIT_MASK 0x7F // B0|1111111 // data in data block
|
||||
#define NHP_DATA_4BIT_MASK 0x0F // B0000|1111 // data in lead (32 bit special MSB case)
|
||||
#define NHP_DATA_3BIT_MASK 0x07 // B00000|111 // data in lead
|
||||
|
|
@ -79,9 +87,13 @@ THE SOFTWARE.
|
|||
#define UINT16_AT_OFFSET(p_to_8, offset) ((uint16_t)*((const uint16_t *)((p_to_8)+(offset))))
|
||||
#define UINT32_AT_OFFSET(p_to_8, offset) ((uint32_t)*((const uint32_t *)((p_to_8)+(offset))))
|
||||
|
||||
// protocol data for temporary variables
|
||||
//================================================================================
|
||||
// Typedefs
|
||||
//================================================================================
|
||||
|
||||
// protocol read data for temporary variables
|
||||
typedef union {
|
||||
struct { //TODO change order to save flash?
|
||||
struct {
|
||||
// buffer for read operations
|
||||
uint8_t readBuffer[NHP_READ_BUFFER_SIZE];
|
||||
|
||||
|
|
@ -96,15 +108,15 @@ typedef union {
|
|||
// temporary + final data
|
||||
uint32_t data;
|
||||
uint32_t data32;
|
||||
uint16_t data16[sizeof(data) / sizeof(uint16_t)];
|
||||
uint8_t data8[sizeof(data)];
|
||||
uint16_t data16[sizeof(uint32_t) / sizeof(uint16_t)];
|
||||
uint8_t data8[sizeof(uint32_t) / sizeof(uint8_t)];
|
||||
uint8_t command : 4;
|
||||
};
|
||||
};
|
||||
uint8_t raw[sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(readBuffer)];
|
||||
uint8_t raw[NHP_READ_BUFFER_SIZE + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t)];
|
||||
} NHP_Read_Data_t;
|
||||
|
||||
// protocol data for temporary variables
|
||||
// protocol write data for temporary variables
|
||||
typedef union {
|
||||
struct{
|
||||
// buffer for write operations
|
||||
|
|
@ -112,177 +124,19 @@ typedef union {
|
|||
uint8_t writeLength;
|
||||
};
|
||||
|
||||
uint8_t raw[sizeof(writeBuffer) + sizeof(uint8_t)];
|
||||
uint8_t raw[NHP_WRITE_BUFFER_SIZE + sizeof(uint8_t)];
|
||||
} NHP_Write_Data_t;
|
||||
|
||||
//================================================================================
|
||||
// Protocol Function Prototypes
|
||||
// Function Prototypes
|
||||
//================================================================================
|
||||
|
||||
static bool NHPread(uint8_t input, NHP_Read_Data_t* protocol) {
|
||||
// get old protocol states and save into temporary variables (better compiler optimization)
|
||||
uint8_t readLength = protocol->readLength;
|
||||
uint8_t mode;
|
||||
uint8_t blocks = protocol->blocks;
|
||||
uint8_t errorLevel = protocol->errorLevel;
|
||||
uint32_t data = protocol->data;
|
||||
uint8_t address;
|
||||
bool newInput = false;
|
||||
bool readNHP(uint8_t input, NHP_Read_Data_t* protocol);
|
||||
uint8_t writeNHPCommand(uint8_t command);
|
||||
void writeNHPAddress(uint8_t address, uint32_t data, NHP_Write_Data_t* protocol);
|
||||
|
||||
// completely reset the protocol after sucessfull reading/error last time
|
||||
if (protocol->mode) {
|
||||
blocks = 0;
|
||||
readLength = 0;
|
||||
}
|
||||
// check if previous reading had a lead error, copy that lead byte to the beginning
|
||||
else if (errorLevel == NHP_ERR_LEAD) {
|
||||
protocol->readBuffer[0] = protocol->readBuffer[readLength];
|
||||
readLength = 1;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// write new byte input to the buffer
|
||||
protocol->readBuffer[readLength++] = input;
|
||||
|
||||
// reset mode and errorLevel to the default (no error, no input)
|
||||
errorLevel = NHP_ERR_NONE;
|
||||
mode = NHP_IN_PROGRESS;
|
||||
|
||||
// check the header(lead/data/end) indicator
|
||||
uint8_t header = input & NHP_HEADER_MASK;
|
||||
|
||||
if (header == NHP_HEADER_LEAD)
|
||||
{
|
||||
if (blocks) {
|
||||
// we were still reading! Log an error but continue reading with this new lead
|
||||
// set indicator to move this lead byte to the beginning next reading
|
||||
errorLevel = NHP_ERR_LEAD;
|
||||
// write the buffer without the new lead, move it next reading
|
||||
readLength--;
|
||||
}
|
||||
|
||||
// read command indicator or block length
|
||||
blocks = (input >> NHP_LENGTH_OFFSET) & (NHP_LENGTH_MASK >> NHP_LENGTH_OFFSET);
|
||||
|
||||
if (blocks == 0 || blocks == 1) {
|
||||
// save command in data variable
|
||||
data = input & NHP_COMMAND_MASK;
|
||||
// return command indicator, reset next reading
|
||||
mode = NHP_COMMAND;
|
||||
newInput = true;
|
||||
}
|
||||
// address data
|
||||
else if (blocks == 7) {
|
||||
// save block length + first 4 data bits (special 32 bit case)
|
||||
data = input & NHP_DATA_4BIT_MASK;
|
||||
blocks -= 2;
|
||||
}
|
||||
else {
|
||||
// save block length + first 3 data bits
|
||||
data = input & NHP_DATA_3BIT_MASK;
|
||||
blocks--;
|
||||
}
|
||||
}
|
||||
|
||||
else if (header == NHP_HEADER_END)
|
||||
{
|
||||
// reset next reading on both: valid input or error
|
||||
if (blocks == 1){
|
||||
// valid input, save the address
|
||||
address = input & NHP_ADDRESS_MASK;
|
||||
mode = NHP_ADDRESS;
|
||||
newInput = true;
|
||||
}
|
||||
else{
|
||||
// too early for an end, reset next time
|
||||
errorLevel = NHP_ERR_END;
|
||||
mode = NHP_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
else if (header == NHP_HEADER_DATA_A || header == NHP_HEADER_DATA_B)
|
||||
{
|
||||
if (blocks >= 2) {
|
||||
// get next 7 bits of data
|
||||
blocks--;
|
||||
data <<= 7;
|
||||
// normally dont need & NHP_DATA_7BIT_MASK because the MSB bit is zero
|
||||
data |= (input & NHP_DATA_7BIT_MASK);
|
||||
}
|
||||
else {
|
||||
// log an error, expecting a lead or end byte
|
||||
errorLevel = NHP_ERR_DATA;
|
||||
mode = NHP_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
// save temporary values to the data struct
|
||||
protocol->blocks = blocks;
|
||||
protocol->mode = mode;
|
||||
protocol->readLength = readLength;
|
||||
protocol->address = address;
|
||||
protocol->errorLevel = errorLevel;
|
||||
protocol->data = data;
|
||||
|
||||
// return if we have a new address or command
|
||||
return newInput;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
// Write NHP
|
||||
//================================================================================
|
||||
|
||||
static uint8_t NHPwriteCommand(uint8_t command) {
|
||||
// write lead mask 11 + length 00|0 or 00|1 including the last bit for the 4 bit command
|
||||
// return the command with protocol around
|
||||
return NHP_HEADER_LEAD | (command & NHP_COMMAND_MASK);
|
||||
}
|
||||
|
||||
static void NHPwriteAddress(uint8_t address, uint32_t data, NHP_Write_Data_t* protocol) {
|
||||
// start with the maximum size of blocks (6+1 for special MSB case)
|
||||
uint8_t blocks = 7;
|
||||
|
||||
// check for the first 7 bit block that doesnt fit into the first 3 bits
|
||||
while (blocks > 2) {
|
||||
uint8_t nextvalue = (data >> (7 * (blocks - 3)));
|
||||
if (nextvalue > NHP_DATA_3BIT_MASK) {
|
||||
// data won't fit into the first 3 bits, wee need an extra block for them
|
||||
// don't write them to the lead block, keep the data for the data blocks
|
||||
if (blocks == 7) {
|
||||
// special case for the MSB where we still want to write
|
||||
// the 'too big' value into the lead block
|
||||
protocol->writeBuffer[0] = nextvalue;
|
||||
blocks = 6;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// write the possible first 3 bits and check again if the value is zero
|
||||
// this also ensures that the first byte is always initialized
|
||||
protocol->writeBuffer[0] = nextvalue;
|
||||
blocks--;
|
||||
|
||||
// we have our first bits, stop
|
||||
if (nextvalue)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the rest of the data blocks
|
||||
uint8_t datablocks = blocks - 2;
|
||||
while (datablocks > 0) {
|
||||
protocol->writeBuffer[datablocks] = data & NHP_DATA_7BIT_MASK;
|
||||
data >>= 7;
|
||||
datablocks--;
|
||||
}
|
||||
|
||||
// add lead 11 + length to the first 3 (or 4 for special MSB case) data bits
|
||||
protocol->writeBuffer[0] |= NHP_HEADER_LEAD | (blocks << NHP_LENGTH_OFFSET);
|
||||
|
||||
// write end 10 + address
|
||||
protocol->writeBuffer[blocks - 1] = NHP_HEADER_END | (address & NHP_ADDRESS_MASK);
|
||||
|
||||
// save the number of blocks
|
||||
protocol->writeLength = blocks;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // include guard
|
||||
Loading…
Reference in a new issue