Skip to content

Commit

Permalink
better Piezo Speaker emulation, status led update
Browse files Browse the repository at this point in the history
  • Loading branch information
PlayWithIt committed Sep 24, 2022
1 parent 99ac578 commit 6ab4ce3
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 20 deletions.
10 changes: 6 additions & 4 deletions src/stubserver/DeviceDualAnalogIn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ DeviceDualAnalogIn::SensorData::SensorData(ValueProvider *v, uint8_t cbCode)
, values(v)
, channelStatusMin(0)
, channelStatusMax(0)
, channelLedConfig(0)
{ }
, channelLedConfig(INDUSTRIAL_DUAL_ANALOG_IN_V2_CHANNEL_LED_CONFIG_ON)
{
setStatusLedConfig(StatusLedConfig::LED_ON);
}

DeviceDualAnalogIn::SensorData::~SensorData()
{
Expand All @@ -60,7 +62,6 @@ DeviceDualAnalogIn::DeviceDualAnalogIn(ValueProvider *v1, ValueProvider *v2, boo

if (isV2) {
s1 = new SensorData(v1, INDUSTRIAL_DUAL_ANALOG_IN_V2_CALLBACK_VOLTAGE);
s1->setStatusLedConfig(StatusLedConfig::LED_OFF);
s1->setMinMax(-35 * 1000, 35 * 1000);
s1->setInternalSensorNo(0);

Expand All @@ -70,7 +71,7 @@ DeviceDualAnalogIn::DeviceDualAnalogIn(ValueProvider *v1, ValueProvider *v2, boo

s2 = new SensorData(v2, INDUSTRIAL_DUAL_ANALOG_IN_V2_CALLBACK_VOLTAGE);
s2->rangeCallback = s1->rangeCallback;
s2->setStatusLedConfig(StatusLedConfig::LED_OFF);
s2->setStatusLedConfig(StatusLedConfig::LED_ON);
s2->setMinMax(-35 * 1000, 35 * 1000);
s2->setInternalSensorNo(1);

Expand Down Expand Up @@ -181,6 +182,7 @@ bool DeviceDualAnalogIn::consumeCommand(uint64_t relativeTimeMs, IOPacket &p, Vi
if (func == INDUSTRIAL_DUAL_ANALOG_IN_V2_FUNCTION_SET_CHANNEL_LED_CONFIG) {
sensor = checkIndex(p.uint8Value);
sensor->setStatusLedConfig(p.thresholdChannelInt.option);
sensor->notify(visualizationClient, VisibleDeviceState::LED_CHANGE);
return true;
}
if (func == INDUSTRIAL_DUAL_ANALOG_IN_V2_FUNCTION_GET_CHANNEL_LED_STATUS_CONFIG) {
Expand Down
120 changes: 114 additions & 6 deletions src/stubserver/DevicePiezoSpeaker.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* DevicePiezoSpeaker.cpp
*
* Copyright (C) 2013-2021 Holger Grosenick
* Copyright (C) 2013-2022 Holger Grosenick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -29,14 +29,26 @@ namespace stubserver {

DevicePiezoSpeaker::DevicePiezoSpeaker(bool isV2)
: V2Device(NULL, this, isV2)
, VisibleDeviceState(0)
, SensorState(0, 44000)
, callbackTime(0)
, alarmUpdateTime(0)
, callbackFunctionId(false)
, sendCallback(false)
, plusFrequency(true)
, frequency(0)
, duration(0)
, volume(5)
, startFrequency(0)
, endFrequency(0)
, stepSize(0)
, stepDelay(0)
, currentFrequency(0)
{
// default is on
if (isV2) {
printf("PiezoSpeaker created\n");
setStatusLedOn(true);
}
}

DevicePiezoSpeaker::~DevicePiezoSpeaker()
Expand Down Expand Up @@ -72,6 +84,10 @@ bool DevicePiezoSpeaker::consumeCommand(uint64_t relativeTimeMs, IOPacket &p, Vi
callbackFunctionId = PIEZO_SPEAKER_CALLBACK_BEEP_FINISHED;
sendCallback = true;
callbackTime = relativeTimeMs + duration;

// show frequency in UI is connected:
sensorValue = frequency;
notify(c);
return true;

case PIEZO_SPEAKER_FUNCTION_MORSE_CODE:
Expand Down Expand Up @@ -150,6 +166,10 @@ bool DevicePiezoSpeaker::consumeCommandV2(uint64_t relativeTimeMs, IOPacket &p,
callbackFunctionId = PIEZO_SPEAKER_V2_CALLBACK_BEEP_FINISHED;
sendCallback = true;
callbackTime = relativeTimeMs + duration;

// show frequency in UI is connected:
sensorValue = frequency;
notify(visualizationClient);
return true;

case PIEZO_SPEAKER_V2_FUNCTION_GET_BEEP:
Expand All @@ -165,8 +185,61 @@ bool DevicePiezoSpeaker::consumeCommandV2(uint64_t relativeTimeMs, IOPacket &p,
return true;

case PIEZO_SPEAKER_V2_FUNCTION_SET_ALARM:
// start_frequency – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [50 bis 14999]
// end_frequency – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [51 bis 15000]
// step_size – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [0 bis 14950]
// step_delay – Typ: uint16_t, Einheit: 1 ms, Wertebereich: [0 bis 216 - 1]
// volume – Typ: uint8_t, Wertebereich: [0 bis 10]
// duration – Typ: uint32_t, Einheit: 1 ms, Wertebereich: [0 bis 232 - 1] mit Konstanten
if (p.alarmRequest.start_frequency <= p.alarmRequest.end_frequency) {
startFrequency = p.alarmRequest.start_frequency;
endFrequency = p.alarmRequest.end_frequency;
}
else {
startFrequency = p.alarmRequest.end_frequency;
endFrequency = p.alarmRequest.start_frequency;
}
stepSize = p.alarmRequest.step_size;
stepDelay = p.alarmRequest.step_delay;
duration = p.alarmRequest.duration;
wavBuffer = player.makeWav(duration, startFrequency, p.alarmRequest.volume);
currentFrequency = startFrequency;
plusFrequency = true;

callbackFunctionId = PIEZO_SPEAKER_V2_CALLBACK_ALARM_FINISHED;
sendCallback = true;
callbackTime = relativeTimeMs + duration;
alarmUpdateTime = relativeTimeMs + stepDelay;

// show frequency in UI is connected:
sensorValue = currentFrequency;
notify(visualizationClient);
return true;

case PIEZO_SPEAKER_V2_FUNCTION_GET_ALARM:
break;
// ret_start_frequency – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [50 bis 14999]
// ret_end_frequency – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [51 bis 15000]
// ret_step_size – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [50 bis 14950]
// ret_step_delay – Typ: uint16_t, Einheit: 1 ms, Wertebereich: [0 bis 216 - 1]
// ret_volume – Typ: uint8_t, Wertebereich: [0 bis 10]
// ret_duration – Typ: uint32_t, Einheit: 1 ms, Wertebereich: [0 bis 232 - 1] mit Konstanten
// ret_duration_remaining – Typ: uint32_t, Einheit: 1 ms, Wertebereich: [0 bis 232 - 1] mit Konstanten
// ret_current_frequency – Typ: uint16_t, Einheit: 1 Hz, Wertebereich: [50 bis 15000]
p.header.length += sizeof(p.alarmRequest);
p.alarmRequest.start_frequency = startFrequency;
p.alarmRequest.end_frequency = endFrequency;
p.alarmRequest.step_size = stepSize;
p.alarmRequest.step_delay = stepDelay;
p.alarmRequest.volume = volume;
p.alarmRequest.duration = duration;
p.alarmRequest.current_frequency = currentFrequency;

// alarm was activated at least once and not yet elapsed
if (callbackTime > 0 && relativeTimeMs < callbackTime)
p.alarmRequest.duration_remaining = callbackTime - relativeTimeMs;
else
p.alarmRequest.duration_remaining = 0;
return true;

default:
return V2Device::consumeCommand(relativeTimeMs, p, visualizationClient);
Expand All @@ -178,14 +251,49 @@ bool DevicePiezoSpeaker::consumeCommandV2(uint64_t relativeTimeMs, IOPacket &p,
/**
* Check for the switchDone callbacks.
*/
void DevicePiezoSpeaker::checkCallbacks(uint64_t relativeTimeMs, unsigned int uid, BrickStack *brickStack, VisualizationClient &)
void DevicePiezoSpeaker::checkCallbacks(uint64_t relativeTimeMs, unsigned int uid, BrickStack *brickStack, VisualizationClient &c)
{
if (sendCallback && callbackTime <= relativeTimeMs)
if (!sendCallback)
return;

if (callbackFunctionId == PIEZO_SPEAKER_V2_CALLBACK_ALARM_FINISHED && alarmUpdateTime <= relativeTimeMs) {
if (plusFrequency) {
// plus: increase frequency
if (currentFrequency < endFrequency) {
currentFrequency += stepSize;
} else {
// max reached: start to decrease
plusFrequency = false;
currentFrequency -= stepSize;
}
}
else {
// not plus: decrease frequency
if (currentFrequency > startFrequency) {
currentFrequency -= stepSize;
} else {
// max reached: start to decrease
plusFrequency = true;
currentFrequency += stepSize;
}
}
alarmUpdateTime += stepSize;

// show frequency in UI is connected:
sensorValue = currentFrequency;
notify(c);
}

if (callbackTime <= relativeTimeMs)
{
// trigger switching done callback
// trigger sound done callback
IOPacket packet(uid, callbackFunctionId);
brickStack->dispatchCallback(packet);
sendCallback = false;

// show frequency in UI is connected:
sensorValue = 0;
notify(c);
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/stubserver/DevicePiezoSpeaker.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,29 @@ using utils::SoundPlayback;

/**
* This simulated devices makes some sound via ALSA API.
* The "visible state" of this device is only the status LED of the v2 speaker.
* The "visible state" of this device is only the status LED of the v2 speaker and the frequency.
*/
class DevicePiezoSpeaker : public V2Device, public VisibleDeviceState
class DevicePiezoSpeaker : public V2Device, public SensorState
{
// these are to handle the callback when sound finishes
uint64_t callbackTime;
uint64_t alarmUpdateTime;
int8_t callbackFunctionId;
bool sendCallback;
bool plusFrequency;

// frequency & duration of the last buffer
unsigned frequency;
unsigned duration;
unsigned volume;

// alaram data for V2 device
uint16_t startFrequency;
uint16_t endFrequency;
uint16_t stepSize;
uint16_t stepDelay;
uint16_t currentFrequency;

SoundPlayback::WavBuffer wavBuffer;
SoundPlayback player;

Expand Down
11 changes: 11 additions & 0 deletions src/stubserver/PacketTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ typedef struct IOPacket
uint32_t duration;
} ATTRIBUTE_PACKED beepV2Request;

struct {
uint16_t start_frequency;
uint16_t end_frequency;
uint16_t step_size;
uint16_t step_delay;
uint8_t volume;
uint32_t duration;
uint32_t duration_remaining;
uint16_t current_frequency;
} ATTRIBUTE_PACKED alarmRequest;

struct {
uint8_t channel;
int32_t value1;
Expand Down
24 changes: 17 additions & 7 deletions src/stubserver/StatusLed.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,27 @@ class StatusLed {
return static_cast<uint8_t>(config);
}

/**
* Read current status.
*/
bool isLedOn() const {
return ledOn;
}

/**
* Update LED status unconditionally
*/
void setLedOn(bool on) {
ledOn = on;
}

/**
* Change LED on/off based on bricklet or channel activity:
* if config is ON or OFF, this method does nothing, only in state ACTIVITY
* this updates the led state.
*/
void setActivity(bool on);

/**
* Change the LED config:
* OFF and ON don't need the activity, but if the cfg is ACTIVITY, the
Expand All @@ -87,13 +104,6 @@ class StatusLed {
* first map the value to valid config values and then set the led.
*/
void setLedConfig(uint8_t cfg);

/**
* Change LED on/off based on bricklet or channel activity:
* if config is ON or OFF, this method does nothing, only in state ACTIVITY
* this updates the led state.
*/
void setActivity(bool on);
};

} /* namespace stubserver */
Expand Down
5 changes: 4 additions & 1 deletion src/stubserver/VisualizationClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,15 @@ class VisibleDeviceState
void setStatusLedConfig(StatusLedConfig cfg) {
statusLed.setLedConfig(cfg, 0);
}
void setStatusLedOn(bool on) {
statusLed.setLedOn(on);
}

/**
* Returns true if there is any light on the LED in some cases.
*/
bool isStatusLedOn() const {
return statusLed.getConfig() != StatusLedConfig::LED_OFF;
return statusLed.isLedOn();
}

StatusLedConfig getStatusLedConfig() const {
Expand Down

0 comments on commit 6ab4ce3

Please sign in to comment.