From bbf50ef812c4bfd0cbbb39a29b3cc755d3605a0b Mon Sep 17 00:00:00 2001 From: superstrom Date: Mon, 3 Nov 2025 01:04:33 +0000 Subject: [PATCH] add Kraken V3 X --- .../RazerController/RazerControllerDetect.cpp | 24 ++ Controllers/RazerController/RazerDevices.cpp | 36 +++ Controllers/RazerController/RazerDevices.h | 1 + .../RGBController_RazerKrakenV3.cpp | 170 ++++++++++++ .../RGBController_RazerKrakenV3.h | 41 +++ .../RazerKrakenV3Controller.cpp | 246 ++++++++++++++++++ .../RazerKrakenV3Controller.h | 81 ++++++ 7 files changed, 599 insertions(+) create mode 100644 Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.cpp create mode 100644 Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.h create mode 100644 Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.cpp create mode 100644 Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.h diff --git a/Controllers/RazerController/RazerControllerDetect.cpp b/Controllers/RazerController/RazerControllerDetect.cpp index 253601f7e..48328eab6 100644 --- a/Controllers/RazerController/RazerControllerDetect.cpp +++ b/Controllers/RazerController/RazerControllerDetect.cpp @@ -14,6 +14,7 @@ #include "Detector.h" #include "RazerController.h" #include "RazerKrakenController.h" +#include "RazerKrakenV3Controller.h" #include "RazerKrakenV4Controller.h" #include "RazerHanboController.h" #include "RazerDevices.h" @@ -21,6 +22,7 @@ #include "RGBController_Razer.h" #include "RGBController_RazerAddressable.h" #include "RGBController_RazerKraken.h" +#include "RGBController_RazerKrakenV3.h" #include "RGBController_RazerKrakenV4.h" #include "RGBController_RazerHanbo.h" @@ -155,6 +157,27 @@ void DetectRazerKrakenControllers(hid_device_info* info, const std::string& name } } /* DetectRazerKrakenControllers() */ +/******************************************************************************************\ +* * +* DetectRazerKrakenV3Controllers * +* * +* Tests the USB address to see if a Razer Kraken V3 controller exists there. * +* * +\******************************************************************************************/ + +void DetectRazerKrakenV3Controllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + RazerKrakenV3Controller* controller = new RazerKrakenV3Controller(dev, info->path, info->product_id, name); + + RGBController_RazerKrakenV3* rgb_controller = new RGBController_RazerKrakenV3(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} /* DetectRazerKrakenV3Controllers() */ + /******************************************************************************************\ * * * DetectRazerKrakenV4Controllers * @@ -365,6 +388,7 @@ REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty Edition", Det REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty Black Edition", DetectRazerControllers, RAZER_VID, RAZER_KRAKEN_KITTY_BLACK_EDITION_PID, 0x01, 0x01, 0x03); REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty Black Edition V2", DetectRazerKrakenControllers, RAZER_VID, RAZER_KRAKEN_KITTY_BLACK_EDITION_V2_PID, 0x03, 0x0C, 0x01); REGISTER_HID_DETECTOR_IPU("Razer Kraken Ultimate", DetectRazerKrakenControllers, RAZER_VID, RAZER_KRAKEN_ULTIMATE_PID, 0x03, 0x0C, 0x01); +REGISTER_HID_DETECTOR_IPU("Razer Kraken V3 X", DetectRazerKrakenV3Controllers,RAZER_VID, RAZER_KRAKEN_V3_X_PID, 0x03, 0x0C, 0x01); REGISTER_HID_DETECTOR_IPU("Razer Kraken V4 (Wired)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_V4_WIRED_PID, 0x05, 0xFF14, 0x01); REGISTER_HID_DETECTOR_IPU("Razer Kraken V4 (Wireless)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_V4_WIRELESS_PID, 0x05, 0xFF14, 0x01); REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty V3 Pro (Wired)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_KITTY_V3_PRO_WIRED_PID, 0x05, 0xFF14, 0x01); diff --git a/Controllers/RazerController/RazerDevices.cpp b/Controllers/RazerController/RazerDevices.cpp index 50c65ff71..d9f296221 100644 --- a/Controllers/RazerController/RazerDevices.cpp +++ b/Controllers/RazerController/RazerDevices.cpp @@ -7701,6 +7701,41 @@ static const razer_device kraken_kitty_black_v2_device = NULL }; +/*-------------------------------------------------------------*\ +| Razer Kraken V3 X 1532:0537 | +| | +| Zone "Headset" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_v3_x_zone = +{ + "Headset", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device kraken_v3_x_device = +{ + "Razer Kraken V3 X", + RAZER_KRAKEN_V3_X_PID, + DEVICE_TYPE_HEADSET, + RAZER_MATRIX_TYPE_NONE, + 0, + 1, + 1, + { + &kraken_v3_x_zone, + NULL, + NULL, + NULL, + NULL, + NULL + }, + NULL +}; + /*-------------------------------------------------------------*\ | Razer Kraken V4 Wired 1532:056B | | | @@ -9041,6 +9076,7 @@ const razer_device* razer_device_list[] = &kraken_ultimate_device, &kraken_kitty_device, &kraken_kitty_black_v2_device, + &kraken_v3_x_device, &kraken_v4_wired_device, &kraken_v4_wireless_device, &kraken_kitty_v3_pro_wired_device, diff --git a/Controllers/RazerController/RazerDevices.h b/Controllers/RazerController/RazerDevices.h index 2ff74107b..162e452db 100644 --- a/Controllers/RazerController/RazerDevices.h +++ b/Controllers/RazerController/RazerDevices.h @@ -224,6 +224,7 @@ #define RAZER_KRAKEN_ULTIMATE_PID 0x0527 #define RAZER_KRAKEN_V2_PID 0x0510 #define RAZER_KRAKEN_KITTY_BLACK_EDITION_V2_PID 0x0560 +#define RAZER_KRAKEN_V3_X_PID 0x0537 #define RAZER_KRAKEN_V4_WIRED_PID 0x056B #define RAZER_KRAKEN_V4_WIRELESS_PID 0x056C #define RAZER_KRAKEN_KITTY_V3_PRO_WIRED_PID 0x0587 diff --git a/Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.cpp b/Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.cpp new file mode 100644 index 000000000..1f8459292 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.cpp @@ -0,0 +1,170 @@ +/*---------------------------------------------------------*\ +| RGBController_RazerKrakenV3.cpp | +| | +| RGBController for Razer devices with 9-byte report | +| | +| Greg Sandstrom (superstrom) 1 Nov 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "RazerDevices.h" +#include "RGBController_RazerKrakenV3.h" + +RGBController_RazerKrakenV3::RGBController_RazerKrakenV3(RazerKrakenV3Controller* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetName(); + vendor = "Razer"; + type = controller->GetDeviceType(); + description = "Razer Device"; + location = controller->GetDeviceLocation(); + version = controller->GetFirmwareString(); + serial = controller->GetSerialString(); + uint8_t max_brightness = controller->GetMaxBrightness(); + + // By default, the device starts as Wave/Spectrum Cycle. + // Set Wave as first mode, so switching to Direct calls DeviceUpdateMode() + + mode Wave; + Wave.name = "Wave"; + Wave.value = RAZER_KRAKEN_V3_MODE_WAVE; + Wave.flags = MODE_FLAG_HAS_BRIGHTNESS; + Wave.direction = MODE_DIRECTION_RIGHT; + Wave.color_mode = MODE_COLORS_NONE; + Wave.brightness_min = 0; + Wave.brightness_max = max_brightness; + Wave.brightness = max_brightness; + modes.push_back(Wave); + + + mode Direct; + Direct.name = "Direct"; + Direct.value = RAZER_KRAKEN_V3_MODE_DIRECT; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS; + Direct.color_mode = MODE_COLORS_PER_LED; + Direct.brightness_min = 0; + Direct.brightness_max = max_brightness; + Direct.brightness = max_brightness; + modes.push_back(Direct); + + SetupZones(); +} + +RGBController_RazerKrakenV3::~RGBController_RazerKrakenV3() +{ + delete controller; +} + +void RGBController_RazerKrakenV3::SetupZones() +{ + unsigned int device_index = controller->GetDeviceIndex(); + + /*---------------------------------------------------------*\ + | Fill in zone information based on device table | + \*---------------------------------------------------------*/ + for(unsigned int zone_id = 0; zone_id < RAZER_MAX_ZONES; zone_id++) + { + if(device_list[device_index]->zones[zone_id] != NULL) + { + zone new_zone; + + new_zone.name = device_list[device_index]->zones[zone_id]->name; + new_zone.type = device_list[device_index]->zones[zone_id]->type; + + new_zone.leds_count = device_list[device_index]->zones[zone_id]->rows * device_list[device_index]->zones[zone_id]->cols; + new_zone.leds_min = new_zone.leds_count; + new_zone.leds_max = new_zone.leds_count; + + if(new_zone.type == ZONE_TYPE_MATRIX) + { + matrix_map_type * new_map = new matrix_map_type; + new_zone.matrix_map = new_map; + + new_map->height = device_list[device_index]->zones[zone_id]->rows; + new_map->width = device_list[device_index]->zones[zone_id]->cols; + + new_map->map = new unsigned int[new_map->height * new_map->width]; + + for(unsigned int y = 0; y < new_map->height; y++) + { + for(unsigned int x = 0; x < new_map->width; x++) + { + new_map->map[(y * new_map->width) + x] = (y * new_map->width) + x; + } + } + } + else + { + new_zone.matrix_map = NULL; + } + + zones.push_back(new_zone); + } + } + + for(unsigned int zone_id = 0; zone_id < zones.size(); zone_id++) + { + for (unsigned int row_id = 0; row_id < device_list[device_index]->zones[zone_id]->rows; row_id++) + { + for (unsigned int col_id = 0; col_id < device_list[device_index]->zones[zone_id]->cols; col_id++) + { + led* new_led = new led(); + + new_led->name = device_list[device_index]->zones[zone_id]->name; + + if(zones[zone_id].leds_count > 1) + { + new_led->name.append(" LED "); + new_led->name.append(std::to_string(col_id + 1)); + } + + leds.push_back(*new_led); + } + } + } + + SetupColors(); +} + +void RGBController_RazerKrakenV3::ResizeZone(int /*zone*/, int /*new_size*/) +{ + +} + +void RGBController_RazerKrakenV3::DeviceUpdateLEDs() +{ + if(modes[active_mode].value == RAZER_KRAKEN_V3_MODE_DIRECT) + { + controller->SetDirect(&colors[0]); + } +} + +void RGBController_RazerKrakenV3::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_RazerKrakenV3::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_RazerKrakenV3::DeviceUpdateMode() +{ + switch(modes[active_mode].value) + { + case RAZER_KRAKEN_V3_MODE_DIRECT: + controller->SetModeDirect(); + controller->SetBrightness(modes[active_mode].brightness); + break; + + case RAZER_KRAKEN_V3_MODE_WAVE: + controller->SetModeWave(); + controller->SetBrightness(modes[active_mode].brightness); + break; + } +} diff --git a/Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.h b/Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.h new file mode 100644 index 000000000..1c95f7405 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV3Controller/RGBController_RazerKrakenV3.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------*\ +| RGBController_RazerKrakenV3.h | +| | +| RGBController for Razer devices with 9-byte report | +| | +| Greg Sandstrom (superstrom) 1 Nov 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "RazerKrakenV3Controller.h" + +enum +{ + RAZER_KRAKEN_V3_MODE_DIRECT, + RAZER_KRAKEN_V3_MODE_WAVE, +}; + +class RGBController_RazerKrakenV3 : public RGBController +{ +public: + RGBController_RazerKrakenV3(RazerKrakenV3Controller* controller_ptr); + ~RGBController_RazerKrakenV3(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + RazerKrakenV3Controller* controller; +}; diff --git a/Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.cpp b/Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.cpp new file mode 100644 index 000000000..0a4a8fc42 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.cpp @@ -0,0 +1,246 @@ +/*---------------------------------------------------------*\ +| RazerKrakenV3Controller.cpp | +| | +| Driver for Razer devices with 9-byte report | +| | +| Greg Sandstrom (superstrom) 1 Nov 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "RazerKrakenController.h" +#include "RazerKrakenV3Controller.h" +#include "RazerDevices.h" + +using namespace std::chrono_literals; + +RazerKrakenV3Controller::RazerKrakenV3Controller(hid_device* dev_handle, const char* path, unsigned short pid, std::string dev_name) +{ + dev = dev_handle; + dev_pid = pid; + location = path; + name = dev_name; + + /*-----------------------------------------------------------------*\ + | Loop through all known devices to look for a name match | + \*-----------------------------------------------------------------*/ + for(unsigned int i = 0; i < RAZER_NUM_DEVICES; i++) + { + if(device_list[i]->pid == dev_pid) + { + /*---------------------------------------------------------*\ + | Set device ID | + \*---------------------------------------------------------*/ + device_index = i; + } + } + + /*-----------------------------------------------------------------*\ + | Determine matrix type for device | + \*-----------------------------------------------------------------*/ + matrix_type = device_list[device_index]->matrix_type; +} + +RazerKrakenV3Controller::~RazerKrakenV3Controller() +{ + hid_close(dev); +} + +std::string RazerKrakenV3Controller::GetName() +{ + return(name); +} + +unsigned int RazerKrakenV3Controller::GetDeviceIndex() +{ + return(device_index); +} + +device_type RazerKrakenV3Controller::GetDeviceType() +{ + return(device_list[device_index]->type); +} + +std::string RazerKrakenV3Controller::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string RazerKrakenV3Controller::GetFirmwareString() +{ + return(razer_get_firmware()); +} + +std::string RazerKrakenV3Controller::GetSerialString() +{ + return(razer_get_serial()); +} + +unsigned char RazerKrakenV3Controller::GetMaxBrightness() +{ + /*-----------------------------------------------------*\ + | Max brightness for most devices is 0xFF (255) | + | Add PIDs only for devices that use 0x64 (100) | + | or any another arbitrary value | + \*-----------------------------------------------------*/ + unsigned char max_brightness = 255; + + return(max_brightness); +} + +void RazerKrakenV3Controller::SetModeDirect() +{ + unsigned char usb_buf[9]; + + memset(usb_buf, 0, sizeof(usb_buf)); + + // 0 1 2 3 4 5 6 7 8 + // 4001000f0800000000 + usb_buf[0] = 0x40; + usb_buf[1] = 0x01; + usb_buf[3] = 0x0F; + usb_buf[4] = 0x08; + + hid_write(dev, usb_buf, sizeof(usb_buf)); +} + +void RazerKrakenV3Controller::SetDirect(RGBColor* colors) +{ + unsigned char usb_buf[9]; + + memset(usb_buf, 0, sizeof(usb_buf)); + + // how to get the number of leds? + unsigned int led_count = device_list[device_index]->cols; + + // 0 1 2 3 4 5 6 7 8 + // 400300ffffff000000 + usb_buf[0] = 0x40; + usb_buf[1] = 0x03; + + for(unsigned int led_idx = 0; led_idx < led_count; led_idx++) + { + usb_buf[3 + (led_idx * 3)] = RGBGetRValue(colors[led_idx]); + usb_buf[4 + (led_idx * 3)] = RGBGetGValue(colors[led_idx]); + usb_buf[5 + (led_idx * 3)] = RGBGetBValue(colors[led_idx]); + } + + hid_write(dev, usb_buf, sizeof(usb_buf)); +} + +void RazerKrakenV3Controller::SetBrightness(unsigned char brightness) +{ + unsigned char usb_buf[24]; + + memset(usb_buf, 0, sizeof(usb_buf)); + + // 0 1 2 3 4 5 6 7 8 + // 40020000ff00000000 + usb_buf[0] = 0x40; + usb_buf[1] = 0x02; + + usb_buf[4] = brightness; + + hid_write(dev, usb_buf, sizeof(usb_buf)); +} + +void RazerKrakenV3Controller::SetModeWave() +{ + unsigned char usb_buf[9]; + + memset(usb_buf, 0, sizeof(usb_buf)); + + // 0 1 2 3 4 5 6 7 8 + // 4001000f0300000000 + usb_buf[0] = 0x40; + usb_buf[1] = 0x01; + usb_buf[3] = 0x0F; + usb_buf[4] = 0x03; + + hid_write(dev, usb_buf, sizeof(usb_buf)); +} + +razer_kraken_request_report RazerKrakenV3Controller::razer_kraken_create_report(unsigned char report_id, unsigned char destination, unsigned char length, unsigned short address) +{ + razer_kraken_request_report new_report; + + /*---------------------------------------------------------*\ + | Zero out the new report | + \*---------------------------------------------------------*/ + memset(&new_report, 0, sizeof(razer_kraken_request_report)); + + /*---------------------------------------------------------*\ + | Fill in the new report with the given parameters | + \*---------------------------------------------------------*/ + new_report.report_id = report_id; + new_report.destination = destination; + new_report.length = length; + new_report.addr_h = (address >> 8); + new_report.addr_l = (address & 0xFF); + + return new_report; +} + +std::string RazerKrakenV3Controller::razer_get_firmware() +{ + std::string firmware_string = ""; + struct razer_kraken_request_report report = razer_kraken_create_report(0x04, 0x20, 0x02, 0x0030); + struct razer_kraken_response_report response_report; + + std::this_thread::sleep_for(1ms); + razer_usb_send(&report); + std::this_thread::sleep_for(1ms); + razer_usb_receive(&response_report); + + if(response_report.report_id == 0x05) + { + firmware_string = "v" + std::to_string(response_report.arguments[1]) + "." + std::to_string(response_report.arguments[2]); + } + + return firmware_string; +} + +std::string RazerKrakenV3Controller::razer_get_serial() +{ + char serial_string[64] = ""; + struct razer_kraken_request_report report = razer_kraken_create_report(0x04, 0x20, 0x16, 0x7f00); + struct razer_kraken_response_report response_report; + + std::this_thread::sleep_for(1ms); + razer_usb_send(&report); + std::this_thread::sleep_for(1ms); + razer_usb_receive(&response_report); + + if(response_report.report_id == 0x05) + { + strncpy(&serial_string[0], (const char*)&response_report.arguments[0], 22); + serial_string[22] = '\0'; + } + + for(size_t i = 0; i < 22; i++) + { + if(serial_string[i] < 30 || serial_string[i] > 126) + { + serial_string[i] = ' '; + } + } + + std::string ret_string = serial_string; + return ret_string; +} + +/*---------------------------------------------------------------------------------*\ +| USB transfer functions | +\*---------------------------------------------------------------------------------*/ + +int RazerKrakenV3Controller::razer_usb_receive(razer_kraken_response_report* report) +{ + return hid_read(dev, (unsigned char*)report, sizeof(*report)); +} + +int RazerKrakenV3Controller::razer_usb_send(razer_kraken_request_report* report) +{ + return hid_write(dev, (unsigned char*)report, sizeof(*report)); +} diff --git a/Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.h b/Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.h new file mode 100644 index 000000000..14ea8a164 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV3Controller/RazerKrakenV3Controller.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------*\ +| RazerKrakenV3Controller.h | +| | +| Driver for Razer devices with 9-byte report | +| | +| Greg Sandstrom (superstrom) 1 Nov 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" +#include "DeviceGuardManager.h" +#include "RazerKrakenController.h" + +class RazerKrakenV3Controller +{ +public: + RazerKrakenV3Controller(hid_device* dev_handle, const char* path, unsigned short pid, std::string dev_name); + ~RazerKrakenV3Controller(); + + unsigned int GetDeviceIndex(); + device_type GetDeviceType(); + std::string GetDeviceLocation(); + std::string GetFirmwareString(); + std::string GetName(); + std::string GetSerialString(); + unsigned char GetMaxBrightness(); + + void SetDirect(RGBColor* colors); + void SetBrightness(unsigned char brightness); + + void SetModeDirect(); + void SetModeWave(); + +private: + hid_device* dev; + unsigned short dev_pid; + + /*---------------------------------------------------------*\ + | Device-specific protocol settings | + \*---------------------------------------------------------*/ + unsigned char dev_transaction_id; + unsigned char dev_led_id; + + /*---------------------------------------------------------*\ + | Device information strings | + \*---------------------------------------------------------*/ + std::string firmware_version; + std::string location; + std::string name; + + /*---------------------------------------------------------*\ + | Index of device in Razer device list | + \*---------------------------------------------------------*/ + unsigned int device_index; + + /*---------------------------------------------------------*\ + | HID report index for request and response | + \*---------------------------------------------------------*/ + unsigned char report_index; + unsigned char response_index; + + /*---------------------------------------------------------*\ + | Matrix type | + \*---------------------------------------------------------*/ + unsigned char matrix_type; + + /*---------------------------------------------------------*\ + | Private functions based on OpenRazer | + \*---------------------------------------------------------*/ + std::string razer_get_firmware(); + std::string razer_get_serial(); + + razer_kraken_request_report razer_kraken_create_report(unsigned char report_id, unsigned char destination, unsigned char length, unsigned short address); + int razer_usb_receive(razer_kraken_response_report* report); + int razer_usb_send(razer_kraken_request_report* report); +};