/** Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[5]. @param[in] VarName A Null-terminated string that is the name of the vendor's variable. @param[in] VendorGuid A unique identifier for the vendor. @param[out] VarSize The size of the variable data. @param[out] VarData Pointer to the content of the variable. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. @retval EFI_DEVICE_ERROR The operation was unsuccessful. **/ EFI_STATUS EFIAPI ReadAndMeasureBootVariable ( IN CHAR16 *VarName, IN EFI_GUID *VendorGuid, OUT UINTN *VarSize, OUT VOID **VarData ) { EFI_STATUS Status; *VarData = ReadVariable (VarName, VendorGuid, VarSize); if (*VarData == NULL) { return EFI_NOT_FOUND; } Status = MeasureVariable ( 5, EV_EFI_VARIABLE_BOOT, VarName, VendorGuid, *VarData, *VarSize ); return Status; }
int main(int argc, char* argv[]) { if (argc != 2) { printf("param error!\n"); return 0; } char *filename = argv[1]; lua_State *L = luaL_newstate(); luaL_openlibs(L); if(luaL_loadfile(L,filename) || lua_pcall(L,0,0,0)){ luaL_error(L,"loadfile error! %s \n",lua_tostring(L,-1)); } int w=1, h=2; ReadVariable(L, &w, &h); ReadTableFromItem(L, "luat_Test1", "a"); // 等价与lua代码:print(luat_Test1.a) ReadTableFromItem(L, "luat_Test1", "b"); ReadTableFromItem(L, "luat_Test1", "c"); EnumTableItem(L, "luat_Test1"); // 枚举Table ReadTableFromIndex(L, "luat_Test2", 1); // 等价与lua代码:print(luat_Test1[1]) ReadTableFromIndex(L, "luat_Test2", 2); ReadTableFromIndex(L, "luat_Test2", 3); EnumTableItem(L, "luat_Test2"); return 0; }
void MutableVars::ReadValues(std::istream& is) { while (is) { skip_comment(is); ReadVariable(is); } }
vtkDataSet * avtGTCFileFormat::GetMesh(int domain, const char *meshname) { Initialize(); // Allocate mesh. vtkPoints *points = vtkPoints::New(); points->SetNumberOfPoints(nPoints); vtkUnstructuredGrid *grid = vtkUnstructuredGrid::New(); grid->SetPoints(points); grid->Allocate(nPoints); //Read in particles. float *ptrXYZ = (float *) points->GetVoidPointer(0); ReadVariable( domain, 0, 3, &ptrXYZ ); // Set the IDs in the grid. vtkIdType vertID; for ( int i = 0; i < nPoints; i++ ) { vertID = i; grid->InsertNextCell( VTK_VERTEX, 1, &vertID ); } points->Delete(); return grid; }
void* InterpretedVM::ReadVariable(std::string name) const { for (auto& nameOp : prog.Names) { if (nameOp.second.Name == name) { return ReadVariable(nameOp.second.TargetId); } } return nullptr; }
; /*\ ;---|*|----====< Play MIDI >====---- ;---|*| ;---|*| play/record blocks of MIDI ;---|*| ;---|*| Copyright (c) 1993,1994 V.E.S.A, Inc. All Rights Reserved. ;---|*| Borland Turbo C++ adaptation (c) 2015 Krzysztof Kondrak ;---|*| ;---|*| VBE/AI 1.0 Specification ;---|*| February 2, 1994. 1.00 release ;---|*| ;---|*| Additional Changes: ;---|*| 04/05 - Changed the handling of the delta and track processing ;---|*| because the cheap quantization threw things out of order. ;---|*| 04/05 - Program didn't exit since the break was nested 2 deep. ;---|*| 03/10 - Added cheap quantization of the tempo to reduce the ;---|*| interrupt rate to drive the tempo. ;---|*| 02/27 - Removed a bunch of unused code to clean up the pgm ;---|*| 02/16 - Added a switch to allow sending Active Sensing as an option. ;---|*| 02/16 - Added a routine to send All Notes Off before exiting. ;---|*| ; \*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <ctype.h> #include "src/sound/midi.h" #include "src/sound/vbeai.h" #include "src/sound/vesa.h" #define TRUE -1 #define FALSE 0 #define ON TRUE #define OFF FALSE #if DEBUG #define BREAKPOINT _asm{int 3}; #else #define BREAKPOINT _asm{nop}; #endif ; /*\ ;---|*| External Variables ; \*/ // see: PDATA.C extern char *melodicnames[]; extern char *percussivenames[]; ; /*\ ;---|*| Global Variables ; \*/ typedef struct { char fileid[4]; // file ID - "MThd" long flen; // header length int ftype; // midi file type int ftracks; // number of tracks int fdiv; // time division } MIDIheader; typedef struct { char fileid[4]; // file ID - "MTrk" long flen; // midi track len } MDtrack; typedef struct { MDtrack mt; // Track Header int tnum; // track number long delta; // delta time counting char far *p; // pointer to the data } MIDItrack; int deltastep = 1; // incrementing step count long deltacount = 0; // full delta count #define MAXTRACKS 32 MIDIheader mhdr = { 0 }; // midi file header MIDItrack mtrk[32] = { 0 }; // track structures int CallBackOccured; int clocktick = 0; int ScatteredMessages = TRUE; VESAHANDLE hMIDI = 0; FILE *rfile; char far *memptr = 0; char far *midptr = 0; char *MIDFileName; GeneralDeviceClass gdc; // receives a copy of the VESA driver info block fpMIDServ msv; // pointer to MIDI functions #define FILE_UNK 0 #define FILE_MIDI 1 int filetype = FILE_UNK; char DoTracks[16] = { TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }; unsigned char PatchXlate[256]; // patch translation table unsigned char ChannelXlate[16]; // channel translation table int keyoffset = 0; // key (note) offset by one octave int patchoffset = 0; // no patch offset int tempooffset = 0; // no tempo offset int MicrosoftGMfmt = FALSE; // microsoft GM file format long micros = 500000; // 500ms per quarter note int sigdenom = 2; // qnote gets the beat int SystemMsgTick = 0; // system msg (0xFE) needed int msgsent = FALSE; // any msg has been sent int ActiveSensing = FALSE; // defaults to OFF ; /*\ ;---|*| prototypes ; \*/ int LoadMIDITrack(MIDItrack *); void MIDIEndFrame(void); int ProcessMidiMsg(MIDItrack *); void SystemMessage(unsigned int, MIDItrack *); void KeepActive(void); void ReportCallback(void); void DumpSomeInfo(void); int readblock(int, char huge *, int); int swapdw(int); long swapdd(long); long ReadVariable(MIDItrack *); void far pascal OurSystemMSGCallBack(void); void far pascal OurTimerCallBack(void); void far pascal OurMIDIReceiver(int, int, char, long); void SetSongTempo(long, int); VESAHANDLE OpenTheDriver(int); void OutputMidiMsg(char far *, int); void PrintMsg(int, char far *, int); int PatchIsLoaded(int ptch); int DriverError; int VerboseMode = FALSE; int StatusMode = FALSE; int UserPref = 0; // highest level to be used int maxtones; // maximum # of tones supported by the h/w int InputOnly = FALSE; // MIDI receiver tests int Breakneckspeed = FALSE;// helps me debug, not useful otherwise... char *msgnames[8] = { "Note Off", // 0x80 "Note On ", // 0x90 "Poly Key", // 0xA0 "Ctlr Chg", // 0xB0 "Pgm Chg", // 0xC0 "Chan Pre", // 0xD0 "Pitch wh", // 0xE0 "System " // 0xF0 }; // only allows us to run on this version of the VBE interface. This // will be removed after the interface is ratified. Changes may be made // that would cause this code to crash if run on other version. Again, // this will be removed in the final software. static int VersionControl = 0x0100; ; /*\ ;---|*|----------------------=======================--------------------------- ;---|*|----------------------====< Subroutines >====--------------------------- ;---|*|----------------------=======================--------------------------- ; \*/ int SetupMIDIDriver() { int n; // Find one MIDI device if (!OpenTheDriver(UserPref)) { // get the driver the user prefer printf("Cannot find any installed VBE/AI devices! (Did you run OPL2.COM?)\n"); return 0; } // setup a callback for active system messages VESARegisterTimer(254, &OurSystemMSGCallBack, VESARateToDivisor(5)); VESARegisterTimer(255, &OurTimerCallBack, VESARateToDivisor(120)); for (n=0; n<256; n++) PatchXlate[n] = n & 0x7F; // only 7 bits worth return 1; } int UpdateMIDI() { int n; int maxticks, ticks; int NotHalted; long l; int trk, deadcnt; int all, nxt; KeepActive(); // Callbacks occur to give us a tempo for MIDI timing if (CallBackOccured) { ReportCallback(); CallBackOccured--; // if we have run out of data, exit the program... deltacount += deltastep; while (1) { // find the track with the lowest delta time deadcnt = 0; for (nxt = n = 0; n < mhdr.ftracks; n++) { if (mtrk[n].mt.flen > 0) { if (mtrk[n].delta < mtrk[nxt].delta) nxt = n; } else { deadcnt++; if (nxt == n) nxt++; } } // if all tracks are dead, exit if (deadcnt >= mhdr.ftracks) { return 1; } // if higher that the current delta count, exit if (mtrk[nxt].delta > deltacount) break; ProcessMidiMsg(&mtrk[nxt]); } } // blast through the file for debugging purposes. Not for normal use if (Breakneckspeed) CallBackOccured++; MIDIEndFrame(); return 0; } void FastFwdMIDI() { int n; for (n = 0; n < mhdr.ftracks; n++) mtrk[n].delta = deltacount; } void PauseMIDI() { // flush our callback control VESARegisterTimer(255, 0, 0); // wait on the user... printf("Song Now Paused!\n"); while (!kbhit()) KeepActive(); getch(); // set the tempo & let'er rip! SetSongTempo(micros, sigdenom); } void MIDIEndFrame() { int laps = 10; // if the driver posts an error, go report it DriverError = (msv->msGetLastError)(); if (DriverError) printf("Driver is reporting an internal error! (code=%d)\n", DriverError); // if in status mode, dump status every x times through the loop if (StatusMode) { if (!--laps) { laps = 10; DumpSomeInfo(); } } } ; /*\ ;---|*|----====< AllNotesOff >====---- ;---|*| ;---|*| Turn each track off ;---|*| ; \*/ void AllNotesOff() { int n; char msg[3] = { 0, 0x7b, 0x00 }; for (n = 0; n < 16; n++) { msg[0] = 0xb0 + n; OutputMidiMsg(msg, 3); } } ; /*\ ;---|*|----====< ShutdownMIDI >====---- ;---|*| ;---|*| Shut down MIDI driver ;---|*| ; \*/ void ShutdownMIDI() { // close the device if already opened if (msv) VESACloseDevice(hMIDI); // close the device // flush our callback control VESARegisterTimer(255, 0, 0); VESARegisterTimer(254, 0, 0); } ; /*\ ;---|*|----====< ProcessMidiMsg >====---- ;---|*| ;---|*| Process the MIDI notes ;---|*| ; \*/ int ProcessMidiMsg(MIDItrack *m) { unsigned int status; char far *msg; char far *patch; int psize, ch, doit, idx; unsigned int ptch; static unsigned int running = 0; // if no more data, bail... if (!m->mt.flen) return 0; // get the status, make it running status = running; // maintain running status if (*m->p & 0x80) { if (((status = *m->p++ & 0xFF) & 0xF0) != 0xF0) running = status; m->mt.flen--; } // always send the message. Running status will be done later. *(msg = m->p - 1) = status; // load the message into memory // make sound if this is a track we want to hear if (DoTracks[ch = status & 0x0F]) { switch (status & 0xF0) { case 0x80: // Note Off if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { msg[0] = 0x89; // make it channel #9 msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF] & 0x7F; } else { msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits } PrintMsg(9, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0x90: // Note On // make sure all GM MIDI percussive channel patches // are loaded before starting if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { // for Microsofts MIDI channel 15 to channel 9 if ((ch == 15) && MicrosoftGMfmt) msg[0] = 0x99; // make it channel #9 // translate the patch from the 2nd half of the tbl ptch = PatchXlate[(msg[1] | 0x80) & 0xFF]; // if there are external patches, load them now if (gdc.u.gdmi.milibrary[0]) { // skip if preloaded if (!PatchIsLoaded(ptch | 0x80)) { // load the percussive patch now VESAPreLoadPatch(hMIDI, ptch, (msg[0] & 0x0F)); if (VerboseMode >= 7) printf("%s ", percussivenames[ptch]); PrintMsg(7, msg, 3); } } // save the translated patch # msg[1] = ptch; } else { msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits } PrintMsg(9, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xA0: // Poly Key Pressure if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF] & 0x7F; else msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits // falls through... case 0xB0: // Control Change case 0xE0: // Pitch Wheel change PrintMsg(6, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xC0: // Program Change // handle the percussive channel separate from melodics if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { // patch xlate on percussive patches ptch = (msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF]); // if MSGMFMT & channel 15, force to channel #9 if ((MicrosoftGMfmt) && (ch == 15)) { msg[0] = 0xC9; // make it channel #9 } if (VerboseMode >= 7) printf("%s ", percussivenames[ptch]); PrintMsg(7, msg, 2); } else { // patch xlate on melodic patches ptch = PatchXlate[msg[1] & 0x7F]; // translate to a new patch ptch = (ptch + patchoffset) & 0x7F;// offset the patch msg[1] = ptch; // save the patch if (VerboseMode >= 7) printf("%s ", melodicnames[ptch]); PrintMsg(7, msg, 2); } // if there is an external library, load a patch now if (gdc.u.gdmi.milibrary[0]) { // if preloaded, skip the process doit = FALSE; if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { if (!PatchIsLoaded(ptch | 0x80)) doit = TRUE; } else { if (!PatchIsLoaded(ptch)) doit = TRUE; } // if percussive or melodic needs one, do it if (doit) { // get the patch & get the size VESAPreLoadPatch(hMIDI, ptch, msg[0] & 0x0F); } } OutputMidiMsg(msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xD0: // Channel Pressure PrintMsg(6, msg, 2); OutputMidiMsg(msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xF0: PrintMsg(6, msg, 5); SystemMessage(status, m); break; default: PrintMsg(1, msg, 5); printf("Broken MIDI stream! (no status/running status!)\n"); return 0; } } // toss out these tracks else { switch (status & 0xF0) { case 0x80: // Note Off case 0x90: // Note On case 0xA0: // Poly Key Pressure case 0xB0: // Control Change case 0xE0: // Pitch Wheel change if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 3); m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xC0: // Program Change case 0xD0: // Channel Pressure if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xF0: // always do these... PrintMsg(9, msg, 5); SystemMessage(status, m); break; default: if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 5); printf("Broken MIDI stream! (no status/running status!)\n"); return -1; } } // get the next midi msg, or bail out if (m->mt.flen) m->delta += ReadVariable(m); // read the 1st delta from the file // return the adjusted track pointer return 1; } ; /*\ ;---|*|----====< OpenTheDriver >====---- ;---|*| ;---|*| Find the driver with the highest user preference, and return it to ;---|*| the caller ;---|*| ; \*/ VESAHANDLE OpenTheDriver(int pref) { int driverpref = 256; // real low preference long l; // get the device information do { // Find one MIDI device, else ]ail if non found if ((hMIDI = VESAFindADevice(MIDDEVICE)) == 0) { printf("No MIDI devices found.\n"); return 0; } // get the device information if (VESAQueryDevice(hMIDI, VESAQUERY2, &gdc) == 0) { printf("Cannot query the installed VBE/AI devices!\n"); return -1; } // make sure it's midi if (gdc.gdclassid != MIDDEVICE) { printf("The VESA find device query returned a NON MIDI device!\n"); return -1; } // make sure it's matches the beta version # if (gdc.gdvbever != VersionControl) { printf("The VESA device version # does not match, cannot continue!\n"); return -1; } // get the drivers user preference level driverpref = gdc.u.gdmi.midevpref; // if the caller is not expressing a preference, then use this one if (pref == -1) break; } while (driverpref != pref); // get the memory needed by the device if (!(memptr = AllocateBuffer(gdc.u.gdmi.mimemreq))) { printf("We don't have memory for the device!\n"); return -1; } if (!(midptr = AllocateBuffer(0xffff))) { printf("We don't have memory for the loading the MIDI file!\n"); return -1; } // if the MIDI device doesn't open, bomb out... if ((msv = (fpMIDServ)VESAOpenADevice(hMIDI, 0, memptr)) == 0) { printf("Cannot Open the installed devices!\n"); return -1; } // if there is a patch library, load it now... if (gdc.u.gdmi.milibrary[0]) if (VESALoadPatchBank(hMIDI, msv, &gdc.u.gdmi.milibrary[0]) == 0) { printf("Failed loading patch library.\n"); return -1; } // callbacks, reset & other things... msv->msApplMIDIIn = &OurMIDIReceiver; (msv->msGlobalReset)(); maxtones = gdc.u.gdmi.miactivetones; return(hMIDI); } ; /*\ ;---|*|----====< PatchIsLoaded >====---- ;---|*| ;---|*| Test the driver's bit table to determine if the patch is preloaded ;---|*| ; \*/ int PatchIsLoaded(int ptch) { int far *p = &msv->mspatches[0]; _asm { push es les bx, [p] mov ax, [ptch] and ax, 0FFh mov cx, ax shr ax, 3 add bx, ax and cx, 007h mov ax, 0080h shr ax, cl and ax, es:[bx] pop es } } ; /*\ ;---|*|----====< PrintMsg >====---- ;---|*| ;---|*| Print the MIDI messages (use for debugging) ;---|*| ; \*/ void PrintMsg(int level, char far *msg, int len) { int n; int cmd; char far *m; // verbose mode must be active to print if (!VerboseMode) return; // the priority level must be higher (0=highest, 5=lowest) if (level > VerboseMode) return; // get the command. change zero velocity NOTE ON to NOTE OFF cmd = (*msg & 0xF0) >> 4; if (cmd == 9) if (msg[2] == 0) cmd = 8; // print each byte in the string as a hex pair m = msg; for (n = len; n; n--) printf("%02x ", *m++ & 0xFF); // print the command name and a CR/LF printf("%s\n", msgnames[cmd - 8]); } ; /*\ ;---|*|----====< ReadVariable >====---- ;---|*| ;---|*| Read a variable length 32 bit number ;---|*| ; \*/ long ReadVariable(MIDItrack *m) { long result = 0; register char c; while (m->mt.flen) { result = (result << 7) + ((c = *m->p++) & 0x7F); m->mt.flen--; if (!(c & 0x80)) break; } return(result); } ; /*\ ;---|*|----====< SystemMessage >====---- ;---|*| ;---|*| Process a system message ;---|*| ; \*/ void SystemMessage(unsigned int status, MIDItrack *mtk) { long melen; long us; char metype; int n; // parse the SYSTEM mesage switch (status) { case 0xF7: // sysex scan case 0xF0: // sysex scan for the eot melen = ReadVariable(mtk); mtk->p += melen; // skip over the sysex mtk->mt.flen -= melen; break; case 0xF2: // state mtk->mt.flen--; // eat two parameters by mtk->p++; // falling through case 0xF1: // MTC Quarter-Frame case 0xF3: // continue mtk->mt.flen--; // eat one parameter... mtk->p++; case 0xF4: // undefined - no parameters case 0xF5: // undefined - no parameters case 0xF6: // active sensing case 0xF8: // timing clock case 0xF9: // undefined case 0xFA: // state case 0xFB: // continue case 0xFC: // stop case 0xFD: // undefined case 0xFE: // active sensing break; case 0xFF: // meta event. metype = *mtk->p++; // get the type mtk->mt.flen--; melen = ReadVariable(mtk); // get the length switch (metype) { case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // text messages mtk->mt.flen -= melen; // print all characters under 128 for (n = melen; n; n--) { if ((*mtk->p & 0x80) == 0) putchar(*mtk->p); mtk->p++; } printf("\n"); break; case 0x51: // microseconds per division us = (long)(*mtk->p++ & 0xff) << 16; us += (long)(*mtk->p++ & 0xff) << 8; us += (long)(*mtk->p++ & 0xff); mtk->mt.flen -= 3; SetSongTempo((micros = us), sigdenom); break; case 0x58: sigdenom = mtk->p[1]; // get the sign. denom mtk->mt.flen -= melen; mtk->p += melen; ////SetSongTempo ( micros, sigdenom ); break; default: mtk->p += melen; // just blow it off mtk->mt.flen -= melen; if (metype == 0x2F) { if (VerboseMode) printf("End of Track #%d\n", mtk->tnum); mtk->mt.flen = 0; mtk->delta = deltacount; } break; } break; default: break; } } ; /*\ ;---|*|----====< ProcessNote >====---- ;---|*| ;---|*| Perfrom a ramp of notes up and down ;---|*| ; \*/ void ProcessNote() { int n; int p; #define BASENOTE 30 static int direction = ON; static int note = BASENOTE; char midimsg[3] = { 0x90, 0x30, 0x7f }; // turn the voice on, or off if (direction == ON) { // if out of voices, start turning them off if ((msv->msDeviceCheck) (MIDITONES, 0) == 0) { direction = OFF; note = BASENOTE; } else { // build a message for NOTEON midimsg[1] += note++; // make each note different midimsg[2] = 0x7f; // full velocity if (note > 90) note = 90; // go play the note OutputMidiMsg(&midimsg[0], 3); } } if (direction == OFF) { if ((msv->msDeviceCheck) (MIDITONES, 0) == maxtones) { direction = ON; note = BASENOTE; } else { // build a message for NOTEON midimsg[1] += note++; // make each note different midimsg[2] = 0x00; // zero velocity if (note > 90) note = 90; // go stop the note OutputMidiMsg(&midimsg[0], 3); } } } ; /*\ ;---|*|----====< DumpSomeInfo >====---- ;---|*| ;---|*| Do direct screen writes to display our status information. Dumps ;---|*| 256 characters indicating the preloaded bits ;---|*| ; \*/ void DumpSomeInfo() { int far *vp = (int far *)0xB8000320; // starting on video row 5 int x, y, v, m; // display the preloaded bits in the services table for (y = 0; y < 16; y++) { v = msv->mspatches[y]; m = 0x0001; for (x = 0; x < 16; x++) { *vp++ = 0x3f30 + ((v & m) ? 1 : 0); m <<= 1; } } } ; /*\ ;---|*|----====< LoadMIDI >====---- ;---|*| ;---|*| Load the MIDI file ;---|*| ; \*/ int LoadMIDI(const char *filename) { int n; int fhan; long len; // This is playback, so load the MIDI file header, then each track if ((rfile = fopen(filename, "rb")) == NULL) { printf("cannot open the MIDI file %s!\n", filename); return -1; } fhan = fileno(rfile); readblock(fhan, (char huge *)&mhdr, sizeof(MIDIheader)); // intel fixup mhdr.flen = swapdd(mhdr.flen); mhdr.ftype = swapdw(mhdr.ftype); mhdr.ftracks = swapdw(mhdr.ftracks); mhdr.fdiv = swapdw(mhdr.fdiv); if (VerboseMode) { printf("mhdr.flen = %ld\n", mhdr.flen); printf("mhdr.ftype = %d\n", mhdr.ftype); printf("mhdr.ftracks = %d\n", mhdr.ftracks); printf("mhdr.fdiv = %d\n", mhdr.fdiv); } if (mhdr.fdiv < 0) { printf("%s file is not based upon PPQN time!\n", filename); return -1; } if (mhdr.ftracks > MAXTRACKS) { printf("WARNING: %s file has too many tracks!\n", filename); mhdr.ftracks = MAXTRACKS; // limit it to MAXTRACKS tracks } for (n = 0; n < mhdr.ftracks; n++) { mtrk[n].p = midptr; LoadMIDITrack(&mtrk[n]); midptr += mtrk[n].mt.flen; // get the next ptr mtrk[n].delta = ReadVariable(&mtrk[n]); // read the 1st delta from the file } deltacount = 0; fclose(rfile); return 1; }
// Serializable's functions const bool AreaLight::Read(std::istream &stream) { // Read the base if( !ReadHeader( stream, "Light" ) || !Light::Read( stream ) ) return false; Vector<float> vertex1, vertex2, vertex3; int numHorizontalSamples, numVerticalSamples; if( !ReadVariable( stream, "vertex1", vertex1 ) || !ReadVariable( stream, "vertex2", vertex2 ) || !ReadVariable( stream, "vertex3", vertex3 ) || !ReadVariable( stream, "numHorizontalSamples", numHorizontalSamples ) || !ReadVariable( stream, "numVerticalSamples", numVerticalSamples ) ) return false; SetRectangularArea( vertex1, vertex2, vertex3, numHorizontalSamples, numVerticalSamples ); if( !ReadFooter( stream, "AreaLight" ) ) return false; return true; }
void GBStackBrain::ExecuteInstruction(GBStackInstruction ins, GBRobot * robot, GBWorld * world) { GBStackInstruction index = ins & kOpcodeIndexMask; switch ( ins >> kOpcodeTypeShift ) { case otPrimitive: ExecutePrimitive(index, robot, world); break; case otConstantRead: Push(spec->ReadConstant(index)); break; case otVariableRead: Push(ReadVariable(index)); break; case otVariableWrite: WriteVariable(index, Pop()); break; case otVectorRead: PushVector(ReadVectorVariable(index)); break; case otVectorWrite: WriteVectorVariable(index, PopVector()); break; case otLabelRead: Push(spec->ReadLabel(index)); break; case otLabelCall: ExecuteCall(spec->ReadLabel(index)); break; case otHardwareRead: Push(ReadHardware(index, robot, world)); break; case otHardwareWrite: WriteHardware(index, Pop(), robot, world); break; case otHardwareVectorRead: PushVector(ReadHardwareVector(index, robot, world)); break; case otHardwareVectorWrite: WriteHardwareVector(index, PopVector(), robot, world); break; default: throw GBUnknownInstructionError(); break; } }
vtkDataArray * avtGTCFileFormat::GetVar(int domain, const char *varname) { const char *mName = "avtGTCFileFormat::GetVar: "; Initialize(); // Determine the variable index from the varname int varIdx = VarNameToIndex( varname ); if ( varIdx == -1 ) EXCEPTION1(InvalidVariableException, varname); debug4 << mName << "We want var " << varIdx << " for " << varname << endl; // Allocate the variable. vtkFloatArray *rv = vtkFloatArray::New(); rv->SetNumberOfTuples(nPoints); float *ptrVar = (float *) rv->GetVoidPointer(0); ReadVariable( domain, varIdx, 1, &ptrVar ); return rv; }
; /*\ ;---|*|----====< Play MIDI >====---- ;---|*| ;---|*| play/record blocks of MIDI ;---|*| ;---|*| Copyright (c) 1993,1994 V.E.S.A, Inc. All Rights Reserved. ;---|*| Borland Turbo C++ adaptation (c) 2015 Krzysztof Kondrak ;---|*| ;---|*| VBE/AI 1.0 Specification ;---|*| February 2, 1994. 1.00 release ;---|*| ;---|*| Additional Changes: ;---|*| 04/05 - Changed the handling of the delta and track processing ;---|*| because the cheap quantization threw things out of order. ;---|*| 04/05 - Program didn't exit since the break was nested 2 deep. ;---|*| 03/10 - Added cheap quantization of the tempo to reduce the ;---|*| interrupt rate to drive the tempo. ;---|*| 02/27 - Removed a bunch of unused code to clean up the pgm ;---|*| 02/16 - Added a switch to allow sending Active Sensing as an option. ;---|*| 02/16 - Added a routine to send All Notes Off before exiting. ;---|*| ; \*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <ctype.h> #include "src/sound/midi.h" #include "src/sound/vbeai.h" #include "src/sound/vesa.h" #define TRUE -1 #define FALSE 0 #define ON TRUE #define OFF FALSE #if DEBUG #define BREAKPOINT _asm{int 3}; #else #define BREAKPOINT _asm{nop}; #endif ; /*\ ;---|*| External Variables ; \*/ // see: PDATA.C extern char *melodicnames[]; extern char *percussivenames[]; ; /*\ ;---|*| Global Variables ; \*/ typedef struct { char fileid[4]; // file ID - "MThd" long flen; // header length int ftype; // midi file type int ftracks; // number of tracks int fdiv; // time division } MIDIheader; typedef struct { char fileid[4]; // file ID - "MTrk" long flen; // midi track len } MDtrack; typedef struct { MDtrack mt; // Track Header int tnum; // track number long delta; // delta time counting char far *p; // pointer to the data } MIDItrack; int deltastep = 1; // incrementing step count long deltacount = 0; // full delta count #define MAXTRACKS 32 MIDIheader mhdr = { 0 }; // midi file header MIDItrack mtrk[32] = { 0 }; // track structures int CallBackOccured; int clocktick = 0; int ScatteredMessages = TRUE; VESAHANDLE hMIDI = 0; FILE *rfile; char far *memptr = 0; char far *midptr = 0; char *MIDFileName; GeneralDeviceClass gdc; // receives a copy of the VESA driver info block fpMIDServ msv; // pointer to MIDI functions #define FILE_UNK 0 #define FILE_MIDI 1 int filetype = FILE_UNK; char DoTracks[16] = { TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }; unsigned char PatchXlate[256]; // patch translation table unsigned char ChannelXlate[16]; // channel translation table int keyoffset = 0; // key (note) offset by one octave int patchoffset = 0; // no patch offset int tempooffset = 0; // no tempo offset int MicrosoftGMfmt = FALSE; // microsoft GM file format long micros = 500000; // 500ms per quarter note int sigdenom = 2; // qnote gets the beat int SystemMsgTick = 0; // system msg (0xFE) needed int msgsent = FALSE; // any msg has been sent int ActiveSensing = FALSE; // defaults to OFF ; /*\ ;---|*| prototypes ; \*/ int LoadMIDITrack(MIDItrack *); void MIDIEndFrame(void); int ProcessMidiMsg(MIDItrack *); void SystemMessage(unsigned int, MIDItrack *); void KeepActive(void); void ReportCallback(void); void DumpSomeInfo(void); int readblock(int, char huge *, int); int swapdw(int); long swapdd(long); long ReadVariable(MIDItrack *); void far pascal OurSystemMSGCallBack(void); void far pascal OurTimerCallBack(void); void far pascal OurMIDIReceiver(int, int, char, long); void SetSongTempo(long, int); VESAHANDLE OpenTheDriver(int); void OutputMidiMsg(char far *, int); void PrintMsg(int, char far *, int); int PatchIsLoaded(int ptch); int DriverError; int VerboseMode = FALSE; int StatusMode = FALSE; int UserPref = 0; // highest level to be used int maxtones; // maximum # of tones supported by the h/w int InputOnly = FALSE; // MIDI receiver tests int Breakneckspeed = FALSE;// helps me debug, not useful otherwise... char *msgnames[8] = { "Note Off", // 0x80 "Note On ", // 0x90 "Poly Key", // 0xA0 "Ctlr Chg", // 0xB0 "Pgm Chg", // 0xC0 "Chan Pre", // 0xD0 "Pitch wh", // 0xE0 "System " // 0xF0 }; // only allows us to run on this version of the VBE interface. This // will be removed after the interface is ratified. Changes may be made // that would cause this code to crash if run on other version. Again, // this will be removed in the final software. static int VersionControl = 0x0100; ; /*\ ;---|*|----------------------=======================--------------------------- ;---|*|----------------------====< Subroutines >====--------------------------- ;---|*|----------------------=======================--------------------------- ; \*/ int SetupMIDIDriver() { int n; // Find one MIDI device if (!OpenTheDriver(UserPref)) { // get the driver the user prefer printf("Cannot find any installed VBE/AI devices! (Did you run OPL2.COM?)\n"); return 0; } // setup a callback for active system messages VESARegisterTimer(254, &OurSystemMSGCallBack, VESARateToDivisor(5)); VESARegisterTimer(255, &OurTimerCallBack, VESARateToDivisor(120)); for (n=0; n<256; n++) PatchXlate[n] = n & 0x7F; // only 7 bits worth return 1; } int UpdateMIDI() { int n; int maxticks, ticks; int NotHalted; long l; int trk, deadcnt; int all, nxt; KeepActive(); // Callbacks occur to give us a tempo for MIDI timing if (CallBackOccured) { ReportCallback(); CallBackOccured--; // if we have run out of data, exit the program... deltacount += deltastep; while (1) { // find the track with the lowest delta time deadcnt = 0; for (nxt = n = 0; n < mhdr.ftracks; n++) { if (mtrk[n].mt.flen > 0) { if (mtrk[n].delta < mtrk[nxt].delta) nxt = n; } else { deadcnt++; if (nxt == n) nxt++; } } // if all tracks are dead, exit if (deadcnt >= mhdr.ftracks) { return 1; } // if higher that the current delta count, exit if (mtrk[nxt].delta > deltacount) break; ProcessMidiMsg(&mtrk[nxt]); } } // blast through the file for debugging purposes. Not for normal use if (Breakneckspeed) CallBackOccured++; MIDIEndFrame(); return 0; } void FastFwdMIDI() { int n; for (n = 0; n < mhdr.ftracks; n++) mtrk[n].delta = deltacount; } void PauseMIDI() { // flush our callback control VESARegisterTimer(255, 0, 0); // wait on the user... printf("Song Now Paused!\n"); while (!kbhit()) KeepActive(); getch(); // set the tempo & let'er rip! SetSongTempo(micros, sigdenom); } void MIDIEndFrame() { int laps = 10; // if the driver posts an error, go report it DriverError = (msv->msGetLastError)(); if (DriverError) printf("Driver is reporting an internal error! (code=%d)\n", DriverError); // if in status mode, dump status every x times through the loop if (StatusMode) { if (!--laps) { laps = 10; DumpSomeInfo(); } } } ; /*\ ;---|*|----====< AllNotesOff >====---- ;---|*| ;---|*| Turn each track off ;---|*| ; \*/ void AllNotesOff() { int n; char msg[3] = { 0, 0x7b, 0x00 }; for (n = 0; n < 16; n++) { msg[0] = 0xb0 + n; OutputMidiMsg(msg, 3); } } ; /*\ ;---|*|----====< ShutdownMIDI >====---- ;---|*| ;---|*| Shut down MIDI driver ;---|*| ; \*/ void ShutdownMIDI() { // close the device if already opened if (msv) VESACloseDevice(hMIDI); // close the device // flush our callback control VESARegisterTimer(255, 0, 0); VESARegisterTimer(254, 0, 0); } ; /*\ ;---|*|----====< ProcessMidiMsg >====---- ;---|*| ;---|*| Process the MIDI notes ;---|*| ; \*/ int ProcessMidiMsg(MIDItrack *m) { unsigned int status; char far *msg; char far *patch; int psize, ch, doit, idx; unsigned int ptch; static unsigned int running = 0; // if no more data, bail... if (!m->mt.flen) return 0; // get the status, make it running status = running; // maintain running status if (*m->p & 0x80) { if (((status = *m->p++ & 0xFF) & 0xF0) != 0xF0) running = status; m->mt.flen--; } // always send the message. Running status will be done later. *(msg = m->p - 1) = status; // load the message into memory // make sound if this is a track we want to hear if (DoTracks[ch = status & 0x0F]) { switch (status & 0xF0) { case 0x80: // Note Off if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { msg[0] = 0x89; // make it channel #9 msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF] & 0x7F; } else { msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits } PrintMsg(9, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0x90: // Note On // make sure all GM MIDI percussive channel patches // are loaded before starting if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { // for Microsofts MIDI channel 15 to channel 9 if ((ch == 15) && MicrosoftGMfmt) msg[0] = 0x99; // make it channel #9 // translate the patch from the 2nd half of the tbl ptch = PatchXlate[(msg[1] | 0x80) & 0xFF]; // if there are external patches, load them now if (gdc.u.gdmi.milibrary[0]) { // skip if preloaded if (!PatchIsLoaded(ptch | 0x80)) { // load the percussive patch now VESAPreLoadPatch(hMIDI, ptch, (msg[0] & 0x0F)); if (VerboseMode >= 7) printf("%s ", percussivenames[ptch]); PrintMsg(7, msg, 3); } } // save the translated patch # msg[1] = ptch; } else { msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits } PrintMsg(9, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xA0: // Poly Key Pressure if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF] & 0x7F; else msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits // falls through... case 0xB0: // Control Change case 0xE0: // Pitch Wheel change PrintMsg(6, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xC0: // Program Change // handle the percussive channel separate from melodics if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { // patch xlate on percussive patches ptch = (msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF]); // if MSGMFMT & channel 15, force to channel #9 if ((MicrosoftGMfmt) && (ch == 15)) { msg[0] = 0xC9; // make it channel #9 } if (VerboseMode >= 7) printf("%s ", percussivenames[ptch]); PrintMsg(7, msg, 2); } else { // patch xlate on melodic patches ptch = PatchXlate[msg[1] & 0x7F]; // translate to a new patch ptch = (ptch + patchoffset) & 0x7F;// offset the patch msg[1] = ptch; // save the patch if (VerboseMode >= 7) printf("%s ", melodicnames[ptch]); PrintMsg(7, msg, 2); } // if there is an external library, load a patch now if (gdc.u.gdmi.milibrary[0]) { // if preloaded, skip the process doit = FALSE; if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { if (!PatchIsLoaded(ptch | 0x80)) doit = TRUE; } else { if (!PatchIsLoaded(ptch)) doit = TRUE; } // if percussive or melodic needs one, do it if (doit) { // get the patch & get the size VESAPreLoadPatch(hMIDI, ptch, msg[0] & 0x0F); } } OutputMidiMsg(msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xD0: // Channel Pressure PrintMsg(6, msg, 2); OutputMidiMsg(msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xF0: PrintMsg(6, msg, 5); SystemMessage(status, m); break; default: PrintMsg(1, msg, 5); printf("Broken MIDI stream! (no status/running status!)\n"); return 0; } } // toss out these tracks else { switch (status & 0xF0) { case 0x80: // Note Off case 0x90: // Note On case 0xA0: // Poly Key Pressure case 0xB0: // Control Change case 0xE0: // Pitch Wheel change if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 3); m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xC0: // Program Change case 0xD0: // Channel Pressure if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xF0: // always do these... PrintMsg(9, msg, 5); SystemMessage(status, m); break; default: if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 5); printf("Broken MIDI stream! (no status/running status!)\n"); return -1; } } // get the next midi msg, or bail out if (m->mt.flen) m->delta += ReadVariable(m); // read the 1st delta from the file // return the adjusted track pointer return 1; } ; /*\ ;---|*|----====< OpenTheDriver >====---- ;---|*| ;---|*| Find the driver with the highest user preference, and return it to ;---|*| the caller ;---|*| ; \*/ VESAHANDLE OpenTheDriver(int pref) { int driverpref = 256; // real low preference long l; // get the device information do { // Find one MIDI device, else ]ail if non found if ((hMIDI = VESAFindADevice(MIDDEVICE)) == 0) { printf("No MIDI devices found.\n"); return 0; } // get the device information if (VESAQueryDevice(hMIDI, VESAQUERY2, &gdc) == 0) { printf("Cannot query the installed VBE/AI devices!\n"); return -1; } // make sure it's midi if (gdc.gdclassid != MIDDEVICE) { printf("The VESA find device query returned a NON MIDI device!\n"); return -1; } // make sure it's matches the beta version # if (gdc.gdvbever != VersionControl) { printf("The VESA device version # does not match, cannot continue!\n"); return -1; } // get the drivers user preference level driverpref = gdc.u.gdmi.midevpref; // if the caller is not expressing a preference, then use this one if (pref == -1) break; } while (driverpref != pref); // get the memory needed by the device if (!(memptr = AllocateBuffer(gdc.u.gdmi.mimemreq))) { printf("We don't have memory for the device!\n"); return -1; } if (!(midptr = AllocateBuffer(0xffff))) { printf("We don't have memory for the loading the MIDI file!\n"); return -1; } // if the MIDI device doesn't open, bomb out... if ((msv = (fpMIDServ)VESAOpenADevice(hMIDI, 0, memptr)) == 0) { printf("Cannot Open the installed devices!\n"); return -1; } // if there is a patch library, load it now... if (gdc.u.gdmi.milibrary[0]) if (VESALoadPatchBank(hMIDI, msv, &gdc.u.gdmi.milibrary[0]) == 0) { printf("Failed loading patch library.\n"); return -1; } // callbacks, reset & other things... msv->msApplMIDIIn = &OurMIDIReceiver; (msv->msGlobalReset)(); maxtones = gdc.u.gdmi.miactivetones; return(hMIDI); } ; /*\ ;---|*|----====< PatchIsLoaded >====---- ;---|*| ;---|*| Test the driver's bit table to determine if the patch is preloaded ;---|*| ; \*/ int PatchIsLoaded(int ptch) { int far *p = &msv->mspatches[0]; _asm { push es les bx, [p] mov ax, [ptch] and ax, 0FFh mov cx, ax shr ax, 3 add bx, ax and cx, 007h mov ax, 0080h shr ax, cl and ax, es:[bx] pop es } } ; /*\ ;---|*|----====< PrintMsg >====---- ;---|*| ;---|*| Print the MIDI messages (use for debugging) ;---|*| ; \*/ void PrintMsg(int level, char far *msg, int len) { int n; int cmd; char far *m; // verbose mode must be active to print if (!VerboseMode) return; // the priority level must be higher (0=highest, 5=lowest) if (level > VerboseMode) return; // get the command. change zero velocity NOTE ON to NOTE OFF cmd = (*msg & 0xF0) >> 4; if (cmd == 9) if (msg[2] == 0) cmd = 8; // print each byte in the string as a hex pair m = msg; for (n = len; n; n--) printf("%02x ", *m++ & 0xFF); // print the command name and a CR/LF printf("%s\n", msgnames[cmd - 8]); } ; /*\ ;---|*|----====< ReadVariable >====---- ;---|*| ;---|*| Read a variable length 32 bit number ;---|*| ; \*/ long ReadVariable(MIDItrack *m) { long result = 0; register char c; while (m->mt.flen) { result = (result << 7) + ((c = *m->p++) & 0x7F); m->mt.flen--; if (!(c & 0x80)) break; } return(result); } ; /*\ ;---|*|----====< SystemMessage >====---- ;---|*| ;---|*| Process a system message ;---|*| ; \*/ void SystemMessage(unsigned int status, MIDItrack *mtk) { long melen; long us; char metype; int n; // parse the SYSTEM mesage switch (status) { case 0xF7: // sysex scan case 0xF0: // sysex scan for the eot melen = ReadVariable(mtk); mtk->p += melen; // skip over the sysex mtk->mt.flen -= melen; break; case 0xF2: // state mtk->mt.flen--; // eat two parameters by mtk->p++; // falling through case 0xF1: // MTC Quarter-Frame case 0xF3: // continue mtk->mt.flen--; // eat one parameter... mtk->p++; case 0xF4: // undefined - no parameters case 0xF5: // undefined - no parameters case 0xF6: // active sensing case 0xF8: // timing clock case 0xF9: // undefined case 0xFA: // state case 0xFB: // continue case 0xFC: // stop case 0xFD: // undefined case 0xFE: // active sensing break; case 0xFF: // meta event. metype = *mtk->p++; // get the type mtk->mt.flen--; melen = ReadVariable(mtk); // get the length switch (metype) { case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // text messages mtk->mt.flen -= melen; // print all characters under 128 for (n = melen; n; n--) { if ((*mtk->p & 0x80) == 0) putchar(*mtk->p); mtk->p++; } printf("\n"); break; case 0x51: // microseconds per division us = (long)(*mtk->p++ & 0xff) << 16; us += (long)(*mtk->p++ & 0xff) << 8; us += (long)(*mtk->p++ & 0xff); mtk->mt.flen -= 3; SetSongTempo((micros = us), sigdenom); break; case 0x58: sigdenom = mtk->p[1]; // get the sign. denom mtk->mt.flen -= melen; mtk->p += melen; ////SetSongTempo ( micros, sigdenom ); break; default: mtk->p += melen; // just blow it off mtk->mt.flen -= melen; if (metype == 0x2F) { if (VerboseMode) printf("End of Track #%d\n", mtk->tnum); mtk->mt.flen = 0; mtk->delta = deltacount; } break; } break; default: break; } }
; /*\ ;---|*|----====< Play MIDI >====---- ;---|*| ;---|*| play/record blocks of MIDI ;---|*| ;---|*| Copyright (c) 1993,1994 V.E.S.A, Inc. All Rights Reserved. ;---|*| Borland Turbo C++ adaptation (c) 2015 Krzysztof Kondrak ;---|*| ;---|*| VBE/AI 1.0 Specification ;---|*| February 2, 1994. 1.00 release ;---|*| ;---|*| Additional Changes: ;---|*| 04/05 - Changed the handling of the delta and track processing ;---|*| because the cheap quantization threw things out of order. ;---|*| 04/05 - Program didn't exit since the break was nested 2 deep. ;---|*| 03/10 - Added cheap quantization of the tempo to reduce the ;---|*| interrupt rate to drive the tempo. ;---|*| 02/27 - Removed a bunch of unused code to clean up the pgm ;---|*| 02/16 - Added a switch to allow sending Active Sensing as an option. ;---|*| 02/16 - Added a routine to send All Notes Off before exiting. ;---|*| ; \*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <ctype.h> #include "src/sound/midi.h" #include "src/sound/vbeai.h" #include "src/sound/vesa.h" #define TRUE -1 #define FALSE 0 #define ON TRUE #define OFF FALSE #if DEBUG #define BREAKPOINT _asm{int 3}; #else #define BREAKPOINT _asm{nop}; #endif ; /*\ ;---|*| External Variables ; \*/ // see: PDATA.C extern char *melodicnames[]; extern char *percussivenames[]; ; /*\ ;---|*| Global Variables ; \*/ typedef struct { char fileid[4]; // file ID - "MThd" long flen; // header length int ftype; // midi file type int ftracks; // number of tracks int fdiv; // time division } MIDIheader; typedef struct { char fileid[4]; // file ID - "MTrk" long flen; // midi track len } MDtrack; typedef struct { MDtrack mt; // Track Header int tnum; // track number long delta; // delta time counting char far *p; // pointer to the data } MIDItrack; int deltastep = 1; // incrementing step count long deltacount = 0; // full delta count #define MAXTRACKS 32 MIDIheader mhdr = { 0 }; // midi file header MIDItrack mtrk[32] = { 0 }; // track structures int CallBackOccured; int clocktick = 0; int ScatteredMessages = TRUE; VESAHANDLE hMIDI = 0; FILE *rfile; char far *memptr = 0; char far *midptr = 0; char *MIDFileName; GeneralDeviceClass gdc; // receives a copy of the VESA driver info block fpMIDServ msv; // pointer to MIDI functions #define FILE_UNK 0 #define FILE_MIDI 1 int filetype = FILE_UNK; char DoTracks[16] = { TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }; unsigned char PatchXlate[256]; // patch translation table unsigned char ChannelXlate[16]; // channel translation table int keyoffset = 0; // key (note) offset by one octave int patchoffset = 0; // no patch offset int tempooffset = 0; // no tempo offset int MicrosoftGMfmt = FALSE; // microsoft GM file format long micros = 500000; // 500ms per quarter note int sigdenom = 2; // qnote gets the beat int SystemMsgTick = 0; // system msg (0xFE) needed int msgsent = FALSE; // any msg has been sent int ActiveSensing = FALSE; // defaults to OFF ; /*\ ;---|*| prototypes ; \*/ int LoadMIDITrack(MIDItrack *); void MIDIEndFrame(void); int ProcessMidiMsg(MIDItrack *); void SystemMessage(unsigned int, MIDItrack *); void KeepActive(void); void ReportCallback(void); void DumpSomeInfo(void); int readblock(int, char huge *, int); int swapdw(int); long swapdd(long); long ReadVariable(MIDItrack *); void far pascal OurSystemMSGCallBack(void); void far pascal OurTimerCallBack(void); void far pascal OurMIDIReceiver(int, int, char, long); void SetSongTempo(long, int); VESAHANDLE OpenTheDriver(int); void OutputMidiMsg(char far *, int); void PrintMsg(int, char far *, int); int PatchIsLoaded(int ptch); int DriverError; int VerboseMode = FALSE; int StatusMode = FALSE; int UserPref = 0; // highest level to be used int maxtones; // maximum # of tones supported by the h/w int InputOnly = FALSE; // MIDI receiver tests int Breakneckspeed = FALSE;// helps me debug, not useful otherwise... char *msgnames[8] = { "Note Off", // 0x80 "Note On ", // 0x90 "Poly Key", // 0xA0 "Ctlr Chg", // 0xB0 "Pgm Chg", // 0xC0 "Chan Pre", // 0xD0 "Pitch wh", // 0xE0 "System " // 0xF0 }; // only allows us to run on this version of the VBE interface. This // will be removed after the interface is ratified. Changes may be made // that would cause this code to crash if run on other version. Again, // this will be removed in the final software. static int VersionControl = 0x0100; ; /*\ ;---|*|----------------------=======================--------------------------- ;---|*|----------------------====< Subroutines >====--------------------------- ;---|*|----------------------=======================--------------------------- ; \*/ int SetupMIDIDriver() { int n; // Find one MIDI device if (!OpenTheDriver(UserPref)) { // get the driver the user prefer printf("Cannot find any installed VBE/AI devices! (Did you run OPL2.COM?)\n"); return 0; } // setup a callback for active system messages VESARegisterTimer(254, &OurSystemMSGCallBack, VESARateToDivisor(5)); VESARegisterTimer(255, &OurTimerCallBack, VESARateToDivisor(120)); for (n=0; n<256; n++) PatchXlate[n] = n & 0x7F; // only 7 bits worth return 1; } int UpdateMIDI() { int n; int maxticks, ticks; int NotHalted; long l; int trk, deadcnt; int all, nxt; KeepActive(); // Callbacks occur to give us a tempo for MIDI timing if (CallBackOccured) { ReportCallback(); CallBackOccured--; // if we have run out of data, exit the program... deltacount += deltastep; while (1) { // find the track with the lowest delta time deadcnt = 0; for (nxt = n = 0; n < mhdr.ftracks; n++) { if (mtrk[n].mt.flen > 0) { if (mtrk[n].delta < mtrk[nxt].delta) nxt = n; } else { deadcnt++; if (nxt == n) nxt++; } } // if all tracks are dead, exit if (deadcnt >= mhdr.ftracks) { return 1; } // if higher that the current delta count, exit if (mtrk[nxt].delta > deltacount) break; ProcessMidiMsg(&mtrk[nxt]); } } // blast through the file for debugging purposes. Not for normal use if (Breakneckspeed) CallBackOccured++; MIDIEndFrame(); return 0; } void FastFwdMIDI() { int n; for (n = 0; n < mhdr.ftracks; n++) mtrk[n].delta = deltacount; } void PauseMIDI() { // flush our callback control VESARegisterTimer(255, 0, 0); // wait on the user... printf("Song Now Paused!\n"); while (!kbhit()) KeepActive(); getch(); // set the tempo & let'er rip! SetSongTempo(micros, sigdenom); } void MIDIEndFrame() { int laps = 10; // if the driver posts an error, go report it DriverError = (msv->msGetLastError)(); if (DriverError) printf("Driver is reporting an internal error! (code=%d)\n", DriverError); // if in status mode, dump status every x times through the loop if (StatusMode) { if (!--laps) { laps = 10; DumpSomeInfo(); } } } ; /*\ ;---|*|----====< AllNotesOff >====---- ;---|*| ;---|*| Turn each track off ;---|*| ; \*/ void AllNotesOff() { int n; char msg[3] = { 0, 0x7b, 0x00 }; for (n = 0; n < 16; n++) { msg[0] = 0xb0 + n; OutputMidiMsg(msg, 3); } } ; /*\ ;---|*|----====< ShutdownMIDI >====---- ;---|*| ;---|*| Shut down MIDI driver ;---|*| ; \*/ void ShutdownMIDI() { // close the device if already opened if (msv) VESACloseDevice(hMIDI); // close the device // flush our callback control VESARegisterTimer(255, 0, 0); VESARegisterTimer(254, 0, 0); } ; /*\ ;---|*|----====< ProcessMidiMsg >====---- ;---|*| ;---|*| Process the MIDI notes ;---|*| ; \*/ int ProcessMidiMsg(MIDItrack *m) { unsigned int status; char far *msg; char far *patch; int psize, ch, doit, idx; unsigned int ptch; static unsigned int running = 0; // if no more data, bail... if (!m->mt.flen) return 0; // get the status, make it running status = running; // maintain running status if (*m->p & 0x80) { if (((status = *m->p++ & 0xFF) & 0xF0) != 0xF0) running = status; m->mt.flen--; } // always send the message. Running status will be done later. *(msg = m->p - 1) = status; // load the message into memory // make sound if this is a track we want to hear if (DoTracks[ch = status & 0x0F]) { switch (status & 0xF0) { case 0x80: // Note Off if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { msg[0] = 0x89; // make it channel #9 msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF] & 0x7F; } else { msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits } PrintMsg(9, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0x90: // Note On // make sure all GM MIDI percussive channel patches // are loaded before starting if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { // for Microsofts MIDI channel 15 to channel 9 if ((ch == 15) && MicrosoftGMfmt) msg[0] = 0x99; // make it channel #9 // translate the patch from the 2nd half of the tbl ptch = PatchXlate[(msg[1] | 0x80) & 0xFF]; // if there are external patches, load them now if (gdc.u.gdmi.milibrary[0]) { // skip if preloaded if (!PatchIsLoaded(ptch | 0x80)) { // load the percussive patch now VESAPreLoadPatch(hMIDI, ptch, (msg[0] & 0x0F)); if (VerboseMode >= 7) printf("%s ", percussivenames[ptch]); PrintMsg(7, msg, 3); } } // save the translated patch # msg[1] = ptch; } else { msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits } PrintMsg(9, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xA0: // Poly Key Pressure if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF] & 0x7F; else msg[1] += keyoffset; // offset the note msg[1] &= 0x7F; // keep it in 7 bits // falls through... case 0xB0: // Control Change case 0xE0: // Pitch Wheel change PrintMsg(6, msg, 3); // display the msg OutputMidiMsg(msg, 3); // send it to the h/w m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xC0: // Program Change // handle the percussive channel separate from melodics if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { // patch xlate on percussive patches ptch = (msg[1] = PatchXlate[(msg[1] | 0x80) & 0xFF]); // if MSGMFMT & channel 15, force to channel #9 if ((MicrosoftGMfmt) && (ch == 15)) { msg[0] = 0xC9; // make it channel #9 } if (VerboseMode >= 7) printf("%s ", percussivenames[ptch]); PrintMsg(7, msg, 2); } else { // patch xlate on melodic patches ptch = PatchXlate[msg[1] & 0x7F]; // translate to a new patch ptch = (ptch + patchoffset) & 0x7F;// offset the patch msg[1] = ptch; // save the patch if (VerboseMode >= 7) printf("%s ", melodicnames[ptch]); PrintMsg(7, msg, 2); } // if there is an external library, load a patch now if (gdc.u.gdmi.milibrary[0]) { // if preloaded, skip the process doit = FALSE; if (((ch == 9) && DoTracks[9]) || ((MicrosoftGMfmt) && (ch == 15))) { if (!PatchIsLoaded(ptch | 0x80)) doit = TRUE; } else { if (!PatchIsLoaded(ptch)) doit = TRUE; } // if percussive or melodic needs one, do it if (doit) { // get the patch & get the size VESAPreLoadPatch(hMIDI, ptch, msg[0] & 0x0F); } } OutputMidiMsg(msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xD0: // Channel Pressure PrintMsg(6, msg, 2); OutputMidiMsg(msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xF0: PrintMsg(6, msg, 5); SystemMessage(status, m); break; default: PrintMsg(1, msg, 5); printf("Broken MIDI stream! (no status/running status!)\n"); return 0; } } // toss out these tracks else { switch (status & 0xF0) { case 0x80: // Note Off case 0x90: // Note On case 0xA0: // Poly Key Pressure case 0xB0: // Control Change case 0xE0: // Pitch Wheel change if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 3); m->mt.flen -= 2; // adjust the length m->p += 2; break; case 0xC0: // Program Change case 0xD0: // Channel Pressure if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 2); m->mt.flen--; // adjust the length m->p++; break; case 0xF0: // always do these... PrintMsg(9, msg, 5); SystemMessage(status, m); break; default: if (VerboseMode >= 9) printf(" "); PrintMsg(9, msg, 5); printf("Broken MIDI stream! (no status/running status!)\n"); return -1; } } // get the next midi msg, or bail out if (m->mt.flen) m->delta += ReadVariable(m); // read the 1st delta from the file // return the adjusted track pointer return 1; }
void LaserDiodeWork_Process(uint16_t pic_id) { bool update = false; uint16_t new_pic_id = pic_id; DGUS_LASERDIODE* value; ReadVariable(FRAMEDATA_LASERDIODE_BASE, (void**)&value, sizeof(frameData_LaserDiode)); if ((osSignalWait(DGUS_EVENT_SEND_COMPLETED, g_wDGUSTimeout).status != osEventTimeout) && (osSignalWait(DGUS_EVENT_RECEIVE_COMPLETED, g_wDGUSTimeout).status != osEventTimeout)) convert_laserdata(&frameData_LaserDiode, value); else return; if (pic_id == FRAME_PICID_LASERDIODE_STARTED) { if (Profile == PROFILE_SINGLE) { FlushesCount = 1; } if ((Profile != PROFILE_SINGLE) && (Profile != PROFILE_FAST)) FlushesCount = 1000000; DiodeLaser_en = true; g_procedure_type = PROCEDURE_TYPE_LDPHOTOEPILATION; } else { DiodeLaser_en = false; DiodeLaserOnePulse_en = false; } // Control peltier cooling CoolOn(); g_cooling_level = frameData_LaserDiode.cooling; CoolSet((frameData_LaserDiode.cooling + 1) * 17); if (frameData_LaserDiode.buttons.onReadyBtn != 0) { // On Ready Pressed frameData_LaserDiode.buttons.onReadyBtn = 0; new_pic_id = FRAME_PICID_LASERDIODE_START; __MISC_LASERDIODE_ON(); update = true; } if (frameData_LaserDiode.buttons.onStartBtn != 0) { // On Start Pressed frameData_LaserDiode.buttons.onStartBtn = 0; new_pic_id = FRAME_PICID_LASERDIODE_STARTED; DiodeLaser_en = true; update = true; } if (frameData_LaserDiode.buttons.onStopBtn != 0) { // On Stop Pressed frameData_LaserDiode.buttons.onStopBtn = 0; new_pic_id = FRAME_PICID_LASERDIODE_INPUT; DiodeLaser_en = false; DiodeControlPulseStop(); __MISC_LASERDIODE_OFF(); SetDACValue(0.0f); update = true; StoreGlobalVariables(); } if (frameData_LaserDiode.buttons.onCancelBtn != 0) { // On Stop Pressed frameData_LaserDiode.buttons.onCancelBtn = 0; new_pic_id = FRAME_PICID_LASERDIODE_INPUT; DiodeLaser_en = false; DiodeControlPulseStop(); __MISC_LASERDIODE_OFF(); SetDACValue(0.0f); update = true; StoreGlobalVariables(); } switch (pic_id) { case FRAME_PICID_LASERDIODE_READY: //__MISC_LASERDIODE_OFF(); break; case FRAME_PICID_LASERDIODE_START: //__MISC_LASERDIODE_ON(); break; case FRAME_PICID_LASERDIODE_STARTED: //__MISC_LASERDIODE_ON(); break; } if (frameData_LaserDiode.PulseCounter != FlushesGlobalLD) { frameData_LaserDiode.PulseCounter = FlushesGlobalLD; frameData_LaserDiode.SessionPulseCounter = FlushesSessionLD; update = true; } if (update) { WriteLaserDiodeDataConvert16(FRAMEDATA_LASERDIODE_BASE, &frameData_LaserDiode); osSignalWait(DGUS_EVENT_SEND_COMPLETED, g_wDGUSTimeout); } if (pic_id != new_pic_id && update) SetPicId(new_pic_id, g_wDGUSTimeout); }
void LongPulseLaserWork_Process(uint16_t pic_id) { bool update = false; uint16_t new_pic_id = pic_id; static int timeout_cnt = 0; DGUS_SOLIDSTATELASER* value; ReadVariable(FRAMEDATA_SOLIDSTATELASER_BASE, (void**)&value, sizeof(frameData_SolidStateLaser)); if ((osSignalWait(DGUS_EVENT_SEND_COMPLETED, g_wDGUSTimeout).status != osEventTimeout) && (osSignalWait(DGUS_EVENT_RECEIVE_COMPLETED, g_wDGUSTimeout).status != osEventTimeout)) { convert_laserdata_ss(&frameData_SolidStateLaser, value); timeout_cnt = 0; } else { timeout_cnt++; if (timeout_cnt > 2) { timeout_cnt = 0; // Solid State Laser Off footswitch_en = false; SolidStateLaser_en = false; LampControlPulseStop(); osDelay(100); __SOLIDSTATELASER_SIMMEROFF(); osDelay(100); __SOLIDSTATELASER_HVOFF(); osDelay(100); __SOLIDSTATELASER_DISCHARGEON(); new_pic_id = FRAME_PICID_LONGPULSE_INPUT; SoundOn(); __HAL_TIM_SET_AUTORELOAD(&hTIM11, 42000); HAL_TIM_Base_Start_IT(&hTIM11); update = true; } return; } uint16_t state = frameData_SolidStateLaser.state; osDelay(50); __SOLIDSTATELASER_DISCHARGEOFF(); if (pic_id >= 51 && pic_id <= 62 && pic_id != 55 && pic_id != 53) __SOLIDSTATELASER_HVON(); else __SOLIDSTATELASER_HVOFF(); if (pic_id >= 51 && pic_id <= 62 && pic_id != 53) __SOLIDSTATELASER_SIMMERON(); else __SOLIDSTATELASER_SIMMEROFF(); if (pic_id == FRAME_PICID_LONGPULSE_WORK) SolidStateLaser_en = true; else SolidStateLaser_en = false; //frameData_SolidStateLaser.state = 0; // Input pressed if (frameData_SolidStateLaser.buttons.onSimmerBtn != 0) { new_pic_id = FRAME_PICID_LONGPULSE_SIMMER; frameData_SolidStateLaser.state = 2; // On Input Pressed frameData_SolidStateLaser.buttons.onSimmerBtn = 0; update = true; } #ifdef DEBUG_SOLID_STATE_LASER static int16_t simmer_off_cnt = 0; if (!(__MISC_GETSIMMERSENSOR())) { simmer_off_cnt++; if (simmer_off_cnt > 10) simmer_off_cnt = 10; } else { simmer_off_cnt--; if (simmer_off_cnt < 0) simmer_off_cnt = 0; } if ((simmer_off_cnt > 5) && pic_id != 55 && pic_id != 53) { new_pic_id = FRAME_PICID_LONGPULSE_SIMMERSTART; // Solid State Laser Off footswitch_en = false; SolidStateLaser_en = false; LampControlPulseStop(); osDelay(1000); __SOLIDSTATELASER_HVOFF(); osDelay(1000); __SOLIDSTATELASER_SIMMEROFF(); osDelay(1000); __SOLIDSTATELASER_DISCHARGEON(); update = true; } #endif // Simmer wait if (pic_id == FRAME_PICID_LONGPULSE_SIMMER) { frameData_SolidStateLaser.state = 2; #ifdef DEBUG_SOLID_STATE_LASER if (__MISC_GETSIMMERSENSOR()) #endif { frameData_SolidStateLaser.state = 3; new_pic_id = FRAME_PICID_LONGPULSE_INPUT; update = true; } } // Start pressed if (frameData_SolidStateLaser.buttons.onStartBtn != 0) { // On Start Pressed frameData_SolidStateLaser.buttons.onStartBtn = 0; //LampControlPulseStart(); __MISC_LASERLED_ON(); new_pic_id = FRAME_PICID_LONGPULSE_WORK; update = true; } if (frameData_SolidStateLaser.buttons.onStopBtn != 0) { // On Input Pressed frameData_SolidStateLaser.buttons.onStopBtn = 0; __MISC_LASERLED_OFF(); SolidStateLaser_en = false; LampControlPulseStop(); __SOLIDSTATELASER_HVOFF(); //__SOLIDSTATELASER_SIMMEROFF(); SetDACValue(0.0f); frameData_SolidStateLaser.state = 0; new_pic_id = FRAME_PICID_LONGPULSE_INPUT; update = true; StoreGlobalVariables(); } if (frameData_SolidStateLaser.buttons.onCancelBtn != 0) { // On Input Pressed frameData_SolidStateLaser.buttons.onCancelBtn = 0; SolidStateLaser_en = false; LampControlPulseStop(); __SOLIDSTATELASER_HVOFF(); //__SOLIDSTATELASER_SIMMEROFF(); SetDACValue(0.0f); frameData_SolidStateLaser.state = 0; new_pic_id = FRAME_PICID_LONGPULSE_INPUT; update = true; StoreGlobalVariables(); } if (state != frameData_SolidStateLaser.state) update = true; if (frameData_SolidStateLaser.PulseCounter != GetSolidStateGlobalPulse(LaserID)) { frameData_SolidStateLaser.PulseCounter = GetSolidStateGlobalPulse(LaserID); frameData_SolidStateLaser.SessionPulseCounter = GetSolidStateSessionPulse(LaserID); update = true; } if (update) { WriteSolidStateLaserDataConvert16(FRAMEDATA_SOLIDSTATELASER_BASE, &frameData_SolidStateLaser); osSignalWait(DGUS_EVENT_SEND_COMPLETED, g_wDGUSTimeout); } if (pic_id != new_pic_id && update) SetPicId(new_pic_id, g_wDGUSTimeout); }
void CoolingServiceFrame_Process(uint16_t pic_id) { bool update = false; DGUS_COOLINGSETTINGS* value; ReadVariable(FRAMEDATA_COOLINGSERVICE_BASE, (void**)&value, sizeof(frameData_CoolingService)); if ((osSignalWait(DGUS_EVENT_SEND_COMPLETED, g_wDGUSTimeout).status != osEventTimeout) && (osSignalWait(DGUS_EVENT_RECEIVE_COMPLETED, g_wDGUSTimeout).status != osEventTimeout)) convert_array_w((uint16_t*)&frameData_CoolingService, (uint16_t*)value, sizeof(frameData_CoolingService)); else return; // Timeout if (frameData_CoolingService.CoolOffT != (uint16_t)(temperature_cool_off * 10)) { frameData_CoolingService.CoolOffT = (uint16_t)(temperature_cool_off * 10); update = true; } if (frameData_CoolingService.CoolOnT != (uint16_t)(temperature_cool_on * 10)) { frameData_CoolingService.CoolOnT = (uint16_t)(temperature_cool_on * 10); update = true; } if (frameData_CoolingService.DiodeOverheatingT != (uint16_t)(temperature_overheat * 10)) { frameData_CoolingService.DiodeOverheatingT = (uint16_t)(temperature_overheat * 10); update = true; } if (frameData_CoolingService.SSOverheatingT != (uint16_t)(temperature_overheat_solidstate * 10)) { frameData_CoolingService.SSOverheatingT = (uint16_t)(temperature_overheat_solidstate * 10); update = true; } if (frameData_CoolingService.FlowLowThreshold != (uint16_t)(flow_low * 10)) { frameData_CoolingService.FlowLowThreshold = (uint16_t)(flow_low * 10); update = true; } if (frameData_CoolingService.FlowNormalThreshold != (uint16_t)(flow_normal * 10)) { frameData_CoolingService.FlowNormalThreshold = (uint16_t)(flow_normal * 10); update = true; } uint16_t flowlow; if (flow1 < flow_low) flowlow = 1; else flowlow = 0; if (frameData_CoolingService.FlowLow != flowlow) { frameData_CoolingService.FlowLow = flowlow; update = true; } uint16_t flowready; if (flow1 >= flow_normal) flowready = 1; else flowready = 0; if (frameData_CoolingService.FlowReady != flowready) { frameData_CoolingService.FlowReady = flowready; update = true; } uint16_t overheating; if (temperature > temperature_overheat) overheating = 1; else overheating = 0; if (frameData_CoolingService.Overheating != overheating) { frameData_CoolingService.Overheating = overheating; update = true; } uint16_t ready; if ((flowlow != 1) && (flowready == 1) && (overheating != 0) && (temperature < temperature_cool_on)) ready = 1; else ready = 0; if (frameData_CoolingService.TemperatureReady != ready) { frameData_CoolingService.TemperatureReady = ready; update = true; } if (update) { WriteVariableConvert16(FRAMEDATA_COOLINGSERVICE_BASE, &frameData_CoolingService, sizeof(frameData_CoolingService)); osSignalWait(DGUS_EVENT_SEND_COMPLETED, g_wDGUSTimeout); } }