/*

		Benchmark dialogue

*/

#include "netfone.h"

#define BenchInterval	3000L		// Benchmark interval in milliseconds
#define BenchSamples	(8000L * (BenchInterval / 1000))  // Samples per interval

#define Speedo(item) wsprintf(ebuf, Format(76), (nbytes * 100) / BenchSamples); \
					 SetDlgItemText(hwnd, item, ebuf); \
					 DefaultMessageLoop(); \
					 SetCursor(LoadCursor(NULL, IDC_WAIT)); \
					 if (quitBench) goto bailOut

static int quitBench;


//	BENCHDLGPROC  --  Benchmark dialogue procedure

BOOL CALLBACK benchDlgProc(HWND hwnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
    switch (nMessage) {
        case WM_INITDIALOG:
#ifndef CRYPTO
			//	Disable all crypto-dependent fields if non-CRYPTO build
			{
				int i;

#define Dis(x) EnableWindow(GetDlgItem(hwnd, x), FALSE) 
				for (i = IDC_BE_CR1; i <= IDC_BE_CR8; i++) {
					Dis(i);
				}
				Dis(IDC_BE_E_AES);
				Dis(IDC_BE_D_AES);
				Dis(IDC_BE_E_DES);
				Dis(IDC_BE_D_DES);
				Dis(IDC_BE_E_DES_RTP);
				Dis(IDC_BE_D_DES_RTP);
				Dis(IDC_BE_E_IDEA);
				Dis(IDC_BE_D_IDEA);
				Dis(IDC_BE_E_BLOWFISH);
				Dis(IDC_BE_D_BLOWFISH);
				Dis(IDC_BE_E_KEYFILE);
				Dis(IDC_BE_D_KEYFILE);
			}
#endif
			ShowWindow(GetDlgItem(hwnd, IDC_BE_CANCEL), SW_HIDE);
			SetFocus(GetDlgItem(hwnd, IDC_BE_RUN));
			break;
				
        case WM_COMMAND:
        	switch ((short) WM_COMMAND_ID(wParam)) {
        	
		    	case IDOK:
				case IDCANCEL:
					EndDialog(hwnd, TRUE);
					break;

				case IDC_BE_CANCEL:
					quitBench = TRUE;
					break;

				case IDC_BE_RUN:
					ShowWindow(GetDlgItem(hwnd, IDC_BE_CANCEL), SW_SHOW);
					ShowWindow(GetDlgItem(hwnd, IDC_BE_RUN), SW_HIDE);
					EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
					SetFocus(GetDlgItem(hwnd, IDC_BE_CANCEL));
					UpdateWindow(hwnd);

					{
						/*	Attempt to diagnose wrong modes on coprocessor.
							Some versions of the Monkey C library don't set the
							coprocessor interrupt mask as documented.  This is
							a handy place to see if our work-around for this in
							the WinMain function (Netfone.c) has succeeded in
							setting the correct modes.  */

						unsigned int cpstat = _control87(0, 0);

						if ((cpstat & _MCW_EM) != _MCW_EM) {
							MsgBox(hwnd, MB_OK, "Coprocessor interrupt mask wrong: 0x%X, expected 0x%X",
								cpstat, _MCW_EM);
							_control87(_MCW_EM, _MCW_EM);
							cpstat = _control87(0, 0);
							if ((cpstat & _MCW_EM) != _MCW_EM) {
								MsgBox(hwnd, MB_OK, "Could not reset interrupt mask:  got 0x%X, expected 0x%X",
									cpstat, _MCW_EM);
							}
						}
					}
					quitBench = FALSE;
					{
						char *raw = ebuf.buffer.buffer_val,
							 *out = raw + 1600;
						DWORD sticks, nbytes;
						char ebuf[20];
						int running;
						HCURSOR ocursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

						/*	Create some data for the CODECs to chew on.  Since
							all the existing algorithms run at the same speed
							regardless of the input, this is just a nicety.  */

						{
							int i;

							srand(1234);
							for (i = 0; i < 1600; i++) {
#ifndef WHITE_NOISE
								raw[i] = rand() & 0xFF;
#else
#define Hz(x)	8191.0 * sin((i * 3.14159 * 8000.0) / (x))
								raw[i] = audio_s2u((int) (Hz(75) + Hz(800) + Hz(1200) +
											Hz(200))); 							
#endif
							}
						}

						//	Compression mode benchmarks

						//	Simple (2X)

						{
#ifdef OBSOLETE
							int i;
							register char *ab;
							char *val;
#else
							rate_t srate;
							int li, lo;
							unsigned char odecode[1600];
#endif

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							rate_start(&srate, 8000, 4000);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
#ifdef OBSOLETE
								for (i = 0; i < 800; i++) {
									out[i] = raw[i * 2];
								}
#else
								li = 1600;
								lo = 800;
								rate_flow(&srate, (unsigned char *) raw, (unsigned char *) out,
										  &li, &lo);
#endif
								nbytes += 1600;
							}
							Speedo(IDC_BE_C_SIMPLE);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							rate_start(&srate, 4000, 8000);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
#ifdef OBSOLETE
								ab = out + 800;
								val = out;
								for (i = 0; i < 800; i++) {
									*ab++ = i == 0 ? *val :
										(audio_s2u((audio_u2s(*val) + audio_u2s(val[-1])) / 2));
									*ab++ = *val++;
									ab -= 2;		// Kludge so it doesn't overflow
								}
#else
								li = 800;
								lo = 1600;

								rate_flow(&srate, (unsigned char *) out, odecode, &li, &lo);
#endif
								nbytes += 1600;
							}
							Speedo(IDC_BE_D_SIMPLE);
						}

						//	ADPCM

						{
							struct adpcm_state adpcm;	  // ADPCM compression state

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								adpcm_coder_u(raw, out, 1600, &adpcm);
								nbytes += 1600;
							}
							Speedo(IDC_BE_C_ADPCM);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								adpcm_decoder_u(out, raw, 1600, &adpcm);
								nbytes += 1600;
							}
							Speedo(IDC_BE_D_ADPCM);
						}

						//	CELP

						{
							short src[240];
							char celp_frame[18];
							int i, j, k;

#ifdef CELP_USE_CONTEXT
							struct celp_context *b_celpc;

							b_celpc = (struct celp_context *) GlobalAllocPtr(GPTR, sizeof(struct celp_context));
							if (b_celpc != NULL) {
								celp_context_init(b_celpc);
								celp_init(b_celpc, FALSE);
#endif
	    
								sticks = GetTickCount();
								nbytes = 0;
								running = TRUE;
								while (running) {
									for (i = k = 0; i < 1440; i += 240) {
										if ((GetTickCount() - sticks) > BenchInterval) {
											running = FALSE;
											break;
										}
										for (j = 0; j < 240; j++) {
											src[j] = audio_u2s(raw[i + j]);
										}
#ifdef CELP_USE_CONTEXT
										celp_encode(b_celpc, src, celp_frame);
#else
										celp_encode(src, celp_frame);
#endif
										nbytes += 240;
										memcpy(out + k, celp_frame, sizeof celp_frame);
										k += sizeof sizeof celp_frame; 
									}
								}
								Speedo(IDC_BE_C_CELP);

								sticks = GetTickCount();
								nbytes = 0;
								running = TRUE;
								while (running) {
									for (i = j = 0; i < 6; i++) {
										if ((GetTickCount() - sticks) > BenchInterval) {
											running = FALSE;
											break;
										}
#ifdef CELP_USE_CONTEXT
										celp_decode(b_celpc, out + j, src);
#else
										celp_decode(out + j, src);
#endif
										for (k = 0; k < 240; k++) {
											celp_frame[k & 15] = audio_s2u(out[k]);
										}
										j += 18;
										nbytes += 240;
									}
								}
								Speedo(IDC_BE_D_CELP);
								GlobalFreePtr(b_celpc);
							}
						}

						//	GSM

						{
							gsm_signal src[160];
							gsm_frame dst;
							int i, j, k;
    
							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								for (i = k = 0; i < 1600; i += 160) {
									if ((GetTickCount() - sticks) > BenchInterval) {
										running = FALSE;
										break;
									}
									for (j = 0; j < 160; j++) {
										src[j] = audio_u2s(raw[i + j]);
									}
									gsm_encode(gsmh, src, dst);
									nbytes += 160;
									memcpy(out + k, &dst, sizeof dst);
									k += sizeof dst; 
								}
							}
							Speedo(IDC_BE_C_GSM);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								for (i = 0; i < 10; i++) {
									if ((GetTickCount() - sticks) > BenchInterval) {
										running = FALSE;
										break;
									}
									gsm_decode(gsmh, (gsm_byte *) (out + (i * sizeof dst)), src);
									for (j = 0; j < 160; j++) {
										out[400 + j] = audio_s2u(dst[j]);
									}
									nbytes += 160;
								}
							}
							Speedo(IDC_BE_D_GSM);
						}

						//	LPC

						{
							lpcparams_t lp;
							int i, k;
							lpcstate_t state;
    
							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								for (i = k = 0; i < 1600; i += 160) {
									if ((GetTickCount() - sticks) > BenchInterval) {
										running = FALSE;
										break;
									}
									lpc_analyze(raw + i, &lp);
									nbytes += 160;
									memcpy(out + k, &lp, sizeof lp);
									k += sizeof lp; 
								}
							}
							Speedo(IDC_BE_C_LPC);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								for (i = 0; i < 10; i++) {
									if ((GetTickCount() - sticks) > BenchInterval) {
										running = FALSE;
										break;
									}
									lpc_synthesize(out + 400,
										(lpcparams_t *) (out + (i * sizeof lp)),
										&state);
									nbytes += 160;
								}
							}
							Speedo(IDC_BE_D_LPC);
						}

						//	LPC-10

						{
							int i, j;
    
							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								j = lpc10encode(raw, out, 1440);
								nbytes += 1440;
							}
							Speedo(IDC_BE_C_LPC10);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								i = lpc10decode(out, out + 100, j);
								nbytes += i;
							}
							Speedo(IDC_BE_D_LPC10);
						}

