Skip to content

Instantly share code, notes, and snippets.

@moyashipan
Created July 2, 2026 07:57
Show Gist options
  • Select an option

  • Save moyashipan/0e9c004d3167f9983e63f0e3a4c103c8 to your computer and use it in GitHub Desktop.

Select an option

Save moyashipan/0e9c004d3167f9983e63f0e3a4c103c8 to your computer and use it in GitHub Desktop.
M5Stack_ChainDualKey_Muter
#include <M5Unified.h>
#include <Adafruit_NeoPixel.h>
#include "USB.h"
#include "USBHID.h"
#define LED_PWR_PIN 40 // LED用電源ピン
#define LED_SIG_PIN 21 // LED信号用ピン
#define NUM_LEDS 2 // 搭載されているLEDの数
#define BUTTON_LEFT_PIN 17 // 左ボタンのピン (Mute ON用)
#define BUTTON_RIGHT_PIN 0 // 右ボタンのピン (Mute OFF用)
// HIDレポートの設定
constexpr uint8_t REPORT_ID = 5;
Adafruit_NeoPixel strip(NUM_LEDS, LED_SIG_PIN, NEO_GRB + NEO_KHZ800);
m5::Button_Class ButtonLeft;
m5::Button_Class ButtonRight;
USBHID HID;
const uint8_t report_descriptor[] = {
0x05, 0x0B, // Usage Page (Telephony Device)
0x09, 0x01, // Usage (Phone)
0xA1, 0x01, // Collection (Application)
0x85, REPORT_ID, // Report ID
0x05, 0x0B, // Usage Page (Telephony Device)
0x09, 0x2F, // Usage (Phone Mute)
0x09, 0x20, // Usage (Hook Switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x75, 0x06, // Padding (6bit)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Constant, Variable, Absolute)
0x05, 0x08, // Usage Page (LEDs)
0x09, 0x09, // Usage (Mute)
0x09, 0x17, // Usage (Off-Hook)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x02, // Report Count (2)
0x91, 0x02, // Output (Data, Variable, Absolute)
0x75, 0x06, // Padding (6bit)
0x95, 0x01, // Report Count (1)
0x91, 0x03, // Output (Constant, Variable, Absolute)
0xC0 // End Collection
};
class CustomTelephonyDevice : public USBHIDDevice {
public:
CustomTelephonyDevice() {
HID.addDevice(this, sizeof(report_descriptor));
}
uint16_t _onGetDescriptor(uint8_t* buffer) override {
memcpy(buffer, report_descriptor, sizeof(report_descriptor));
return sizeof(report_descriptor);
}
void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len) override {
if (report_id == REPORT_ID && len > 0) {
const bool pcIsMuted = (buffer[0] & 0x01) != 0;
const bool pcIsOffHook = (buffer[0] & 0x02) != 0;
if (!pcIsOffHook) {
// 通話終了時: 両方のLEDを消灯
strip.setPixelColor(0, strip.Color(0, 0, 0));
strip.setPixelColor(1, strip.Color(0, 0, 0));
} else if (pcIsMuted) {
// 通話中かつミュートON時: 左側のLEDを赤で点灯
strip.setPixelColor(0, strip.Color(255, 0, 0));
strip.setPixelColor(1, strip.Color(0, 0, 0));
} else {
// 通話中かつミュートOFF時: 右側のLEDを緑で点灯
strip.setPixelColor(0, strip.Color(0, 0, 0));
strip.setPixelColor(1, strip.Color(0, 255, 0));
}
strip.show();
}
}
void sendMuteOn() {
uint8_t p[1] = { 0x03 }; // 11: 通話中, ミュートON
HID.SendReport(REPORT_ID, p, 1);
}
void sendMuteOff() {
uint8_t p[1] = { 0x02 }; // 10: 通話中, ミュートOFF
HID.SendReport(REPORT_ID, p, 1);
}
void sendCallEnd() {
uint8_t p[1] = { 0x01 }; // 01: 通話終了, ミュートON
HID.SendReport(REPORT_ID, p, 1);
}
};
CustomTelephonyDevice TelephonyDevice;
void setup() {
pinMode(LED_PWR_PIN, OUTPUT);
digitalWrite(LED_PWR_PIN, HIGH);
USB.VID(0x1209);
USB.PID(0x0040);
USB.manufacturerName("Moyashipan");
USB.productName("M5Chain DualKey Muter");
auto cfg = M5.config();
M5.begin(cfg);
ButtonLeft.setHoldThresh(1000); // 長押し判定時間
pinMode(BUTTON_LEFT_PIN, INPUT);
pinMode(BUTTON_RIGHT_PIN, INPUT);
strip.begin();
strip.show();
HID.begin();
USB.begin();
}
void loop() {
const uint32_t ms = millis();
ButtonLeft.setRawState(ms, !digitalRead(BUTTON_LEFT_PIN));
ButtonRight.setRawState(ms, !digitalRead(BUTTON_RIGHT_PIN));
if (ButtonLeft.wasHold()) {
TelephonyDevice.sendCallEnd();
} else if (ButtonLeft.wasPressed()) {
TelephonyDevice.sendMuteOn();
}
if (ButtonRight.wasPressed()) {
TelephonyDevice.sendMuteOff();
}
delay(10);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment