====== 부저 ======
jPC에는 SoC의 PWM 출력에 연결된 전자식 부저(Electro-Mechanical Buzzer)가 내장되어 있습니다.
===== 터미널에서 부저 울리기 =====
[[https://manpages.debian.org/trixie/beep/beep.1.en.html|beep]] 프로그램을 사용하여 원하는 주파수와 시간으로 부저음을 발생시킬 수 있습니다.
예를 들어 2kHz 주파수의 소리를 100ms 동안 출력하려면 다음과 같이 실행합니다.
beep -f 2000 -l 100
* ''-f'' : 주파수(Hz)
* ''-l'' : 지속 시간(ms)
===== 프로그램에서 부저 제어하기 =====
프로그램에서는 ''/dev/input/by-path/platform-buzzer-event'' 장치에 ''EV_SND'' 이벤트를 전송하여 부저를 제어할 수 있습니다.
아래 예제는 부저의 주파수를 지속적으로 변경하여 사이렌 효과를 발생시키는 프로그램입니다.
자세한 내용은 Linux Input Subsystem 문서를 참고하십시오.
[[https://www.kernel.org/doc/html/latest/input/input_uapi.html|Linux Input Subsystem]]
++++[소스 코드]|
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
class Siren
{
static void Main(string[] args)
{
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
exiting = true;
Console.WriteLine("\nCtrl+C received. Stopping siren...");
};
const string eventPath = "/dev/input/by-path/platform-buzzer-event";
Console.WriteLine("Siren generator running. Press Ctrl+C to stop.");
double time = 0;
double step = 0.02; // 50 Hz update rate (20ms)
FileStream? fs = null;
try
{
fs = new FileStream(eventPath, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
while (!exiting)
{
// Siren: 500 Hz to 1500 Hz and back in 2 seconds
double cycleTime = time % 2.0;
double frequency;
if (cycleTime < 1.0)
frequency = 500 + (cycleTime * 1000); // Rise
else
frequency = 1500 - ((cycleTime - 1.0) * 1000); // Fall
int hz = (int)Math.Round(frequency);
SendTone(fs, hz);
Thread.Sleep((int)(step * 1000));
time += step;
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
finally
{
// Ensure buzzer is silenced
try
{
if (fs != null)
{
SendTone(fs, 0);
fs.Dispose();
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
Console.WriteLine("Siren stopped.");
}
}
// Linux input event constants
const ushort EV_SYN = 0x00;
const ushort EV_SND = 0x12;
const ushort SYN_REPORT = 0x00;
const ushort SND_BELL = 0x01;
const ushort SND_TONE = 0x02;
static bool exiting = false;
// input_event struct from
// struct timeval { long tv_sec; long tv_usec; };
// struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; };
[StructLayout(LayoutKind.Sequential)]
struct TimeVal
{
public long tv_sec;
public long tv_usec;
}
[StructLayout(LayoutKind.Sequential)]
struct InputEvent
{
public TimeVal time;
public ushort type;
public ushort code;
public int value;
}
// Compute once to avoid repeated reflection-ish cost
static readonly int InputEventSize = Marshal.SizeOf();
static void SendTone(FileStream fs, int hz)
{
// hz > 0 => play tone at hz
// hz == 0 => stop tone
WriteEvent(fs, EV_SND, SND_TONE, hz);
WriteEvent(fs, EV_SYN, SYN_REPORT, 0);
fs.Flush();
}
static void WriteEvent(FileStream fs, ushort type, ushort code, int value)
{
// Local struct lives on the stack (no heap allocation)
InputEvent ev = new InputEvent
{
time = default, // kernel will timestamp; zeroed is fine
type = type,
code = code,
value = value
};
// Stack-allocated byte buffer
Span buffer = stackalloc byte[InputEventSize];
// Copy struct bytes into the stack buffer
MemoryMarshal.Write(buffer, in ev);
// Write without allocating
fs.Write(buffer);
}
}
++++
[[..:index|JPC (임베디드 리눅스 Panel PC)]]