#ifdef CRYPTO

						//	Encryption benchmarks

						//	AES

						{
							aes_ctx ectx, dctx;

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							ectx.n_rnd = ectx.n_blk = 0;
							aes_enc_key(raw, 16, &ectx);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								AES_cbc_encrypt((unsigned char *) raw,
											    (unsigned char *) raw,
											    1600, &ectx);
								nbytes += 1600;
							}
							Speedo(IDC_BE_E_AES);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							dctx.n_rnd = dctx.n_blk = 0;
							aes_dec_key(raw, 16, &dctx);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}        
								AES_cbc_decrypt((unsigned char *) raw,
											    (unsigned char *) raw,
											    1600, &dctx);
								nbytes += 1600;
							}
							Speedo(IDC_BE_D_AES);
						}

						//	DES (Speak Freely protocol)

						{
							int i;
							char tbuf[8], bbuf[8];

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							setkey(raw);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								for (i = 0; i < 1600; i += 8) {
									if (i > 0) {
										int j;

										for (j = 0; j < 8; j++) {
											raw[(i + j)] ^= raw[(i + j) - 8];
										}
									}
									endes(raw + i);
								}
								nbytes += 1600;
							}
							Speedo(IDC_BE_E_DES);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								for (i = 0; i < 1600; i += 8) {
									memcpy(tbuf, raw + i, 8);
									dedes(raw + i);

									/* Reverse cipher block chaining. */

									if (i > 0) {
										int j;

										for (j = 0; j < 8; j++) {
											raw[(i + j)] ^= bbuf[j];
										}
									}
									memcpy(bbuf, tbuf, 8);
								}
								nbytes += 1600;
							}
							Speedo(IDC_BE_D_DES);
						}

						//	DES (VAT/RTP protocol)

						{
							des_key_schedule sched;
							des_cblock ivec;

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							des_set_key((des_cblock *) raw, sched);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								memset(ivec, 0, 8);
								des_ncbc_encrypt((des_cblock *) raw,
									(des_cblock *) raw, 1600, sched,
									(des_cblock *) ivec, DES_ENCRYPT);
								nbytes += 1600;
							}
							Speedo(IDC_BE_E_DES_RTP);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								memset(ivec, 0, 8);
								des_ncbc_encrypt((des_cblock *) raw,
									(des_cblock *) raw, 1600, sched,
									(des_cblock *) ivec, DES_DECRYPT);
								nbytes += 1600;
							}
							Speedo(IDC_BE_D_DES_RTP);
						}

						//	IDEA

						{
							unsigned short iv[4];

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							memset(iv, 0, sizeof(iv));
							initcfb_idea(iv, raw, FALSE);
							while (running) {
	        					if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								ideacfb(raw, 1600);
								nbytes += 1600;
							}
							close_idea();
							Speedo(IDC_BE_E_IDEA);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							memset(iv, 0, sizeof(iv));
							initcfb_idea(iv, raw, TRUE);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								ideacfb(raw, 1600);
								nbytes += 1600;
							}
							close_idea();
							Speedo(IDC_BE_D_IDEA);
						}

						//	Blowfish

						{
							BF_KEY bfkey;

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							BF_set_key(&bfkey, 16, raw);
							while (running) {
								unsigned char iv[8];
	        
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								memset(iv, 0, sizeof(iv));
								BF_cbc_encrypt((unsigned char *) raw,
											   (unsigned char *) raw,
											   1600, &bfkey, iv, BF_ENCRYPT);
								nbytes += 1600;
							}
							Speedo(IDC_BE_E_BLOWFISH);

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							BF_set_key(&bfkey, 16, raw);
							while (running) {
								unsigned char iv[8];
        
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								memset(iv, 0, sizeof(iv));
        
								BF_cbc_encrypt((unsigned char *) raw,
											   (unsigned char *) raw,
											   1600, &bfkey, iv, BF_DECRYPT);
								nbytes += 1600;
							}
							Speedo(IDC_BE_D_BLOWFISH);
						}

						//	Key file

						{
							int i;

							sticks = GetTickCount();
							nbytes = 0;
							running = TRUE;
							setkey(raw);
							while (running) {
								if ((GetTickCount() - sticks) > BenchInterval) {
									running = FALSE;
									break;
								}
								for (i = 0; i < 1600; i++) {
									raw[i] ^= out[i];	
								}
								nbytes += 1600;
							}
							Speedo(IDC_BE_E_KEYFILE);
							Speedo(IDC_BE_D_KEYFILE);
						}
#endif // CRYPTO

bailOut:				SetCursor(ocursor);
					}
					ShowWindow(GetDlgItem(hwnd, IDC_BE_CANCEL), SW_HIDE);
					ShowWindow(GetDlgItem(hwnd, IDC_BE_RUN), SW_SHOW);
					EnableWindow(GetDlgItem(hwnd, IDOK), TRUE);
					SetFocus(GetDlgItem(hwnd, IDOK));
					break;

                case ID_HELP:
                	displayHelpTopic(IDS_HELP_BENCH);
                	break;
			}
    }
    return FALSE;
}

//	BENCHDIALOGUE  --  Benchmark dialogue

VOID benchDialogue(HWND hwnd)
{
    DialogBox(hInst, MAKEINTRESOURCE(IDD_BENCH), hwnd, benchDlgProc);
}
