Wim Huiskamp
/
mbed_audio_alert
IEC60601-1-8 Audible Alert Generator
See here for more info.
Diff: IEC60601-1-8.cpp
- Revision:
- 0:07767204347b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IEC60601-1-8.cpp Fri May 18 19:51:12 2012 +0000 @@ -0,0 +1,430 @@ +/**************************************************************** + * IEC601601-1-8 + * + * This modules provides the IEC Medical Alert tones. + * + * + * Copyright(C) 2007, NXP Semiconductor + * All rights reserved. + * + * Port to mbed 2012 (WH) + ****************************************************************/ +#include "mbed.h" +#include "IEC60601-1-8.h" + +#define DEBUG_ON 0 // Activate Testpins for timing +#if(DEBUG_ON) +// Activate Testpins for timing +DigitalOut TimInt(p19); +DigitalOut SeqInt(p20); +#endif + +#define AMPL 200 // Output Amplitude +#define PI 3.1415926 +#define FSAMPLE 25000 // Timer Reload Frequency + + +// define rise and fall time of tones +#define HP_RISE 12 // rise time setting for high priority tones (12 = ~20ms Tr) + // decrease to make slower, increase to make faster +#define HP_FALL 12 // fall time setting for high priority tones (12 = ~20ms Tf) + // decrease to make slower, increase to make faster +#define MP_RISE 8 // rise time setting for high priority tones (8 = ~30ms Tr) + // decrease to make slower, increase to make faster +#define MP_FALL 8 // fall time setting for high priority tones (8 = ~30ms Tf) + // decrease to make slower, increase to make faster + + +Note_Type const _TuneSequence [][5] = {{C4,C4,C4,C4,C4}, // general + {C5,B4,A4,G4,F4}, // oxygen + {C4,A4,F4,A4,F4}, // ventilation + {C4,E4,G4,G4,C5}, // cardiovascular + {C4,D4,E4,F4,G4}, // temperature + {C5,D4,G4,C5,D4}, // drug_delivery + {C4,Fsharp4,C4,C4,Fsharp4}, // perfusion + {C5,C4,C4,C5,C4}, // power_fail +// {E4,C4,0,0,0}}; // low_alarm + {E4,C4,C4,C4,C4}}; // low_alarm + +float const _FreqArray[][5]= {{261.626,523.252,784.878,1046.50,1308.13}, // C4 + {293.67,587.34,881.01,1174.7,1468.3}, // D4 + {329.63,659.26,988.89,1318.52,1648.15}, // E4 + {349.23,698.46,1047.69,1396.9,1746.15}, // F4 + {369.99,739.98,1109.97,1479.96,1849.95}, // FSharp4 + {392.00,784.00,1176.0,1568.0,1960.0}, // G4 + {440.000,880.00,1320.0,1760.00,2200.00}, // A4 + {493.88,987.76,1481.64,1975.5,2469.4}, // B4 + {523.251,1046.50,1569.756,2093.00,2616.25}}; // C5 + +unsigned char _ToneWeights[] = {255,255,255,255,255}; // used for test and + // adjusting harmonic levels + +struct wave _Waves[9][5]; // 'Waves' holds tone gen coefficients and variables + // the coefficients are calculated during initialization. + + +IEC60601::IEC60601() { + + _InitDAC(); + _InitSequencer(); + _InitToneCoefArray(); + _ticker.attach_us(this, &IEC60601::_TimerInteruptHandler, 40); +}; + + + +void IEC60601::TurnOnAlarm(Prio_Type priority, Alarm_Type alarm_type) { + + _priority = priority; + _alarm_type = alarm_type; + + _mscount = 0; + _sequence = 1; + +} + +void IEC60601::TurnOffAlarm(void) { + _sequence = 0; +} + +void IEC60601::TestAlarm(Note_Type active_note, int w0, int w1, int w2, int w3, int w4) { + + _priority = TEST; + + _active_note = active_note; + _ToneWeights[0]= w0; + _ToneWeights[1]= w1; + _ToneWeights[2]= w2; + _ToneWeights[3]= w3; + _ToneWeights[4]= w4; + + _mscount = 0; + _sequence = 1; +} + + +// This modules provides the note sequencers and envelope control +// functions for the alarm notes for the IEC Medical Alert tone demo. + +void IEC60601::_InitSequencer(void) { + _envelope_on = false; + _envelope_off = false; +} + + +void IEC60601::_TurnOnNote(void) { + _envelope = 0; + _note_on = true; + _envelope_on = true; +} + +void IEC60601::_TurnOffNote(void) { + _note_on = false; +} + + +void IEC60601::_HighPriSequence (void) { + + switch (_mscount) { + case 1: + _active_note = _TuneSequence [_alarm_type][0]; // 1rst note of sequence + _note_level = 170; + _TurnOnNote(); + break; + case 145: // 145 ms (trise + tduration) + _note_on = false; // begin decay as note turns "off" + break; + case 224: + _active_note = _TuneSequence [_alarm_type][1]; // 2nd note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 368: + _note_on = false; // begin decay as note turns "off" + break; + case 447: + _active_note = _TuneSequence [_alarm_type][2]; // 3rd note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 591: + _note_on = false; // begin decay as note turns "off" + break; + case 835: + _active_note = _TuneSequence [_alarm_type][3]; // 4th note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 979: + _note_on = false; // begin decay as note turns "off" + break; + case 1058: + _active_note = _TuneSequence [_alarm_type][4]; // 5th note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 1202: + _note_on = false; // begin decay as note turns "off" + break; + + case 1250: // allows for fall time of envelope + if (_sequence == 2) { // Done after one repeat + _sequence = 0; + _mscount = 0; + } + break; + case 1750: + if (_sequence == 1) { // If this is the first time through, repeat + _sequence = 2; + } + _mscount = 0; + break; + } +} + + +void IEC60601::_MedPriSequence (void) { + + switch (_mscount) { + case 1: + _active_note = _TuneSequence [_alarm_type][0]; + _note_level = 170; + _TurnOnNote(); + break; + case 221: // 221 ms (trise(30) + tduration(190)+ start(1)) + _note_on = false; // begin decay as note turns "off" + break; + case 441: + _active_note = _TuneSequence [_alarm_type][1]; // 2nd note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 661: + _note_on = false; // begin decay as note turns "off" + break; + case 881: + _active_note = _TuneSequence [_alarm_type][2]; // 3rd note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 1101: + _note_on = false; // begin decay as note turns "off" + break; + case 1151: // allows for fall time of envelope + _sequence = 0; // Medium Prio does not repeat + _mscount = 0; + } + +} + +void IEC60601::_LowPriSequence (void) { + + switch (_mscount) { + case 1: + _active_note = _TuneSequence [_alarm_type][0]; + _note_level = 170; + _TurnOnNote(); + break; + case 261: // 261 ms (trise(35) + tduration(225)) + _note_on = false; // begin decay as note turns "off" + break; + case 521: + _active_note = _TuneSequence [_alarm_type][1]; // 2nd note of sequence + _note_level = 255; + _TurnOnNote(); + break; + case 781: + _note_on = false; // begin decay as note turns "off" + break; + case 816: // Low Prio does not repeat + _sequence = 0; + _mscount = 0; + } +} + +void IEC60601::_TestSequence (void) { + + switch (_mscount) { + case 1: +// _active_note = _TuneSequence [_alarm_type][0]; + _note_level = 255; + _TurnOnNote(); + break; + + case 1000: + _note_on = false; // begin decay as note turns "off" + break; + + case 1035: + + for (int i=0; i<5; i++) { // Restore weights + _ToneWeights[i] = 255; + }; + _sequence = 0; // Test does not repeat + _mscount = 0; + break; + } +} + +void IEC60601::_EnvelopeControl(void) { + + if (_note_on) { + if (_envelope >= _note_level) { + _envelope = _note_level; + } + else { + if (_priority == HIGH) { + _envelope += HP_RISE; // high priority risetime control + } + else { + _envelope += MP_RISE; // Medium priority risetime control + } + } + } + else { + if (_envelope > 0) { + if (_priority == HIGH) { + _envelope -= HP_FALL; // high priority falltime control + } + else { + _envelope -= MP_FALL; // Medium priority falltime control + } + } + } + if ((_envelope <= 0) && (!_note_on) && (_envelope_on) ) { + _envelope = 0; + _envelope_off = true; // synchronize with zero cross + } +} + + + +// This module generates multiple sine waves that are combined +// to generate tones that contain a fundamental and 4 harmonics +// per the IEC60601-1-8 Medical Alarm specification + +void IEC60601::_InitDAC(void) { + + LPC_PINCON->PINSEL1 &= ~0x00300000; // enable DAC P0.26 + LPC_PINCON->PINSEL1 |= 0x00200000; + LPC_PINCON->PINMODE1 &= ~0x00300000; // disable Rs on P0.26 + LPC_PINCON->PINMODE1 |= 0x00200000; + + LPC_DAC->DACR = 0x8000; // init DAC to half on voltage +} + + +void IEC60601::_InitToneCoefArray(void) { // generate the coefficients and init array for tones + + unsigned char n; + unsigned char j; + + for (j=0;j<9;j++) // Initialize all nine scale tones (C4-C5) + { + for (n=0;n<5;n++) // fundamental and 4 harmonics for IEC60601-1-8 + { + _Waves[j][n].coef = ((cos (2*PI*(float)(_FreqArray[j][n]/FSAMPLE)))* 32768) ; // 2* taken out, put in final calc as a shift + _Waves[j][n].y1 = 0; + _Waves[j][n].y2 = ((sin (2*PI*(float)((_FreqArray[j][n]/FSAMPLE))) * AMPL * 32768)); // Try 8388608 (+8 bits) w/ long coef + } + } +} + + +void IEC60601::_GenerateMultiTone (struct wave *t) { + long int y; + int i; + int env_weights; + long int output; + static long int output_old; + + output = 0; // clear output accumulator + for (i=0; i<5; i++) { // cycle through the 5 structures in the array + y = ((t->coef *(long long)(t->y1)>>14)) - t->y2; // Goertzel Calculation + t->y2 = t->y1; // store for next time + t->y1 = y; // store for next time + env_weights = _envelope * _ToneWeights[i]>>8; + output += ((t->y1 * env_weights) >> 8); // sum fundamental and harmonics + t++; // increment structure pointer + } + +//// DAC->DACR = ((output >> 10) & 0xFFC0) + 0x8000; // make unsigned and output to DAC +///// Adapt to mbed !!!! + LPC_DAC->DACR = ((output >> 10) & 0xFFC0) + 0x8000; // make unsigned and output to DAC + + + if ((output >= 0) && (output_old <= 0)) { // zero crossing detect + if (_envelope_off && (!_note_on)) { + _envelope_on = false; // sychronizes turn off with zero cross + _envelope_off = false; // reset envelope flag + } + } + output_old = output; +} + +#if(0) +void IEC60601::_OutputTones(Note_Type note, unsigned char level) { + + _note_level = level; + _GenerateMultiTone (&Waves[note][0]); +} +#endif + + +void IEC60601::_TimerInteruptHandler (void){ + static int timeval = 0; + +#if(DEBUG_ON) +// Activate Testpins for timing + TimInt = 1; +#endif + + if (_envelope_on) { +//Oude code +// _OutputTones(_active_note, _note_level); // parameters are set in sequencer + + _GenerateMultiTone (&_Waves[_active_note][0]); // parameters set in sequencer + } + + timeval++; + if (timeval == 25) { // millisecond interval (@ 25 khz sample rate) + +#if(DEBUG_ON) + // Activate Testpins for timing + SeqInt=1; +#endif + if (_sequence != 0) { + switch (_priority) { + case HIGH: + _HighPriSequence(); + break; + case MEDIUM: + _MedPriSequence(); + break; + case LOW: + _LowPriSequence(); + break; + case TEST: + _TestSequence(); + break; + } + } + timeval = 0; // clear interval counter + _mscount++; // increment ms counter + _EnvelopeControl(); + +#if(DEBUG_ON) + // Activate Testpins for timing + SeqInt=0; +#endif + } + +#if(DEBUG_ON) +// Activate Testpins for timing + TimInt = 0; +#endif + +} + + +