Feedback History working!

This commit is contained in:
Florian Märkl 2019-07-04 23:46:26 +02:00
commit e37ac7bc77
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
9 changed files with 326 additions and 36 deletions

View file

@ -117,6 +117,17 @@ void StreamSession::UpdateGamepads()
connect(gamepad, &QGamepad::buttonBChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonXChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonYChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonLeftChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonRightChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonUpChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonDownChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonL1Changed, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonR1Changed, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonL3Changed, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonR3Changed, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonStartChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonSelectChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::buttonGuideChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::axisLeftXChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::axisLeftYChanged, this, &StreamSession::SendFeedbackState);
connect(gamepad, &QGamepad::axisRightXChanged, this, &StreamSession::SendFeedbackState);
@ -137,6 +148,17 @@ void StreamSession::SendFeedbackState()
state.buttons |= gamepad->buttonB() ? CHIAKI_CONTROLLER_BUTTON_MOON : 0;
state.buttons |= gamepad->buttonX() ? CHIAKI_CONTROLLER_BUTTON_BOX : 0;
state.buttons |= gamepad->buttonY() ? CHIAKI_CONTROLLER_BUTTON_PYRAMID : 0;
state.buttons |= gamepad->buttonLeft() ? CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT : 0;
state.buttons |= gamepad->buttonRight() ? CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT : 0;
state.buttons |= gamepad->buttonUp() ? CHIAKI_CONTROLLER_BUTTON_DPAD_UP : 0;
state.buttons |= gamepad->buttonDown() ? CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN : 0;
state.buttons |= gamepad->buttonL1() ? CHIAKI_CONTROLLER_BUTTON_L1 : 0;
state.buttons |= gamepad->buttonR1() ? CHIAKI_CONTROLLER_BUTTON_R1 : 0;
state.buttons |= gamepad->buttonL3() ? CHIAKI_CONTROLLER_BUTTON_L3 : 0;
state.buttons |= gamepad->buttonR3() ? CHIAKI_CONTROLLER_BUTTON_R3 : 0;
state.buttons |= gamepad->buttonStart() ? CHIAKI_CONTROLLER_BUTTON_OPTIONS : 0;
state.buttons |= gamepad->buttonSelect() ? CHIAKI_CONTROLLER_BUTTON_SHARE : 0;
state.buttons |= gamepad->buttonGuide() ? CHIAKI_CONTROLLER_BUTTON_PS : 0;
state.left_x = static_cast<int16_t>(gamepad->axisLeftX() * 0x7fff);
state.left_y = static_cast<int16_t>(gamepad->axisLeftY() * 0x7fff);
state.right_x = static_cast<int16_t>(gamepad->axisRightX() * 0x7fff);

View file

@ -32,9 +32,23 @@ typedef enum chiaki_controller_button_t
CHIAKI_CONTROLLER_BUTTON_CROSS = (1 << 0),
CHIAKI_CONTROLLER_BUTTON_MOON = (1 << 1),
CHIAKI_CONTROLLER_BUTTON_BOX = (1 << 2),
CHIAKI_CONTROLLER_BUTTON_PYRAMID = (1 << 3)
CHIAKI_CONTROLLER_BUTTON_PYRAMID = (1 << 3),
CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT = (1 << 4),
CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT = (1 << 5),
CHIAKI_CONTROLLER_BUTTON_DPAD_UP = (1 << 6),
CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN = (1 << 7),
CHIAKI_CONTROLLER_BUTTON_L1 = (1 << 8),
CHIAKI_CONTROLLER_BUTTON_R1 = (1 << 9),
CHIAKI_CONTROLLER_BUTTON_L3 = (1 << 10),
CHIAKI_CONTROLLER_BUTTON_R3 = (1 << 11),
CHIAKI_CONTROLLER_BUTTON_OPTIONS = (1 << 12),
CHIAKI_CONTROLLER_BUTTON_SHARE = (1 << 13),
CHIAKI_CONTROLLER_BUTTON_TOUCHPAD = (1 << 14),
CHIAKI_CONTROLLER_BUTTON_PS = (1 << 15)
} ChiakiControllerButton;
#define CHIAKI_CONTROLLER_BUTTONS_COUNT 16
typedef struct chiaki_controller_state_t
{
/**
@ -42,6 +56,9 @@ typedef struct chiaki_controller_state_t
*/
uint32_t buttons;
uint8_t l2_state;
uint8_t r2_state;
int16_t left_x;
int16_t left_y;
int16_t right_x;

View file

@ -20,6 +20,7 @@
#include "common.h"
#include "log.h"
#include "controller.h"
#include <stdint.h>
@ -29,7 +30,6 @@ extern "C" {
typedef struct chiaki_feedback_state_t
{
uint32_t buttons;
int16_t left_x;
int16_t left_y;
int16_t right_x;
@ -43,6 +43,44 @@ typedef struct chiaki_feedback_state_t
*/
CHIAKI_EXPORT void chiaki_feedback_state_format(uint8_t *buf, ChiakiFeedbackState *state);
#define CHIAKI_HISTORY_EVENT_SIZE_MAX 0x3 // TODO: will be bigger later for touchpad at least
typedef struct chiaki_feedback_history_event_t
{
uint8_t buf[CHIAKI_HISTORY_EVENT_SIZE_MAX];
size_t len;
} ChiakiFeedbackHistoryEvent;
/**
* @param state 0x0 for not pressed, 0xff for pressed, intermediate values for analog triggers
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_event_set_button(ChiakiFeedbackHistoryEvent *event, ChiakiControllerButton button, uint8_t state);
/**
* Ring buffer of ChiakiFeedbackHistoryEvent
*/
typedef struct chiaki_feedback_history_buffer_t
{
ChiakiFeedbackHistoryEvent *events;
size_t size;
size_t begin;
size_t len;
} ChiakiFeedbackHistoryBuffer;
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_buffer_init(ChiakiFeedbackHistoryBuffer *feedback_history_buffer, size_t size);
CHIAKI_EXPORT void chiaki_feedback_history_buffer_fini(ChiakiFeedbackHistoryBuffer *feedback_history_buffer);
/**
* @param buf_size Pointer to the allocated size of buf, will contain the written size after a successful formatting.
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_buffer_format(ChiakiFeedbackHistoryBuffer *feedback_history_buffer, uint8_t *buf, size_t *buf_size);
/**
* Push an event to the front of the buffer
*/
CHIAKI_EXPORT void chiaki_feedback_history_buffer_push(ChiakiFeedbackHistoryBuffer *feedback_history_buffer, ChiakiFeedbackHistoryEvent *event);
#ifdef __cplusplus
}
#endif

View file

@ -35,6 +35,9 @@ typedef struct chiaki_feedback_sender_t
ChiakiSeqNum16 state_seq_num;
ChiakiSeqNum16 history_seq_num;
ChiakiFeedbackHistoryBuffer history_buf;
bool should_stop;
ChiakiControllerState controller_state_prev;
ChiakiControllerState controller_state;

View file

@ -205,6 +205,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_congestion(ChiakiTakion *takion
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_feedback_state(ChiakiTakion *takion, ChiakiSeqNum16 seq_num, ChiakiFeedbackState *feedback_state);
/**
* Thread-safe while Takion is running.
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_feedback_history(ChiakiTakion *takion, ChiakiSeqNum16 seq_num, uint8_t *payload, size_t payload_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_av_packet_parse(ChiakiTakionAVPacket *packet, uint8_t base_type, uint8_t *buf, size_t buf_size);

View file

@ -19,6 +19,7 @@
#include <chiaki/controller.h>
#include <arpa/inet.h>
#include <string.h>
CHIAKI_EXPORT void chiaki_feedback_state_format(uint8_t *buf, ChiakiFeedbackState *state)
{
@ -44,3 +45,109 @@ CHIAKI_EXPORT void chiaki_feedback_state_format(uint8_t *buf, ChiakiFeedbackStat
*((uint16_t *)(buf + 0x15)) = htons((uint16_t)state->right_x);
*((uint16_t *)(buf + 0x17)) = htons((uint16_t)state->right_y);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_event_set_button(ChiakiFeedbackHistoryEvent *event, ChiakiControllerButton button, uint8_t state)
{
// some buttons use a third byte for the state, some don't
event->buf[0] = 0x80;
event->len = 2;
switch(button)
{
case CHIAKI_CONTROLLER_BUTTON_CROSS:
event->buf[1] = 0x88;
break;
case CHIAKI_CONTROLLER_BUTTON_MOON:
event->buf[1] = 0x89;
break;
case CHIAKI_CONTROLLER_BUTTON_BOX:
event->buf[1] = 0x8a;
break;
case CHIAKI_CONTROLLER_BUTTON_PYRAMID:
event->buf[1] = 0x8b;
break;
case CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT:
event->buf[1] = 0x82;
break;
case CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT:
event->buf[1] = 0x83;
break;
case CHIAKI_CONTROLLER_BUTTON_DPAD_UP:
event->buf[1] = 0x80;
break;
case CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN:
event->buf[1] = 0x81;
break;
case CHIAKI_CONTROLLER_BUTTON_L1:
event->buf[1] = 0x84;
break;
case CHIAKI_CONTROLLER_BUTTON_R1:
event->buf[1] = 0x85;
break;
case CHIAKI_CONTROLLER_BUTTON_L3:
event->buf[1] = state ? 0xaf : 0x8f;
return CHIAKI_ERR_SUCCESS;
case CHIAKI_CONTROLLER_BUTTON_R3:
event->buf[1] = state ? 0xb0 : 0x90;
return CHIAKI_ERR_SUCCESS;
case CHIAKI_CONTROLLER_BUTTON_OPTIONS:
event->buf[1] = state ? 0xac : 0x8c;
return CHIAKI_ERR_SUCCESS;
case CHIAKI_CONTROLLER_BUTTON_SHARE:
event->buf[1] = state ? 0xad : 0x8d;
return CHIAKI_ERR_SUCCESS;
case CHIAKI_CONTROLLER_BUTTON_TOUCHPAD:
event->buf[1] = state ? 0xb1 : 0x91;
return CHIAKI_ERR_SUCCESS;
case CHIAKI_CONTROLLER_BUTTON_PS:
event->buf[1] = state ? 0xae : 0x8e;
return CHIAKI_ERR_SUCCESS;
default:
return CHIAKI_ERR_INVALID_DATA;
}
event->buf[2] = state;
event->len = 3;
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_buffer_init(ChiakiFeedbackHistoryBuffer *feedback_history_buffer, size_t size)
{
feedback_history_buffer->events = calloc(size, sizeof(ChiakiFeedbackHistoryEvent));
if(!feedback_history_buffer->events)
return CHIAKI_ERR_MEMORY;
feedback_history_buffer->size = size;
feedback_history_buffer->begin = 0;
feedback_history_buffer->len = 0;
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT void chiaki_feedback_history_buffer_fini(ChiakiFeedbackHistoryBuffer *feedback_history_buffer)
{
free(feedback_history_buffer->events);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_buffer_format(ChiakiFeedbackHistoryBuffer *feedback_history_buffer, uint8_t *buf, size_t *buf_size)
{
size_t size_max = *buf_size;
size_t written = 0;
for(size_t i=0; i<feedback_history_buffer->len; i++)
{
ChiakiFeedbackHistoryEvent *event = &feedback_history_buffer->events[(feedback_history_buffer->begin + i) % feedback_history_buffer->size];
if(written + event->len > size_max)
return CHIAKI_ERR_BUF_TOO_SMALL;
memcpy(buf + written, event->buf, event->len);
written += event->len;
}
*buf_size = written;
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT void chiaki_feedback_history_buffer_push(ChiakiFeedbackHistoryBuffer *feedback_history_buffer, ChiakiFeedbackHistoryEvent *event)
{
feedback_history_buffer->begin = (feedback_history_buffer->begin + feedback_history_buffer->size - 1) % feedback_history_buffer->size;
feedback_history_buffer->len++;
if(feedback_history_buffer->len >= feedback_history_buffer->size)
feedback_history_buffer->len = feedback_history_buffer->size;
feedback_history_buffer->events[feedback_history_buffer->begin] = *event;
}

View file

@ -20,6 +20,8 @@
#define FEEDBACK_STATE_TIMEOUT_MIN_MS 8 // minimum time to wait between sending 2 packets
#define FEEDBACK_STATE_TIMEOUT_MAX_MS 200 // maximum time to wait between sending 2 packets
#define FEEDBACK_HISTORY_BUFFER_SIZE 0x10
static void *feedback_sender_thread_func(void *user);
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_init(ChiakiFeedbackSender *feedback_sender, ChiakiTakion *takion)
@ -32,10 +34,15 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_init(ChiakiFeedbackSender *
feedback_sender->state_seq_num = 0;
ChiakiErrorCode err = chiaki_mutex_init(&feedback_sender->state_mutex, false);
feedback_sender->history_seq_num = 0;
ChiakiErrorCode err = chiaki_feedback_history_buffer_init(&feedback_sender->history_buf, FEEDBACK_HISTORY_BUFFER_SIZE);
if(err != CHIAKI_ERR_SUCCESS)
return err;
err = chiaki_mutex_init(&feedback_sender->state_mutex, false);
if(err != CHIAKI_ERR_SUCCESS)
goto error_history_buffer;
err = chiaki_cond_init(&feedback_sender->state_cond);
if(err != CHIAKI_ERR_SUCCESS)
goto error_mutex;
@ -49,6 +56,8 @@ error_cond:
chiaki_cond_fini(&feedback_sender->state_cond);
error_mutex:
chiaki_mutex_fini(&feedback_sender->state_mutex);
error_history_buffer:
chiaki_feedback_history_buffer_fini(&feedback_sender->history_buf);
return err;
}
@ -61,6 +70,7 @@ CHIAKI_EXPORT void chiaki_feedback_sender_fini(ChiakiFeedbackSender *feedback_se
chiaki_thread_join(&feedback_sender->thread, NULL);
chiaki_cond_fini(&feedback_sender->state_cond);
chiaki_mutex_fini(&feedback_sender->state_mutex);
chiaki_feedback_history_buffer_fini(&feedback_sender->history_buf);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_set_controller_state(ChiakiFeedbackSender *feedback_sender, ChiakiControllerState *state)
@ -84,10 +94,17 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_set_controller_state(Chiaki
return CHIAKI_ERR_SUCCESS;
}
static bool controller_state_equals_for_feedback_state(ChiakiControllerState *a, ChiakiControllerState *b)
{
return a->left_x == b->left_x
&& a->left_y == b->left_y
&& a->right_x == b->right_x
&& a->right_y == b->right_y;
}
static void feedback_sender_send_state(ChiakiFeedbackSender *feedback_sender)
{
ChiakiFeedbackState state;
state.buttons = feedback_sender->controller_state.buttons;
state.left_x = feedback_sender->controller_state.left_x;
state.left_y = feedback_sender->controller_state.left_y;
state.right_x = feedback_sender->controller_state.right_x;
@ -97,6 +114,53 @@ static void feedback_sender_send_state(ChiakiFeedbackSender *feedback_sender)
CHIAKI_LOGE(feedback_sender->log, "FeedbackSender failed to send Feedback State\n");
}
static bool controller_state_equals_for_feedback_history(ChiakiControllerState *a, ChiakiControllerState *b)
{
return a->buttons == b->buttons;
}
static void feedback_sender_send_history(ChiakiFeedbackSender *feedback_sender)
{
// TODO: Is it legal to have more than one new event per packet?
size_t new_events_count = 0;
uint64_t buttons_prev = feedback_sender->controller_state_prev.buttons;
uint64_t buttons_now = feedback_sender->controller_state.buttons;
for(uint8_t i=0; i<CHIAKI_CONTROLLER_BUTTONS_COUNT; i++)
{
uint64_t button_id = 1 << i;
bool prev = buttons_prev & button_id;
bool now = buttons_now & button_id;
if(prev != now)
{
ChiakiFeedbackHistoryEvent event;
ChiakiErrorCode err = chiaki_feedback_history_event_set_button(&event, button_id, now ? 0xff : 0);
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(feedback_sender->log, "Feedback Sender failed to format button history event for button id %llu\n", (unsigned long long)button_id);
continue;
}
chiaki_feedback_history_buffer_push(&feedback_sender->history_buf, &event);
new_events_count++;
}
}
if(!new_events_count) // TODO: also send on timeout sometimes?
return;
uint8_t buf[0x300];
size_t buf_size = sizeof(buf);
ChiakiErrorCode err = chiaki_feedback_history_buffer_format(&feedback_sender->history_buf, buf, &buf_size);
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(feedback_sender->log, "Feedback Sender failed to format history buffer\n");
return;
}
CHIAKI_LOGD(feedback_sender->log, "Feedback History:\n");
chiaki_log_hexdump(feedback_sender->log, CHIAKI_LOG_DEBUG, buf, buf_size);
chiaki_takion_send_feedback_history(feedback_sender->takion, feedback_sender->history_seq_num++, buf, buf_size);
}
static bool state_cond_check(void *user)
{
ChiakiFeedbackSender *feedback_sender = user;
@ -121,14 +185,27 @@ static void *feedback_sender_thread_func(void *user)
if(feedback_sender->should_stop)
break;
bool send_feedback_state = true;
bool send_feedback_history = false;
if(feedback_sender->controller_state_changed)
{
// TODO: FEEDBACK_STATE_TIMEOUT_MIN_MS
feedback_sender->controller_state_changed = false;
}
// don't need to send feedback state if nothing relevant changed
if(controller_state_equals_for_feedback_state(&feedback_sender->controller_state, &feedback_sender->controller_state_prev))
send_feedback_state = false;
send_feedback_history = !controller_state_equals_for_feedback_history(&feedback_sender->controller_state, &feedback_sender->controller_state_prev);
} // else: timeout
if(send_feedback_state)
feedback_sender_send_state(feedback_sender);
if(send_feedback_history)
feedback_sender_send_history(feedback_sender);
feedback_sender->controller_state_prev = feedback_sender->controller_state;
}

View file

@ -21,7 +21,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_init(ChiakiMirai *mirai)
{
mirai->request = -1;
mirai->response = -1;
ChiakiErrorCode err = chiaki_mutex_init(&mirai->mutex);
ChiakiErrorCode err = chiaki_mutex_init(&mirai->mutex, false);
if(err != CHIAKI_ERR_SUCCESS)
return err;
err = chiaki_cond_init(&mirai->cond);

View file

@ -408,6 +408,38 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_congestion(ChiakiTakion *takion
return chiaki_takion_send_raw(takion, buf, sizeof(buf));
}
static ChiakiErrorCode takion_send_feedback_packet(ChiakiTakion *takion, uint8_t *buf, size_t buf_size)
{
assert(buf_size >= 0xc);
size_t payload_size = buf_size - 0xc;
ChiakiErrorCode err = chiaki_mutex_lock(&takion->gkcrypt_local_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
size_t key_pos;
err = chiaki_takion_crypt_advance_key_pos(takion, payload_size + CHIAKI_GKCRYPT_BLOCK_SIZE, &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
err = chiaki_gkcrypt_encrypt(takion->gkcrypt_local, key_pos + CHIAKI_GKCRYPT_BLOCK_SIZE, buf + 0xc, payload_size);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
*((uint32_t *)(buf + 4)) = htonl((uint32_t)key_pos);
err = chiaki_gkcrypt_gmac(takion->gkcrypt_local, key_pos, buf, buf_size, buf + 8);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
chiaki_takion_send_raw(takion, buf, buf_size);
beach:
chiaki_mutex_unlock(&takion->gkcrypt_local_mutex);
return err;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_feedback_state(ChiakiTakion *takion, ChiakiSeqNum16 seq_num, ChiakiFeedbackState *feedback_state)
{
uint8_t buf[0xc + CHIAKI_FEEDBACK_STATE_BUF_SIZE];
@ -417,33 +449,23 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_feedback_state(ChiakiTakion *ta
*((uint32_t *)(buf + 4)) = 0; // key pos
*((uint32_t *)(buf + 8)) = 0; // gmac
chiaki_feedback_state_format(buf + 0xc, feedback_state);
return takion_send_feedback_packet(takion, buf, sizeof(buf));
}
//CHIAKI_LOGD(takion->log, "Takion sending Feedback State:\n");
//chiaki_log_hexdump(takion->log, CHIAKI_LOG_DEBUG, buf, sizeof(buf));
ChiakiErrorCode err = chiaki_mutex_lock(&takion->gkcrypt_local_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
size_t key_pos;
err = chiaki_takion_crypt_advance_key_pos(takion, CHIAKI_FEEDBACK_STATE_BUF_SIZE + CHIAKI_GKCRYPT_BLOCK_SIZE, &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
err = chiaki_gkcrypt_encrypt(takion->gkcrypt_local, key_pos + CHIAKI_GKCRYPT_BLOCK_SIZE, buf + 0xc, CHIAKI_FEEDBACK_STATE_BUF_SIZE);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
*((uint32_t *)(buf + 4)) = htonl((uint32_t)key_pos);
err = chiaki_gkcrypt_gmac(takion->gkcrypt_local, key_pos, buf, sizeof(buf), buf + 8);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
chiaki_takion_send_raw(takion, buf, sizeof(buf));
beach:
chiaki_mutex_unlock(&takion->gkcrypt_local_mutex);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_feedback_history(ChiakiTakion *takion, ChiakiSeqNum16 seq_num, uint8_t *payload, size_t payload_size)
{
size_t buf_size = 0xc + payload_size;
uint8_t *buf = malloc(buf_size);
if(!buf)
return CHIAKI_ERR_MEMORY;
buf[0] = TAKION_PACKET_TYPE_FEEDBACK_HISTORY;
*((uint16_t *)(buf + 1)) = htons(seq_num);
buf[3] = 0; // TODO
*((uint32_t *)(buf + 4)) = 0; // key pos
*((uint32_t *)(buf + 8)) = 0; // gmac
memcpy(buf + 0xc, payload, payload_size);
ChiakiErrorCode err = takion_send_feedback_packet(takion, buf, buf_size);
free(buf);
return err;
}